From dianders at chromium.org  Mon Oct  2 08:14:50 2017
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 2 Oct 2017 08:14:50 -0700
Subject: [PATCH] ASoC: rockchip: Fix wrong allocation size of dapm routes
In-Reply-To: <20170929035252.19808-1-jeffy.chen@rock-chips.com>
References: <20170929035252.19808-1-jeffy.chen@rock-chips.com>
Message-ID: <CAD=FV=V+sVf8E_ka1u5kDBKWS6MY3vMpaVgmjDV1CnVSOkQ3AA@mail.gmail.com>

Hi,

On Thu, Sep 28, 2017 at 8:52 PM, Jeffy Chen <jeffy.chen at rock-chips.com> wrote:
> The allocation size of dapm routes is wrong, correct it.
>
> Fixes: d9f9c167edae ("ASoC: rockchip: Init dapm routes dynamically")
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
>
>  sound/soc/rockchip/rk3399_gru_sound.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)

I guess Jeffy and I found this independently.  In
http://crosreview.com/693319 Jeffy indicated that he thought my patch
could land, so I guess drop his and take mine from
<https://patchwork.kernel.org/patch/9978763/>?

Thanks!

-Doug


From wens at csie.org  Mon Oct  2 19:32:04 2017
From: wens at csie.org (Chen-Yu Tsai)
Date: Tue, 3 Oct 2017 10:32:04 +0800
Subject: [PATCH] extcon: Split out extcon header file for consumer and
 provider device
In-Reply-To: <1506643305-4581-1-git-send-email-cw00.choi@samsung.com>
References: <CGME20170929000148epcas2p200e56186b067ec626a033c7ae2d4bbdb@epcas2p2.samsung.com>
 <1506643305-4581-1-git-send-email-cw00.choi@samsung.com>
Message-ID: <CAGb2v641HBJ0MPZMx0YhOMWZeNKNiUJ48r-2Gh3WE7x41wJy4g@mail.gmail.com>

On Fri, Sep 29, 2017 at 8:01 AM, Chanwoo Choi <cw00.choi at samsung.com> wrote:
> The extcon has two type of extcon devices as following.
> - 'extcon provider deivce' adds new extcon device and detect the
>    state/properties of external connector. Also, it notifies the
>    state/properties to the extcon consumer device.
> - 'extcon consumer device' gets the change state/properties
>    from extcon provider device.
> Prior to that, include/linux/extcon.h contains all exported API for
> both provider and consumer device driver. To clarify the meaning of
> header file and to remove the wrong use-case on consumer device,
> this patch separates into extcon.h and extcon-provider.h.
>
> [Description for include/linux/{extcon.h|extcon-provider.h}]
> - extcon.h includes the extcon API and data structure for extcon consumer
>   device driver. This header file contains the following APIs:
>   : Register/unregister the notifier to catch the change of extcon device
>   : Get the extcon device instance
>   : Get the extcon device name
>   : Get the state of each external connector
>   : Get the property value of each external connector
>   : Get the property capability of each external connector
>
> - extcon-provider.h includes the extcon API and data structure for extcon
>   provider device driver. This header file contains the following APIs:
>   : Include 'include/linux/extcon.h'
>   : Allocate the memory for extcon device instance
>   : Register/unregister extcon device
>   : Set the state of each external connector
>   : Set the property value of each external connector
>   : Set the property capability of each external connector
>
> Cc: Felipe Balbi <balbi at kernel.org>
> Cc: Kishon Vijay Abraham I <kishon at ti.com>
> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> Cc: Sebastian Reichel <sre at kernel.org>
> Cc: Lee Jones <lee.jones at linaro.org>
> Signed-off-by: Chanwoo Choi <cw00.choi at samsung.com>
> ---

For

>  drivers/extcon/extcon-axp288.c                |   2 +-

and

>  drivers/phy/allwinner/phy-sun4i-usb.c         |   2 +-

Acked-by: Chen-Yu Tsai <wens at csie.org>


From ckeepax at opensource.cirrus.com  Tue Oct  3 01:58:48 2017
From: ckeepax at opensource.cirrus.com (Charles Keepax)
Date: Tue, 3 Oct 2017 09:58:48 +0100
Subject: [PATCH] extcon: Split out extcon header file for consumer and
 provider device
In-Reply-To: <1506643305-4581-1-git-send-email-cw00.choi@samsung.com>
References: <CGME20170929000148epcas2p200e56186b067ec626a033c7ae2d4bbdb@epcas2p2.samsung.com>
 <1506643305-4581-1-git-send-email-cw00.choi@samsung.com>
Message-ID: <20171003085848.tma5l5lq4yavddli@localhost.localdomain>

On Fri, Sep 29, 2017 at 09:01:45AM +0900, Chanwoo Choi wrote:
> The extcon has two type of extcon devices as following.
> - 'extcon provider deivce' adds new extcon device and detect the
>    state/properties of external connector. Also, it notifies the
>    state/properties to the extcon consumer device.
> - 'extcon consumer device' gets the change state/properties
>    from extcon provider device.
> Prior to that, include/linux/extcon.h contains all exported API for
> both provider and consumer device driver. To clarify the meaning of
> header file and to remove the wrong use-case on consumer device,
> this patch separates into extcon.h and extcon-provider.h.
> 
> [Description for include/linux/{extcon.h|extcon-provider.h}]
> - extcon.h includes the extcon API and data structure for extcon consumer
>   device driver. This header file contains the following APIs:
>   : Register/unregister the notifier to catch the change of extcon device
>   : Get the extcon device instance
>   : Get the extcon device name
>   : Get the state of each external connector
>   : Get the property value of each external connector
>   : Get the property capability of each external connector
> 
> - extcon-provider.h includes the extcon API and data structure for extcon
>   provider device driver. This header file contains the following APIs:
>   : Include 'include/linux/extcon.h'
>   : Allocate the memory for extcon device instance
>   : Register/unregister extcon device
>   : Set the state of each external connector
>   : Set the property value of each external connector
>   : Set the property capability of each external connector
> 
> Cc: Felipe Balbi <balbi at kernel.org>
> Cc: Kishon Vijay Abraham I <kishon at ti.com>
> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> Cc: Sebastian Reichel <sre at kernel.org>
> Cc: Lee Jones <lee.jones at linaro.org>
> Signed-off-by: Chanwoo Choi <cw00.choi at samsung.com>
> ---
>  drivers/extcon/extcon-arizona.c               |   2 +-

Acked-by: Charles Keepax <ckeepax at opensource.cirrus.com>

Thanks,
Charles


From jacobchen110 at gmail.com  Tue Oct  3 02:04:35 2017
From: jacobchen110 at gmail.com (Jacob Chen)
Date: Tue, 3 Oct 2017 17:04:35 +0800
Subject: [PATCH v9 1/4] rockchip/rga: v4l2 m2m support
In-Reply-To: <cadb4981-ca1c-babc-b8b2-6c9f01196ea2@xs4all.nl>
References: <1505351957-14479-1-git-send-email-jacob-chen@iotwrt.com>
 <1505351957-14479-2-git-send-email-jacob-chen@iotwrt.com>
 <cadb4981-ca1c-babc-b8b2-6c9f01196ea2@xs4all.nl>
Message-ID: <CAFLEztS=0kK7q_R=SV2rVR3kp22oos6Gb-XS8mGkoNGpN6w_wQ@mail.gmail.com>

Hi Hans,

2017-09-22 20:02 GMT+08:00 Hans Verkuil <hverkuil at xs4all.nl>:
> Hi Jacob,
>
> Sorry for the delay, but here is my review.
>
> I noticed that there is no patch for the MAINTAINERS file, please add an entry
> there for this driver.
>
> On 14/09/17 03:19, Jacob Chen wrote:
>> Rockchip RGA is a separate 2D raster graphic acceleration unit. It
>> accelerates 2D graphics operations, such as point/line drawing, image
>> scaling, rotation, BitBLT, alpha blending and image blur/sharpness
>>
>> The drvier is mostly based on s5p-g2d v4l2 m2m driver
>
> drvier -> driver
>
>> And supports various operations from the rendering pipeline.
>>  - copy
>>  - fast solid color fill
>>  - rotation
>>  - flip
>>  - alpha blending
>>
>> The code in rga-hw.c is used to configure regs according to operations
>> The code in rga-buf.c is used to create private mmu table for RGA.
>>
>> changes in V7:
>> - fix some warning reported by "checkpatch --strict"
>>
>> Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
>> ---
>>  drivers/media/platform/Kconfig                |   11 +
>>  drivers/media/platform/Makefile               |    2 +
>>  drivers/media/platform/rockchip-rga/Makefile  |    3 +
>>  drivers/media/platform/rockchip-rga/rga-buf.c |  156 ++++
>>  drivers/media/platform/rockchip-rga/rga-hw.c  |  435 +++++++++++
>>  drivers/media/platform/rockchip-rga/rga-hw.h  |  437 +++++++++++
>>  drivers/media/platform/rockchip-rga/rga.c     | 1030 +++++++++++++++++++++++++
>>  drivers/media/platform/rockchip-rga/rga.h     |  110 +++
>>  8 files changed, 2184 insertions(+)
>>  create mode 100644 drivers/media/platform/rockchip-rga/Makefile
>>  create mode 100644 drivers/media/platform/rockchip-rga/rga-buf.c
>>  create mode 100644 drivers/media/platform/rockchip-rga/rga-hw.c
>>  create mode 100644 drivers/media/platform/rockchip-rga/rga-hw.h
>>  create mode 100644 drivers/media/platform/rockchip-rga/rga.c
>>  create mode 100644 drivers/media/platform/rockchip-rga/rga.h
>
> If there are more rockchip v4l2 drivers planned, then I recommend changing
> the patch to rockchip/rga. That way other drivers can be added under the
> rockchip directory.
>
>>
>> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
>> index 7e7cc49..9b79350 100644
>> --- a/drivers/media/platform/Kconfig
>> +++ b/drivers/media/platform/Kconfig
>> @@ -458,6 +458,17 @@ config VIDEO_RENESAS_VSP1
>>         To compile this driver as a module, choose M here: the module
>>         will be called vsp1.
>>
>> +config VIDEO_ROCKCHIP_RGA
>> +     tristate "Rockchip Raster 2d Grapphic Acceleration Unit"
>> +     depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
>> +     depends on ARCH_ROCKCHIP || COMPILE_TEST
>> +     select VIDEOBUF2_DMA_SG
>> +     select V4L2_MEM2MEM_DEV
>> +     default n
>> +     ---help---
>> +       This is a v4l2 driver for Rockchip SOC RGA2
>> +       2d graphics accelerator.
>
> This is a bit too short. Why not use the same text as in this commit log?
>
>> +
>>  config VIDEO_TI_VPE
>>       tristate "TI VPE (Video Processing Engine) driver"
>>       depends on VIDEO_DEV && VIDEO_V4L2
>> diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
>> index c1ef946..06039c3 100644
>> --- a/drivers/media/platform/Makefile
>> +++ b/drivers/media/platform/Makefile
>> @@ -62,6 +62,8 @@ obj-$(CONFIG_VIDEO_RENESAS_FDP1)    += rcar_fdp1.o
>>  obj-$(CONFIG_VIDEO_RENESAS_JPU)      += rcar_jpu.o
>>  obj-$(CONFIG_VIDEO_RENESAS_VSP1)     += vsp1/
>>
>> +obj-$(CONFIG_VIDEO_ROCKCHIP_RGA)     += rockchip-rga/
>> +
>>  obj-y        += omap/
>>
>>  obj-$(CONFIG_VIDEO_AM437X_VPFE)              += am437x/
>> diff --git a/drivers/media/platform/rockchip-rga/Makefile b/drivers/media/platform/rockchip-rga/Makefile
>> new file mode 100644
>> index 0000000..92fe254
>> --- /dev/null
>> +++ b/drivers/media/platform/rockchip-rga/Makefile
>> @@ -0,0 +1,3 @@
>> +rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
>> +
>> +obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
>> diff --git a/drivers/media/platform/rockchip-rga/rga-buf.c b/drivers/media/platform/rockchip-rga/rga-buf.c
>> new file mode 100644
>> index 0000000..373c36f
>> --- /dev/null
>> +++ b/drivers/media/platform/rockchip-rga/rga-buf.c
>> @@ -0,0 +1,156 @@
>> +/*
>> + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd
>> + * Author: Jacob Chen <jacob-chen at iotwrt.com>
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * 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 <linux/pm_runtime.h>
>> +
>> +#include <media/v4l2-device.h>
>> +#include <media/v4l2-ioctl.h>
>> +#include <media/v4l2-mem2mem.h>
>> +#include <media/videobuf2-dma-sg.h>
>> +#include <media/videobuf2-v4l2.h>
>> +
>> +#include "rga-hw.h"
>> +#include "rga.h"
>> +
>> +static int
>> +rga_queue_setup(struct vb2_queue *vq,
>> +             unsigned int *nbuffers, unsigned int *nplanes,
>> +             unsigned int sizes[], struct device *alloc_devs[])
>> +{
>> +     struct rga_ctx *ctx = vb2_get_drv_priv(vq);
>> +     struct rga_frame *f = rga_get_frame(ctx, vq->type);
>> +
>> +     if (IS_ERR(f))
>> +             return PTR_ERR(f);
>> +
>> +     if (*nplanes)
>> +             return sizes[0] < f->size ? -EINVAL : 0;
>> +
>> +     sizes[0] = f->size;
>> +     *nplanes = 1;
>> +
>> +     return 0;
>> +}
>> +
>> +static int rga_buf_prepare(struct vb2_buffer *vb)
>> +{
>> +     struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
>> +     struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
>> +
>> +     if (IS_ERR(f))
>> +             return PTR_ERR(f);
>> +
>> +     vb2_set_plane_payload(vb, 0, f->size);
>> +
>> +     return 0;
>> +}
>> +
>> +static void rga_buf_queue(struct vb2_buffer *vb)
>> +{
>> +     struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> +     struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
>> +
>> +     v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
>> +}
>> +
>> +static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
>> +{
>> +     struct rga_ctx *ctx = vb2_get_drv_priv(q);
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     int ret, i;
>> +
>> +     ret = pm_runtime_get_sync(rga->dev);
>> +
>> +     if (ret < 0) {
>
> I'd change this to:
>
>         if (!ret)
>                 return 0;
>
> then do the for loop. Saves one indent and is easier to read.
>
>> +             for (i = 0; i < q->num_buffers; ++i) {
>> +                     if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
>> +                             v4l2_m2m_buf_done(
>> +                                     to_vb2_v4l2_buffer(q->bufs[i]),
>> +                                     VB2_BUF_STATE_QUEUED);
>> +                     }
>> +             }
>> +
>> +             return ret;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static void rga_buf_stop_streaming(struct vb2_queue *q)
>> +{
>> +     struct rga_ctx *ctx = vb2_get_drv_priv(q);
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     struct vb2_v4l2_buffer *vbuf;
>> +
>> +     for (;;) {
>> +             if (V4L2_TYPE_IS_OUTPUT(q->type))
>> +                     vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
>> +             else
>> +                     vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
>> +             if (!vbuf)
>> +                     break;
>> +             v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
>> +     }
>> +
>> +     pm_runtime_put(rga->dev);
>> +}
>> +
>> +const struct vb2_ops rga_qops = {
>> +     .queue_setup = rga_queue_setup,
>> +     .buf_prepare = rga_buf_prepare,
>> +     .buf_queue = rga_buf_queue,
>> +     .wait_prepare = vb2_ops_wait_prepare,
>> +     .wait_finish = vb2_ops_wait_finish,
>> +     .start_streaming = rga_buf_start_streaming,
>> +     .stop_streaming = rga_buf_stop_streaming,
>> +};
>> +
>> +/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API.
>> + * We use it more like a scatter-gather list.
>> + */
>> +void rga_buf_map(struct vb2_buffer *vb)
>> +{
>> +     struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     struct sg_table *sgt;
>> +     struct scatterlist *sgl;
>> +     unsigned int *pages;
>> +     unsigned int address, len, i, p;
>> +     unsigned int mapped_size = 0;
>> +
>> +     if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
>> +             pages = rga->src_mmu_pages;
>> +     else
>> +             pages = rga->dst_mmu_pages;
>> +
>> +     /* Create local MMU table for RGA */
>> +     sgt = vb2_plane_cookie(vb, 0);
>> +
>> +     for_each_sg(sgt->sgl, sgl, sgt->nents, i) {
>> +             len = sg_dma_len(sgl) >> PAGE_SHIFT;
>> +             address = sg_phys(sgl);
>> +
>> +             for (p = 0; p < len; p++) {
>> +                     dma_addr_t phys = address + (p << PAGE_SHIFT);
>> +
>> +                     pages[mapped_size + p] = phys;
>> +             }
>> +
>> +             mapped_size += len;
>> +     }
>> +
>> +     /* sync local MMU table for RGA */
>> +     dma_sync_single_for_device(rga->dev, virt_to_phys(pages),
>> +                                8 * PAGE_SIZE, DMA_BIDIRECTIONAL);
>> +}
>> diff --git a/drivers/media/platform/rockchip-rga/rga-hw.c b/drivers/media/platform/rockchip-rga/rga-hw.c
>> new file mode 100644
>> index 0000000..38c5242
>> --- /dev/null
>> +++ b/drivers/media/platform/rockchip-rga/rga-hw.c
>> @@ -0,0 +1,435 @@
>> +/*
>> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
>> + * Author: Jacob Chen <jacob-chen at iotwrt.com>
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * 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 <linux/pm_runtime.h>
>> +
>> +#include "rga-hw.h"
>> +#include "rga.h"
>> +
>> +enum e_rga_start_pos {
>> +     LT = 0,
>> +     LB = 1,
>> +     RT = 2,
>> +     RB = 3,
>> +};
>> +
>> +struct rga_addr_offset {
>> +     unsigned int y_off;
>> +     unsigned int u_off;
>> +     unsigned int v_off;
>> +};
>> +
>> +struct rga_corners_addr_offset {
>> +     struct rga_addr_offset left_top;
>> +     struct rga_addr_offset right_top;
>> +     struct rga_addr_offset left_bottom;
>> +     struct rga_addr_offset right_bottom;
>> +};
>> +
>> +static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
>> +{
>> +     /*
>> +      * The rga hw scaling factor is a normalized inverse of the
>> +      * scaling factor.
>> +      * For example: When source width is 100 and destination width is 200
>> +      * (scaling of 2x), then the hw factor is NC * 100 / 200.
>> +      * The normalization factor (NC) is 2^16 = 0x10000.
>> +      */
>> +
>> +     return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);
>> +}
>> +
>> +static struct rga_corners_addr_offset
>> +rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y,
>> +                 unsigned int w, unsigned int h)
>> +{
>> +     struct rga_corners_addr_offset offsets;
>> +     struct rga_addr_offset *lt, *lb, *rt, *rb;
>> +     unsigned int x_div = 0,
>> +                  y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0;
>> +
>> +     lt = &offsets.left_top;
>> +     lb = &offsets.left_bottom;
>> +     rt = &offsets.right_top;
>> +     rb = &offsets.right_bottom;
>> +
>> +     x_div = frm->fmt->x_div;
>> +     y_div = frm->fmt->y_div;
>> +     uv_factor = frm->fmt->uv_factor;
>> +     uv_stride = frm->stride / x_div;
>> +     pixel_width = frm->stride / frm->width;
>> +
>> +     lt->y_off = y * frm->stride + x * pixel_width;
>> +     lt->u_off =
>> +             frm->width * frm->height + (y / y_div) * uv_stride + x / x_div;
>> +     lt->v_off = lt->u_off + frm->width * frm->height / uv_factor;
>> +
>> +     lb->y_off = lt->y_off + (h - 1) * frm->stride;
>> +     lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
>> +     lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;
>> +
>> +     rt->y_off = lt->y_off + (w - 1) * pixel_width;
>> +     rt->u_off = lt->u_off + w / x_div - 1;
>> +     rt->v_off = lt->v_off + w / x_div - 1;
>> +
>> +     rb->y_off = lb->y_off + (w - 1) * pixel_width;
>> +     rb->u_off = lb->u_off + w / x_div - 1;
>> +     rb->v_off = lb->v_off + w / x_div - 1;
>> +
>> +     return offsets;
>> +}
>> +
>> +static struct rga_addr_offset *rga_lookup_draw_pos(struct
>> +             rga_corners_addr_offset
>> +             * offsets, u32 rotate_mode,
>> +             u32 mirr_mode)
>> +{
>> +     static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {
>> +             {
>> +                     LT, RT, LB, RB,
>> +             },
>> +             {
>> +                     RT, LT, RB, LB,
>> +             },
>> +             {
>> +                     RB, LB, RT, LT,
>> +             },
>> +             {
>> +                     LB, RB, LT, RT,
>> +             },
>> +     };
>> +
>> +     if (!offsets)
>> +             return NULL;
>> +
>> +     switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {
>> +     case LT:
>> +             return &offsets->left_top;
>> +     case LB:
>> +             return &offsets->left_bottom;
>> +     case RT:
>> +             return &offsets->right_top;
>> +     case RB:
>> +             return &offsets->right_bottom;
>> +     }
>> +
>> +     return NULL;
>> +}
>> +
>> +static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages)
>> +{
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     u32 *dest = rga->cmdbuf_virt;
>> +     unsigned int reg;
>> +
>> +     reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
>> +     dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
>> +
>> +     reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
>> +     dest[reg >> 2] |= 0x7;
>> +}
>> +
>> +static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages)
>> +{
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     u32 *dest = rga->cmdbuf_virt;
>> +     unsigned int reg;
>> +
>> +     reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
>> +     dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
>> +
>> +     reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
>> +     dest[reg >> 2] |= 0x7 << 4;
>> +}
>> +
>> +static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages)
>> +{
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     u32 *dest = rga->cmdbuf_virt;
>> +     unsigned int reg;
>> +
>> +     reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
>> +     dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
>> +
>> +     reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
>> +     dest[reg >> 2] |= 0x7 << 8;
>> +}
>> +
>> +static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
>> +{
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     u32 *dest = rga->cmdbuf_virt;
>> +     unsigned int scale_dst_w, scale_dst_h;
>> +     unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y;
>> +     union rga_src_info src_info;
>> +     union rga_dst_info dst_info;
>> +     union rga_src_x_factor x_factor;
>> +     union rga_src_y_factor y_factor;
>> +     union rga_src_vir_info src_vir_info;
>> +     union rga_src_act_info src_act_info;
>> +     union rga_dst_vir_info dst_vir_info;
>> +     union rga_dst_act_info dst_act_info;
>> +
>> +     struct rga_addr_offset *dst_offset;
>> +     struct rga_corners_addr_offset offsets;
>> +     struct rga_corners_addr_offset src_offsets;
>> +
>> +     src_h = ctx->in.crop.height;
>> +     src_w = ctx->in.crop.width;
>> +     src_x = ctx->in.crop.left;
>> +     src_y = ctx->in.crop.top;
>> +     dst_h = ctx->out.crop.height;
>> +     dst_w = ctx->out.crop.width;
>> +     dst_x = ctx->out.crop.left;
>> +     dst_y = ctx->out.crop.top;
>> +
>> +     src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2];
>> +     dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2];
>> +     x_factor.val = dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2];
>> +     y_factor.val = dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2];
>> +     src_vir_info.val = dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
>> +     src_act_info.val = dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
>> +     dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
>> +     dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
>> +
>> +     src_info.data.format = ctx->in.fmt->hw_format;
>> +     src_info.data.swap = ctx->in.fmt->color_swap;
>> +     dst_info.data.format = ctx->out.fmt->hw_format;
>> +     dst_info.data.swap = ctx->out.fmt->color_swap;
>> +
>> +     if (ctx->in.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
>> +             if (ctx->out.fmt->hw_format < RGA_COLOR_FMT_YUV422SP) {
>> +                     switch (ctx->in.colorspace) {
>> +                     case V4L2_COLORSPACE_REC709:
>> +                             src_info.data.csc_mode =
>> +                                     RGA_SRC_CSC_MODE_BT709_R0;
>> +                             break;
>> +                     default:
>> +                             src_info.data.csc_mode =
>> +                                     RGA_SRC_CSC_MODE_BT601_R0;
>> +                             break;
>> +                     }
>> +             }
>> +     }
>> +
>> +     if (ctx->out.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
>> +             switch (ctx->out.colorspace) {
>> +             case V4L2_COLORSPACE_REC709:
>> +                     dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
>> +                     break;
>> +             default:
>> +                     dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0;
>> +                     break;
>> +             }
>> +     }
>> +
>> +     if (ctx->vflip)
>> +             src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X;
>> +
>> +     if (ctx->hflip)
>> +             src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y;
>> +
>> +     switch (ctx->rotate) {
>> +     case 90:
>> +             src_info.data.rot_mode = RGA_SRC_ROT_MODE_90_DEGREE;
>> +             break;
>> +     case 180:
>> +             src_info.data.rot_mode = RGA_SRC_ROT_MODE_180_DEGREE;
>> +             break;
>> +     case 270:
>> +             src_info.data.rot_mode = RGA_SRC_ROT_MODE_270_DEGREE;
>> +             break;
>> +     default:
>> +             src_info.data.rot_mode = RGA_SRC_ROT_MODE_0_DEGREE;
>> +             break;
>> +     }
>> +
>> +     /*
>> +      * Cacluate the up/down scaling mode/factor.
>> +      *
>> +      * RGA used to scale the picture first, and then rotate second,
>> +      * so we need to swap the w/h when rotate degree is 90/270.
>> +      */
>> +     if (src_info.data.rot_mode == RGA_SRC_ROT_MODE_90_DEGREE ||
>> +         src_info.data.rot_mode == RGA_SRC_ROT_MODE_270_DEGREE) {
>> +             if (rga->version.major == 0 || rga->version.minor == 0) {
>> +                     if (dst_w == src_h)
>> +                             src_h -= 8;
>> +                     if (abs(src_w - dst_h) < 16)
>> +                             src_w -= 16;
>> +             }
>> +
>> +             scale_dst_h = dst_w;
>> +             scale_dst_w = dst_h;
>> +     } else {
>> +             scale_dst_w = dst_w;
>> +             scale_dst_h = dst_h;
>> +     }
>> +
>> +     if (src_w == scale_dst_w) {
>> +             src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_NO;
>> +             x_factor.val = 0;
>> +     } else if (src_w > scale_dst_w) {
>> +             src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN;
>> +             x_factor.data.down_scale_factor =
>> +                     rga_get_scaling(src_w, scale_dst_w) + 1;
>> +     } else {
>> +             src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_UP;
>> +             x_factor.data.up_scale_factor =
>> +                     rga_get_scaling(src_w - 1, scale_dst_w - 1);
>> +     }
>> +
>> +     if (src_h == scale_dst_h) {
>> +             src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_NO;
>> +             y_factor.val = 0;
>> +     } else if (src_h > scale_dst_h) {
>> +             src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN;
>> +             y_factor.data.down_scale_factor =
>> +                     rga_get_scaling(src_h, scale_dst_h) + 1;
>> +     } else {
>> +             src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_UP;
>> +             y_factor.data.up_scale_factor =
>> +                     rga_get_scaling(src_h - 1, scale_dst_h - 1);
>> +     }
>> +
>> +     /*
>> +      * Cacluate the framebuffer virtual strides and active size,
>> +      * note that the step of vir_stride / vir_width is 4 byte words
>> +      */
>> +     src_vir_info.data.vir_stride = ctx->in.stride >> 2;
>> +     src_vir_info.data.vir_width = ctx->in.stride >> 2;
>> +
>> +     src_act_info.data.act_height = src_h - 1;
>> +     src_act_info.data.act_width = src_w - 1;
>> +
>> +     dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
>> +     dst_act_info.data.act_height = dst_h - 1;
>> +     dst_act_info.data.act_width = dst_w - 1;
>> +
>> +     /*
>> +      * Cacluate the source framebuffer base address with offset pixel.
>> +      */
>> +     src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y,
>> +                                       src_w, src_h);
>> +
>> +     /*
>> +      * Configure the dest framebuffer base address with pixel offset.
>> +      */
>> +     offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h);
>> +     dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode,
>> +                                      src_info.data.mir_mode);
>> +
>> +     dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
>> +             src_offsets.left_top.y_off;
>> +     dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
>> +             src_offsets.left_top.u_off;
>> +     dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
>> +             src_offsets.left_top.v_off;
>> +
>> +     dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;
>> +     dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;
>> +     dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;
>> +     dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;
>> +
>> +     dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;
>> +
>> +     dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
>> +             dst_offset->y_off;
>> +     dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
>> +             dst_offset->u_off;
>> +     dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
>> +             dst_offset->v_off;
>> +
>> +     dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;
>> +     dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;
>> +
>> +     dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;
>> +}
>> +
>> +static void rga_cmd_set_mode(struct rga_ctx *ctx)
>> +{
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     u32 *dest = rga->cmdbuf_virt;
>> +     union rga_mode_ctrl mode;
>> +     union rga_alpha_ctrl0 alpha_ctrl0;
>> +     union rga_alpha_ctrl1 alpha_ctrl1;
>> +
>> +     mode.val = 0;
>> +     alpha_ctrl0.val = 0;
>> +     alpha_ctrl1.val = 0;
>> +
>> +     mode.data.gradient_sat = 1;
>> +     mode.data.render = RGA_MODE_RENDER_BITBLT;
>> +     mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST;
>> +
>> +     /* disable alpha blending */
>> +     dest[(RGA_ALPHA_CTRL0 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl0.val;
>> +     dest[(RGA_ALPHA_CTRL1 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl1.val;
>> +
>> +     dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;
>> +}
>> +
>> +void rga_cmd_set(struct rga_ctx *ctx)
>> +{
>> +     struct rockchip_rga *rga = ctx->rga;
>> +
>> +     memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
>> +
>> +     rga_cmd_set_src_addr(ctx, rga->src_mmu_pages);
>> +     /*
>> +      * Due to hardware bug,
>> +      * src1 mmu also should be configured when using alpha blending.
>> +      */
>> +     rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages);
>> +
>> +     rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages);
>> +     rga_cmd_set_mode(ctx);
>> +
>> +     rga_cmd_set_trans_info(ctx);
>> +
>> +     rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
>> +}
>> +
>> +void rga_write(struct rockchip_rga *rga, u32 reg, u32 value)
>> +{
>> +     writel(value, rga->regs + reg);
>> +}
>> +
>> +u32 rga_read(struct rockchip_rga *rga, u32 reg)
>> +{
>> +     return readl(rga->regs + reg);
>> +}
>> +
>> +void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
>> +{
>> +     u32 temp = rga_read(rga, reg) & ~(mask);
>> +
>> +     temp |= val & mask;
>> +     rga_write(rga, reg, temp);
>> +}
>> +
>> +void rga_start(struct rockchip_rga *rga)
>> +{
>> +     /* sync CMD buf for RGA */
>> +     dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
>> +                                PAGE_SIZE, DMA_BIDIRECTIONAL);
>> +
>> +     rga_write(rga, RGA_SYS_CTRL, 0x00);
>> +
>> +     rga_write(rga, RGA_SYS_CTRL, 0x22);
>> +
>> +     rga_write(rga, RGA_INT, 0x600);
>> +
>> +     rga_write(rga, RGA_CMD_CTRL, 0x1);
>> +}
>> diff --git a/drivers/media/platform/rockchip-rga/rga-hw.h b/drivers/media/platform/rockchip-rga/rga-hw.h
>> new file mode 100644
>> index 0000000..ca3c204
>> --- /dev/null
>> +++ b/drivers/media/platform/rockchip-rga/rga-hw.h
>> @@ -0,0 +1,437 @@
>> +/*
>> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
>> + * Author: Jacob Chen <jacob-chen at iotwrt.com>
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * 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 __RGA_HW_H__
>> +#define __RGA_HW_H__
>> +
>> +#define RGA_CMDBUF_SIZE 0x20
>> +
>> +/* Hardware limits */
>> +#define MAX_WIDTH 8192
>> +#define MAX_HEIGHT 8192
>> +
>> +#define MIN_WIDTH 34
>> +#define MIN_HEIGHT 34
>> +
>> +#define DEFAULT_WIDTH 100
>> +#define DEFAULT_HEIGHT 100
>> +
>> +#define RGA_TIMEOUT 500
>> +
>> +/* Registers address */
>> +#define RGA_SYS_CTRL 0x0000
>> +#define RGA_CMD_CTRL 0x0004
>> +#define RGA_CMD_BASE 0x0008
>> +#define RGA_INT 0x0010
>> +#define RGA_MMU_CTRL0 0x0014
>> +#define RGA_VERSION_INFO 0x0028
>> +
>> +#define RGA_MODE_BASE_REG 0x0100
>> +#define RGA_MODE_MAX_REG 0x017C
>> +
>> +#define RGA_MODE_CTRL 0x0100
>> +#define RGA_SRC_INFO 0x0104
>> +#define RGA_SRC_Y_RGB_BASE_ADDR 0x0108
>> +#define RGA_SRC_CB_BASE_ADDR 0x010c
>> +#define RGA_SRC_CR_BASE_ADDR 0x0110
>> +#define RGA_SRC1_RGB_BASE_ADDR 0x0114
>> +#define RGA_SRC_VIR_INFO 0x0118
>> +#define RGA_SRC_ACT_INFO 0x011c
>> +#define RGA_SRC_X_FACTOR 0x0120
>> +#define RGA_SRC_Y_FACTOR 0x0124
>> +#define RGA_SRC_BG_COLOR 0x0128
>> +#define RGA_SRC_FG_COLOR 0x012c
>> +#define RGA_SRC_TR_COLOR0 0x0130
>> +#define RGA_SRC_TR_COLOR1 0x0134
>> +
>> +#define RGA_DST_INFO 0x0138
>> +#define RGA_DST_Y_RGB_BASE_ADDR 0x013c
>> +#define RGA_DST_CB_BASE_ADDR 0x0140
>> +#define RGA_DST_CR_BASE_ADDR 0x0144
>> +#define RGA_DST_VIR_INFO 0x0148
>> +#define RGA_DST_ACT_INFO 0x014c
>> +
>> +#define RGA_ALPHA_CTRL0 0x0150
>> +#define RGA_ALPHA_CTRL1 0x0154
>> +#define RGA_FADING_CTRL 0x0158
>> +#define RGA_PAT_CON 0x015c
>> +#define RGA_ROP_CON0 0x0160
>> +#define RGA_ROP_CON1 0x0164
>> +#define RGA_MASK_BASE 0x0168
>> +
>> +#define RGA_MMU_CTRL1 0x016C
>> +#define RGA_MMU_SRC_BASE 0x0170
>> +#define RGA_MMU_SRC1_BASE 0x0174
>> +#define RGA_MMU_DST_BASE 0x0178
>> +
>> +/* Registers value */
>> +#define RGA_MODE_RENDER_BITBLT 0
>> +#define RGA_MODE_RENDER_COLOR_PALETTE 1
>> +#define RGA_MODE_RENDER_RECTANGLE_FILL 2
>> +#define RGA_MODE_RENDER_UPDATE_PALETTE_LUT_RAM 3
>> +
>> +#define RGA_MODE_BITBLT_MODE_SRC_TO_DST 0
>> +#define RGA_MODE_BITBLT_MODE_SRC_SRC1_TO_DST 1
>> +
>> +#define RGA_MODE_CF_ROP4_SOLID 0
>> +#define RGA_MODE_CF_ROP4_PATTERN 1
>> +
>> +#define RGA_COLOR_FMT_ABGR8888 0
>> +#define RGA_COLOR_FMT_XBGR8888 1
>> +#define RGA_COLOR_FMT_RGB888 2
>> +#define RGA_COLOR_FMT_BGR565 4
>> +#define RGA_COLOR_FMT_ABGR1555 5
>> +#define RGA_COLOR_FMT_ABGR4444 6
>> +#define RGA_COLOR_FMT_YUV422SP 8
>> +#define RGA_COLOR_FMT_YUV422P 9
>> +#define RGA_COLOR_FMT_YUV420SP 10
>> +#define RGA_COLOR_FMT_YUV420P 11
>> +/* SRC_COLOR Palette */
>> +#define RGA_COLOR_FMT_CP_1BPP 12
>> +#define RGA_COLOR_FMT_CP_2BPP 13
>> +#define RGA_COLOR_FMT_CP_4BPP 14
>> +#define RGA_COLOR_FMT_CP_8BPP 15
>> +#define RGA_COLOR_FMT_MASK 15
>> +
>> +#define RGA_COLOR_NONE_SWAP 0
>> +#define RGA_COLOR_RB_SWAP 1
>> +#define RGA_COLOR_ALPHA_SWAP 2
>> +#define RGA_COLOR_UV_SWAP 4
>> +
>> +#define RGA_SRC_CSC_MODE_BYPASS 0
>> +#define RGA_SRC_CSC_MODE_BT601_R0 1
>> +#define RGA_SRC_CSC_MODE_BT601_R1 2
>> +#define RGA_SRC_CSC_MODE_BT709_R0 3
>> +#define RGA_SRC_CSC_MODE_BT709_R1 4
>> +
>> +#define RGA_SRC_ROT_MODE_0_DEGREE 0
>> +#define RGA_SRC_ROT_MODE_90_DEGREE 1
>> +#define RGA_SRC_ROT_MODE_180_DEGREE 2
>> +#define RGA_SRC_ROT_MODE_270_DEGREE 3
>> +
>> +#define RGA_SRC_MIRR_MODE_NO 0
>> +#define RGA_SRC_MIRR_MODE_X 1
>> +#define RGA_SRC_MIRR_MODE_Y 2
>> +#define RGA_SRC_MIRR_MODE_X_Y 3
>> +
>> +#define RGA_SRC_HSCL_MODE_NO 0
>> +#define RGA_SRC_HSCL_MODE_DOWN 1
>> +#define RGA_SRC_HSCL_MODE_UP 2
>> +
>> +#define RGA_SRC_VSCL_MODE_NO 0
>> +#define RGA_SRC_VSCL_MODE_DOWN 1
>> +#define RGA_SRC_VSCL_MODE_UP 2
>> +
>> +#define RGA_SRC_TRANS_ENABLE_R 1
>> +#define RGA_SRC_TRANS_ENABLE_G 2
>> +#define RGA_SRC_TRANS_ENABLE_B 4
>> +#define RGA_SRC_TRANS_ENABLE_A 8
>> +
>> +#define RGA_SRC_BIC_COE_SELEC_CATROM 0
>> +#define RGA_SRC_BIC_COE_SELEC_MITCHELL 1
>> +#define RGA_SRC_BIC_COE_SELEC_HERMITE 2
>> +#define RGA_SRC_BIC_COE_SELEC_BSPLINE 3
>> +
>> +#define RGA_DST_DITHER_MODE_888_TO_666 0
>> +#define RGA_DST_DITHER_MODE_888_TO_565 1
>> +#define RGA_DST_DITHER_MODE_888_TO_555 2
>> +#define RGA_DST_DITHER_MODE_888_TO_444 3
>> +
>> +#define RGA_DST_CSC_MODE_BYPASS 0
>> +#define RGA_DST_CSC_MODE_BT601_R0 1
>> +#define RGA_DST_CSC_MODE_BT601_R1 2
>> +#define RGA_DST_CSC_MODE_BT709_R0 3
>> +
>> +#define RGA_ALPHA_ROP_MODE_2 0
>> +#define RGA_ALPHA_ROP_MODE_3 1
>> +#define RGA_ALPHA_ROP_MODE_4 2
>> +
>> +#define RGA_ALPHA_SELECT_ALPHA 0
>> +#define RGA_ALPHA_SELECT_ROP 1
>> +
>> +#define RGA_ALPHA_MASK_BIG_ENDIAN 0
>> +#define RGA_ALPHA_MASK_LITTLE_ENDIAN 1
>> +
>> +#define RGA_ALPHA_NORMAL 0
>> +#define RGA_ALPHA_REVERSE 1
>> +
>> +#define RGA_ALPHA_BLEND_GLOBAL 0
>> +#define RGA_ALPHA_BLEND_NORMAL 1
>> +#define RGA_ALPHA_BLEND_MULTIPLY 2
>> +
>> +#define RGA_ALPHA_CAL_CUT 0
>> +#define RGA_ALPHA_CAL_NORMAL 1
>> +
>> +#define RGA_ALPHA_FACTOR_ZERO 0
>> +#define RGA_ALPHA_FACTOR_ONE 1
>> +#define RGA_ALPHA_FACTOR_OTHER 2
>> +#define RGA_ALPHA_FACTOR_OTHER_REVERSE 3
>> +#define RGA_ALPHA_FACTOR_SELF 4
>> +
>> +#define RGA_ALPHA_COLOR_NORMAL 0
>> +#define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
>> +
>> +/* Registers union */
>> +union rga_mode_ctrl {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:2] */
>> +             unsigned int render:3;
>> +             /* [3:6] */
>> +             unsigned int bitblt:1;
>> +             unsigned int cf_rop4_pat:1;
>> +             unsigned int alpha_zero_key:1;
>> +             unsigned int gradient_sat:1;
>> +             /* [7:31] */
>> +             unsigned int reserved:25;
>> +     } data;
>> +};
>> +
>> +union rga_src_info {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:3] */
>> +             unsigned int format:4;
>> +             /* [4:7] */
>> +             unsigned int swap:3;
>> +             unsigned int cp_endian:1;
>> +             /* [8:17] */
>> +             unsigned int csc_mode:2;
>> +             unsigned int rot_mode:2;
>> +             unsigned int mir_mode:2;
>> +             unsigned int hscl_mode:2;
>> +             unsigned int vscl_mode:2;
>> +             /* [18:22] */
>> +             unsigned int trans_mode:1;
>> +             unsigned int trans_enable:4;
>> +             /* [23:25] */
>> +             unsigned int dither_up_en:1;
>> +             unsigned int bic_coe_sel:2;
>> +             /* [26:31] */
>> +             unsigned int reserved:6;
>> +     } data;
>> +};
>> +
>> +union rga_src_vir_info {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:15] */
>> +             unsigned int vir_width:15;
>> +             unsigned int reserved:1;
>> +             /* [16:25] */
>> +             unsigned int vir_stride:10;
>> +             /* [26:31] */
>> +             unsigned int reserved1:6;
>> +     } data;
>> +};
>> +
>> +union rga_src_act_info {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:15] */
>> +             unsigned int act_width:13;
>> +             unsigned int reserved:3;
>> +             /* [16:31] */
>> +             unsigned int act_height:13;
>> +             unsigned int reserved1:3;
>> +     } data;
>> +};
>> +
>> +union rga_src_x_factor {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:15] */
>> +             unsigned int down_scale_factor:16;
>> +             /* [16:31] */
>> +             unsigned int up_scale_factor:16;
>> +     } data;
>> +};
>> +
>> +union rga_src_y_factor {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:15] */
>> +             unsigned int down_scale_factor:16;
>> +             /* [16:31] */
>> +             unsigned int up_scale_factor:16;
>> +     } data;
>> +};
>> +
>> +/* Alpha / Red / Green / Blue */
>> +union rga_src_cp_gr_color {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:15] */
>> +             unsigned int gradient_x:16;
>> +             /* [16:31] */
>> +             unsigned int gradient_y:16;
>> +     } data;
>> +};
>> +
>> +union rga_src_transparency_color0 {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:7] */
>> +             unsigned int trans_rmin:8;
>> +             /* [8:15] */
>> +             unsigned int trans_gmin:8;
>> +             /* [16:23] */
>> +             unsigned int trans_bmin:8;
>> +             /* [24:31] */
>> +             unsigned int trans_amin:8;
>> +     } data;
>> +};
>> +
>> +union rga_src_transparency_color1 {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:7] */
>> +             unsigned int trans_rmax:8;
>> +             /* [8:15] */
>> +             unsigned int trans_gmax:8;
>> +             /* [16:23] */
>> +             unsigned int trans_bmax:8;
>> +             /* [24:31] */
>> +             unsigned int trans_amax:8;
>> +     } data;
>> +};
>> +
>> +union rga_dst_info {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:3] */
>> +             unsigned int format:4;
>> +             /* [4:6] */
>> +             unsigned int swap:3;
>> +             /* [7:9] */
>> +             unsigned int src1_format:3;
>> +             /* [10:11] */
>> +             unsigned int src1_swap:2;
>> +             /* [12:15] */
>> +             unsigned int dither_up_en:1;
>> +             unsigned int dither_down_en:1;
>> +             unsigned int dither_down_mode:2;
>> +             /* [16:18] */
>> +             unsigned int csc_mode:2;
>> +             unsigned int csc_clip:1;
>> +             /* [19:31] */
>> +             unsigned int reserved:13;
>> +     } data;
>> +};
>> +
>> +union rga_dst_vir_info {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:15] */
>> +             unsigned int vir_stride:15;
>> +             unsigned int reserved:1;
>> +             /* [16:31] */
>> +             unsigned int src1_vir_stride:15;
>> +             unsigned int reserved1:1;
>> +     } data;
>> +};
>> +
>> +union rga_dst_act_info {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:15] */
>> +             unsigned int act_width:12;
>> +             unsigned int reserved:4;
>> +             /* [16:31] */
>> +             unsigned int act_height:12;
>> +             unsigned int reserved1:4;
>> +     } data;
>> +};
>> +
>> +union rga_alpha_ctrl0 {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:3] */
>> +             unsigned int rop_en:1;
>> +             unsigned int rop_select:1;
>> +             unsigned int rop_mode:2;
>> +             /* [4:11] */
>> +             unsigned int src_fading_val:8;
>> +             /* [12:20] */
>> +             unsigned int dst_fading_val:8;
>> +             unsigned int mask_endian:1;
>> +             /* [21:31] */
>> +             unsigned int reserved:11;
>> +     } data;
>> +};
>> +
>> +union rga_alpha_ctrl1 {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:1] */
>> +             unsigned int dst_color_m0:1;
>> +             unsigned int src_color_m0:1;
>> +             /* [2:7] */
>> +             unsigned int dst_factor_m0:3;
>> +             unsigned int src_factor_m0:3;
>> +             /* [8:9] */
>> +             unsigned int dst_alpha_cal_m0:1;
>> +             unsigned int src_alpha_cal_m0:1;
>> +             /* [10:13] */
>> +             unsigned int dst_blend_m0:2;
>> +             unsigned int src_blend_m0:2;
>> +             /* [14:15] */
>> +             unsigned int dst_alpha_m0:1;
>> +             unsigned int src_alpha_m0:1;
>> +             /* [16:21] */
>> +             unsigned int dst_factor_m1:3;
>> +             unsigned int src_factor_m1:3;
>> +             /* [22:23] */
>> +             unsigned int dst_alpha_cal_m1:1;
>> +             unsigned int src_alpha_cal_m1:1;
>> +             /* [24:27] */
>> +             unsigned int dst_blend_m1:2;
>> +             unsigned int src_blend_m1:2;
>> +             /* [28:29] */
>> +             unsigned int dst_alpha_m1:1;
>> +             unsigned int src_alpha_m1:1;
>> +             /* [30:31] */
>> +             unsigned int reserved:2;
>> +     } data;
>> +};
>> +
>> +union rga_fading_ctrl {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:7] */
>> +             unsigned int fading_offset_r:8;
>> +             /* [8:15] */
>> +             unsigned int fading_offset_g:8;
>> +             /* [16:23] */
>> +             unsigned int fading_offset_b:8;
>> +             /* [24:31] */
>> +             unsigned int fading_en:1;
>> +             unsigned int reserved:7;
>> +     } data;
>> +};
>> +
>> +union rga_pat_con {
>> +     unsigned int val;
>> +     struct {
>> +             /* [0:7] */
>> +             unsigned int width:8;
>> +             /* [8:15] */
>> +             unsigned int height:8;
>> +             /* [16:23] */
>> +             unsigned int offset_x:8;
>> +             /* [24:31] */
>> +             unsigned int offset_y:8;
>> +     } data;
>> +};
>> +
>> +#endif
>> diff --git a/drivers/media/platform/rockchip-rga/rga.c b/drivers/media/platform/rockchip-rga/rga.c
>> new file mode 100644
>> index 0000000..0c27e49
>> --- /dev/null
>> +++ b/drivers/media/platform/rockchip-rga/rga.c
>> @@ -0,0 +1,1030 @@
>> +/*
>> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
>> + * Author: Jacob Chen <jacob-chen at iotwrt.com>
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * 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 <linux/clk.h>
>> +#include <linux/debugfs.h>
>> +#include <linux/delay.h>
>> +#include <linux/fs.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/reset.h>
>> +#include <linux/sched.h>
>> +#include <linux/slab.h>
>> +#include <linux/timer.h>
>> +
>> +#include <linux/platform_device.h>
>> +#include <media/v4l2-device.h>
>> +#include <media/v4l2-event.h>
>> +#include <media/v4l2-ioctl.h>
>> +#include <media/v4l2-mem2mem.h>
>> +#include <media/videobuf2-dma-sg.h>
>> +#include <media/videobuf2-v4l2.h>
>> +
>> +#include "rga-hw.h"
>> +#include "rga.h"
>> +
>> +static int debug;
>> +module_param(debug, int, 0644);
>> +
>> +static void job_abort(void *prv)
>> +{
>> +     struct rga_ctx *ctx = prv;
>> +     struct rockchip_rga *rga = ctx->rga;
>> +
>> +     if (!rga->curr) /* No job currently running */
>> +             return;
>> +
>> +     wait_event_timeout(rga->irq_queue,
>> +                        !rga->curr, msecs_to_jiffies(RGA_TIMEOUT));
>> +}
>> +
>> +static void device_run(void *prv)
>> +{
>> +     struct rga_ctx *ctx = prv;
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     struct vb2_buffer *src, *dst;
>> +     unsigned long flags;
>> +
>> +     spin_lock_irqsave(&rga->ctrl_lock, flags);
>> +
>> +     rga->curr = ctx;
>> +
>> +     src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
>> +     dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
>> +
>> +     rga_buf_map(src);
>> +     rga_buf_map(dst);
>> +
>> +     rga_cmd_set(ctx);
>> +
>> +     rga_start(rga);
>> +
>> +     spin_unlock_irqrestore(&rga->ctrl_lock, flags);
>> +}
>> +
>> +static irqreturn_t rga_isr(int irq, void *prv)
>> +{
>> +     struct rockchip_rga *rga = prv;
>> +     int intr;
>> +
>> +     intr = rga_read(rga, RGA_INT) & 0xf;
>> +
>> +     rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
>> +
>> +     if (intr & 0x04) {
>> +             struct vb2_v4l2_buffer *src, *dst;
>> +             struct rga_ctx *ctx = rga->curr;
>> +
>> +             BUG_ON(!ctx);
>> +
>> +             rga->curr = NULL;
>> +
>> +             src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
>> +             dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
>> +
>> +             BUG_ON(!src);
>> +             BUG_ON(!dst);
>> +
>> +             dst->timecode = src->timecode;
>> +             dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
>> +             dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
>> +             dst->flags |= src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
>> +
>> +             v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
>> +             v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
>> +             v4l2_m2m_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx);
>> +
>> +             wake_up(&rga->irq_queue);
>> +     }
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +static struct v4l2_m2m_ops rga_m2m_ops = {
>> +     .device_run = device_run,
>> +     .job_abort = job_abort,
>> +};
>> +
>> +static int
>> +queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
>> +{
>> +     struct rga_ctx *ctx = priv;
>> +     int ret;
>> +
>> +     src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
>> +     src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>> +     src_vq->drv_priv = ctx;
>> +     src_vq->ops = &rga_qops;
>> +     src_vq->mem_ops = &vb2_dma_sg_memops;
>> +     src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
>> +     src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>> +     src_vq->lock = &ctx->rga->mutex;
>> +     src_vq->dev = ctx->rga->v4l2_dev.dev;
>> +
>> +     ret = vb2_queue_init(src_vq);
>> +     if (ret)
>> +             return ret;
>> +
>> +     dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>> +     dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
>> +     dst_vq->drv_priv = ctx;
>> +     dst_vq->ops = &rga_qops;
>> +     dst_vq->mem_ops = &vb2_dma_sg_memops;
>> +     dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
>> +     dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
>> +     dst_vq->lock = &ctx->rga->mutex;
>> +     dst_vq->dev = ctx->rga->v4l2_dev.dev;
>> +
>> +     return vb2_queue_init(dst_vq);
>> +}
>> +
>> +static int rga_s_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> +     struct rga_ctx *ctx = container_of(ctrl->handler, struct rga_ctx,
>> +                                        ctrl_handler);
>> +     unsigned long flags;
>> +
>> +     spin_lock_irqsave(&ctx->rga->ctrl_lock, flags);
>> +     switch (ctrl->id) {
>> +     case V4L2_CID_HFLIP:
>> +             ctx->hflip = ctrl->val;
>> +             break;
>> +     case V4L2_CID_VFLIP:
>> +             ctx->vflip = ctrl->val;
>> +             break;
>> +     case V4L2_CID_ROTATE:
>> +             ctx->rotate = ctrl->val;
>
> Changing the rotate control while vb2_is_busy() returns true is not allowed
> since rotate changes the buffer layout.
>
> This has never been handled well by the few drivers that support ROTATE.
>
> Some months ago we did some work to improve this: the V4L2_CTRL_FLAG_MODIFY_LAYOUT
> was added and is set for this control in v4l2-ctrls.c.
>
> What that means is that when queue_setup is called this control should be marked
> as 'grabbed' (call v4l2_ctrl_grab() to do this). That means that any attempt to
> change it will return -EBUSY.
>
> When all queue buffers are freed, then v4l2_ctrl_grab() should be called again
> with a 'false' argument to 'ungrab' it, i.e. it can be changed again.
>
> What is still missing is a queue op that the driver can hook into that is called
> when all buffers are released.
>
> I've made a patch for that which I will post.

Thanks for info, but i don't think RGA should concern about it, since
it have scale ability.
In this driver, buffer layout isn't changed when rotate is changed.

e.g:
intput size: 1920x1080
rotate : 0
output size: (1920 -- > 1920)x(1080 --> 1080)
buffer layout: height: 1920, width:1080

intput size: 1920x1080
rotate : 90
output size: (1080 -- > 1920)x(1920 --> 1080)
buffer layout: height: 1920, width:1080


>
>> +             break;
>> +     case V4L2_CID_BG_COLOR:
>> +             ctx->fill_color = ctrl->val;
>> +             break;
>> +     }
>> +     spin_unlock_irqrestore(&ctx->rga->ctrl_lock, flags);
>> +     return 0;
>> +}
>> +
>> +static const struct v4l2_ctrl_ops rga_ctrl_ops = {
>> +     .s_ctrl = rga_s_ctrl,
>> +};
>> +
>> +static int rga_setup_ctrls(struct rga_ctx *ctx)
>> +{
>> +     struct rockchip_rga *rga = ctx->rga;
>> +
>> +     v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
>> +
>> +     v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
>> +                       V4L2_CID_HFLIP, 0, 1, 1, 0);
>> +
>> +     v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
>> +                       V4L2_CID_VFLIP, 0, 1, 1, 0);
>> +
>> +     v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
>> +                       V4L2_CID_ROTATE, 0, 270, 90, 0);
>> +
>> +     v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
>> +                       V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
>> +
>> +     if (ctx->ctrl_handler.error) {
>> +             int err = ctx->ctrl_handler.error;
>> +
>> +             v4l2_err(&rga->v4l2_dev, "%s failed\n", __func__);
>> +             v4l2_ctrl_handler_free(&ctx->ctrl_handler);
>> +             return err;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +struct rga_fmt formats[] = {
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_ARGB32,
>> +             .color_swap = RGA_COLOR_RB_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_ABGR8888,
>> +             .depth = 32,
>> +             .uv_factor = 1,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_XRGB32,
>> +             .color_swap = RGA_COLOR_RB_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_XBGR8888,
>> +             .depth = 32,
>> +             .uv_factor = 1,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_ABGR32,
>> +             .color_swap = RGA_COLOR_ALPHA_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_ABGR8888,
>> +             .depth = 32,
>> +             .uv_factor = 1,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_XBGR32,
>> +             .color_swap = RGA_COLOR_ALPHA_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_XBGR8888,
>> +             .depth = 32,
>> +             .uv_factor = 1,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_RGB24,
>> +             .color_swap = RGA_COLOR_NONE_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_RGB888,
>> +             .depth = 24,
>> +             .uv_factor = 1,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_BGR24,
>> +             .color_swap = RGA_COLOR_RB_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_RGB888,
>> +             .depth = 24,
>> +             .uv_factor = 1,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_ARGB444,
>> +             .color_swap = RGA_COLOR_RB_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_ABGR4444,
>> +             .depth = 16,
>> +             .uv_factor = 1,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_ARGB555,
>> +             .color_swap = RGA_COLOR_RB_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_ABGR1555,
>> +             .depth = 16,
>> +             .uv_factor = 1,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_RGB565,
>> +             .color_swap = RGA_COLOR_RB_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_BGR565,
>> +             .depth = 16,
>> +             .uv_factor = 1,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_NV21,
>> +             .color_swap = RGA_COLOR_UV_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_YUV420SP,
>> +             .depth = 12,
>> +             .uv_factor = 4,
>> +             .y_div = 2,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_NV61,
>> +             .color_swap = RGA_COLOR_UV_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_YUV422SP,
>> +             .depth = 16,
>> +             .uv_factor = 2,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_NV12,
>> +             .color_swap = RGA_COLOR_NONE_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_YUV420SP,
>> +             .depth = 12,
>> +             .uv_factor = 4,
>> +             .y_div = 2,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_NV16,
>> +             .color_swap = RGA_COLOR_NONE_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_YUV422SP,
>> +             .depth = 16,
>> +             .uv_factor = 2,
>> +             .y_div = 1,
>> +             .x_div = 1,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_YUV420,
>> +             .color_swap = RGA_COLOR_NONE_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_YUV420P,
>> +             .depth = 12,
>> +             .uv_factor = 4,
>> +             .y_div = 2,
>> +             .x_div = 2,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_YUV422P,
>> +             .color_swap = RGA_COLOR_NONE_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_YUV422P,
>> +             .depth = 16,
>> +             .uv_factor = 2,
>> +             .y_div = 1,
>> +             .x_div = 2,
>> +     },
>> +     {
>> +             .fourcc = V4L2_PIX_FMT_YVU420,
>> +             .color_swap = RGA_COLOR_UV_SWAP,
>> +             .hw_format = RGA_COLOR_FMT_YUV420P,
>> +             .depth = 12,
>> +             .uv_factor = 4,
>> +             .y_div = 2,
>> +             .x_div = 2,
>> +     },
>> +};
>> +
>> +#define NUM_FORMATS ARRAY_SIZE(formats)
>> +
>> +struct rga_fmt *rga_fmt_find(struct v4l2_format *f)
>> +{
>> +     unsigned int i;
>> +
>> +     for (i = 0; i < NUM_FORMATS; i++) {
>> +             if (formats[i].fourcc == f->fmt.pix.pixelformat)
>> +                     return &formats[i];
>> +     }
>> +     return NULL;
>> +}
>> +
>> +static struct rga_frame def_frame = {
>> +     .width = DEFAULT_WIDTH,
>> +     .height = DEFAULT_HEIGHT,
>> +     .colorspace = V4L2_COLORSPACE_DEFAULT,
>> +     .crop.left = 0,
>> +     .crop.top = 0,
>> +     .crop.width = DEFAULT_WIDTH,
>> +     .crop.height = DEFAULT_HEIGHT,
>> +     .fmt = &formats[0],
>> +};
>> +
>> +struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
>> +{
>> +     switch (type) {
>> +     case V4L2_BUF_TYPE_VIDEO_OUTPUT:
>> +             return &ctx->in;
>> +     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
>> +             return &ctx->out;
>> +     default:
>> +             return ERR_PTR(-EINVAL);
>> +     }
>> +}
>> +
>> +static int rga_open(struct file *file)
>> +{
>> +     struct rockchip_rga *rga = video_drvdata(file);
>> +     struct rga_ctx *ctx = NULL;
>> +     int ret = 0;
>> +
>> +     ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>> +     if (!ctx)
>> +             return -ENOMEM;
>> +     ctx->rga = rga;
>> +     /* Set default formats */
>> +     ctx->in = def_frame;
>> +     ctx->out = def_frame;
>> +
>> +     if (mutex_lock_interruptible(&rga->mutex)) {
>> +             kfree(ctx);
>> +             return -ERESTARTSYS;
>> +     }
>> +     ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init);
>> +     if (IS_ERR(ctx->fh.m2m_ctx)) {
>> +             ret = PTR_ERR(ctx->fh.m2m_ctx);
>> +             mutex_unlock(&rga->mutex);
>> +             kfree(ctx);
>> +             return ret;
>> +     }
>> +     v4l2_fh_init(&ctx->fh, video_devdata(file));
>> +     file->private_data = &ctx->fh;
>> +     v4l2_fh_add(&ctx->fh);
>> +
>> +     rga_setup_ctrls(ctx);
>> +
>> +     /* Write the default values to the ctx struct */
>> +     v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
>> +
>> +     ctx->fh.ctrl_handler = &ctx->ctrl_handler;
>> +     mutex_unlock(&rga->mutex);
>> +
>> +     return 0;
>> +}
>> +
>> +static int rga_release(struct file *file)
>> +{
>> +     struct rga_ctx *ctx =
>> +             container_of(file->private_data, struct rga_ctx, fh);
>> +     struct rockchip_rga *rga = ctx->rga;
>> +
>> +     mutex_lock(&rga->mutex);
>> +
>> +     v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
>> +
>> +     v4l2_ctrl_handler_free(&ctx->ctrl_handler);
>> +     v4l2_fh_del(&ctx->fh);
>> +     v4l2_fh_exit(&ctx->fh);
>> +     kfree(ctx);
>> +
>> +     mutex_unlock(&rga->mutex);
>> +
>> +     return 0;
>> +}
>> +
>> +static const struct v4l2_file_operations rga_fops = {
>> +     .owner = THIS_MODULE,
>> +     .open = rga_open,
>> +     .release = rga_release,
>> +     .poll = v4l2_m2m_fop_poll,
>> +     .unlocked_ioctl = video_ioctl2,
>> +     .mmap = v4l2_m2m_fop_mmap,
>> +};
>> +
>> +static int
>> +vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
>> +{
>> +     strlcpy(cap->driver, RGA_NAME, sizeof(cap->driver));
>> +     strlcpy(cap->card, "rockchip-rga", sizeof(cap->card));
>> +     strlcpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
>> +
>> +     return 0;
>> +}
>> +
>> +static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
>> +{
>> +     struct rga_fmt *fmt;
>> +
>> +     if (f->index >= NUM_FORMATS)
>> +             return -EINVAL;
>> +
>> +     fmt = &formats[f->index];
>> +     f->pixelformat = fmt->fourcc;
>> +
>> +     return 0;
>> +}
>> +
>> +static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
>> +{
>> +     struct rga_ctx *ctx = prv;
>> +     struct vb2_queue *vq;
>> +     struct rga_frame *frm;
>> +
>> +     vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
>> +     if (!vq)
>> +             return -EINVAL;
>> +     frm = rga_get_frame(ctx, f->type);
>> +     if (IS_ERR(frm))
>> +             return PTR_ERR(frm);
>> +
>> +     f->fmt.pix.width = frm->width;
>> +     f->fmt.pix.height = frm->height;
>> +     f->fmt.pix.field = V4L2_FIELD_NONE;
>> +     f->fmt.pix.pixelformat = frm->fmt->fourcc;
>> +     f->fmt.pix.bytesperline = frm->stride;
>> +     f->fmt.pix.sizeimage = frm->size;
>> +     f->fmt.pix.colorspace = frm->colorspace;
>> +
>> +     return 0;
>> +}
>> +
>> +static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
>> +{
>> +     struct rga_fmt *fmt;
>> +
>> +     fmt = rga_fmt_find(f);
>> +     if (!fmt) {
>> +             fmt = &formats[0];
>> +             f->fmt.pix.pixelformat = fmt->fourcc;
>> +     }
>> +
>> +     f->fmt.pix.field = V4L2_FIELD_NONE;
>> +
>> +     if (f->fmt.pix.width > MAX_WIDTH)
>> +             f->fmt.pix.width = MAX_WIDTH;
>> +     if (f->fmt.pix.height > MAX_HEIGHT)
>> +             f->fmt.pix.height = MAX_HEIGHT;
>> +
>> +     if (f->fmt.pix.width < MIN_WIDTH)
>> +             f->fmt.pix.width = MIN_WIDTH;
>> +     if (f->fmt.pix.height < MIN_HEIGHT)
>> +             f->fmt.pix.height = MIN_HEIGHT;
>> +
>> +     if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP)
>> +             f->fmt.pix.bytesperline = f->fmt.pix.width;
>> +     else
>> +             f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
>> +
>> +     f->fmt.pix.sizeimage =
>> +             f->fmt.pix.height * (f->fmt.pix.width * fmt->depth) >> 3;
>> +
>> +     return 0;
>> +}
>> +
>> +static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
>> +{
>> +     struct rga_ctx *ctx = prv;
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     struct vb2_queue *vq;
>> +     struct rga_frame *frm;
>> +     struct rga_fmt *fmt;
>> +     int ret = 0;
>> +
>> +     /* Adjust all values accordingly to the hardware capabilities
>> +      * and chosen format.
>> +      */
>> +     ret = vidioc_try_fmt(file, prv, f);
>> +     if (ret)
>> +             return ret;
>> +     vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
>> +     if (vb2_is_busy(vq)) {
>> +             v4l2_err(&rga->v4l2_dev, "queue (%d) bust\n", f->type);
>> +             return -EBUSY;
>> +     }
>> +     frm = rga_get_frame(ctx, f->type);
>> +     if (IS_ERR(frm))
>> +             return PTR_ERR(frm);
>> +     fmt = rga_fmt_find(f);
>> +     if (!fmt)
>> +             return -EINVAL;
>> +     frm->width = f->fmt.pix.width;
>> +     frm->height = f->fmt.pix.height;
>> +     frm->size = f->fmt.pix.sizeimage;
>> +     frm->fmt = fmt;
>> +     frm->stride = f->fmt.pix.bytesperline;
>> +     frm->colorspace = f->fmt.pix.colorspace;
>> +
>> +     /* Reset crop settings */
>> +     frm->crop.left = 0;
>> +     frm->crop.top = 0;
>> +     frm->crop.width = frm->width;
>> +     frm->crop.height = frm->height;
>> +
>> +     return 0;
>> +}
>> +
>> +static int
>> +vidioc_try_crop(struct rga_ctx *ctx, struct v4l2_selection *s)
>> +{
>> +     struct rockchip_rga *rga = ctx->rga;
>> +     struct rga_frame *f;
>> +
>> +     f = rga_get_frame(ctx, s->type);
>> +     if (IS_ERR(f))
>> +             return PTR_ERR(f);
>> +
>> +     switch (s->target) {
>> +     case V4L2_SEL_TGT_COMPOSE:
>> +             /*
>> +              * COMPOSE target is only valid for capture buffer type, return
>> +              * error for output buffer type
>> +              */
>> +             if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>> +                     return -EINVAL;
>> +             break;
>> +     case V4L2_SEL_TGT_CROP:
>> +             /*
>> +              * CROP target is only valid for output buffer type, return
>> +              * error for capture buffer type
>> +              */
>> +             if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
>> +                     return -EINVAL;
>> +             break;
>> +     /*
>> +      * bound and default crop/compose targets are invalid targets to
>> +      * try/set
>> +      */
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     if (s->r.top < 0 || s->r.left < 0) {
>> +             v4l2_dbg(debug, 1, &rga->v4l2_dev,
>> +                      "doesn't support negative values for top & left.\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     if (s->r.left + s->r.width > f->width ||
>> +         s->r.top + s->r.height > f->height ||
>> +         s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
>> +             v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
>> +             return -EINVAL;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int vidioc_g_selection(struct file *file, void *prv,
>> +                           struct v4l2_selection *s)
>> +{
>> +     struct rga_ctx *ctx = prv;
>> +     struct rga_frame *f;
>> +     bool use_frame = false;
>> +
>> +     f = rga_get_frame(ctx, s->type);
>> +     if (IS_ERR(f))
>> +             return PTR_ERR(f);
>> +
>> +     switch (s->target) {
>> +     case V4L2_SEL_TGT_COMPOSE_DEFAULT:
>> +     case V4L2_SEL_TGT_COMPOSE_BOUNDS:
>> +             if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>> +                     return -EINVAL;
>> +             break;
>> +     case V4L2_SEL_TGT_CROP_DEFAULT:
>> +     case V4L2_SEL_TGT_CROP_BOUNDS:
>> +             if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
>> +                     return -EINVAL;
>> +             break;
>> +     case V4L2_SEL_TGT_COMPOSE:
>> +             if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>> +                     return -EINVAL;
>> +             use_frame = true;
>> +             break;
>> +     case V4L2_SEL_TGT_CROP:
>> +             if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
>> +                     return -EINVAL;
>> +             use_frame = true;
>> +             break;
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     if (use_frame) {
>> +             s->r = f->crop;
>> +     } else {
>> +             s->r.left = 0;
>> +             s->r.top = 0;
>> +             s->r.width = f->width;
>> +             s->r.height = f->height;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int vidioc_s_selection(struct file *file, void *prv,
>> +                           struct v4l2_selection *s)
>> +{
>> +     struct rga_ctx *ctx = prv;
>> +     struct rga_frame *f;
>> +     int ret = 0;
>> +
>
> You can't use s_selection for the DEFAULT and BOUNDS rectangles,
> yet this code allows it. Doesn't v4l2-compliance complain about that?
> I thought it tested for that.
>
>> +     ret = vidioc_try_crop(ctx, s);
>> +     if (ret)
>> +             return ret;
>> +
>> +     f = rga_get_frame(ctx, s->type);
>> +     if (IS_ERR(f))
>> +             return PTR_ERR(f);
>> +
>> +     f->crop = s->r;
>> +
>> +     return ret;
>> +}
>> +
>> +static const struct v4l2_ioctl_ops rga_ioctl_ops = {
>> +     .vidioc_querycap = vidioc_querycap,
>> +
>> +     .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
>> +     .vidioc_g_fmt_vid_cap = vidioc_g_fmt,
>> +     .vidioc_try_fmt_vid_cap = vidioc_try_fmt,
>> +     .vidioc_s_fmt_vid_cap = vidioc_s_fmt,
>> +
>> +     .vidioc_enum_fmt_vid_out = vidioc_enum_fmt,
>> +     .vidioc_g_fmt_vid_out = vidioc_g_fmt,
>> +     .vidioc_try_fmt_vid_out = vidioc_try_fmt,
>> +     .vidioc_s_fmt_vid_out = vidioc_s_fmt,
>> +
>> +     .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
>> +     .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
>> +     .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
>> +     .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
>> +     .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
>> +     .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
>> +     .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
>> +
>> +     .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
>> +     .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
>> +
>> +     .vidioc_streamon = v4l2_m2m_ioctl_streamon,
>> +     .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
>> +
>> +     .vidioc_g_selection = vidioc_g_selection,
>> +     .vidioc_s_selection = vidioc_s_selection,
>> +};
>> +
>> +static struct video_device rga_videodev = {
>> +     .name = "rockchip-rga",
>> +     .fops = &rga_fops,
>> +     .ioctl_ops = &rga_ioctl_ops,
>> +     .minor = -1,
>> +     .release = video_device_release,
>> +     .vfl_dir = VFL_DIR_M2M,
>> +     .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
>> +};
>> +
>> +static int rga_enable_clocks(struct rockchip_rga *rga)
>> +{
>> +     int ret;
>> +
>> +     ret = clk_prepare_enable(rga->sclk);
>> +     if (ret) {
>> +             dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret);
>> +             return ret;
>> +     }
>> +
>> +     ret = clk_prepare_enable(rga->aclk);
>> +     if (ret) {
>> +             dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret);
>> +             goto err_disable_sclk;
>> +     }
>> +
>> +     ret = clk_prepare_enable(rga->hclk);
>> +     if (ret) {
>> +             dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret);
>> +             goto err_disable_aclk;
>> +     }
>> +
>> +     return 0;
>> +
>> +err_disable_sclk:
>> +     clk_disable_unprepare(rga->sclk);
>> +err_disable_aclk:
>> +     clk_disable_unprepare(rga->aclk);
>> +
>> +     return ret;
>> +}
>> +
>> +static void rga_disable_clocks(struct rockchip_rga *rga)
>> +{
>> +     clk_disable_unprepare(rga->sclk);
>> +     clk_disable_unprepare(rga->hclk);
>> +     clk_disable_unprepare(rga->aclk);
>> +}
>> +
>> +static int rga_parse_dt(struct rockchip_rga *rga)
>> +{
>> +     struct reset_control *core_rst, *axi_rst, *ahb_rst;
>> +
>> +     core_rst = devm_reset_control_get(rga->dev, "core");
>> +     if (IS_ERR(core_rst)) {
>> +             dev_err(rga->dev, "failed to get core reset controller\n");
>> +             return PTR_ERR(core_rst);
>> +     }
>> +
>> +     axi_rst = devm_reset_control_get(rga->dev, "axi");
>> +     if (IS_ERR(axi_rst)) {
>> +             dev_err(rga->dev, "failed to get axi reset controller\n");
>> +             return PTR_ERR(axi_rst);
>> +     }
>> +
>> +     ahb_rst = devm_reset_control_get(rga->dev, "ahb");
>> +     if (IS_ERR(ahb_rst)) {
>> +             dev_err(rga->dev, "failed to get ahb reset controller\n");
>> +             return PTR_ERR(ahb_rst);
>> +     }
>> +
>> +     reset_control_assert(core_rst);
>> +     udelay(1);
>> +     reset_control_deassert(core_rst);
>> +
>> +     reset_control_assert(axi_rst);
>> +     udelay(1);
>> +     reset_control_deassert(axi_rst);
>> +
>> +     reset_control_assert(ahb_rst);
>> +     udelay(1);
>> +     reset_control_deassert(ahb_rst);
>> +
>> +     rga->sclk = devm_clk_get(rga->dev, "sclk");
>> +     if (IS_ERR(rga->sclk)) {
>> +             dev_err(rga->dev, "failed to get sclk clock\n");
>> +             return PTR_ERR(rga->sclk);
>> +     }
>> +
>> +     rga->aclk = devm_clk_get(rga->dev, "aclk");
>> +     if (IS_ERR(rga->aclk)) {
>> +             dev_err(rga->dev, "failed to get aclk clock\n");
>> +             return PTR_ERR(rga->aclk);
>> +     }
>> +
>> +     rga->hclk = devm_clk_get(rga->dev, "hclk");
>> +     if (IS_ERR(rga->hclk)) {
>> +             dev_err(rga->dev, "failed to get hclk clock\n");
>> +             return PTR_ERR(rga->hclk);
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int rga_probe(struct platform_device *pdev)
>> +{
>> +     struct rockchip_rga *rga;
>> +     struct video_device *vfd;
>> +     struct resource *res;
>> +     int ret = 0;
>> +     int irq;
>> +
>> +     if (!pdev->dev.of_node)
>> +             return -ENODEV;
>> +
>> +     rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
>> +     if (!rga)
>> +             return -ENOMEM;
>> +
>> +     rga->dev = &pdev->dev;
>> +     spin_lock_init(&rga->ctrl_lock);
>> +     mutex_init(&rga->mutex);
>> +
>> +     init_waitqueue_head(&rga->irq_queue);
>> +
>> +     ret = rga_parse_dt(rga);
>> +     if (ret)
>> +             dev_err(&pdev->dev, "Unable to parse OF data\n");
>> +
>> +     pm_runtime_enable(rga->dev);
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +
>> +     rga->regs = devm_ioremap_resource(rga->dev, res);
>> +     if (IS_ERR(rga->regs)) {
>> +             ret = PTR_ERR(rga->regs);
>> +             goto err_put_clk;
>> +     }
>> +
>> +     irq = platform_get_irq(pdev, 0);
>> +     if (irq < 0) {
>> +             dev_err(rga->dev, "failed to get irq\n");
>> +             ret = irq;
>> +             goto err_put_clk;
>> +     }
>> +
>> +     ret = devm_request_irq(rga->dev, irq, rga_isr, 0,
>> +                            dev_name(rga->dev), rga);
>> +     if (ret < 0) {
>> +             dev_err(rga->dev, "failed to request irq\n");
>> +             goto err_put_clk;
>> +     }
>> +
>> +     ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev);
>> +     if (ret)
>> +             goto err_put_clk;
>> +     vfd = video_device_alloc();
>> +     if (!vfd) {
>> +             v4l2_err(&rga->v4l2_dev, "Failed to allocate video device\n");
>> +             ret = -ENOMEM;
>> +             goto unreg_v4l2_dev;
>> +     }
>> +     *vfd = rga_videodev;
>> +     vfd->lock = &rga->mutex;
>> +     vfd->v4l2_dev = &rga->v4l2_dev;
>> +
>> +     video_set_drvdata(vfd, rga);
>> +     snprintf(vfd->name, sizeof(vfd->name), "%s", rga_videodev.name);
>> +     rga->vfd = vfd;
>> +
>> +     platform_set_drvdata(pdev, rga);
>> +     rga->m2m_dev = v4l2_m2m_init(&rga_m2m_ops);
>> +     if (IS_ERR(rga->m2m_dev)) {
>> +             v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n");
>> +             ret = PTR_ERR(rga->m2m_dev);
>> +             goto unreg_video_dev;
>> +     }
>> +
>> +     pm_runtime_get_sync(rga->dev);
>> +
>> +     rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
>> +     rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
>> +
>> +     v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
>> +               rga->version.major, rga->version.minor);
>> +
>> +     pm_runtime_put(rga->dev);
>> +
>> +     /* Create CMD buffer */
>> +     rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
>> +                                        &rga->cmdbuf_phy, GFP_KERNEL,
>> +                                        DMA_ATTR_WRITE_COMBINE);
>> +
>> +     rga->src_mmu_pages =
>> +             (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
>> +     rga->dst_mmu_pages =
>> +             (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
>> +
>> +     def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
>> +     def_frame.size = def_frame.stride * def_frame.height;
>> +
>> +     ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
>> +     if (ret) {
>> +             v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
>> +             goto rel_vdev;
>> +     }
>> +
>> +     v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
>> +               vfd->name, video_device_node_name(vfd));
>> +
>> +     return 0;
>> +
>> +rel_vdev:
>> +     video_device_release(vfd);
>> +unreg_video_dev:
>> +     video_unregister_device(rga->vfd);
>> +unreg_v4l2_dev:
>> +     v4l2_device_unregister(&rga->v4l2_dev);
>> +err_put_clk:
>> +     pm_runtime_disable(rga->dev);
>> +
>> +     return ret;
>> +}
>> +
>> +static int rga_remove(struct platform_device *pdev)
>> +{
>> +     struct rockchip_rga *rga = platform_get_drvdata(pdev);
>> +
>> +     dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, &rga->cmdbuf_virt,
>> +                    rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
>> +
>> +     free_pages((unsigned long)rga->src_mmu_pages, 3);
>> +     free_pages((unsigned long)rga->dst_mmu_pages, 3);
>> +
>> +     v4l2_info(&rga->v4l2_dev, "Removing\n");
>> +
>> +     v4l2_m2m_release(rga->m2m_dev);
>> +     video_unregister_device(rga->vfd);
>> +     v4l2_device_unregister(&rga->v4l2_dev);
>> +
>> +     pm_runtime_disable(rga->dev);
>> +
>> +     return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static int rga_runtime_suspend(struct device *dev)
>> +{
>> +     struct rockchip_rga *rga = dev_get_drvdata(dev);
>> +
>> +     rga_disable_clocks(rga);
>> +
>> +     return 0;
>> +}
>> +
>> +static int rga_runtime_resume(struct device *dev)
>> +{
>> +     struct rockchip_rga *rga = dev_get_drvdata(dev);
>> +
>> +     return rga_enable_clocks(rga);
>> +}
>> +#endif
>> +
>> +static const struct dev_pm_ops rga_pm = {
>> +     SET_RUNTIME_PM_OPS(rga_runtime_suspend,
>> +                        rga_runtime_resume, NULL)
>> +};
>> +
>> +static const struct of_device_id rockchip_rga_match[] = {
>> +     {
>> +             .compatible = "rockchip,rk3288-rga",
>> +     },
>> +     {
>> +             .compatible = "rockchip,rk3399-rga",
>> +     },
>> +     {},
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, rockchip_rga_match);
>> +
>> +static struct platform_driver rga_pdrv = {
>> +     .probe = rga_probe,
>> +     .remove = rga_remove,
>> +     .driver = {
>> +             .name = RGA_NAME,
>> +             .pm = &rga_pm,
>> +             .of_match_table = rockchip_rga_match,
>> +     },
>> +};
>> +
>> +module_platform_driver(rga_pdrv);
>> +
>> +MODULE_AUTHOR("Jacob Chen <jacob-chen at iotwrt.com>");
>> +MODULE_DESCRIPTION("Rockchip Raster 2d Grapphic Acceleration Unit");
>
> Grapphic -> Graphic
>
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/media/platform/rockchip-rga/rga.h b/drivers/media/platform/rockchip-rga/rga.h
>> new file mode 100644
>> index 0000000..c7d35b8
>> --- /dev/null
>> +++ b/drivers/media/platform/rockchip-rga/rga.h
>> @@ -0,0 +1,110 @@
>> +/*
>> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
>> + * Author: Jacob Chen <jacob-chen at iotwrt.com>
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * 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 __RGA_H__
>> +#define __RGA_H__
>> +
>> +#include <linux/platform_device.h>
>> +#include <media/videobuf2-v4l2.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-device.h>
>> +
>> +#define RGA_NAME "rockchip-rga"
>> +
>> +struct rga_fmt {
>> +     u32 fourcc;
>> +     int depth;
>> +     u8 uv_factor;
>> +     u8 y_div;
>> +     u8 x_div;
>> +     u8 color_swap;
>> +     u8 hw_format;
>> +};
>> +
>> +struct rga_frame {
>> +     /* Original dimensions */
>> +     u32 width;
>> +     u32 height;
>> +     u32 colorspace;
>> +
>> +     /* Crop */
>> +     struct v4l2_rect crop;
>> +
>> +     /* Image format */
>> +     struct rga_fmt *fmt;
>> +
>> +     /* Variables that can calculated once and reused */
>> +     u32 stride;
>> +     u32 size;
>> +};
>> +
>> +struct rockchip_rga_version {
>> +     u32 major;
>> +     u32 minor;
>> +};
>> +
>> +struct rga_ctx {
>> +     struct v4l2_fh fh;
>> +     struct rockchip_rga *rga;
>> +     struct rga_frame in;
>> +     struct rga_frame out;
>> +     struct v4l2_ctrl_handler ctrl_handler;
>> +
>> +     /* Control values */
>> +     u32 op;
>> +     u32 hflip;
>> +     u32 vflip;
>> +     u32 rotate;
>> +     u32 fill_color;
>> +};
>> +
>> +struct rockchip_rga {
>> +     struct v4l2_device v4l2_dev;
>> +     struct v4l2_m2m_dev *m2m_dev;
>> +     struct video_device *vfd;
>> +
>> +     struct device *dev;
>> +     struct regmap *grf;
>> +     void __iomem *regs;
>> +     struct clk *sclk;
>> +     struct clk *aclk;
>> +     struct clk *hclk;
>> +     struct rockchip_rga_version version;
>> +
>> +     struct mutex mutex;
>> +     spinlock_t ctrl_lock;
>> +
>> +     wait_queue_head_t irq_queue;
>> +
>> +     struct rga_ctx *curr;
>> +     dma_addr_t cmdbuf_phy;
>> +     void *cmdbuf_virt;
>> +     unsigned int *src_mmu_pages;
>> +     unsigned int *dst_mmu_pages;
>> +};
>> +
>> +struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type);
>> +
>> +/* RGA Buffers Manage Part */
>> +extern const struct vb2_ops rga_qops;
>> +void rga_buf_map(struct vb2_buffer *vb);
>> +
>> +/* RGA Hardware Part */
>> +void rga_write(struct rockchip_rga *rga, u32 reg, u32 value);
>> +u32 rga_read(struct rockchip_rga *rga, u32 reg);
>> +void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask);
>> +void rga_start(struct rockchip_rga *rga);
>> +
>> +void rga_cmd_set(struct rga_ctx *ctx);
>> +
>> +#endif
>>
>
> Regards,
>
>         Hans


From jacob-chen at iotwrt.com  Tue Oct  3 02:28:35 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Tue,  3 Oct 2017 17:28:35 +0800
Subject: [PATCH v10 0/4] Add Rockchip RGA V4l2 support
Message-ID: <20171003092839.26236-1-jacob-chen@iotwrt.com>

This patch series add a v4l2 m2m drvier for rockchip RGA direct rendering based 2d graphics acceleration module.

change in V10:
- move to rockchip/rga
- changes according to comments
- some style changes

change in V9:
- remove protduff things
- test with the latest v4l2-compliance

change in V8:
- remove protduff things

change in V6,V7:
- correct warning in checkpatch.pl

change in V5:
- v4l2-compliance: handle invalid pxielformat
- v4l2-compliance: add subscribe_event
- add colorspace support

change in V4:
- document the controls.
- change according to Hans's comments

change in V3:
- rename the controls.
- add pm_runtime support.
- enable node by default.
- correct spelling in documents.

change in V2:
- generalize the controls.
- map buffers (10-50 us) in every cmd-run rather than in buffer-import to avoid get_free_pages failed on
actively used systems.
- remove status in dt-bindings examples.

Jacob Chen (4):
  rockchip/rga: v4l2 m2m support
  ARM: dts: rockchip: add RGA device node for RK3288
  arm64: dts: rockchip: add RGA device node for RK3399
  dt-bindings: Document the Rockchip RGA bindings

 .../devicetree/bindings/media/rockchip-rga.txt     |   33 +
 arch/arm/boot/dts/rk3288.dtsi                      |   11 +
 arch/arm64/boot/dts/rockchip/rk3399.dtsi           |   11 +
 drivers/media/platform/Kconfig                     |   15 +
 drivers/media/platform/Makefile                    |    2 +
 drivers/media/platform/rockchip/rga/Makefile       |    3 +
 drivers/media/platform/rockchip/rga/rga-buf.c      |  154 +++
 drivers/media/platform/rockchip/rga/rga-hw.c       |  421 ++++++++
 drivers/media/platform/rockchip/rga/rga-hw.h       |  437 +++++++++
 drivers/media/platform/rockchip/rga/rga.c          | 1012 ++++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga.h          |  123 +++
 11 files changed, 2222 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/rockchip-rga.txt
 create mode 100644 drivers/media/platform/rockchip/rga/Makefile
 create mode 100644 drivers/media/platform/rockchip/rga/rga-buf.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.h
 create mode 100644 drivers/media/platform/rockchip/rga/rga.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga.h

-- 
2.14.1



From jacob-chen at iotwrt.com  Tue Oct  3 02:28:37 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Tue,  3 Oct 2017 17:28:37 +0800
Subject: [PATCH v10 2/4] ARM: dts: rockchip: add RGA device node for RK3288
In-Reply-To: <20171003092839.26236-1-jacob-chen@iotwrt.com>
References: <20171003092839.26236-1-jacob-chen@iotwrt.com>
Message-ID: <20171003092839.26236-3-jacob-chen@iotwrt.com>

This patch add the RGA dt config of rk3288 SoC.

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm/boot/dts/rk3288.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index a0a0b08bff74..8c6dfc0abc42 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -972,6 +972,17 @@
 		status = "disabled";
 	};
 
+	rga: rga at ff920000 {
+		compatible = "rockchip,rk3288-rga";
+		reg = <0x0 0xff920000 0x0 0x180>;
+		interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA>;
+		clock-names = "aclk", "hclk", "sclk";
+		power-domains = <&power RK3288_PD_VIO>;
+		resets = <&cru SRST_RGA_CORE>, <&cru SRST_RGA_AXI>, <&cru SRST_RGA_AHB>;
+		reset-names = "core", "axi", "ahb";
+	};
+
 	vopb: vop at ff930000 {
 		compatible = "rockchip,rk3288-vop";
 		reg = <0x0 0xff930000 0x0 0x19c>;
-- 
2.14.1



From jacob-chen at iotwrt.com  Tue Oct  3 02:28:38 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Tue,  3 Oct 2017 17:28:38 +0800
Subject: [PATCH v10 3/4] arm64: dts: rockchip: add RGA device node for RK3399
In-Reply-To: <20171003092839.26236-1-jacob-chen@iotwrt.com>
References: <20171003092839.26236-1-jacob-chen@iotwrt.com>
Message-ID: <20171003092839.26236-4-jacob-chen@iotwrt.com>

This patch add the RGA dt config of RK3399 SoC.

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d79e9b3265b9..a3fab6af5a17 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1204,6 +1204,17 @@
 		status = "disabled";
 	};
 
+	rga: rga at ff680000 {
+		compatible = "rockchip,rk3399-rga";
+		reg = <0x0 0xff680000 0x0 0x10000>;
+		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+		resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>;
+		reset-names = "core", "axi", "ahb";
+		power-domains = <&power RK3399_PD_RGA>;
+	};
+
 	efuse0: efuse at ff690000 {
 		compatible = "rockchip,rk3399-efuse";
 		reg = <0x0 0xff690000 0x0 0x80>;
-- 
2.14.1



From jacob-chen at iotwrt.com  Tue Oct  3 02:28:39 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Tue,  3 Oct 2017 17:28:39 +0800
Subject: [PATCH v10 4/4] dt-bindings: Document the Rockchip RGA bindings
In-Reply-To: <20171003092839.26236-1-jacob-chen@iotwrt.com>
References: <20171003092839.26236-1-jacob-chen@iotwrt.com>
Message-ID: <20171003092839.26236-5-jacob-chen@iotwrt.com>

Add DT bindings documentation for Rockchip RGA

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
Acked-by: Rob Herring <robh at kernel.org>
---
 .../devicetree/bindings/media/rockchip-rga.txt     | 33 ++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/rockchip-rga.txt

diff --git a/Documentation/devicetree/bindings/media/rockchip-rga.txt b/Documentation/devicetree/bindings/media/rockchip-rga.txt
new file mode 100644
index 000000000000..fd5276abfad6
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/rockchip-rga.txt
@@ -0,0 +1,33 @@
+device-tree bindings for rockchip 2D raster graphic acceleration controller (RGA)
+
+RGA is a standalone 2D raster graphic acceleration unit. It accelerates 2D
+graphics operations, such as point/line drawing, image scaling, rotation,
+BitBLT, alpha blending and image blur/sharpness.
+
+Required properties:
+- compatible: value should be one of the following
+		"rockchip,rk3288-rga";
+		"rockchip,rk3399-rga";
+
+- interrupts: RGA interrupt specifier.
+
+- clocks: phandle to RGA sclk/hclk/aclk clocks
+
+- clock-names: should be "aclk", "hclk" and "sclk"
+
+- resets: Must contain an entry for each entry in reset-names.
+  See ../reset/reset.txt for details.
+- reset-names: should be "core", "axi" and "ahb"
+
+Example:
+SoC-specific DT entry:
+	rga: rga at ff680000 {
+		compatible = "rockchip,rk3399-rga";
+		reg = <0xff680000 0x10000>;
+		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+
+		resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>;
+		reset-names = "core, "axi", "ahb";
+	};
-- 
2.14.1



From jacob-chen at iotwrt.com  Tue Oct  3 02:28:36 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Tue,  3 Oct 2017 17:28:36 +0800
Subject: [PATCH v10 1/4] rockchip/rga: v4l2 m2m support
In-Reply-To: <20171003092839.26236-1-jacob-chen@iotwrt.com>
References: <20171003092839.26236-1-jacob-chen@iotwrt.com>
Message-ID: <20171003092839.26236-2-jacob-chen@iotwrt.com>

Rockchip RGA is a separate 2D raster graphic acceleration unit. It
accelerates 2D graphics operations, such as point/line drawing, image
scaling, rotation, BitBLT, alpha blending and image blur/sharpness

The driver supports various operations from the rendering pipeline.
 - copy
 - fast solid color fill
 - rotation
 - flip
 - alpha blending

The code in rga-hw.c is used to configure regs according to operations
The code in rga-buf.c is used to create private mmu table for RGA.

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
---
 drivers/media/platform/Kconfig                |   15 +
 drivers/media/platform/Makefile               |    2 +
 drivers/media/platform/rockchip/rga/Makefile  |    3 +
 drivers/media/platform/rockchip/rga/rga-buf.c |  154 ++++
 drivers/media/platform/rockchip/rga/rga-hw.c  |  421 ++++++++++
 drivers/media/platform/rockchip/rga/rga-hw.h  |  437 +++++++++++
 drivers/media/platform/rockchip/rga/rga.c     | 1012 +++++++++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga.h     |  123 +++
 8 files changed, 2167 insertions(+)
 create mode 100644 drivers/media/platform/rockchip/rga/Makefile
 create mode 100644 drivers/media/platform/rockchip/rga/rga-buf.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.h
 create mode 100644 drivers/media/platform/rockchip/rga/rga.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 7e7cc49b8674..d0ddc7ef7e94 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -458,6 +458,21 @@ config VIDEO_RENESAS_VSP1
 	  To compile this driver as a module, choose M here: the module
 	  will be called vsp1.
 
+config VIDEO_ROCKCHIP_RGA
+	tristate "Rockchip Raster 2d Grapphic Acceleration Unit"
+	depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	select VIDEOBUF2_DMA_SG
+	select V4L2_MEM2MEM_DEV
+	default n
+	---help---
+	  This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator.
+	  Rockchip RGA is a separate 2D raster graphic acceleration unit.
+	  It accelerates 2D graphics operations, such as point/line drawing,
+	  image scaling, rotation, BitBLT, alpha blending and image blur/sharpness.
+
+	  To compile this driver as a module choose m here.
+
 config VIDEO_TI_VPE
 	tristate "TI VPE (Video Processing Engine) driver"
 	depends on VIDEO_DEV && VIDEO_V4L2
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index c1ef946bf032..c179de1c98c3 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -62,6 +62,8 @@ obj-$(CONFIG_VIDEO_RENESAS_FDP1)	+= rcar_fdp1.o
 obj-$(CONFIG_VIDEO_RENESAS_JPU) 	+= rcar_jpu.o
 obj-$(CONFIG_VIDEO_RENESAS_VSP1)	+= vsp1/
 
+obj-$(CONFIG_VIDEO_ROCKCHIP_RGA)	+= rockchip/rga/
+
 obj-y	+= omap/
 
 obj-$(CONFIG_VIDEO_AM437X_VPFE)		+= am437x/
diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
new file mode 100644
index 000000000000..92fe25490ccd
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/Makefile
@@ -0,0 +1,3 @@
+rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
+
+obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
new file mode 100644
index 000000000000..49cacc7a48d1
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/pm_runtime.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "rga-hw.h"
+#include "rga.h"
+
+static int
+rga_queue_setup(struct vb2_queue *vq,
+		unsigned int *nbuffers, unsigned int *nplanes,
+		unsigned int sizes[], struct device *alloc_devs[])
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(vq);
+	struct rga_frame *f = rga_get_frame(ctx, vq->type);
+
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	if (*nplanes)
+		return sizes[0] < f->size ? -EINVAL : 0;
+
+	sizes[0] = f->size;
+	*nplanes = 1;
+
+	return 0;
+}
+
+static int rga_buf_prepare(struct vb2_buffer *vb)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
+
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	vb2_set_plane_payload(vb, 0, f->size);
+
+	return 0;
+}
+
+static void rga_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(q);
+	struct rockchip_rga *rga = ctx->rga;
+	int ret, i;
+
+	ret = pm_runtime_get_sync(rga->dev);
+
+	if (!ret)
+		return 0;
+
+	for (i = 0; i < q->num_buffers; ++i) {
+		if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
+			v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]),
+					  VB2_BUF_STATE_QUEUED);
+		}
+	}
+
+	return ret;
+}
+
+static void rga_buf_stop_streaming(struct vb2_queue *q)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(q);
+	struct rockchip_rga *rga = ctx->rga;
+	struct vb2_v4l2_buffer *vbuf;
+
+	for (;;) {
+		if (V4L2_TYPE_IS_OUTPUT(q->type))
+			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		else
+			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+		if (!vbuf)
+			break;
+		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+	}
+
+	pm_runtime_put(rga->dev);
+}
+
+const struct vb2_ops rga_qops = {
+	.queue_setup = rga_queue_setup,
+	.buf_prepare = rga_buf_prepare,
+	.buf_queue = rga_buf_queue,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.start_streaming = rga_buf_start_streaming,
+	.stop_streaming = rga_buf_stop_streaming,
+};
+
+/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API.
+ * We use it more like a scatter-gather list.
+ */
+void rga_buf_map(struct vb2_buffer *vb)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct rockchip_rga *rga = ctx->rga;
+	struct sg_table *sgt;
+	struct scatterlist *sgl;
+	unsigned int *pages;
+	unsigned int address, len, i, p;
+	unsigned int mapped_size = 0;
+
+	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		pages = rga->src_mmu_pages;
+	else
+		pages = rga->dst_mmu_pages;
+
+	/* Create local MMU table for RGA */
+	sgt = vb2_plane_cookie(vb, 0);
+
+	for_each_sg(sgt->sgl, sgl, sgt->nents, i) {
+		len = sg_dma_len(sgl) >> PAGE_SHIFT;
+		address = sg_phys(sgl);
+
+		for (p = 0; p < len; p++) {
+			dma_addr_t phys = address + (p << PAGE_SHIFT);
+
+			pages[mapped_size + p] = phys;
+		}
+
+		mapped_size += len;
+	}
+
+	/* sync local MMU table for RGA */
+	dma_sync_single_for_device(rga->dev, virt_to_phys(pages),
+				   8 * PAGE_SIZE, DMA_BIDIRECTIONAL);
+}
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
new file mode 100644
index 000000000000..0645481c9a5e
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/pm_runtime.h>
+
+#include "rga-hw.h"
+#include "rga.h"
+
+enum e_rga_start_pos {
+	LT = 0,
+	LB = 1,
+	RT = 2,
+	RB = 3,
+};
+
+struct rga_addr_offset {
+	unsigned int y_off;
+	unsigned int u_off;
+	unsigned int v_off;
+};
+
+struct rga_corners_addr_offset {
+	struct rga_addr_offset left_top;
+	struct rga_addr_offset right_top;
+	struct rga_addr_offset left_bottom;
+	struct rga_addr_offset right_bottom;
+};
+
+static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
+{
+	/*
+	 * The rga hw scaling factor is a normalized inverse of the
+	 * scaling factor.
+	 * For example: When source width is 100 and destination width is 200
+	 * (scaling of 2x), then the hw factor is NC * 100 / 200.
+	 * The normalization factor (NC) is 2^16 = 0x10000.
+	 */
+
+	return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);
+}
+
+static struct rga_corners_addr_offset
+rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y,
+		    unsigned int w, unsigned int h)
+{
+	struct rga_corners_addr_offset offsets;
+	struct rga_addr_offset *lt, *lb, *rt, *rb;
+	unsigned int x_div = 0,
+		     y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0;
+
+	lt = &offsets.left_top;
+	lb = &offsets.left_bottom;
+	rt = &offsets.right_top;
+	rb = &offsets.right_bottom;
+
+	x_div = frm->fmt->x_div;
+	y_div = frm->fmt->y_div;
+	uv_factor = frm->fmt->uv_factor;
+	uv_stride = frm->stride / x_div;
+	pixel_width = frm->stride / frm->width;
+
+	lt->y_off = y * frm->stride + x * pixel_width;
+	lt->u_off =
+		frm->width * frm->height + (y / y_div) * uv_stride + x / x_div;
+	lt->v_off = lt->u_off + frm->width * frm->height / uv_factor;
+
+	lb->y_off = lt->y_off + (h - 1) * frm->stride;
+	lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
+	lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;
+
+	rt->y_off = lt->y_off + (w - 1) * pixel_width;
+	rt->u_off = lt->u_off + w / x_div - 1;
+	rt->v_off = lt->v_off + w / x_div - 1;
+
+	rb->y_off = lb->y_off + (w - 1) * pixel_width;
+	rb->u_off = lb->u_off + w / x_div - 1;
+	rb->v_off = lb->v_off + w / x_div - 1;
+
+	return offsets;
+}
+
+static struct rga_addr_offset *rga_lookup_draw_pos(struct
+		rga_corners_addr_offset
+		* offsets, u32 rotate_mode,
+		u32 mirr_mode)
+{
+	static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {
+		{
+			LT, RT, LB, RB,
+		},
+		{
+			RT, LT, RB, LB,
+		},
+		{
+			RB, LB, RT, LT,
+		},
+		{
+			LB, RB, LT, RT,
+		},
+	};
+
+	if (!offsets)
+		return NULL;
+
+	switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {
+	case LT:
+		return &offsets->left_top;
+	case LB:
+		return &offsets->left_bottom;
+	case RT:
+		return &offsets->right_top;
+	case RB:
+		return &offsets->right_bottom;
+	}
+
+	return NULL;
+}
+
+static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
+	dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+
+	reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
+	dest[reg >> 2] |= 0x7;
+}
+
+static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
+	dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+
+	reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
+	dest[reg >> 2] |= 0x7 << 4;
+}
+
+static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
+	dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+
+	reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
+	dest[reg >> 2] |= 0x7 << 8;
+}
+
+static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int scale_dst_w, scale_dst_h;
+	unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y;
+	union rga_src_info src_info;
+	union rga_dst_info dst_info;
+	union rga_src_x_factor x_factor;
+	union rga_src_y_factor y_factor;
+	union rga_src_vir_info src_vir_info;
+	union rga_src_act_info src_act_info;
+	union rga_dst_vir_info dst_vir_info;
+	union rga_dst_act_info dst_act_info;
+
+	struct rga_addr_offset *dst_offset;
+	struct rga_corners_addr_offset offsets;
+	struct rga_corners_addr_offset src_offsets;
+
+	src_h = ctx->in.crop.height;
+	src_w = ctx->in.crop.width;
+	src_x = ctx->in.crop.left;
+	src_y = ctx->in.crop.top;
+	dst_h = ctx->out.crop.height;
+	dst_w = ctx->out.crop.width;
+	dst_x = ctx->out.crop.left;
+	dst_y = ctx->out.crop.top;
+
+	src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2];
+	dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2];
+	x_factor.val = dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2];
+	y_factor.val = dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2];
+	src_vir_info.val = dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
+	src_act_info.val = dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
+	dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
+	dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
+
+	src_info.data.format = ctx->in.fmt->hw_format;
+	src_info.data.swap = ctx->in.fmt->color_swap;
+	dst_info.data.format = ctx->out.fmt->hw_format;
+	dst_info.data.swap = ctx->out.fmt->color_swap;
+
+	if (ctx->in.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
+		if (ctx->out.fmt->hw_format < RGA_COLOR_FMT_YUV422SP) {
+			switch (ctx->in.colorspace) {
+			case V4L2_COLORSPACE_REC709:
+				src_info.data.csc_mode =
+					RGA_SRC_CSC_MODE_BT709_R0;
+				break;
+			default:
+				src_info.data.csc_mode =
+					RGA_SRC_CSC_MODE_BT601_R0;
+				break;
+			}
+		}
+	}
+
+	if (ctx->out.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
+		switch (ctx->out.colorspace) {
+		case V4L2_COLORSPACE_REC709:
+			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
+			break;
+		default:
+			dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0;
+			break;
+		}
+	}
+
+	if (ctx->vflip)
+		src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X;
+
+	if (ctx->hflip)
+		src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y;
+
+	switch (ctx->rotate) {
+	case 90:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_90_DEGREE;
+		break;
+	case 180:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_180_DEGREE;
+		break;
+	case 270:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_270_DEGREE;
+		break;
+	default:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_0_DEGREE;
+		break;
+	}
+
+	/*
+	 * Cacluate the up/down scaling mode/factor.
+	 *
+	 * RGA used to scale the picture first, and then rotate second,
+	 * so we need to swap the w/h when rotate degree is 90/270.
+	 */
+	if (src_info.data.rot_mode == RGA_SRC_ROT_MODE_90_DEGREE ||
+	    src_info.data.rot_mode == RGA_SRC_ROT_MODE_270_DEGREE) {
+		if (rga->version.major == 0 || rga->version.minor == 0) {
+			if (dst_w == src_h)
+				src_h -= 8;
+			if (abs(src_w - dst_h) < 16)
+				src_w -= 16;
+		}
+
+		scale_dst_h = dst_w;
+		scale_dst_w = dst_h;
+	} else {
+		scale_dst_w = dst_w;
+		scale_dst_h = dst_h;
+	}
+
+	if (src_w == scale_dst_w) {
+		src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_NO;
+		x_factor.val = 0;
+	} else if (src_w > scale_dst_w) {
+		src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN;
+		x_factor.data.down_scale_factor =
+			rga_get_scaling(src_w, scale_dst_w) + 1;
+	} else {
+		src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_UP;
+		x_factor.data.up_scale_factor =
+			rga_get_scaling(src_w - 1, scale_dst_w - 1);
+	}
+
+	if (src_h == scale_dst_h) {
+		src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_NO;
+		y_factor.val = 0;
+	} else if (src_h > scale_dst_h) {
+		src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN;
+		y_factor.data.down_scale_factor =
+			rga_get_scaling(src_h, scale_dst_h) + 1;
+	} else {
+		src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_UP;
+		y_factor.data.up_scale_factor =
+			rga_get_scaling(src_h - 1, scale_dst_h - 1);
+	}
+
+	/*
+	 * Cacluate the framebuffer virtual strides and active size,
+	 * note that the step of vir_stride / vir_width is 4 byte words
+	 */
+	src_vir_info.data.vir_stride = ctx->in.stride >> 2;
+	src_vir_info.data.vir_width = ctx->in.stride >> 2;
+
+	src_act_info.data.act_height = src_h - 1;
+	src_act_info.data.act_width = src_w - 1;
+
+	dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
+	dst_act_info.data.act_height = dst_h - 1;
+	dst_act_info.data.act_width = dst_w - 1;
+
+	/*
+	 * Cacluate the source framebuffer base address with offset pixel.
+	 */
+	src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y,
+					  src_w, src_h);
+
+	/*
+	 * Configure the dest framebuffer base address with pixel offset.
+	 */
+	offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h);
+	dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode,
+					 src_info.data.mir_mode);
+
+	dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		src_offsets.left_top.y_off;
+	dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		src_offsets.left_top.u_off;
+	dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		src_offsets.left_top.v_off;
+
+	dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;
+	dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;
+	dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;
+	dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;
+
+	dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;
+
+	dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		dst_offset->y_off;
+	dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		dst_offset->u_off;
+	dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		dst_offset->v_off;
+
+	dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;
+	dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;
+
+	dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;
+}
+
+static void rga_cmd_set_mode(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	union rga_mode_ctrl mode;
+	union rga_alpha_ctrl0 alpha_ctrl0;
+	union rga_alpha_ctrl1 alpha_ctrl1;
+
+	mode.val = 0;
+	alpha_ctrl0.val = 0;
+	alpha_ctrl1.val = 0;
+
+	mode.data.gradient_sat = 1;
+	mode.data.render = RGA_MODE_RENDER_BITBLT;
+	mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST;
+
+	/* disable alpha blending */
+	dest[(RGA_ALPHA_CTRL0 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl0.val;
+	dest[(RGA_ALPHA_CTRL1 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl1.val;
+
+	dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;
+}
+
+void rga_cmd_set(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+
+	memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
+
+	rga_cmd_set_src_addr(ctx, rga->src_mmu_pages);
+	/*
+	 * Due to hardware bug,
+	 * src1 mmu also should be configured when using alpha blending.
+	 */
+	rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages);
+
+	rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages);
+	rga_cmd_set_mode(ctx);
+
+	rga_cmd_set_trans_info(ctx);
+
+	rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
+
+	/* sync CMD buf for RGA */
+	dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
+		PAGE_SIZE, DMA_BIDIRECTIONAL);
+}
+
+void rga_hw_start(struct rockchip_rga *rga)
+{
+	struct rga_ctx *ctx = rga->curr;
+
+	rga_cmd_set(ctx);
+
+	rga_write(rga, RGA_SYS_CTRL, 0x00);
+
+	rga_write(rga, RGA_SYS_CTRL, 0x22);
+
+	rga_write(rga, RGA_INT, 0x600);
+
+	rga_write(rga, RGA_CMD_CTRL, 0x1);
+}
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
new file mode 100644
index 000000000000..ca3c204abe42
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __RGA_HW_H__
+#define __RGA_HW_H__
+
+#define RGA_CMDBUF_SIZE 0x20
+
+/* Hardware limits */
+#define MAX_WIDTH 8192
+#define MAX_HEIGHT 8192
+
+#define MIN_WIDTH 34
+#define MIN_HEIGHT 34
+
+#define DEFAULT_WIDTH 100
+#define DEFAULT_HEIGHT 100
+
+#define RGA_TIMEOUT 500
+
+/* Registers address */
+#define RGA_SYS_CTRL 0x0000
+#define RGA_CMD_CTRL 0x0004
+#define RGA_CMD_BASE 0x0008
+#define RGA_INT 0x0010
+#define RGA_MMU_CTRL0 0x0014
+#define RGA_VERSION_INFO 0x0028
+
+#define RGA_MODE_BASE_REG 0x0100
+#define RGA_MODE_MAX_REG 0x017C
+
+#define RGA_MODE_CTRL 0x0100
+#define RGA_SRC_INFO 0x0104
+#define RGA_SRC_Y_RGB_BASE_ADDR 0x0108
+#define RGA_SRC_CB_BASE_ADDR 0x010c
+#define RGA_SRC_CR_BASE_ADDR 0x0110
+#define RGA_SRC1_RGB_BASE_ADDR 0x0114
+#define RGA_SRC_VIR_INFO 0x0118
+#define RGA_SRC_ACT_INFO 0x011c
+#define RGA_SRC_X_FACTOR 0x0120
+#define RGA_SRC_Y_FACTOR 0x0124
+#define RGA_SRC_BG_COLOR 0x0128
+#define RGA_SRC_FG_COLOR 0x012c
+#define RGA_SRC_TR_COLOR0 0x0130
+#define RGA_SRC_TR_COLOR1 0x0134
+
+#define RGA_DST_INFO 0x0138
+#define RGA_DST_Y_RGB_BASE_ADDR 0x013c
+#define RGA_DST_CB_BASE_ADDR 0x0140
+#define RGA_DST_CR_BASE_ADDR 0x0144
+#define RGA_DST_VIR_INFO 0x0148
+#define RGA_DST_ACT_INFO 0x014c
+
+#define RGA_ALPHA_CTRL0 0x0150
+#define RGA_ALPHA_CTRL1 0x0154
+#define RGA_FADING_CTRL 0x0158
+#define RGA_PAT_CON 0x015c
+#define RGA_ROP_CON0 0x0160
+#define RGA_ROP_CON1 0x0164
+#define RGA_MASK_BASE 0x0168
+
+#define RGA_MMU_CTRL1 0x016C
+#define RGA_MMU_SRC_BASE 0x0170
+#define RGA_MMU_SRC1_BASE 0x0174
+#define RGA_MMU_DST_BASE 0x0178
+
+/* Registers value */
+#define RGA_MODE_RENDER_BITBLT 0
+#define RGA_MODE_RENDER_COLOR_PALETTE 1
+#define RGA_MODE_RENDER_RECTANGLE_FILL 2
+#define RGA_MODE_RENDER_UPDATE_PALETTE_LUT_RAM 3
+
+#define RGA_MODE_BITBLT_MODE_SRC_TO_DST 0
+#define RGA_MODE_BITBLT_MODE_SRC_SRC1_TO_DST 1
+
+#define RGA_MODE_CF_ROP4_SOLID 0
+#define RGA_MODE_CF_ROP4_PATTERN 1
+
+#define RGA_COLOR_FMT_ABGR8888 0
+#define RGA_COLOR_FMT_XBGR8888 1
+#define RGA_COLOR_FMT_RGB888 2
+#define RGA_COLOR_FMT_BGR565 4
+#define RGA_COLOR_FMT_ABGR1555 5
+#define RGA_COLOR_FMT_ABGR4444 6
+#define RGA_COLOR_FMT_YUV422SP 8
+#define RGA_COLOR_FMT_YUV422P 9
+#define RGA_COLOR_FMT_YUV420SP 10
+#define RGA_COLOR_FMT_YUV420P 11
+/* SRC_COLOR Palette */
+#define RGA_COLOR_FMT_CP_1BPP 12
+#define RGA_COLOR_FMT_CP_2BPP 13
+#define RGA_COLOR_FMT_CP_4BPP 14
+#define RGA_COLOR_FMT_CP_8BPP 15
+#define RGA_COLOR_FMT_MASK 15
+
+#define RGA_COLOR_NONE_SWAP 0
+#define RGA_COLOR_RB_SWAP 1
+#define RGA_COLOR_ALPHA_SWAP 2
+#define RGA_COLOR_UV_SWAP 4
+
+#define RGA_SRC_CSC_MODE_BYPASS 0
+#define RGA_SRC_CSC_MODE_BT601_R0 1
+#define RGA_SRC_CSC_MODE_BT601_R1 2
+#define RGA_SRC_CSC_MODE_BT709_R0 3
+#define RGA_SRC_CSC_MODE_BT709_R1 4
+
+#define RGA_SRC_ROT_MODE_0_DEGREE 0
+#define RGA_SRC_ROT_MODE_90_DEGREE 1
+#define RGA_SRC_ROT_MODE_180_DEGREE 2
+#define RGA_SRC_ROT_MODE_270_DEGREE 3
+
+#define RGA_SRC_MIRR_MODE_NO 0
+#define RGA_SRC_MIRR_MODE_X 1
+#define RGA_SRC_MIRR_MODE_Y 2
+#define RGA_SRC_MIRR_MODE_X_Y 3
+
+#define RGA_SRC_HSCL_MODE_NO 0
+#define RGA_SRC_HSCL_MODE_DOWN 1
+#define RGA_SRC_HSCL_MODE_UP 2
+
+#define RGA_SRC_VSCL_MODE_NO 0
+#define RGA_SRC_VSCL_MODE_DOWN 1
+#define RGA_SRC_VSCL_MODE_UP 2
+
+#define RGA_SRC_TRANS_ENABLE_R 1
+#define RGA_SRC_TRANS_ENABLE_G 2
+#define RGA_SRC_TRANS_ENABLE_B 4
+#define RGA_SRC_TRANS_ENABLE_A 8
+
+#define RGA_SRC_BIC_COE_SELEC_CATROM 0
+#define RGA_SRC_BIC_COE_SELEC_MITCHELL 1
+#define RGA_SRC_BIC_COE_SELEC_HERMITE 2
+#define RGA_SRC_BIC_COE_SELEC_BSPLINE 3
+
+#define RGA_DST_DITHER_MODE_888_TO_666 0
+#define RGA_DST_DITHER_MODE_888_TO_565 1
+#define RGA_DST_DITHER_MODE_888_TO_555 2
+#define RGA_DST_DITHER_MODE_888_TO_444 3
+
+#define RGA_DST_CSC_MODE_BYPASS 0
+#define RGA_DST_CSC_MODE_BT601_R0 1
+#define RGA_DST_CSC_MODE_BT601_R1 2
+#define RGA_DST_CSC_MODE_BT709_R0 3
+
+#define RGA_ALPHA_ROP_MODE_2 0
+#define RGA_ALPHA_ROP_MODE_3 1
+#define RGA_ALPHA_ROP_MODE_4 2
+
+#define RGA_ALPHA_SELECT_ALPHA 0
+#define RGA_ALPHA_SELECT_ROP 1
+
+#define RGA_ALPHA_MASK_BIG_ENDIAN 0
+#define RGA_ALPHA_MASK_LITTLE_ENDIAN 1
+
+#define RGA_ALPHA_NORMAL 0
+#define RGA_ALPHA_REVERSE 1
+
+#define RGA_ALPHA_BLEND_GLOBAL 0
+#define RGA_ALPHA_BLEND_NORMAL 1
+#define RGA_ALPHA_BLEND_MULTIPLY 2
+
+#define RGA_ALPHA_CAL_CUT 0
+#define RGA_ALPHA_CAL_NORMAL 1
+
+#define RGA_ALPHA_FACTOR_ZERO 0
+#define RGA_ALPHA_FACTOR_ONE 1
+#define RGA_ALPHA_FACTOR_OTHER 2
+#define RGA_ALPHA_FACTOR_OTHER_REVERSE 3
+#define RGA_ALPHA_FACTOR_SELF 4
+
+#define RGA_ALPHA_COLOR_NORMAL 0
+#define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
+
+/* Registers union */
+union rga_mode_ctrl {
+	unsigned int val;
+	struct {
+		/* [0:2] */
+		unsigned int render:3;
+		/* [3:6] */
+		unsigned int bitblt:1;
+		unsigned int cf_rop4_pat:1;
+		unsigned int alpha_zero_key:1;
+		unsigned int gradient_sat:1;
+		/* [7:31] */
+		unsigned int reserved:25;
+	} data;
+};
+
+union rga_src_info {
+	unsigned int val;
+	struct {
+		/* [0:3] */
+		unsigned int format:4;
+		/* [4:7] */
+		unsigned int swap:3;
+		unsigned int cp_endian:1;
+		/* [8:17] */
+		unsigned int csc_mode:2;
+		unsigned int rot_mode:2;
+		unsigned int mir_mode:2;
+		unsigned int hscl_mode:2;
+		unsigned int vscl_mode:2;
+		/* [18:22] */
+		unsigned int trans_mode:1;
+		unsigned int trans_enable:4;
+		/* [23:25] */
+		unsigned int dither_up_en:1;
+		unsigned int bic_coe_sel:2;
+		/* [26:31] */
+		unsigned int reserved:6;
+	} data;
+};
+
+union rga_src_vir_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int vir_width:15;
+		unsigned int reserved:1;
+		/* [16:25] */
+		unsigned int vir_stride:10;
+		/* [26:31] */
+		unsigned int reserved1:6;
+	} data;
+};
+
+union rga_src_act_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int act_width:13;
+		unsigned int reserved:3;
+		/* [16:31] */
+		unsigned int act_height:13;
+		unsigned int reserved1:3;
+	} data;
+};
+
+union rga_src_x_factor {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int down_scale_factor:16;
+		/* [16:31] */
+		unsigned int up_scale_factor:16;
+	} data;
+};
+
+union rga_src_y_factor {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int down_scale_factor:16;
+		/* [16:31] */
+		unsigned int up_scale_factor:16;
+	} data;
+};
+
+/* Alpha / Red / Green / Blue */
+union rga_src_cp_gr_color {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int gradient_x:16;
+		/* [16:31] */
+		unsigned int gradient_y:16;
+	} data;
+};
+
+union rga_src_transparency_color0 {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int trans_rmin:8;
+		/* [8:15] */
+		unsigned int trans_gmin:8;
+		/* [16:23] */
+		unsigned int trans_bmin:8;
+		/* [24:31] */
+		unsigned int trans_amin:8;
+	} data;
+};
+
+union rga_src_transparency_color1 {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int trans_rmax:8;
+		/* [8:15] */
+		unsigned int trans_gmax:8;
+		/* [16:23] */
+		unsigned int trans_bmax:8;
+		/* [24:31] */
+		unsigned int trans_amax:8;
+	} data;
+};
+
+union rga_dst_info {
+	unsigned int val;
+	struct {
+		/* [0:3] */
+		unsigned int format:4;
+		/* [4:6] */
+		unsigned int swap:3;
+		/* [7:9] */
+		unsigned int src1_format:3;
+		/* [10:11] */
+		unsigned int src1_swap:2;
+		/* [12:15] */
+		unsigned int dither_up_en:1;
+		unsigned int dither_down_en:1;
+		unsigned int dither_down_mode:2;
+		/* [16:18] */
+		unsigned int csc_mode:2;
+		unsigned int csc_clip:1;
+		/* [19:31] */
+		unsigned int reserved:13;
+	} data;
+};
+
+union rga_dst_vir_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int vir_stride:15;
+		unsigned int reserved:1;
+		/* [16:31] */
+		unsigned int src1_vir_stride:15;
+		unsigned int reserved1:1;
+	} data;
+};
+
+union rga_dst_act_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int act_width:12;
+		unsigned int reserved:4;
+		/* [16:31] */
+		unsigned int act_height:12;
+		unsigned int reserved1:4;
+	} data;
+};
+
+union rga_alpha_ctrl0 {
+	unsigned int val;
+	struct {
+		/* [0:3] */
+		unsigned int rop_en:1;
+		unsigned int rop_select:1;
+		unsigned int rop_mode:2;
+		/* [4:11] */
+		unsigned int src_fading_val:8;
+		/* [12:20] */
+		unsigned int dst_fading_val:8;
+		unsigned int mask_endian:1;
+		/* [21:31] */
+		unsigned int reserved:11;
+	} data;
+};
+
+union rga_alpha_ctrl1 {
+	unsigned int val;
+	struct {
+		/* [0:1] */
+		unsigned int dst_color_m0:1;
+		unsigned int src_color_m0:1;
+		/* [2:7] */
+		unsigned int dst_factor_m0:3;
+		unsigned int src_factor_m0:3;
+		/* [8:9] */
+		unsigned int dst_alpha_cal_m0:1;
+		unsigned int src_alpha_cal_m0:1;
+		/* [10:13] */
+		unsigned int dst_blend_m0:2;
+		unsigned int src_blend_m0:2;
+		/* [14:15] */
+		unsigned int dst_alpha_m0:1;
+		unsigned int src_alpha_m0:1;
+		/* [16:21] */
+		unsigned int dst_factor_m1:3;
+		unsigned int src_factor_m1:3;
+		/* [22:23] */
+		unsigned int dst_alpha_cal_m1:1;
+		unsigned int src_alpha_cal_m1:1;
+		/* [24:27] */
+		unsigned int dst_blend_m1:2;
+		unsigned int src_blend_m1:2;
+		/* [28:29] */
+		unsigned int dst_alpha_m1:1;
+		unsigned int src_alpha_m1:1;
+		/* [30:31] */
+		unsigned int reserved:2;
+	} data;
+};
+
+union rga_fading_ctrl {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int fading_offset_r:8;
+		/* [8:15] */
+		unsigned int fading_offset_g:8;
+		/* [16:23] */
+		unsigned int fading_offset_b:8;
+		/* [24:31] */
+		unsigned int fading_en:1;
+		unsigned int reserved:7;
+	} data;
+};
+
+union rga_pat_con {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int width:8;
+		/* [8:15] */
+		unsigned int height:8;
+		/* [16:23] */
+		unsigned int offset_x:8;
+		/* [24:31] */
+		unsigned int offset_y:8;
+	} data;
+};
+
+#endif
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
new file mode 100644
index 000000000000..d1d451f88a55
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "rga-hw.h"
+#include "rga.h"
+
+static int debug;
+module_param(debug, int, 0644);
+
+static void job_abort(void *prv)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+
+	if (!rga->curr)	/* No job currently running */
+		return;
+
+	wait_event_timeout(rga->irq_queue,
+			   !rga->curr, msecs_to_jiffies(RGA_TIMEOUT));
+}
+
+static void device_run(void *prv)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+	struct vb2_buffer *src, *dst;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rga->ctrl_lock, flags);
+
+	rga->curr = ctx;
+
+	src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+	rga_buf_map(src);
+	rga_buf_map(dst);
+
+	rga_hw_start(rga);
+
+	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
+}
+
+static irqreturn_t rga_isr(int irq, void *prv)
+{
+	struct rockchip_rga *rga = prv;
+	int intr;
+
+	intr = rga_read(rga, RGA_INT) & 0xf;
+
+	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
+
+	if (intr & 0x04) {
+		struct vb2_v4l2_buffer *src, *dst;
+		struct rga_ctx *ctx = rga->curr;
+
+		BUG_ON(!ctx);
+
+		rga->curr = NULL;
+
+		src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+		BUG_ON(!src);
+		BUG_ON(!dst);
+
+		dst->timecode = src->timecode;
+		dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
+		dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+		dst->flags |= src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+
+		v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
+		v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
+		v4l2_m2m_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx);
+
+		wake_up(&rga->irq_queue);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct v4l2_m2m_ops rga_m2m_ops = {
+	.device_run = device_run,
+	.job_abort = job_abort,
+};
+
+static int
+queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+	struct rga_ctx *ctx = priv;
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	src_vq->drv_priv = ctx;
+	src_vq->ops = &rga_qops;
+	src_vq->mem_ops = &vb2_dma_sg_memops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->lock = &ctx->rga->mutex;
+	src_vq->dev = ctx->rga->v4l2_dev.dev;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->ops = &rga_qops;
+	dst_vq->mem_ops = &vb2_dma_sg_memops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->lock = &ctx->rga->mutex;
+	dst_vq->dev = ctx->rga->v4l2_dev.dev;
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int rga_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct rga_ctx *ctx = container_of(ctrl->handler, struct rga_ctx,
+					   ctrl_handler);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->rga->ctrl_lock, flags);
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		ctx->hflip = ctrl->val;
+		break;
+	case V4L2_CID_VFLIP:
+		ctx->vflip = ctrl->val;
+		break;
+	case V4L2_CID_ROTATE:
+		ctx->rotate = ctrl->val;
+		break;
+	case V4L2_CID_BG_COLOR:
+		ctx->fill_color = ctrl->val;
+		break;
+	}
+	spin_unlock_irqrestore(&ctx->rga->ctrl_lock, flags);
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops rga_ctrl_ops = {
+	.s_ctrl = rga_s_ctrl,
+};
+
+static int rga_setup_ctrls(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_ROTATE, 0, 270, 90, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
+
+	if (ctx->ctrl_handler.error) {
+		int err = ctx->ctrl_handler.error;
+
+		v4l2_err(&rga->v4l2_dev, "%s failed\n", __func__);
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+		return err;
+	}
+
+	return 0;
+}
+
+struct rga_fmt formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XRGB32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_XBGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XBGR32,
+		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.hw_format = RGA_COLOR_FMT_XBGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB444,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR4444,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB555,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR1555,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_BGR565,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV422P,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422P,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YVU420,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+struct rga_fmt *rga_fmt_find(struct v4l2_format *f)
+{
+	unsigned int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].fourcc == f->fmt.pix.pixelformat)
+			return &formats[i];
+	}
+	return NULL;
+}
+
+static struct rga_frame def_frame = {
+	.width = DEFAULT_WIDTH,
+	.height = DEFAULT_HEIGHT,
+	.colorspace = V4L2_COLORSPACE_DEFAULT,
+	.crop.left = 0,
+	.crop.top = 0,
+	.crop.width = DEFAULT_WIDTH,
+	.crop.height = DEFAULT_HEIGHT,
+	.fmt = &formats[0],
+};
+
+struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &ctx->in;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &ctx->out;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+static int rga_open(struct file *file)
+{
+	struct rockchip_rga *rga = video_drvdata(file);
+	struct rga_ctx *ctx = NULL;
+	int ret = 0;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+	ctx->rga = rga;
+	/* Set default formats */
+	ctx->in = def_frame;
+	ctx->out = def_frame;
+
+	if (mutex_lock_interruptible(&rga->mutex)) {
+		kfree(ctx);
+		return -ERESTARTSYS;
+	}
+	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init);
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+		mutex_unlock(&rga->mutex);
+		kfree(ctx);
+		return ret;
+	}
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	rga_setup_ctrls(ctx);
+
+	/* Write the default values to the ctx struct */
+	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	mutex_unlock(&rga->mutex);
+
+	return 0;
+}
+
+static int rga_release(struct file *file)
+{
+	struct rga_ctx *ctx =
+		container_of(file->private_data, struct rga_ctx, fh);
+	struct rockchip_rga *rga = ctx->rga;
+
+	mutex_lock(&rga->mutex);
+
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+
+	mutex_unlock(&rga->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations rga_fops = {
+	.owner = THIS_MODULE,
+	.open = rga_open,
+	.release = rga_release,
+	.poll = v4l2_m2m_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = v4l2_m2m_fop_mmap,
+};
+
+static int
+vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+	strlcpy(cap->driver, RGA_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, "rockchip-rga", sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
+
+	return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
+{
+	struct rga_fmt *fmt;
+
+	if (f->index >= NUM_FORMATS)
+		return -EINVAL;
+
+	fmt = &formats[f->index];
+	f->pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct rga_ctx *ctx = prv;
+	struct vb2_queue *vq;
+	struct rga_frame *frm;
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+	frm = rga_get_frame(ctx, f->type);
+	if (IS_ERR(frm))
+		return PTR_ERR(frm);
+
+	f->fmt.pix.width = frm->width;
+	f->fmt.pix.height = frm->height;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat = frm->fmt->fourcc;
+	f->fmt.pix.bytesperline = frm->stride;
+	f->fmt.pix.sizeimage = frm->size;
+	f->fmt.pix.colorspace = frm->colorspace;
+
+	return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct rga_fmt *fmt;
+
+	fmt = rga_fmt_find(f);
+	if (!fmt) {
+		fmt = &formats[0];
+		f->fmt.pix.pixelformat = fmt->fourcc;
+	}
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+
+	if (f->fmt.pix.width > MAX_WIDTH)
+		f->fmt.pix.width = MAX_WIDTH;
+	if (f->fmt.pix.height > MAX_HEIGHT)
+		f->fmt.pix.height = MAX_HEIGHT;
+
+	if (f->fmt.pix.width < MIN_WIDTH)
+		f->fmt.pix.width = MIN_WIDTH;
+	if (f->fmt.pix.height < MIN_HEIGHT)
+		f->fmt.pix.height = MIN_HEIGHT;
+
+	if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP)
+		f->fmt.pix.bytesperline = f->fmt.pix.width;
+	else
+		f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * (f->fmt.pix.width * fmt->depth) >> 3;
+
+	return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+	struct vb2_queue *vq;
+	struct rga_frame *frm;
+	struct rga_fmt *fmt;
+	int ret = 0;
+
+	/* Adjust all values accordingly to the hardware capabilities
+	 * and chosen format.
+	 */
+	ret = vidioc_try_fmt(file, prv, f);
+	if (ret)
+		return ret;
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&rga->v4l2_dev, "queue (%d) bust\n", f->type);
+		return -EBUSY;
+	}
+	frm = rga_get_frame(ctx, f->type);
+	if (IS_ERR(frm))
+		return PTR_ERR(frm);
+	fmt = rga_fmt_find(f);
+	if (!fmt)
+		return -EINVAL;
+	frm->width = f->fmt.pix.width;
+	frm->height = f->fmt.pix.height;
+	frm->size = f->fmt.pix.sizeimage;
+	frm->fmt = fmt;
+	frm->stride = f->fmt.pix.bytesperline;
+	frm->colorspace = f->fmt.pix.colorspace;
+
+	/* Reset crop settings */
+	frm->crop.left = 0;
+	frm->crop.top = 0;
+	frm->crop.width = frm->width;
+	frm->crop.height = frm->height;
+
+	return 0;
+}
+
+static int vidioc_g_selection(struct file *file, void *prv,
+			      struct v4l2_selection *s)
+{
+	struct rga_ctx *ctx = prv;
+	struct rga_frame *f;
+	bool use_frame = false;
+
+	f = rga_get_frame(ctx, s->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		use_frame = true;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		use_frame = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (use_frame) {
+		s->r = f->crop;
+	} else {
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = f->width;
+		s->r.height = f->height;
+	}
+
+	return 0;
+}
+
+static int vidioc_s_selection(struct file *file, void *prv,
+			      struct v4l2_selection *s)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+	struct rga_frame *f;
+	int ret = 0;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:
+		/*
+		 * COMPOSE target is only valid for capture buffer type, return
+		 * error for output buffer type
+		 */
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		/*
+		 * CROP target is only valid for output buffer type, return
+		 * error for capture buffer type
+		 */
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		break;
+	/*
+	 * bound and default crop/compose targets are invalid targets to
+	 * try/set
+	 */
+	default:
+		return -EINVAL;
+	}
+
+	if (s->r.top < 0 || s->r.left < 0) {
+		v4l2_dbg(debug, 1, &rga->v4l2_dev,
+			 "doesn't support negative values for top & left.\n");
+		return -EINVAL;
+	}
+
+	if (s->r.left + s->r.width > f->width ||
+	    s->r.top + s->r.height > f->height ||
+	    s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
+		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
+		return -EINVAL;
+	}
+
+	f = rga_get_frame(ctx, s->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	f->crop = s->r;
+
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops rga_ioctl_ops = {
+	.vidioc_querycap = vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_cap = vidioc_g_fmt,
+	.vidioc_try_fmt_vid_cap = vidioc_try_fmt,
+	.vidioc_s_fmt_vid_cap = vidioc_s_fmt,
+
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_out = vidioc_g_fmt,
+	.vidioc_try_fmt_vid_out = vidioc_try_fmt,
+	.vidioc_s_fmt_vid_out = vidioc_s_fmt,
+
+	.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+	.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+	.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+	.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+	.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+	.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+	.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
+	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+	.vidioc_g_selection = vidioc_g_selection,
+	.vidioc_s_selection = vidioc_s_selection,
+};
+
+static struct video_device rga_videodev = {
+	.name = "rockchip-rga",
+	.fops = &rga_fops,
+	.ioctl_ops = &rga_ioctl_ops,
+	.minor = -1,
+	.release = video_device_release,
+	.vfl_dir = VFL_DIR_M2M,
+	.device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+static int rga_enable_clocks(struct rockchip_rga *rga)
+{
+	int ret;
+
+	ret = clk_prepare_enable(rga->sclk);
+	if (ret) {
+		dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(rga->aclk);
+	if (ret) {
+		dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret);
+		goto err_disable_sclk;
+	}
+
+	ret = clk_prepare_enable(rga->hclk);
+	if (ret) {
+		dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret);
+		goto err_disable_aclk;
+	}
+
+	return 0;
+
+err_disable_sclk:
+	clk_disable_unprepare(rga->sclk);
+err_disable_aclk:
+	clk_disable_unprepare(rga->aclk);
+
+	return ret;
+}
+
+static void rga_disable_clocks(struct rockchip_rga *rga)
+{
+	clk_disable_unprepare(rga->sclk);
+	clk_disable_unprepare(rga->hclk);
+	clk_disable_unprepare(rga->aclk);
+}
+
+static int rga_parse_dt(struct rockchip_rga *rga)
+{
+	struct reset_control *core_rst, *axi_rst, *ahb_rst;
+
+	core_rst = devm_reset_control_get(rga->dev, "core");
+	if (IS_ERR(core_rst)) {
+		dev_err(rga->dev, "failed to get core reset controller\n");
+		return PTR_ERR(core_rst);
+	}
+
+	axi_rst = devm_reset_control_get(rga->dev, "axi");
+	if (IS_ERR(axi_rst)) {
+		dev_err(rga->dev, "failed to get axi reset controller\n");
+		return PTR_ERR(axi_rst);
+	}
+
+	ahb_rst = devm_reset_control_get(rga->dev, "ahb");
+	if (IS_ERR(ahb_rst)) {
+		dev_err(rga->dev, "failed to get ahb reset controller\n");
+		return PTR_ERR(ahb_rst);
+	}
+
+	reset_control_assert(core_rst);
+	udelay(1);
+	reset_control_deassert(core_rst);
+
+	reset_control_assert(axi_rst);
+	udelay(1);
+	reset_control_deassert(axi_rst);
+
+	reset_control_assert(ahb_rst);
+	udelay(1);
+	reset_control_deassert(ahb_rst);
+
+	rga->sclk = devm_clk_get(rga->dev, "sclk");
+	if (IS_ERR(rga->sclk)) {
+		dev_err(rga->dev, "failed to get sclk clock\n");
+		return PTR_ERR(rga->sclk);
+	}
+
+	rga->aclk = devm_clk_get(rga->dev, "aclk");
+	if (IS_ERR(rga->aclk)) {
+		dev_err(rga->dev, "failed to get aclk clock\n");
+		return PTR_ERR(rga->aclk);
+	}
+
+	rga->hclk = devm_clk_get(rga->dev, "hclk");
+	if (IS_ERR(rga->hclk)) {
+		dev_err(rga->dev, "failed to get hclk clock\n");
+		return PTR_ERR(rga->hclk);
+	}
+
+	return 0;
+}
+
+static int rga_probe(struct platform_device *pdev)
+{
+	struct rockchip_rga *rga;
+	struct video_device *vfd;
+	struct resource *res;
+	int ret = 0;
+	int irq;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
+	if (!rga)
+		return -ENOMEM;
+
+	rga->dev = &pdev->dev;
+	spin_lock_init(&rga->ctrl_lock);
+	mutex_init(&rga->mutex);
+
+	init_waitqueue_head(&rga->irq_queue);
+
+	ret = rga_parse_dt(rga);
+	if (ret)
+		dev_err(&pdev->dev, "Unable to parse OF data\n");
+
+	pm_runtime_enable(rga->dev);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	rga->regs = devm_ioremap_resource(rga->dev, res);
+	if (IS_ERR(rga->regs)) {
+		ret = PTR_ERR(rga->regs);
+		goto err_put_clk;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(rga->dev, "failed to get irq\n");
+		ret = irq;
+		goto err_put_clk;
+	}
+
+	ret = devm_request_irq(rga->dev, irq, rga_isr, 0,
+			       dev_name(rga->dev), rga);
+	if (ret < 0) {
+		dev_err(rga->dev, "failed to request irq\n");
+		goto err_put_clk;
+	}
+
+	ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev);
+	if (ret)
+		goto err_put_clk;
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&rga->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_v4l2_dev;
+	}
+	*vfd = rga_videodev;
+	vfd->lock = &rga->mutex;
+	vfd->v4l2_dev = &rga->v4l2_dev;
+
+	video_set_drvdata(vfd, rga);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", rga_videodev.name);
+	rga->vfd = vfd;
+
+	platform_set_drvdata(pdev, rga);
+	rga->m2m_dev = v4l2_m2m_init(&rga_m2m_ops);
+	if (IS_ERR(rga->m2m_dev)) {
+		v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(rga->m2m_dev);
+		goto unreg_video_dev;
+	}
+
+	pm_runtime_get_sync(rga->dev);
+
+	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
+	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
+
+	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
+		  rga->version.major, rga->version.minor);
+
+	pm_runtime_put(rga->dev);
+
+	/* Create CMD buffer */
+	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
+					   &rga->cmdbuf_phy, GFP_KERNEL,
+					   DMA_ATTR_WRITE_COMBINE);
+
+	rga->src_mmu_pages =
+		(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
+	rga->dst_mmu_pages =
+		(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
+
+	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
+	def_frame.size = def_frame.stride * def_frame.height;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret) {
+		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
+		goto rel_vdev;
+	}
+
+	v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+
+	return 0;
+
+rel_vdev:
+	video_device_release(vfd);
+unreg_video_dev:
+	video_unregister_device(rga->vfd);
+unreg_v4l2_dev:
+	v4l2_device_unregister(&rga->v4l2_dev);
+err_put_clk:
+	pm_runtime_disable(rga->dev);
+
+	return ret;
+}
+
+static int rga_remove(struct platform_device *pdev)
+{
+	struct rockchip_rga *rga = platform_get_drvdata(pdev);
+
+	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, &rga->cmdbuf_virt,
+		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
+
+	free_pages((unsigned long)rga->src_mmu_pages, 3);
+	free_pages((unsigned long)rga->dst_mmu_pages, 3);
+
+	v4l2_info(&rga->v4l2_dev, "Removing\n");
+
+	v4l2_m2m_release(rga->m2m_dev);
+	video_unregister_device(rga->vfd);
+	v4l2_device_unregister(&rga->v4l2_dev);
+
+	pm_runtime_disable(rga->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rga_runtime_suspend(struct device *dev)
+{
+	struct rockchip_rga *rga = dev_get_drvdata(dev);
+
+	rga_disable_clocks(rga);
+
+	return 0;
+}
+
+static int rga_runtime_resume(struct device *dev)
+{
+	struct rockchip_rga *rga = dev_get_drvdata(dev);
+
+	return rga_enable_clocks(rga);
+}
+#endif
+
+static const struct dev_pm_ops rga_pm = {
+	SET_RUNTIME_PM_OPS(rga_runtime_suspend,
+			   rga_runtime_resume, NULL)
+};
+
+static const struct of_device_id rockchip_rga_match[] = {
+	{
+		.compatible = "rockchip,rk3288-rga",
+	},
+	{
+		.compatible = "rockchip,rk3399-rga",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_rga_match);
+
+static struct platform_driver rga_pdrv = {
+	.probe = rga_probe,
+	.remove = rga_remove,
+	.driver = {
+		.name = RGA_NAME,
+		.pm = &rga_pm,
+		.of_match_table = rockchip_rga_match,
+	},
+};
+
+module_platform_driver(rga_pdrv);
+
+MODULE_AUTHOR("Jacob Chen <jacob-chen at iotwrt.com>");
+MODULE_DESCRIPTION("Rockchip Raster 2d Graphic Acceleration Unit");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
new file mode 100644
index 000000000000..cf7003647112
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __RGA_H__
+#define __RGA_H__
+
+#include <linux/platform_device.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#define RGA_NAME "rockchip-rga"
+
+struct rga_fmt {
+	u32 fourcc;
+	int depth;
+	u8 uv_factor;
+	u8 y_div;
+	u8 x_div;
+	u8 color_swap;
+	u8 hw_format;
+};
+
+struct rga_frame {
+	/* Original dimensions */
+	u32 width;
+	u32 height;
+	u32 colorspace;
+
+	/* Crop */
+	struct v4l2_rect crop;
+
+	/* Image format */
+	struct rga_fmt *fmt;
+
+	/* Variables that can calculated once and reused */
+	u32 stride;
+	u32 size;
+};
+
+struct rockchip_rga_version {
+	u32 major;
+	u32 minor;
+};
+
+struct rga_ctx {
+	struct v4l2_fh fh;
+	struct rockchip_rga *rga;
+	struct rga_frame in;
+	struct rga_frame out;
+	struct v4l2_ctrl_handler ctrl_handler;
+
+	/* Control values */
+	u32 op;
+	u32 hflip;
+	u32 vflip;
+	u32 rotate;
+	u32 fill_color;
+};
+
+struct rockchip_rga {
+	struct v4l2_device v4l2_dev;
+	struct v4l2_m2m_dev *m2m_dev;
+	struct video_device *vfd;
+
+	struct device *dev;
+	struct regmap *grf;
+	void __iomem *regs;
+	struct clk *sclk;
+	struct clk *aclk;
+	struct clk *hclk;
+	struct rockchip_rga_version version;
+
+	struct mutex mutex;
+	spinlock_t ctrl_lock;
+
+	wait_queue_head_t irq_queue;
+
+	struct rga_ctx *curr;
+	dma_addr_t cmdbuf_phy;
+	void *cmdbuf_virt;
+	unsigned int *src_mmu_pages;
+	unsigned int *dst_mmu_pages;
+};
+
+struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type);
+
+/* RGA Buffers Manage */
+extern const struct vb2_ops rga_qops;
+void rga_buf_map(struct vb2_buffer *vb);
+
+/* RGA Hardware */
+static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value)
+{
+	writel(value, rga->regs + reg);
+};
+
+static inline u32 rga_read(struct rockchip_rga *rga, u32 reg)
+{
+	return readl(rga->regs + reg);
+};
+
+static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
+{
+	u32 temp = rga_read(rga, reg) & ~(mask);
+
+	temp |= val & mask;
+	rga_write(rga, reg, temp);
+};
+
+void rga_hw_start(struct rockchip_rga *rga);
+
+#endif
-- 
2.14.1



From kishon at ti.com  Tue Oct  3 02:41:04 2017
From: kishon at ti.com (Kishon Vijay Abraham I)
Date: Tue, 3 Oct 2017 15:11:04 +0530
Subject: [PATCH] phy: rockchip-typec: Check for errors from
 tcphy_phy_init()
In-Reply-To: <CABXOdTdukST-8tRh6Z2mRTFYwseiknEzB7FL+uiz_PxYrYYjgw@mail.gmail.com>
References: <20170929235846.1913-1-dianders@chromium.org>
 <CABXOdTdukST-8tRh6Z2mRTFYwseiknEzB7FL+uiz_PxYrYYjgw@mail.gmail.com>
Message-ID: <07d21b93-e58b-c5e3-8b9e-7150c023c452@ti.com>



On Saturday 30 September 2017 04:08 PM, Guenter Roeck wrote:
> On Fri, Sep 29, 2017 at 4:58 PM, Douglas Anderson <dianders at chromium.org> wrote:
>> The function tcphy_phy_init() could return an error but the callers
>> weren't checking the return value.  They should.  In at least one case
>> while testing I saw the message "wait pma ready timeout" which
>> indicates that tcphy_phy_init() really could return an error and we
>> should account for it.
>>
>> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> 
> Reviewed-by: Guenter Roeck <groeck at chromium.org>

merged, thanks!

-Kishon
> 
>> ---
>>
>>  drivers/phy/rockchip/phy-rockchip-typec.c | 13 +++++++++----
>>  1 file changed, 9 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
>> index 4d2c57f21d76..38831eebc934 100644
>> --- a/drivers/phy/rockchip/phy-rockchip-typec.c
>> +++ b/drivers/phy/rockchip/phy-rockchip-typec.c
>> @@ -685,8 +685,11 @@ static int rockchip_usb3_phy_power_on(struct phy *phy)
>>         if (tcphy->mode == new_mode)
>>                 goto unlock_ret;
>>
>> -       if (tcphy->mode == MODE_DISCONNECT)
>> -               tcphy_phy_init(tcphy, new_mode);
>> +       if (tcphy->mode == MODE_DISCONNECT) {
>> +               ret = tcphy_phy_init(tcphy, new_mode);
>> +               if (ret)
>> +                       goto unlock_ret;
>> +       }
>>
>>         /* wait TCPHY for pipe ready */
>>         for (timeout = 0; timeout < 100; timeout++) {
>> @@ -760,10 +763,12 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
>>          */
>>         if (new_mode == MODE_DFP_DP && tcphy->mode != MODE_DISCONNECT) {
>>                 tcphy_phy_deinit(tcphy);
>> -               tcphy_phy_init(tcphy, new_mode);
>> +               ret = tcphy_phy_init(tcphy, new_mode);
>>         } else if (tcphy->mode == MODE_DISCONNECT) {
>> -               tcphy_phy_init(tcphy, new_mode);
>> +               ret = tcphy_phy_init(tcphy, new_mode);
>>         }
>> +       if (ret)
>> +               goto unlock_ret;
>>
>>         ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
>>                                  val, val & DP_MODE_A2, 1000,
>> --
>> 2.14.2.822.g60be5d43e6-goog
>>


From narmstrong at baylibre.com  Tue Oct  3 02:52:33 2017
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Tue, 3 Oct 2017 11:52:33 +0200
Subject: [PATCH v2 2/7] drm/rockchip: dw_hdmi: add device type
In-Reply-To: <1506735836-151661-1-git-send-email-algea.cao@rock-chips.com>
References: <1506735713-147081-0>
 <1506735836-151661-1-git-send-email-algea.cao@rock-chips.com>
Message-ID: <7133fdf3-afde-f548-06fa-81b0dc170116@baylibre.com>

On 30/09/2017 03:43, Algea Cao wrote:
> To determine type of SOC, we add a parameter dev_type.
> 
> Signed-off-by: Algea Cao <algea.cao at rock-chips.com>
> ---
>  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c |  5 +++++
>  include/drm/bridge/dw_hdmi.h                | 10 ++++++++++
>  2 files changed, 15 insertions(+)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> index 719452d..09c77f9 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> @@ -46,6 +46,7 @@ struct rockchip_hdmi {
>  	struct regmap *regmap;
>  	struct drm_encoder encoder;
>  	const struct rockchip_hdmi_chip_data *chip_data;
> +	enum dw_hdmi_devtype dev_type;
>  	struct clk *vpll_clk;
>  	struct clk *grf_clk;
>  };
> @@ -305,6 +306,7 @@ static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
>  	.cur_ctr    = rockchip_cur_ctr,
>  	.phy_config = rockchip_phy_config,
>  	.phy_data = &rk3288_chip_data,
> +	.dev_type   = RK3288_HDMI,
>  };
>  
>  static struct rockchip_hdmi_chip_data rk3399_chip_data = {
> @@ -315,6 +317,7 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = {
>  
>  static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
>  	.mode_valid = dw_hdmi_rockchip_mode_valid,
> +	.dev_type   = RK3328_HDMI,
>  };
>  static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
>  	.mode_valid = dw_hdmi_rockchip_mode_valid,
> @@ -322,6 +325,7 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
>  	.cur_ctr    = rockchip_cur_ctr,
>  	.phy_config = rockchip_phy_config,
>  	.phy_data = &rk3399_chip_data,
> +	.dev_type   = RK3399_HDMI,
>  };
>  
>  static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
> @@ -360,6 +364,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
>  	plat_data = match->data;
>  	hdmi->dev = &pdev->dev;
>  	hdmi->chip_data = plat_data->phy_data;
> +	hdmi->dev_type = plat_data->dev_type;
>  	encoder = &hdmi->encoder;
>  
>  	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index 182f832..fdb1f0a 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -92,6 +92,15 @@ enum dw_hdmi_phy_type {
>  	DW_HDMI_PHY_VENDOR_PHY = 0xfe,
>  };
>  
> +enum dw_hdmi_devtype {
> +	RK3228_HDMI,
> +	RK3288_HDMI,
> +	RK3328_HDMI,
> +	RK3366_HDMI,
> +	RK3368_HDMI,
> +	RK3399_HDMI,
> +};
> +
>  struct dw_hdmi_mpll_config {
>  	unsigned long mpixelclock;
>  	struct {
> @@ -124,6 +133,7 @@ struct dw_hdmi_phy_ops {
>  
>  struct dw_hdmi_plat_data {
>  	struct regmap *regm;
> +	enum dw_hdmi_devtype dev_type;

Please don't do that, dw-hdmi driver should not have knowledge of the device type,
if the vendor PHY reporting is broken, add a way to force phy_type to DW_HDMI_PHY_VENDOR_PHY.

Neil

>  	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
>  					   const struct drm_display_mode *mode);
>  	unsigned long input_bus_format;
> 



From dianders at chromium.org  Tue Oct  3 11:45:50 2017
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 3 Oct 2017 11:45:50 -0700
Subject: [PATCH 3/3] mmc: dw_mmc: Add locking to the CTO timer
In-Reply-To: <20170927205631.31559-4-dianders@chromium.org>
References: <20170927205631.31559-1-dianders@chromium.org>
 <20170927205631.31559-4-dianders@chromium.org>
Message-ID: <CAD=FV=U78WfojBJYEObr1M6aR=zxNC1MkOLuREnGXABFoqYXPw@mail.gmail.com>

Hi,

On Wed, Sep 27, 2017 at 1:56 PM, Douglas Anderson <dianders at chromium.org> wrote:
> This attempts to instill a bit of paranoia to the code dealing with
> the CTO timer.  It's believed that this will make the CTO timer more
> robust in the case that we're having very long interrupt latencies.
>
> Note that I originally thought that perhaps this patch was being
> overly paranoid and wasn't really needed, but then while I was running
> mmc_test on an rk3399 board I saw one instance of the message:
>   dwmmc_rockchip fe320000.dwmmc: Unexpected interrupt latency
>
> I had debug prints in the CTO timer code and I found that it was
> running CMD 13 at the time.
>
> ...so even though this patch seems like it might be overly paranoid,
> maybe it really isn't?
>
> Presumably the bad interrupt latency experienced was due to the fact
> that I had serial console enabled as serial console is typically where
> I place blame when I see absurdly large interrupt latencies.  In this
> particular case there was an (unrelated) printout to the serial
> console just before I saw the "Unexpected interrupt latency" printout.
>
> ...and actually, I managed to even reproduce the problems by running
> "iw mlan0 scan > /dev/null" while mmc_test was running.  That not only
> does a bunch of PCIe traffic but it also (on my system) outputs some
> SELinux log spam.
>
> Fixes: 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command transfer over scheme")
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
>
>  drivers/mmc/host/dw_mmc.c | 92 +++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 82 insertions(+), 10 deletions(-)

I'm hoping that someone upstream might have some time to test and
review these three patches since I believe that they fix a regression
in 4.14.  I pinged Shawn Lin and found that it's a Chinese holiday
right now so he won't be able to test util next week, but presumably
others might be noticing problems with SD cards or eMMC using dw_mmc
on kernel 4.14, especially with serial console enabled?

Adding linux-rockchip to the CC here.  Original patches can be found
on patchwork.kernel.org...

Thanks!

-Doug


From robh at kernel.org  Tue Oct  3 14:56:31 2017
From: robh at kernel.org (Rob Herring)
Date: Tue, 3 Oct 2017 16:56:31 -0500
Subject: [PATCH v2 1/3] dt-bindings: Add document for rockchip RGB output
 interface
In-Reply-To: <1506049229-117376-1-git-send-email-hjc@rock-chips.com>
References: <1506049221-117283-1-git-send-email-hjc@rock-chips.com>
 <1506049229-117376-1-git-send-email-hjc@rock-chips.com>
Message-ID: <20171003215631.rc2jsf2m3qgoltsb@rob-hp-laptop>

On Fri, Sep 22, 2017 at 11:00:26AM +0800, Sandy Huang wrote:
> This path add support rv1108 rgb output interface driver.
> 
> Signed-off-by: Sandy Huang <hjc at rock-chips.com>
> ---
> Changes in v2:
>  1. rename rockchip,rgb-mode to rgb-mode;

You can't just drop the vendor. This needs to be documented in a common 
place that others will find and use. See panel-common.txt or 
panel-dpi.txt.

Alternatively, you could just drop it and let the panel compatible imply 
what the mode is. 


>  2. delete reg for signle endpoint;
> 
>  .../bindings/display/rockchip/rockchip-rgb.txt     | 78 ++++++++++++++++++++++
>  1 file changed, 78 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt
> new file mode 100644
> index 0000000..86bd1ce
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt
> @@ -0,0 +1,78 @@
> +Rockchip RV1108 RGB interface
> +================================
> +
> +Required properties:
> +- compatible: matching the soc type:
> +	- "rockchip,rv1108-rgb";
> +
> +Optional properties:
> +- pinctrl-names: must contain a "lcdc" entry.
> +- pinctrl-0: pin control group to be used for this interface.
> +
> +Required nodes:
> +- rgb-mode: should be "p888", "p666", "p565", "s888", "s888-dummy"
> +	- p888: output r8-g8-b8 at each dclk cycle for per-pixel
> +	- p666: output r6-g6-b6 at each dclk cycle for per-pixel
> +	- p565: output r5-g6-b5 at each dclk cycle for per-pixel
> +	- s888: output r8-g8-b8 in three dclk cycle for per-pixel
> +	- s888-dmmy: output r8-g8-b8-dummy in four dclk cycle for per-pixel
> +
> +The rgb has two video ports described by:
> +	Documentation/devicetree/bindings/media/video-interfaces.txt
> +Their connections are modeled using the OF graph bindings specified in
> +	Documentation/devicetree/bindings/graph.txt.
> +
> +- video port 0 for the VOP input, the remote endpoint maybe vopb/vopl/vop
> +- video port 1 for either a panel or subsequent encoder
> +
> +the panel described by:
> +	Documentation/devicetree/bindings/display/panel/simple-panel.txt
> +Panel other required properties:
> +- ports for remote rgb output.
> +
> +Example:
> +
> +panel: panel {
> +	compatible = "auo,b101ean01";
> +	enable-gpios = <&gpio7 21 GPIO_ACTIVE_HIGH>;
> +
> +	ports {
> +		panel_in_rgb: endpoint {
> +			remote-endpoint = <&rgb_out_panel>;
> +		};
> +	};
> +};
> +
> +For Rockchip RV1108:
> +
> +	rgb: rgb {
> +		compatible = "rockchip,rv1108-rgb";
> +		pinctrl-names = "lcdc";
> +		pinctrl-0 = <&lcdc_ctl>;
> +		rgb-mode = "p888";
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			rgb_in: port at 0 {
> +				reg = <0>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				rgb_in_vop: endpoint {
> +					remote-endpoint = <&vop_out_rgb>;
> +				};
> +			};
> +
> +			rgb_out: port at 1 {
> +				reg = <1>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				rgb_out_panel: endpoint {
> +					remote-endpoint = <&panel_in_rgb>;
> +				};
> +			};
> +		};
> +	};
> -- 
> 2.7.4
> 
> 


From davem at davemloft.net  Tue Oct  3 15:40:10 2017
From: davem at davemloft.net (David Miller)
Date: Tue, 03 Oct 2017 15:40:10 -0700 (PDT)
Subject: [PATCH] net: stmmac: dwmac-rk: Add RK3128 GMAC support
In-Reply-To: <1506764843-24681-1-git-send-email-david.wu@rock-chips.com>
References: <1506764843-24681-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <20171003.154010.1496572594893188092.davem@davemloft.net>

From: David Wu <david.wu at rock-chips.com>
Date: Sat, 30 Sep 2017 17:47:23 +0800

> Add constants and callback functions for the dwmac on rk3128 soc.
> As can be seen, the base structure is the same, only registers
> and the bits in them moved slightly.
> 
> Signed-off-by: David Wu <david.wu at rock-chips.com>

Applied, thank you.


From olof at lixom.net  Tue Oct  3 18:13:57 2017
From: olof at lixom.net (Olof Johansson)
Date: Tue, 3 Oct 2017 18:13:57 -0700
Subject: [GIT PULL v2] Rockchip dts64 Fixes for 4.14
In-Reply-To: <2709130.jIo7eQHvkl@phil>
References: <6990785.aOlALvEuSf@phil>
 <2709130.jIo7eQHvkl@phil>
Message-ID: <20171004011357.bclazdklfeuzdqev@localhost>

On Wed, Sep 27, 2017 at 08:11:32PM +0200, Heiko Stuebner wrote:
> Hi Arnd, Kevin, Olof,
> 
> please find below three fixes for 64bit Rockchip devicetrees.
> 
> As the tag explains the main change is the revert of the rk3368 opp
> addition, as this cannot safely run on current rk3368 boards and thus
> shouldn't make a kernel release.
> 
> 
> Please pull, thanks
> Heiko
> 
> changes in v2:
> - remove left over half-sentence at the end of the tag message
> - add rk3399 mipi dsi grf-clock reference (part of the binding already
>   and of course needed on rk3399)
> 
> 
> The following changes since commit 2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e:
> 
>   Linux 4.14-rc1 (2017-09-16 15:47:51 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.14-rockchip-dts64fixes-1
> 
> for you to fetch changes up to 0bc15d85d97d44e8979ff91d0c1fbafe6fd4172c:
> 
>   arm64: dts: rockchip: add the grf clk for dw-mipi-dsi on rk3399 (2017-09-26 15:59:17 +0200)

Merged to fixes, thanks.


-Olof


From lee.jones at linaro.org  Wed Oct  4 03:48:50 2017
From: lee.jones at linaro.org (Lee Jones)
Date: Wed, 4 Oct 2017 11:48:50 +0100
Subject: [PATCH] extcon: Split out extcon header file for consumer and
 provider device
In-Reply-To: <1506643305-4581-1-git-send-email-cw00.choi@samsung.com>
References: <CGME20170929000148epcas2p200e56186b067ec626a033c7ae2d4bbdb@epcas2p2.samsung.com>
 <1506643305-4581-1-git-send-email-cw00.choi@samsung.com>
Message-ID: <20171004104850.aeedla2bkns36iw7@dell>

On Fri, 29 Sep 2017, Chanwoo Choi wrote:

> The extcon has two type of extcon devices as following.
> - 'extcon provider deivce' adds new extcon device and detect the
>    state/properties of external connector. Also, it notifies the
>    state/properties to the extcon consumer device.
> - 'extcon consumer device' gets the change state/properties
>    from extcon provider device.
> Prior to that, include/linux/extcon.h contains all exported API for
> both provider and consumer device driver. To clarify the meaning of
> header file and to remove the wrong use-case on consumer device,
> this patch separates into extcon.h and extcon-provider.h.
> 
> [Description for include/linux/{extcon.h|extcon-provider.h}]
> - extcon.h includes the extcon API and data structure for extcon consumer
>   device driver. This header file contains the following APIs:
>   : Register/unregister the notifier to catch the change of extcon device
>   : Get the extcon device instance
>   : Get the extcon device name
>   : Get the state of each external connector
>   : Get the property value of each external connector
>   : Get the property capability of each external connector
> 
> - extcon-provider.h includes the extcon API and data structure for extcon
>   provider device driver. This header file contains the following APIs:
>   : Include 'include/linux/extcon.h'
>   : Allocate the memory for extcon device instance
>   : Register/unregister extcon device
>   : Set the state of each external connector
>   : Set the property value of each external connector
>   : Set the property capability of each external connector
> 
> Cc: Felipe Balbi <balbi at kernel.org>
> Cc: Kishon Vijay Abraham I <kishon at ti.com>
> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> Cc: Sebastian Reichel <sre at kernel.org>
> Cc: Lee Jones <lee.jones at linaro.org>
> Signed-off-by: Chanwoo Choi <cw00.choi at samsung.com>
> ---
>  drivers/extcon/extcon-adc-jack.c              |   2 +-
>  drivers/extcon/extcon-arizona.c               |   2 +-
>  drivers/extcon/extcon-axp288.c                |   2 +-
>  drivers/extcon/extcon-gpio.c                  |   2 +-
>  drivers/extcon/extcon-intel-cht-wc.c          |   2 +-
>  drivers/extcon/extcon-intel-int3496.c         |   2 +-
>  drivers/extcon/extcon-max14577.c              |   2 +-
>  drivers/extcon/extcon-max3355.c               |   2 +-
>  drivers/extcon/extcon-max77693.c              |   2 +-
>  drivers/extcon/extcon-max77843.c              |   2 +-
>  drivers/extcon/extcon-max8997.c               |   2 +-
>  drivers/extcon/extcon-qcom-spmi-misc.c        |   2 +-
>  drivers/extcon/extcon-rt8973a.c               |   2 +-
>  drivers/extcon/extcon-sm5502.c                |   2 +-
>  drivers/extcon/extcon-usb-gpio.c              |   2 +-
>  drivers/extcon/extcon-usbc-cros-ec.c          |   2 +-
>  drivers/extcon/extcon.h                       |   2 +-
>  drivers/phy/allwinner/phy-sun4i-usb.c         |   2 +-
>  drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c     |   2 +-
>  drivers/phy/renesas/phy-rcar-gen3-usb2.c      |   2 +-
>  drivers/phy/rockchip/phy-rockchip-inno-usb2.c |   2 +-
>  drivers/power/supply/qcom_smbb.c              |   2 +-
>  drivers/usb/gadget/udc/renesas_usb3.c         |   2 +-
>  drivers/usb/phy/phy-tahvo.c                   |   2 +-
>  drivers/usb/renesas_usbhs/common.h            |   2 +-
>  include/linux/extcon-provider.h               | 142 ++++++++++++++++++++++++++
>  include/linux/extcon.h                        | 109 +-------------------

>  include/linux/mfd/palmas.h                    |   2 +-

Acked-by: Lee Jones <lee.jones at linaro.org>

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog


From broonie at kernel.org  Wed Oct  4 04:28:45 2017
From: broonie at kernel.org (Mark Brown)
Date: Wed, 04 Oct 2017 12:28:45 +0100
Subject: Applied "ASoC: rockchip: Allocate enough memory so we don't overflow
 routes" to the asoc tree
In-Reply-To: <20170929220324.16413-1-dianders@chromium.org>
Message-ID: <E1dzhr3-0004Qh-D0@debutante>

The patch

   ASoC: rockchip: Allocate enough memory so we don't overflow routes

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 8eae6c2585b0455f0e7200495d5e513020ca2fa2 Mon Sep 17 00:00:00 2001
From: Douglas Anderson <dianders at chromium.org>
Date: Fri, 29 Sep 2017 15:03:24 -0700
Subject: [PATCH] ASoC: rockchip: Allocate enough memory so we don't overflow
 routes

In the recent commit d9f9c167edae ("ASoC: rockchip: Init dapm routes
dynamically") we improperly allocated memory for the card->dapm_routes
causing us to overflow the allocation on every boot.  Oops.

Let's allocate the correct amount of memory.  We'll also add a check
to make sure that we don't overrun memory even if we encounter some
sort of weird device tree.

Fixes: d9f9c167edae ("ASoC: rockchip: Init dapm routes dynamically")
Signed-off-by: Douglas Anderson <dianders at chromium.org>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/rockchip/rk3399_gru_sound.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 30eed83e8a13..d64fbbd50544 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -494,13 +494,17 @@ static int rockchip_sound_of_parse_dais(struct device *dev,
 	struct snd_soc_dai_link *dai;
 	struct snd_soc_dapm_route *routes;
 	int i, index;
+	int num_routes;
 
 	card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
 				      GFP_KERNEL);
 	if (!card->dai_link)
 		return -ENOMEM;
 
-	routes = devm_kzalloc(dev, sizeof(rockchip_routes),
+	num_routes = 0;
+	for (i = 0; i < ARRAY_SIZE(rockchip_routes); i++)
+		num_routes += rockchip_routes[i].num_routes;
+	routes = devm_kzalloc(dev, num_routes * sizeof(*routes),
 			      GFP_KERNEL);
 	if (!routes)
 		return -ENOMEM;
@@ -538,6 +542,12 @@ static int rockchip_sound_of_parse_dais(struct device *dev,
 		dai->platform_of_node = np_cpu;
 		dai->cpu_of_node = np_cpu;
 
+		if (card->num_dapm_routes + rockchip_routes[index].num_routes >
+		    num_routes) {
+			dev_err(dev, "Too many routes\n");
+			return -EINVAL;
+		}
+
 		memcpy(routes + card->num_dapm_routes,
 		       rockchip_routes[index].routes,
 		       rockchip_routes[index].num_routes * sizeof(*routes));
-- 
2.14.1



From kernel at esmil.dk  Wed Oct  4 10:53:46 2017
From: kernel at esmil.dk (Emil Renner Berthing)
Date: Wed,  4 Oct 2017 19:53:46 +0200
Subject: [PATCH] drm/rockchip: analogix_dp: Use mutex rather than spinlock
Message-ID: <20171004175346.11956-1-kernel@esmil.dk>

On the Samsung Chromebook Plus I get this error with 4.14-rc3:

BUG: scheduling while atomic: kworker/3:1/50/0x00000002
Modules linked in:
CPU: 3 PID: 50 Comm: kworker/3:1 Not tainted 4.14.0-0.rc3-kevin #2
Hardware name: Google Kevin (DT)
Workqueue: events analogix_dp_psr_work
Call trace:
[<ffffff80080873b0>] dump_backtrace+0x0/0x320
[<ffffff80080876e4>] show_stack+0x14/0x20
[<ffffff8008606d38>] dump_stack+0x9c/0xbc
[<ffffff80080c6b5c>] __schedule_bug+0x4c/0x70
[<ffffff80086188c0>] __schedule+0x3f0/0x458
[<ffffff8008618960>] schedule+0x38/0xa0
[<ffffff800861c20c>] schedule_hrtimeout_range_clock+0x84/0xe8
[<ffffff800861c2a0>] schedule_hrtimeout_range+0x10/0x18
[<ffffff800861bcec>] usleep_range+0x64/0x78
[<ffffff8008415a6c>] analogix_dp_transfer+0x16c/0x340
[<ffffff8008412550>] analogix_dpaux_transfer+0x10/0x18
[<ffffff80083ceb14>] drm_dp_dpcd_access+0x4c/0xf0
[<ffffff80083cf614>] drm_dp_dpcd_write+0x1c/0x28
[<ffffff8008413b98>] analogix_dp_disable_psr+0x60/0xa8
[<ffffff800840da3c>] analogix_dp_psr_work+0x4c/0x90
[<ffffff80080bb09c>] process_one_work+0x1d4/0x348
[<ffffff80080bb258>] worker_thread+0x48/0x478
[<ffffff80080c11fc>] kthread+0x12c/0x130
[<ffffff8008084290>] ret_from_fork+0x10/0x18

Changing rockchip_dp_device::psr_lock to a mutex rather
than spinlock seems to fix the issue.

Signed-off-by: Emil Renner Berthing <kernel at esmil.dk>
---
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 9606121fa185..d8f72d87ef08 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -72,7 +72,7 @@ struct rockchip_dp_device {
 	struct reset_control     *rst;
 
 	struct work_struct	 psr_work;
-	spinlock_t		 psr_lock;
+	struct mutex             psr_lock;
 	unsigned int             psr_state;
 
 	const struct rockchip_dp_chip_data *data;
@@ -83,21 +83,20 @@ struct rockchip_dp_device {
 static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
 {
 	struct rockchip_dp_device *dp = to_dp(encoder);
-	unsigned long flags;
 
 	if (!analogix_dp_psr_supported(dp->dev))
 		return;
 
 	dev_dbg(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
 
-	spin_lock_irqsave(&dp->psr_lock, flags);
+	mutex_lock(&dp->psr_lock);
 	if (enabled)
 		dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
 	else
 		dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
 
 	schedule_work(&dp->psr_work);
-	spin_unlock_irqrestore(&dp->psr_lock, flags);
+	mutex_unlock(&dp->psr_lock);
 }
 
 static void analogix_dp_psr_work(struct work_struct *work)
@@ -105,7 +104,6 @@ static void analogix_dp_psr_work(struct work_struct *work)
 	struct rockchip_dp_device *dp =
 				container_of(work, typeof(*dp), psr_work);
 	int ret;
-	unsigned long flags;
 
 	ret = rockchip_drm_wait_vact_end(dp->encoder.crtc,
 					 PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
@@ -114,12 +112,12 @@ static void analogix_dp_psr_work(struct work_struct *work)
 		return;
 	}
 
-	spin_lock_irqsave(&dp->psr_lock, flags);
+	mutex_lock(&dp->psr_lock);
 	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
 		analogix_dp_enable_psr(dp->dev);
 	else
 		analogix_dp_disable_psr(dp->dev);
-	spin_unlock_irqrestore(&dp->psr_lock, flags);
+	mutex_unlock(&dp->psr_lock);
 }
 
 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
@@ -381,7 +379,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	dp->plat_data.power_off = rockchip_dp_powerdown;
 	dp->plat_data.get_modes = rockchip_dp_get_modes;
 
-	spin_lock_init(&dp->psr_lock);
+	mutex_init(&dp->psr_lock);
 	dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
 	INIT_WORK(&dp->psr_work, analogix_dp_psr_work);
 
-- 
2.14.2



From arnd at arndb.de  Thu Oct  5 05:09:39 2017
From: arnd at arndb.de (Arnd Bergmann)
Date: Thu,  5 Oct 2017 14:09:39 +0200
Subject: [PATCH] drm/rockchip: add PINCTRL dependency for LVDS
Message-ID: <20171005120957.485433-1-arnd@arndb.de>

The new driver fails to build when CONFIG_PINCTRL is disabled:

drivers/gpu/drm/rockchip/rockchip_lvds.c: In function 'rockchip_lvds_grf_config':
drivers/gpu/drm/rockchip/rockchip_lvds.c:229:39: error: dereferencing pointer to incomplete type 'struct dev_pin_info'
   if (lvds->pins && !IS_ERR(lvds->pins->default_state))

This adds the respective Kconfig dependency.

Fixes: 34cc0aa25456 ("drm/rockchip: Add support for Rockchip Soc LVDS")
Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 drivers/gpu/drm/rockchip/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 0c31f0a27b9c..3c70c6224bd2 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -60,6 +60,7 @@ config ROCKCHIP_INNO_HDMI
 config ROCKCHIP_LVDS
 	bool "Rockchip LVDS support"
 	depends on DRM_ROCKCHIP
+	depends on PINCTRL
 	help
 	  Choose this option to enable support for Rockchip LVDS controllers.
 	  Rockchip rk3288 SoC has LVDS TX Controller can be used, and it
-- 
2.9.0



From linus.walleij at linaro.org  Sat Oct  7 03:32:51 2017
From: linus.walleij at linaro.org (Linus Walleij)
Date: Sat, 7 Oct 2017 12:32:51 +0200
Subject: [PATCH 2/2] pinctrl: rockchip: Fix the correct routing config for
 the gmac-m1 pins of rmii and rgmii
In-Reply-To: <1908269.6t3djq65xf@phil>
References: <1506773601-27315-1-git-send-email-david.wu@rock-chips.com>
 <1506773601-27315-3-git-send-email-david.wu@rock-chips.com>
 <1908269.6t3djq65xf@phil>
Message-ID: <CACRpkdYOuf_8_EWg1GtV-75YvmnLkpadKrGMfQZ2v2RRqbYvRw@mail.gmail.com>

On Sat, Sep 30, 2017 at 5:07 PM, Heiko Stuebner <heiko at sntech.de> wrote:
> Am Samstag, 30. September 2017, 20:13:21 CEST schrieb David Wu:
>> If the gmac-m1 optimization(bit10) is selected, the gpio function
>> of gmac pins is not valid. We may use the rmii mode for gmac interface,
>> the pins such as rx_d2, rx_d3, which the rgmii mode used, but rmii not
>> used could be taken as gpio function. So gmac_rxd0m1 selects the bit2,
>> and gmac_rxd0m3 select bit10 is more correct.
>>
>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>
> the patch subject should mention the the rk3328 whose routing gets fixed
> (like adding a simple "on rk3328" to it), otherwise
>
> Reviewed-by: Heiko Stuebner <heiko at sntech.de>

I added rk3328 to it, also assumed this Reviewed-by covers patch 1/2
as well and applied both with your tag.

Yours,
Linus Walleij


From heiko at sntech.de  Sat Oct  7 11:50:37 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 07 Oct 2017 20:50:37 +0200
Subject: [PATCH 2/2] pinctrl: rockchip: Fix the correct routing config for
 the gmac-m1 pins of rmii and rgmii
In-Reply-To: <CACRpkdYOuf_8_EWg1GtV-75YvmnLkpadKrGMfQZ2v2RRqbYvRw@mail.gmail.com>
References: <1506773601-27315-1-git-send-email-david.wu@rock-chips.com>
 <1908269.6t3djq65xf@phil>
 <CACRpkdYOuf_8_EWg1GtV-75YvmnLkpadKrGMfQZ2v2RRqbYvRw@mail.gmail.com>
Message-ID: <1879535.2f3c0LOipO@phil>

Hi Linus,

Am Samstag, 7. Oktober 2017, 12:32:51 CEST schrieb Linus Walleij:
> On Sat, Sep 30, 2017 at 5:07 PM, Heiko Stuebner <heiko at sntech.de> wrote:
> > Am Samstag, 30. September 2017, 20:13:21 CEST schrieb David Wu:
> >> If the gmac-m1 optimization(bit10) is selected, the gpio function
> >> of gmac pins is not valid. We may use the rmii mode for gmac interface,
> >> the pins such as rx_d2, rx_d3, which the rgmii mode used, but rmii not
> >> used could be taken as gpio function. So gmac_rxd0m1 selects the bit2,
> >> and gmac_rxd0m3 select bit10 is more correct.
> >>
> >> Signed-off-by: David Wu <david.wu at rock-chips.com>
> >
> > the patch subject should mention the the rk3328 whose routing gets fixed
> > (like adding a simple "on rk3328" to it), otherwise
> >
> > Reviewed-by: Heiko Stuebner <heiko at sntech.de>
> 
> I added rk3328 to it, also assumed this Reviewed-by covers patch 1/2
> as well and applied both with your tag.

while I did mean to cross-check patch 1/2 separately with the soc manual,
I got sidetracked with my current vacation :-) . Anyway, it did look ok on
first glance then and I also cannot find issues with it now. So all is good.


Heiko


From david.wu at rock-chips.com  Sun Oct  8 18:21:22 2017
From: david.wu at rock-chips.com (David.Wu)
Date: Mon, 9 Oct 2017 09:21:22 +0800
Subject: [PATCH 2/2] pinctrl: rockchip: Fix the correct routing config for
 the gmac-m1 pins of rmii and rgmii
In-Reply-To: <CACRpkdYOuf_8_EWg1GtV-75YvmnLkpadKrGMfQZ2v2RRqbYvRw@mail.gmail.com>
References: <1506773601-27315-1-git-send-email-david.wu@rock-chips.com>
 <1506773601-27315-3-git-send-email-david.wu@rock-chips.com>
 <1908269.6t3djq65xf@phil>
 <CACRpkdYOuf_8_EWg1GtV-75YvmnLkpadKrGMfQZ2v2RRqbYvRw@mail.gmail.com>
Message-ID: <19faa81c-aebb-0786-54fd-93b0a5a18b9a@rock-chips.com>

Hi Linus,

Thanks for you adding it.
I left the office for a few days due to holiday.

? 2017/10/7 18:32, Linus Walleij ??:
> On Sat, Sep 30, 2017 at 5:07 PM, Heiko Stuebner <heiko at sntech.de> wrote:
>> Am Samstag, 30. September 2017, 20:13:21 CEST schrieb David Wu:
>>> If the gmac-m1 optimization(bit10) is selected, the gpio function
>>> of gmac pins is not valid. We may use the rmii mode for gmac interface,
>>> the pins such as rx_d2, rx_d3, which the rgmii mode used, but rmii not
>>> used could be taken as gpio function. So gmac_rxd0m1 selects the bit2,
>>> and gmac_rxd0m3 select bit10 is more correct.
>>>
>>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>>
>> the patch subject should mention the the rk3328 whose routing gets fixed
>> (like adding a simple "on rk3328" to it), otherwise
>>
>> Reviewed-by: Heiko Stuebner <heiko at sntech.de>
> 
> I added rk3328 to it, also assumed this Reviewed-by covers patch 1/2
> as well and applied both with your tag.
> 
> Yours,
> Linus Walleij
> 
> 
> 



From jeffy.chen at rock-chips.com  Sun Oct  8 23:49:08 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Mon, 09 Oct 2017 14:49:08 +0800
Subject: [PATCH] drm/rockchip: Fix memory leak in rockchip_drm_sys_resume()
In-Reply-To: <59CC6996.2000402@rock-chips.com>
References: <20170927122642.18628-1-jeffy.chen@rock-chips.com>
 <20170927202709.ugbjyi3ktfjssiyp@art_vandelay>
 <59CC6996.2000402@rock-chips.com>
Message-ID: <59DB1BE4.9080907@rock-chips.com>

Hi Sean,

On 09/28/2017 11:16 AM, jeffy wrote:
> Hi Sean,
>
> On 09/28/2017 04:27 AM, Sean Paul wrote:
>>> >@@ -299,6 +300,7 @@ static int rockchip_drm_sys_resume(struct device
>>> *dev)
>>> >
>>> >      priv = drm->dev_private;
>>> >      drm_atomic_helper_resume(drm, priv->state);
>>> >+    drm_atomic_state_put(priv->state);
>> Won't this be freed for you eventually in commit_tail()?
>>
> i think the drm_atomic_state_put in commit_tail is paired to the
> drm_atomic_state_get in drm_atomic_helper_commit.
>
> and the kmemleak shows(after a few suspend/resume):
>
>      unreferenced object 0xffffffc0ce0fa400 (size 256):
>      ...
>        backtrace:
>          [<ffffffc00034a9a8>] __save_stack_trace+0x48/0x6c
>          [<ffffffc00034b088>] create_object+0x138/0x254
>          [<ffffffc0009d5504>] kmemleak_alloc+0x58/0x8c
>          [<ffffffc000345f78>] __kmalloc+0x1d4/0x2a0
>          [<ffffffc0006765bc>] usb_alloc_urb+0x30/0x60
>          [<ffffffbffc128598>] alloc_ctrl_urb+0x38/0x120 [btusb]
>          [<ffffffbffc129e7c>] btusb_send_frame+0x64/0xf8 [btusb]

oops, the log is wrong...

it should be:
unreferenced object 0xffffffc0c75fe600 (size 256):
   comm "bash", pid 168, jiffies 4294748032 (age 557.932s)
   hex dump (first 32 bytes):
     e0 4a 02 ce c0 ff ff ff 00 98 f2 c8 c0 ff ff ff  .J..............
     00 98 f2 c8 c0 ff ff ff 00 45 9f cb c0 ff ff ff  .........E......
   backtrace:
     [<ffffff9008c76ba0>] kmemleak_alloc+0x58/0x8c
     [<ffffff900828fe70>] __kmalloc+0x1dc/0x2d4
     [<ffffff9008647698>] drm_atomic_state_init+0xb8/0x114
     [<ffffff9008649ed8>] drm_atomic_state_alloc+0x70/0xa4
     [<ffffff90086209f8>] drm_atomic_helper_duplicate_state+0x94/0x210
     [<ffffff9008621184>] drm_atomic_helper_suspend+0xb4/0x160
     [<ffffff9008666f18>] rockchip_drm_sys_suspend+0x5c/0xa0
     [<ffffff9008697f18>] platform_pm_suspend+0x58/0x74
     [<ffffff90086a7f98>] dpm_run_callback+0x13c/0x2f0
     [<ffffff90086a9064>] __device_suspend+0x28c/0x3fc
     [<ffffff90086ab9ec>] dpm_suspend+0x1cc/0x50c
     [<ffffff90086ac5a4>] dpm_suspend_start+0x8c/0xa4
     [<ffffff90081226a0>] suspend_devices_and_enter+0x12c/0xd84
     [<ffffff9008123d30>] pm_suspend+0xa38/0xb98
     [<ffffff9008120f94>] state_store+0xe0/0x108
     [<ffffff9008c63e7c>] kobj_attr_store+0x48/0x58


since it's allocated in the drm_atomic_helper_suspend(), maybe it would 
make more sense to unref it in drm_atomic_helper_resume(), i'll send a 
v2 patch for it :)

>
>
>
>
> checking the current code, i saw only i915/intel_display.c has this
> drm_atomic_state_put for the state allocated by
> drm_atomic_helper_suspend(), there're many drivers missing that(or maybe
> they free it in some other way?)
>
>> Sean
>>
>




From hjc at rock-chips.com  Mon Oct  9 01:06:05 2017
From: hjc at rock-chips.com (Sandy Huang)
Date: Mon, 9 Oct 2017 16:06:05 +0800
Subject: [PATCH v2 1/3] dt-bindings: Add document for rockchip RGB output
 interface
In-Reply-To: <20171003215631.rc2jsf2m3qgoltsb@rob-hp-laptop>
References: <1506049221-117283-1-git-send-email-hjc@rock-chips.com>
 <1506049229-117376-1-git-send-email-hjc@rock-chips.com>
 <20171003215631.rc2jsf2m3qgoltsb@rob-hp-laptop>
Message-ID: <2d502a9d-e952-8afb-d2d7-45c21c36da7e@rock-chips.com>

Hi rob,
     Thanks for your reply.

? 2017/10/4 5:56, Rob Herring ??:
> On Fri, Sep 22, 2017 at 11:00:26AM +0800, Sandy Huang wrote:
>> This path add support rv1108 rgb output interface driver.
>>
>> Signed-off-by: Sandy Huang <hjc at rock-chips.com>
>> ---
>> Changes in v2:
>>   1. rename rockchip,rgb-mode to rgb-mode;
> 
> You can't just drop the vendor. This needs to be documented in a common
> place that others will find and use. See panel-common.txt or
> panel-dpi.txt.
> 
> Alternatively, you could just drop it and let the panel compatible imply
> what the mode is.
> 
> 
ok, get it, i will move the rgb-mode to panel and describe it at 
panel-rgb.txt. the patches will be send soon later.

>>   2. delete reg for signle endpoint;
>>
>>   .../bindings/display/rockchip/rockchip-rgb.txt     | 78 ++++++++++++++++++++++
>>   1 file changed, 78 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt
>>
>> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt
>> new file mode 100644
>> index 0000000..86bd1ce
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt
>> @@ -0,0 +1,78 @@
>> +Rockchip RV1108 RGB interface
>> +================================
>> +
>> +Required properties:
>> +- compatible: matching the soc type:
>> +	- "rockchip,rv1108-rgb";
>> +
>> +Optional properties:
>> +- pinctrl-names: must contain a "lcdc" entry.
>> +- pinctrl-0: pin control group to be used for this interface.
>> +
>> +Required nodes:
>> +- rgb-mode: should be "p888", "p666", "p565", "s888", "s888-dummy"
>> +	- p888: output r8-g8-b8 at each dclk cycle for per-pixel
>> +	- p666: output r6-g6-b6 at each dclk cycle for per-pixel
>> +	- p565: output r5-g6-b5 at each dclk cycle for per-pixel
>> +	- s888: output r8-g8-b8 in three dclk cycle for per-pixel
>> +	- s888-dmmy: output r8-g8-b8-dummy in four dclk cycle for per-pixel
>> +
>> +The rgb has two video ports described by:
>> +	Documentation/devicetree/bindings/media/video-interfaces.txt
>> +Their connections are modeled using the OF graph bindings specified in
>> +	Documentation/devicetree/bindings/graph.txt.
>> +
>> +- video port 0 for the VOP input, the remote endpoint maybe vopb/vopl/vop
>> +- video port 1 for either a panel or subsequent encoder
>> +
>> +the panel described by:
>> +	Documentation/devicetree/bindings/display/panel/simple-panel.txt
>> +Panel other required properties:
>> +- ports for remote rgb output.
>> +
>> +Example:
>> +
>> +panel: panel {
>> +	compatible = "auo,b101ean01";
>> +	enable-gpios = <&gpio7 21 GPIO_ACTIVE_HIGH>;
>> +
>> +	ports {
>> +		panel_in_rgb: endpoint {
>> +			remote-endpoint = <&rgb_out_panel>;
>> +		};
>> +	};
>> +};
>> +
>> +For Rockchip RV1108:
>> +
>> +	rgb: rgb {
>> +		compatible = "rockchip,rv1108-rgb";
>> +		pinctrl-names = "lcdc";
>> +		pinctrl-0 = <&lcdc_ctl>;
>> +		rgb-mode = "p888";
>> +
>> +		ports {
>> +			#address-cells = <1>;
>> +			#size-cells = <0>;
>> +
>> +			rgb_in: port at 0 {
>> +				reg = <0>;
>> +				#address-cells = <1>;
>> +				#size-cells = <0>;
>> +
>> +				rgb_in_vop: endpoint {
>> +					remote-endpoint = <&vop_out_rgb>;
>> +				};
>> +			};
>> +
>> +			rgb_out: port at 1 {
>> +				reg = <1>;
>> +				#address-cells = <1>;
>> +				#size-cells = <0>;
>> +
>> +				rgb_out_panel: endpoint {
>> +					remote-endpoint = <&panel_in_rgb>;
>> +				};
>> +			};
>> +		};
>> +	};
>> -- 
>> 2.7.4
>>
>>
> 
> 
> 



From hjc at rock-chips.com  Mon Oct  9 01:06:36 2017
From: hjc at rock-chips.com (Sandy Huang)
Date: Mon,  9 Oct 2017 16:06:36 +0800
Subject: [PATCH v3 0/4] Add support rockchip RGB output interface
Message-ID: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>

This patches add support rockchip RGB output, Some Rockchip CRTCs, like rv1108,
can directly output parallel and serial RGB data to panel or to conversion chip.
So we add this driver to probe encoder and connector to support this case.

Sandy Huang (4):
  devicetree/bindings: display: Add doucument for RGB panels
  devicetree/bindings: display: Add document for rockchip RGB output
  drm/rockchip: Add support for Rockchip Soc RGB output interface
  drm/rockchip: vop: Add more RGB output interface type

 .../bindings/display/panel/panel-rgb.txt           | 116 +++++++
 .../bindings/display/rockchip/rockchip-rgb.txt     |  72 +++++
 drivers/gpu/drm/rockchip/Kconfig                   |   9 +
 drivers/gpu/drm/rockchip/Makefile                  |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c        |   2 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h        |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h        |   2 +
 drivers/gpu/drm/rockchip/rockchip_rgb.c            | 343 +++++++++++++++++++++
 8 files changed, 546 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/panel-rgb.txt
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_rgb.c

-- 
2.7.4




From hjc at rock-chips.com  Mon Oct  9 01:06:47 2017
From: hjc at rock-chips.com (Sandy Huang)
Date: Mon,  9 Oct 2017 16:06:47 +0800
Subject: [PATCH v3 2/4] devicetree/bindings: display: Add document for
 rockchip RGB output
In-Reply-To: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>
References: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>
Message-ID: <1507536409-110749-1-git-send-email-hjc@rock-chips.com>

This path add support rv1108 rgb output interface driver.

Signed-off-by: Sandy Huang <hjc at rock-chips.com>
---
Changes in v3:
 move rgb-mode to panel node which describe at:
 Documentation/devicetree/bindings/display/panel/panel-rgb.txt

Changes in v2:
 1. rename rockchip,rgb-mode to rgb-mode;
 2. delete reg for signle endpoint;
 .../bindings/display/rockchip/rockchip-rgb.txt     | 72 ++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt
new file mode 100644
index 0000000..d91a7bf
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-rgb.txt
@@ -0,0 +1,72 @@
+Rockchip RV1108 RGB interface
+================================
+
+Required properties:
+- compatible: matching the soc type:
+	- "rockchip,rv1108-rgb";
+
+Optional properties:
+- pinctrl-names: must contain a "lcdc" entry.
+- pinctrl-0: pin control group to be used for this interface.
+
+The rgb has two video ports described by:
+	Documentation/devicetree/bindings/media/video-interfaces.txt
+Their connections are modeled using the OF graph bindings specified in
+	Documentation/devicetree/bindings/graph.txt.
+
+- video port 0 for the VOP input, the remote endpoint maybe vopb/vopl/vop
+- video port 1 for either a panel or subsequent encoder
+
+the panel described by:
+	Documentation/devicetree/bindings/display/panel/simple-panel.txt
+rgb-mode nodes described by:
+	Documentation/devicetree/bindings/display/panel/panel-rgb.txt
+Panel other required properties:
+- ports for remote rgb output.
+
+Example:
+
+panel: panel {
+	compatible = "auo,b101ean01";
+	enable-gpios = <&gpio7 21 GPIO_ACTIVE_HIGH>;
+	rgb-mode = "p888";
+
+	ports {
+		panel_in_rgb: endpoint {
+			remote-endpoint = <&rgb_out_panel>;
+		};
+	};
+};
+
+For Rockchip RV1108:
+
+	rgb: rgb {
+		compatible = "rockchip,rv1108-rgb";
+		pinctrl-names = "lcdc";
+		pinctrl-0 = <&lcdc_ctl>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			rgb_in: port at 0 {
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				rgb_in_vop: endpoint {
+					remote-endpoint = <&vop_out_rgb>;
+				};
+			};
+
+			rgb_out: port at 1 {
+				reg = <1>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				rgb_out_panel: endpoint {
+					remote-endpoint = <&panel_in_rgb>;
+				};
+			};
+		};
+	};
-- 
2.7.4




From hjc at rock-chips.com  Mon Oct  9 01:06:53 2017
From: hjc at rock-chips.com (Sandy Huang)
Date: Mon,  9 Oct 2017 16:06:53 +0800
Subject: [PATCH v3 3/4] drm/rockchip: Add support for Rockchip Soc RGB output
 interface
In-Reply-To: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>
References: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>
Message-ID: <1507536416-110807-1-git-send-email-hjc@rock-chips.com>

Some Rockchip CRTCs, like rv1108, can directly output parallel and
serial RGB data to panel or conversion chip, so we add this driver to
probe encoder and connector.

Signed-off-by: Sandy Huang <hjc at rock-chips.com>
---
Changes in v3:
  update for rgb-mode move to panel node.
Changes in v2:
  1. add error log when probe failed;
  2. update name_to_output_mode() according to sean's suggest;
  3. Fix uninitialized use of ret.

 drivers/gpu/drm/rockchip/Kconfig            |   9 +
 drivers/gpu/drm/rockchip/Makefile           |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   2 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   1 +
 drivers/gpu/drm/rockchip/rockchip_rgb.c     | 343 ++++++++++++++++++++++++++++
 5 files changed, 356 insertions(+)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_rgb.c

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 0c31f0a..85c7cc5 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -8,6 +8,7 @@ config DRM_ROCKCHIP
 	select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
 	select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
 	select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
+	select DRM_RGB if ROCKCHIP_RGB
 	select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
 	help
 	  Choose this option if you have a Rockchip soc chipset.
@@ -65,4 +66,12 @@ config ROCKCHIP_LVDS
 	  Rockchip rk3288 SoC has LVDS TX Controller can be used, and it
 	  support LVDS, rgb, dual LVDS output mode. say Y to enable its
 	  driver.
+
+config ROCKCHIP_RGB
+	bool "Rockchip RGB support"
+	help
+	  Choose this option to enable support for Rockchip RGB output.
+	  Some Rockchip CRTCs, like rv1108, can directly output parallel
+	  and serial RGB format to panel or connect to a conversion chip.
+	  say Y to enable its driver.
 endif
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index a881d2c..f32a17f 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -13,5 +13,6 @@ rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
 rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
 rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
+rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
 
 obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 76d63de..265597c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -459,6 +459,8 @@ static int __init rockchip_drm_init(void)
 				CONFIG_ROCKCHIP_LVDS);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
 				CONFIG_ROCKCHIP_ANALOGIX_DP);
+	ADD_ROCKCHIP_SUB_DRIVER(rockchip_rgb_driver,
+				CONFIG_ROCKCHIP_RGB);
 	ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
 	ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
 				CONFIG_ROCKCHIP_DW_HDMI);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 498dfbc..6b0ec7e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -70,5 +70,6 @@ extern struct platform_driver dw_mipi_dsi_driver;
 extern struct platform_driver inno_hdmi_driver;
 extern struct platform_driver rockchip_dp_driver;
 extern struct platform_driver rockchip_lvds_driver;
+extern struct platform_driver rockchip_rgb_driver;
 extern struct platform_driver vop_platform_driver;
 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
new file mode 100644
index 0000000..6227ed7
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:
+ *      Sandy Huang <hjc at rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_of.h>
+
+#include <linux/component.h>
+#include <linux/of_graph.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_vop.h"
+
+#define connector_to_rgb(c) container_of(c, struct rockchip_rgb, connector)
+#define encoder_to_rgb(c) container_of(c, struct rockchip_rgb, encoder)
+
+struct rockchip_rgb {
+	struct device *dev;
+	struct drm_device *drm_dev;
+	struct drm_panel *panel;
+	struct drm_bridge *bridge;
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct dev_pin_info *pins;
+	int output_mode;
+};
+
+static inline int name_to_output_mode(const char *s)
+{
+	static const struct {
+		const char *name;
+		int format;
+	} formats[] = {
+		{ "p888", ROCKCHIP_OUT_MODE_P888 },
+		{ "p666", ROCKCHIP_OUT_MODE_P666 },
+		{ "p565", ROCKCHIP_OUT_MODE_P565 },
+		{ "s888", ROCKCHIP_OUT_MODE_S888 },
+		{ "s888_dummy", ROCKCHIP_OUT_MODE_S888_DUMMY }
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (!strncmp(s, formats[i].name, strlen(formats[i].name)))
+			return formats[i].format;
+
+	return -EINVAL;
+}
+
+static const struct drm_connector_funcs rockchip_rgb_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int rockchip_rgb_connector_get_modes(struct drm_connector *connector)
+{
+	struct rockchip_rgb *rgb = connector_to_rgb(connector);
+	struct drm_panel *panel = rgb->panel;
+
+	return drm_panel_get_modes(panel);
+}
+
+static const
+struct drm_connector_helper_funcs rockchip_rgb_connector_helper_funcs = {
+	.get_modes = rockchip_rgb_connector_get_modes,
+};
+
+static void rockchip_rgb_encoder_enable(struct drm_encoder *encoder)
+{
+	struct rockchip_rgb *rgb = encoder_to_rgb(encoder);
+
+	drm_panel_prepare(rgb->panel);
+	/* iomux to LCD data/sync mode */
+	if (rgb->pins && !IS_ERR(rgb->pins->default_state))
+		pinctrl_select_state(rgb->pins->p, rgb->pins->default_state);
+
+	drm_panel_enable(rgb->panel);
+}
+
+static void rockchip_rgb_encoder_disable(struct drm_encoder *encoder)
+{
+	struct rockchip_rgb *rgb = encoder_to_rgb(encoder);
+
+	drm_panel_disable(rgb->panel);
+	drm_panel_unprepare(rgb->panel);
+}
+
+static int
+rockchip_rgb_encoder_atomic_check(struct drm_encoder *encoder,
+				   struct drm_crtc_state *crtc_state,
+				   struct drm_connector_state *conn_state)
+{
+	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+	struct rockchip_rgb *rgb = encoder_to_rgb(encoder);
+
+	s->output_mode = rgb->output_mode;
+	s->output_type = DRM_MODE_CONNECTOR_LVDS;
+
+	return 0;
+}
+
+static const
+struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = {
+	.enable = rockchip_rgb_encoder_enable,
+	.disable = rockchip_rgb_encoder_disable,
+	.atomic_check = rockchip_rgb_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs rockchip_rgb_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static const struct of_device_id rockchip_rgb_dt_ids[] = {
+	{
+		.compatible = "rockchip,rv1108-rgb",
+	},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_rgb_dt_ids);
+
+static int rockchip_rgb_bind(struct device *dev, struct device *master,
+			     void *data)
+{
+	struct rockchip_rgb *rgb = dev_get_drvdata(dev);
+	struct drm_device *drm_dev = data;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct device_node *remote = NULL;
+	struct device_node  *port, *endpoint;
+	u32 endpoint_id;
+	const char *name;
+	int ret = 0, child_count = 0;
+
+	rgb->drm_dev = drm_dev;
+	port = of_graph_get_port_by_id(dev->of_node, 1);
+	if (!port) {
+		DRM_DEV_ERROR(dev,
+			      "can't found port point, please init rgb panel port!\n");
+		return -EINVAL;
+	}
+	for_each_child_of_node(port, endpoint) {
+		child_count++;
+		if (of_property_read_u32(endpoint, "reg", &endpoint_id))
+			endpoint_id = 0;
+		ret = drm_of_find_panel_or_bridge(dev->of_node, 1, endpoint_id,
+						  &rgb->panel, &rgb->bridge);
+		if (!ret)
+			break;
+	}
+	if (!child_count) {
+		DRM_DEV_ERROR(dev, "rgb port does not have any children\n");
+		ret = -EINVAL;
+		goto err_put_port;
+	} else if (ret) {
+		DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n");
+		ret = -EPROBE_DEFER;
+		goto err_put_port;
+	}
+	if (rgb->panel)
+		remote = rgb->panel->dev->of_node;
+	else
+		remote = rgb->bridge->of_node;
+	if (of_property_read_string(remote, "rgb-mode", &name))
+		/* default set it as output mode P888 */
+		rgb->output_mode = ROCKCHIP_OUT_MODE_P888;
+	else
+		rgb->output_mode = name_to_output_mode(name);
+	if (rgb->output_mode < 0) {
+		DRM_DEV_ERROR(dev, "invalid rockchip,rgb-mode [%s]\n", name);
+		ret = rgb->output_mode;
+		goto err_put_remote;
+	}
+
+	encoder = &rgb->encoder;
+	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
+							     dev->of_node);
+
+	ret = drm_encoder_init(drm_dev, encoder, &rockchip_rgb_encoder_funcs,
+			       DRM_MODE_ENCODER_NONE, NULL);
+	if (ret < 0) {
+		DRM_DEV_ERROR(drm_dev->dev,
+			      "failed to initialize encoder: %d\n", ret);
+		goto err_put_remote;
+	}
+
+	drm_encoder_helper_add(encoder, &rockchip_rgb_encoder_helper_funcs);
+
+	if (rgb->panel) {
+		connector = &rgb->connector;
+		connector->dpms = DRM_MODE_DPMS_OFF;
+		ret = drm_connector_init(drm_dev, connector,
+					 &rockchip_rgb_connector_funcs,
+					 DRM_MODE_CONNECTOR_Unknown);
+		if (ret < 0) {
+			DRM_DEV_ERROR(drm_dev->dev,
+				      "failed to initialize connector: %d\n",
+				      ret);
+			goto err_free_encoder;
+		}
+
+		drm_connector_helper_add(connector,
+					 &rockchip_rgb_connector_helper_funcs);
+
+		ret = drm_mode_connector_attach_encoder(connector, encoder);
+		if (ret < 0) {
+			DRM_DEV_ERROR(drm_dev->dev,
+				      "failed to attach encoder: %d\n", ret);
+			goto err_free_connector;
+		}
+
+		ret = drm_panel_attach(rgb->panel, connector);
+		if (ret < 0) {
+			DRM_DEV_ERROR(drm_dev->dev,
+				      "failed to attach panel: %d\n", ret);
+			goto err_free_connector;
+		}
+	} else {
+		rgb->bridge->encoder = encoder;
+		ret = drm_bridge_attach(encoder, rgb->bridge, NULL);
+		if (ret) {
+			DRM_DEV_ERROR(drm_dev->dev,
+				      "failed to attach bridge: %d\n", ret);
+			goto err_free_encoder;
+		}
+		encoder->bridge = rgb->bridge;
+	}
+
+	of_node_put(remote);
+	of_node_put(port);
+
+	return 0;
+
+err_free_connector:
+	drm_connector_cleanup(connector);
+err_free_encoder:
+	drm_encoder_cleanup(encoder);
+err_put_remote:
+	of_node_put(remote);
+err_put_port:
+	of_node_put(port);
+
+	return ret;
+}
+
+static void rockchip_rgb_unbind(struct device *dev, struct device *master,
+				void *data)
+{
+	struct rockchip_rgb *rgb = dev_get_drvdata(dev);
+
+	rockchip_rgb_encoder_disable(&rgb->encoder);
+	if (rgb->panel)
+		drm_panel_detach(rgb->panel);
+	drm_connector_cleanup(&rgb->connector);
+	drm_encoder_cleanup(&rgb->encoder);
+}
+
+static const struct component_ops rockchip_rgb_component_ops = {
+	.bind = rockchip_rgb_bind,
+	.unbind = rockchip_rgb_unbind,
+};
+
+static int rockchip_rgb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rockchip_rgb *rgb;
+	const struct of_device_id *match;
+	int ret;
+
+	if (!dev->of_node) {
+		DRM_DEV_ERROR(dev, "dev->of_node is null\n");
+		return -ENODEV;
+	}
+
+	rgb = devm_kzalloc(&pdev->dev, sizeof(*rgb), GFP_KERNEL);
+	if (!rgb)
+		return -ENOMEM;
+
+	rgb->dev = dev;
+	match = of_match_node(rockchip_rgb_dt_ids, dev->of_node);
+	if (!match) {
+		DRM_DEV_ERROR(dev, "match node failed\n");
+		return -ENODEV;
+	}
+
+	rgb->pins = devm_kzalloc(rgb->dev, sizeof(*rgb->pins), GFP_KERNEL);
+	if (!rgb->pins)
+		return -ENOMEM;
+	rgb->pins->p = devm_pinctrl_get(rgb->dev);
+	if (IS_ERR(rgb->pins->p)) {
+		DRM_DEV_ERROR(dev, "no pinctrl handle\n");
+		devm_kfree(rgb->dev, rgb->pins);
+		rgb->pins = NULL;
+	} else {
+		rgb->pins->default_state =
+			pinctrl_lookup_state(rgb->pins->p, "lcdc");
+		if (IS_ERR(rgb->pins->default_state)) {
+			DRM_DEV_ERROR(dev, "no default pinctrl state\n");
+			devm_kfree(rgb->dev, rgb->pins);
+			rgb->pins = NULL;
+		}
+	}
+
+	dev_set_drvdata(dev, rgb);
+	ret = component_add(&pdev->dev, &rockchip_rgb_component_ops);
+	if (ret < 0)
+		DRM_DEV_ERROR(dev, "failed to add component\n");
+
+	return ret;
+}
+
+static int rockchip_rgb_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &rockchip_rgb_component_ops);
+
+	return 0;
+}
+
+struct platform_driver rockchip_rgb_driver = {
+	.probe = rockchip_rgb_probe,
+	.remove = rockchip_rgb_remove,
+	.driver = {
+		   .name = "rockchip-rgb",
+		   .of_match_table = of_match_ptr(rockchip_rgb_dt_ids),
+	},
+};
-- 
2.7.4




From hjc at rock-chips.com  Mon Oct  9 01:07:04 2017
From: hjc at rock-chips.com (Sandy Huang)
Date: Mon,  9 Oct 2017 16:07:04 +0800
Subject: [PATCH v3 4/4] drm/rockchip: vop: Add more RGB output interface type
In-Reply-To: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>
References: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>
Message-ID: <1507536424-110871-1-git-send-email-hjc@rock-chips.com>

This patch add serial RGB output interface for rockchip vop, the
more info about serial RGB output interface described at the
following file:

Documentation/devicetree/bindings/display/panel/panel-rgb.txt

Signed-off-by: Sandy Huang <hjc at rock-chips.com>
---
Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 56bbd2e..59a01c3 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -209,6 +209,8 @@ struct vop_data {
 #define ROCKCHIP_OUT_MODE_P888	0
 #define ROCKCHIP_OUT_MODE_P666	1
 #define ROCKCHIP_OUT_MODE_P565	2
+#define ROCKCHIP_OUT_MODE_S888	8
+#define ROCKCHIP_OUT_MODE_S888_DUMMY	12
 /* for use special outface */
 #define ROCKCHIP_OUT_MODE_AAAA	15
 
-- 
2.7.4




From jacob-chen at iotwrt.com  Mon Oct  9 02:04:20 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Mon,  9 Oct 2017 17:04:20 +0800
Subject: [PATCH v11 0/4] Add Rockchip RGA V4l2 support
Message-ID: <20171009090424.15292-1-jacob-chen@iotwrt.com>

change in V11:
- fix compile warning

change in V10:
- move to rockchip/rga
- changes according to comments
- some style changes

change in V9:
- remove protduff things
- test with the latest v4l2-compliance

change in V8:
- remove protduff things

change in V6,V7:
- correct warning in checkpatch.pl

change in V5:
- v4l2-compliance: handle invalid pxielformat
- v4l2-compliance: add subscribe_event
- add colorspace support

change in V4:
- document the controls.
- change according to Hans's comments

change in V3:
- rename the controls.
- add pm_runtime support.
- enable node by default.
- correct spelling in documents.

change in V2:
- generalize the controls.
- map buffers (10-50 us) in every cmd-run rather than in buffer-import to avoid get_free_pages failed on
actively used systems.
- remove status in dt-bindings examples.

Jacob Chen (4):
  rockchip/rga: v4l2 m2m support
  ARM: dts: rockchip: add RGA device node for RK3288
  arm64: dts: rockchip: add RGA device node for RK3399
  dt-bindings: Document the Rockchip RGA bindings

 .../devicetree/bindings/media/rockchip-rga.txt     |   33 +
 arch/arm/boot/dts/rk3288.dtsi                      |   11 +
 arch/arm64/boot/dts/rockchip/rk3399.dtsi           |   11 +
 drivers/media/platform/Kconfig                     |   15 +
 drivers/media/platform/Makefile                    |    2 +
 drivers/media/platform/rockchip/rga/Makefile       |    3 +
 drivers/media/platform/rockchip/rga/rga-buf.c      |  154 +++
 drivers/media/platform/rockchip/rga/rga-hw.c       |  421 ++++++++
 drivers/media/platform/rockchip/rga/rga-hw.h       |  437 +++++++++
 drivers/media/platform/rockchip/rga/rga.c          | 1012 ++++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga.h          |  123 +++
 11 files changed, 2222 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/rockchip-rga.txt
 create mode 100644 drivers/media/platform/rockchip/rga/Makefile
 create mode 100644 drivers/media/platform/rockchip/rga/rga-buf.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.h
 create mode 100644 drivers/media/platform/rockchip/rga/rga.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga.h

-- 
2.14.1



From jacob-chen at iotwrt.com  Mon Oct  9 02:04:22 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Mon,  9 Oct 2017 17:04:22 +0800
Subject: [PATCH v11 2/4] ARM: dts: rockchip: add RGA device node for RK3288
In-Reply-To: <20171009090424.15292-1-jacob-chen@iotwrt.com>
References: <20171009090424.15292-1-jacob-chen@iotwrt.com>
Message-ID: <20171009090424.15292-3-jacob-chen@iotwrt.com>

This patch add the RGA dt config of rk3288 SoC.

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm/boot/dts/rk3288.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index a0a0b08bff74..8c6dfc0abc42 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -972,6 +972,17 @@
 		status = "disabled";
 	};
 
+	rga: rga at ff920000 {
+		compatible = "rockchip,rk3288-rga";
+		reg = <0x0 0xff920000 0x0 0x180>;
+		interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA>;
+		clock-names = "aclk", "hclk", "sclk";
+		power-domains = <&power RK3288_PD_VIO>;
+		resets = <&cru SRST_RGA_CORE>, <&cru SRST_RGA_AXI>, <&cru SRST_RGA_AHB>;
+		reset-names = "core", "axi", "ahb";
+	};
+
 	vopb: vop at ff930000 {
 		compatible = "rockchip,rk3288-vop";
 		reg = <0x0 0xff930000 0x0 0x19c>;
-- 
2.14.1



From jacob-chen at iotwrt.com  Mon Oct  9 02:04:23 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Mon,  9 Oct 2017 17:04:23 +0800
Subject: [PATCH v11 3/4] arm64: dts: rockchip: add RGA device node for RK3399
In-Reply-To: <20171009090424.15292-1-jacob-chen@iotwrt.com>
References: <20171009090424.15292-1-jacob-chen@iotwrt.com>
Message-ID: <20171009090424.15292-4-jacob-chen@iotwrt.com>

This patch add the RGA dt config of RK3399 SoC.

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d79e9b3265b9..a3fab6af5a17 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1204,6 +1204,17 @@
 		status = "disabled";
 	};
 
+	rga: rga at ff680000 {
+		compatible = "rockchip,rk3399-rga";
+		reg = <0x0 0xff680000 0x0 0x10000>;
+		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+		resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>;
+		reset-names = "core", "axi", "ahb";
+		power-domains = <&power RK3399_PD_RGA>;
+	};
+
 	efuse0: efuse at ff690000 {
 		compatible = "rockchip,rk3399-efuse";
 		reg = <0x0 0xff690000 0x0 0x80>;
-- 
2.14.1



From jacob-chen at iotwrt.com  Mon Oct  9 02:04:24 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Mon,  9 Oct 2017 17:04:24 +0800
Subject: [PATCH v11 4/4] dt-bindings: Document the Rockchip RGA bindings
In-Reply-To: <20171009090424.15292-1-jacob-chen@iotwrt.com>
References: <20171009090424.15292-1-jacob-chen@iotwrt.com>
Message-ID: <20171009090424.15292-5-jacob-chen@iotwrt.com>

Add DT bindings documentation for Rockchip RGA

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
Acked-by: Rob Herring <robh at kernel.org>
---
 .../devicetree/bindings/media/rockchip-rga.txt     | 33 ++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/rockchip-rga.txt

diff --git a/Documentation/devicetree/bindings/media/rockchip-rga.txt b/Documentation/devicetree/bindings/media/rockchip-rga.txt
new file mode 100644
index 000000000000..fd5276abfad6
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/rockchip-rga.txt
@@ -0,0 +1,33 @@
+device-tree bindings for rockchip 2D raster graphic acceleration controller (RGA)
+
+RGA is a standalone 2D raster graphic acceleration unit. It accelerates 2D
+graphics operations, such as point/line drawing, image scaling, rotation,
+BitBLT, alpha blending and image blur/sharpness.
+
+Required properties:
+- compatible: value should be one of the following
+		"rockchip,rk3288-rga";
+		"rockchip,rk3399-rga";
+
+- interrupts: RGA interrupt specifier.
+
+- clocks: phandle to RGA sclk/hclk/aclk clocks
+
+- clock-names: should be "aclk", "hclk" and "sclk"
+
+- resets: Must contain an entry for each entry in reset-names.
+  See ../reset/reset.txt for details.
+- reset-names: should be "core", "axi" and "ahb"
+
+Example:
+SoC-specific DT entry:
+	rga: rga at ff680000 {
+		compatible = "rockchip,rk3399-rga";
+		reg = <0xff680000 0x10000>;
+		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+
+		resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>;
+		reset-names = "core, "axi", "ahb";
+	};
-- 
2.14.1



From jacob-chen at iotwrt.com  Mon Oct  9 02:04:21 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Mon,  9 Oct 2017 17:04:21 +0800
Subject: [PATCH v11 1/4] rockchip/rga: v4l2 m2m support
In-Reply-To: <20171009090424.15292-1-jacob-chen@iotwrt.com>
References: <20171009090424.15292-1-jacob-chen@iotwrt.com>
Message-ID: <20171009090424.15292-2-jacob-chen@iotwrt.com>

Rockchip RGA is a separate 2D raster graphic acceleration unit. It
accelerates 2D graphics operations, such as point/line drawing, image
scaling, rotation, BitBLT, alpha blending and image blur/sharpness

The driver supports various operations from the rendering pipeline.
 - copy
 - fast solid color fill
 - rotation
 - flip
 - alpha blending

The code in rga-hw.c is used to configure regs according to operations
The code in rga-buf.c is used to create private mmu table for RGA.

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
---
 drivers/media/platform/Kconfig                |   15 +
 drivers/media/platform/Makefile               |    2 +
 drivers/media/platform/rockchip/rga/Makefile  |    3 +
 drivers/media/platform/rockchip/rga/rga-buf.c |  154 ++++
 drivers/media/platform/rockchip/rga/rga-hw.c  |  421 ++++++++++
 drivers/media/platform/rockchip/rga/rga-hw.h  |  437 +++++++++++
 drivers/media/platform/rockchip/rga/rga.c     | 1012 +++++++++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga.h     |  123 +++
 8 files changed, 2167 insertions(+)
 create mode 100644 drivers/media/platform/rockchip/rga/Makefile
 create mode 100644 drivers/media/platform/rockchip/rga/rga-buf.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.h
 create mode 100644 drivers/media/platform/rockchip/rga/rga.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 7e7cc49b8674..d0ddc7ef7e94 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -458,6 +458,21 @@ config VIDEO_RENESAS_VSP1
 	  To compile this driver as a module, choose M here: the module
 	  will be called vsp1.
 
+config VIDEO_ROCKCHIP_RGA
+	tristate "Rockchip Raster 2d Grapphic Acceleration Unit"
+	depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	select VIDEOBUF2_DMA_SG
+	select V4L2_MEM2MEM_DEV
+	default n
+	---help---
+	  This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator.
+	  Rockchip RGA is a separate 2D raster graphic acceleration unit.
+	  It accelerates 2D graphics operations, such as point/line drawing,
+	  image scaling, rotation, BitBLT, alpha blending and image blur/sharpness.
+
+	  To compile this driver as a module choose m here.
+
 config VIDEO_TI_VPE
 	tristate "TI VPE (Video Processing Engine) driver"
 	depends on VIDEO_DEV && VIDEO_V4L2
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index c1ef946bf032..c179de1c98c3 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -62,6 +62,8 @@ obj-$(CONFIG_VIDEO_RENESAS_FDP1)	+= rcar_fdp1.o
 obj-$(CONFIG_VIDEO_RENESAS_JPU) 	+= rcar_jpu.o
 obj-$(CONFIG_VIDEO_RENESAS_VSP1)	+= vsp1/
 
+obj-$(CONFIG_VIDEO_ROCKCHIP_RGA)	+= rockchip/rga/
+
 obj-y	+= omap/
 
 obj-$(CONFIG_VIDEO_AM437X_VPFE)		+= am437x/
diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
new file mode 100644
index 000000000000..92fe25490ccd
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/Makefile
@@ -0,0 +1,3 @@
+rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
+
+obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
new file mode 100644
index 000000000000..49cacc7a48d1
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/pm_runtime.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "rga-hw.h"
+#include "rga.h"
+
+static int
+rga_queue_setup(struct vb2_queue *vq,
+		unsigned int *nbuffers, unsigned int *nplanes,
+		unsigned int sizes[], struct device *alloc_devs[])
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(vq);
+	struct rga_frame *f = rga_get_frame(ctx, vq->type);
+
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	if (*nplanes)
+		return sizes[0] < f->size ? -EINVAL : 0;
+
+	sizes[0] = f->size;
+	*nplanes = 1;
+
+	return 0;
+}
+
+static int rga_buf_prepare(struct vb2_buffer *vb)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
+
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	vb2_set_plane_payload(vb, 0, f->size);
+
+	return 0;
+}
+
+static void rga_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(q);
+	struct rockchip_rga *rga = ctx->rga;
+	int ret, i;
+
+	ret = pm_runtime_get_sync(rga->dev);
+
+	if (!ret)
+		return 0;
+
+	for (i = 0; i < q->num_buffers; ++i) {
+		if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
+			v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]),
+					  VB2_BUF_STATE_QUEUED);
+		}
+	}
+
+	return ret;
+}
+
+static void rga_buf_stop_streaming(struct vb2_queue *q)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(q);
+	struct rockchip_rga *rga = ctx->rga;
+	struct vb2_v4l2_buffer *vbuf;
+
+	for (;;) {
+		if (V4L2_TYPE_IS_OUTPUT(q->type))
+			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		else
+			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+		if (!vbuf)
+			break;
+		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+	}
+
+	pm_runtime_put(rga->dev);
+}
+
+const struct vb2_ops rga_qops = {
+	.queue_setup = rga_queue_setup,
+	.buf_prepare = rga_buf_prepare,
+	.buf_queue = rga_buf_queue,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.start_streaming = rga_buf_start_streaming,
+	.stop_streaming = rga_buf_stop_streaming,
+};
+
+/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API.
+ * We use it more like a scatter-gather list.
+ */
+void rga_buf_map(struct vb2_buffer *vb)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct rockchip_rga *rga = ctx->rga;
+	struct sg_table *sgt;
+	struct scatterlist *sgl;
+	unsigned int *pages;
+	unsigned int address, len, i, p;
+	unsigned int mapped_size = 0;
+
+	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		pages = rga->src_mmu_pages;
+	else
+		pages = rga->dst_mmu_pages;
+
+	/* Create local MMU table for RGA */
+	sgt = vb2_plane_cookie(vb, 0);
+
+	for_each_sg(sgt->sgl, sgl, sgt->nents, i) {
+		len = sg_dma_len(sgl) >> PAGE_SHIFT;
+		address = sg_phys(sgl);
+
+		for (p = 0; p < len; p++) {
+			dma_addr_t phys = address + (p << PAGE_SHIFT);
+
+			pages[mapped_size + p] = phys;
+		}
+
+		mapped_size += len;
+	}
+
+	/* sync local MMU table for RGA */
+	dma_sync_single_for_device(rga->dev, virt_to_phys(pages),
+				   8 * PAGE_SIZE, DMA_BIDIRECTIONAL);
+}
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
new file mode 100644
index 000000000000..0645481c9a5e
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/pm_runtime.h>
+
+#include "rga-hw.h"
+#include "rga.h"
+
+enum e_rga_start_pos {
+	LT = 0,
+	LB = 1,
+	RT = 2,
+	RB = 3,
+};
+
+struct rga_addr_offset {
+	unsigned int y_off;
+	unsigned int u_off;
+	unsigned int v_off;
+};
+
+struct rga_corners_addr_offset {
+	struct rga_addr_offset left_top;
+	struct rga_addr_offset right_top;
+	struct rga_addr_offset left_bottom;
+	struct rga_addr_offset right_bottom;
+};
+
+static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
+{
+	/*
+	 * The rga hw scaling factor is a normalized inverse of the
+	 * scaling factor.
+	 * For example: When source width is 100 and destination width is 200
+	 * (scaling of 2x), then the hw factor is NC * 100 / 200.
+	 * The normalization factor (NC) is 2^16 = 0x10000.
+	 */
+
+	return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);
+}
+
+static struct rga_corners_addr_offset
+rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y,
+		    unsigned int w, unsigned int h)
+{
+	struct rga_corners_addr_offset offsets;
+	struct rga_addr_offset *lt, *lb, *rt, *rb;
+	unsigned int x_div = 0,
+		     y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0;
+
+	lt = &offsets.left_top;
+	lb = &offsets.left_bottom;
+	rt = &offsets.right_top;
+	rb = &offsets.right_bottom;
+
+	x_div = frm->fmt->x_div;
+	y_div = frm->fmt->y_div;
+	uv_factor = frm->fmt->uv_factor;
+	uv_stride = frm->stride / x_div;
+	pixel_width = frm->stride / frm->width;
+
+	lt->y_off = y * frm->stride + x * pixel_width;
+	lt->u_off =
+		frm->width * frm->height + (y / y_div) * uv_stride + x / x_div;
+	lt->v_off = lt->u_off + frm->width * frm->height / uv_factor;
+
+	lb->y_off = lt->y_off + (h - 1) * frm->stride;
+	lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
+	lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;
+
+	rt->y_off = lt->y_off + (w - 1) * pixel_width;
+	rt->u_off = lt->u_off + w / x_div - 1;
+	rt->v_off = lt->v_off + w / x_div - 1;
+
+	rb->y_off = lb->y_off + (w - 1) * pixel_width;
+	rb->u_off = lb->u_off + w / x_div - 1;
+	rb->v_off = lb->v_off + w / x_div - 1;
+
+	return offsets;
+}
+
+static struct rga_addr_offset *rga_lookup_draw_pos(struct
+		rga_corners_addr_offset
+		* offsets, u32 rotate_mode,
+		u32 mirr_mode)
+{
+	static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {
+		{
+			LT, RT, LB, RB,
+		},
+		{
+			RT, LT, RB, LB,
+		},
+		{
+			RB, LB, RT, LT,
+		},
+		{
+			LB, RB, LT, RT,
+		},
+	};
+
+	if (!offsets)
+		return NULL;
+
+	switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {
+	case LT:
+		return &offsets->left_top;
+	case LB:
+		return &offsets->left_bottom;
+	case RT:
+		return &offsets->right_top;
+	case RB:
+		return &offsets->right_bottom;
+	}
+
+	return NULL;
+}
+
+static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
+	dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+
+	reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
+	dest[reg >> 2] |= 0x7;
+}
+
+static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
+	dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+
+	reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
+	dest[reg >> 2] |= 0x7 << 4;
+}
+
+static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
+	dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+
+	reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
+	dest[reg >> 2] |= 0x7 << 8;
+}
+
+static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int scale_dst_w, scale_dst_h;
+	unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y;
+	union rga_src_info src_info;
+	union rga_dst_info dst_info;
+	union rga_src_x_factor x_factor;
+	union rga_src_y_factor y_factor;
+	union rga_src_vir_info src_vir_info;
+	union rga_src_act_info src_act_info;
+	union rga_dst_vir_info dst_vir_info;
+	union rga_dst_act_info dst_act_info;
+
+	struct rga_addr_offset *dst_offset;
+	struct rga_corners_addr_offset offsets;
+	struct rga_corners_addr_offset src_offsets;
+
+	src_h = ctx->in.crop.height;
+	src_w = ctx->in.crop.width;
+	src_x = ctx->in.crop.left;
+	src_y = ctx->in.crop.top;
+	dst_h = ctx->out.crop.height;
+	dst_w = ctx->out.crop.width;
+	dst_x = ctx->out.crop.left;
+	dst_y = ctx->out.crop.top;
+
+	src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2];
+	dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2];
+	x_factor.val = dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2];
+	y_factor.val = dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2];
+	src_vir_info.val = dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
+	src_act_info.val = dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
+	dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
+	dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
+
+	src_info.data.format = ctx->in.fmt->hw_format;
+	src_info.data.swap = ctx->in.fmt->color_swap;
+	dst_info.data.format = ctx->out.fmt->hw_format;
+	dst_info.data.swap = ctx->out.fmt->color_swap;
+
+	if (ctx->in.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
+		if (ctx->out.fmt->hw_format < RGA_COLOR_FMT_YUV422SP) {
+			switch (ctx->in.colorspace) {
+			case V4L2_COLORSPACE_REC709:
+				src_info.data.csc_mode =
+					RGA_SRC_CSC_MODE_BT709_R0;
+				break;
+			default:
+				src_info.data.csc_mode =
+					RGA_SRC_CSC_MODE_BT601_R0;
+				break;
+			}
+		}
+	}
+
+	if (ctx->out.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
+		switch (ctx->out.colorspace) {
+		case V4L2_COLORSPACE_REC709:
+			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
+			break;
+		default:
+			dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0;
+			break;
+		}
+	}
+
+	if (ctx->vflip)
+		src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X;
+
+	if (ctx->hflip)
+		src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y;
+
+	switch (ctx->rotate) {
+	case 90:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_90_DEGREE;
+		break;
+	case 180:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_180_DEGREE;
+		break;
+	case 270:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_270_DEGREE;
+		break;
+	default:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_0_DEGREE;
+		break;
+	}
+
+	/*
+	 * Cacluate the up/down scaling mode/factor.
+	 *
+	 * RGA used to scale the picture first, and then rotate second,
+	 * so we need to swap the w/h when rotate degree is 90/270.
+	 */
+	if (src_info.data.rot_mode == RGA_SRC_ROT_MODE_90_DEGREE ||
+	    src_info.data.rot_mode == RGA_SRC_ROT_MODE_270_DEGREE) {
+		if (rga->version.major == 0 || rga->version.minor == 0) {
+			if (dst_w == src_h)
+				src_h -= 8;
+			if (abs(src_w - dst_h) < 16)
+				src_w -= 16;
+		}
+
+		scale_dst_h = dst_w;
+		scale_dst_w = dst_h;
+	} else {
+		scale_dst_w = dst_w;
+		scale_dst_h = dst_h;
+	}
+
+	if (src_w == scale_dst_w) {
+		src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_NO;
+		x_factor.val = 0;
+	} else if (src_w > scale_dst_w) {
+		src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN;
+		x_factor.data.down_scale_factor =
+			rga_get_scaling(src_w, scale_dst_w) + 1;
+	} else {
+		src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_UP;
+		x_factor.data.up_scale_factor =
+			rga_get_scaling(src_w - 1, scale_dst_w - 1);
+	}
+
+	if (src_h == scale_dst_h) {
+		src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_NO;
+		y_factor.val = 0;
+	} else if (src_h > scale_dst_h) {
+		src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN;
+		y_factor.data.down_scale_factor =
+			rga_get_scaling(src_h, scale_dst_h) + 1;
+	} else {
+		src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_UP;
+		y_factor.data.up_scale_factor =
+			rga_get_scaling(src_h - 1, scale_dst_h - 1);
+	}
+
+	/*
+	 * Cacluate the framebuffer virtual strides and active size,
+	 * note that the step of vir_stride / vir_width is 4 byte words
+	 */
+	src_vir_info.data.vir_stride = ctx->in.stride >> 2;
+	src_vir_info.data.vir_width = ctx->in.stride >> 2;
+
+	src_act_info.data.act_height = src_h - 1;
+	src_act_info.data.act_width = src_w - 1;
+
+	dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
+	dst_act_info.data.act_height = dst_h - 1;
+	dst_act_info.data.act_width = dst_w - 1;
+
+	/*
+	 * Cacluate the source framebuffer base address with offset pixel.
+	 */
+	src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y,
+					  src_w, src_h);
+
+	/*
+	 * Configure the dest framebuffer base address with pixel offset.
+	 */
+	offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h);
+	dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode,
+					 src_info.data.mir_mode);
+
+	dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		src_offsets.left_top.y_off;
+	dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		src_offsets.left_top.u_off;
+	dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		src_offsets.left_top.v_off;
+
+	dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;
+	dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;
+	dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;
+	dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;
+
+	dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;
+
+	dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		dst_offset->y_off;
+	dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		dst_offset->u_off;
+	dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		dst_offset->v_off;
+
+	dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;
+	dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;
+
+	dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;
+}
+
+static void rga_cmd_set_mode(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	union rga_mode_ctrl mode;
+	union rga_alpha_ctrl0 alpha_ctrl0;
+	union rga_alpha_ctrl1 alpha_ctrl1;
+
+	mode.val = 0;
+	alpha_ctrl0.val = 0;
+	alpha_ctrl1.val = 0;
+
+	mode.data.gradient_sat = 1;
+	mode.data.render = RGA_MODE_RENDER_BITBLT;
+	mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST;
+
+	/* disable alpha blending */
+	dest[(RGA_ALPHA_CTRL0 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl0.val;
+	dest[(RGA_ALPHA_CTRL1 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl1.val;
+
+	dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;
+}
+
+void rga_cmd_set(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+
+	memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
+
+	rga_cmd_set_src_addr(ctx, rga->src_mmu_pages);
+	/*
+	 * Due to hardware bug,
+	 * src1 mmu also should be configured when using alpha blending.
+	 */
+	rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages);
+
+	rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages);
+	rga_cmd_set_mode(ctx);
+
+	rga_cmd_set_trans_info(ctx);
+
+	rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
+
+	/* sync CMD buf for RGA */
+	dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
+		PAGE_SIZE, DMA_BIDIRECTIONAL);
+}
+
+void rga_hw_start(struct rockchip_rga *rga)
+{
+	struct rga_ctx *ctx = rga->curr;
+
+	rga_cmd_set(ctx);
+
+	rga_write(rga, RGA_SYS_CTRL, 0x00);
+
+	rga_write(rga, RGA_SYS_CTRL, 0x22);
+
+	rga_write(rga, RGA_INT, 0x600);
+
+	rga_write(rga, RGA_CMD_CTRL, 0x1);
+}
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
new file mode 100644
index 000000000000..ca3c204abe42
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __RGA_HW_H__
+#define __RGA_HW_H__
+
+#define RGA_CMDBUF_SIZE 0x20
+
+/* Hardware limits */
+#define MAX_WIDTH 8192
+#define MAX_HEIGHT 8192
+
+#define MIN_WIDTH 34
+#define MIN_HEIGHT 34
+
+#define DEFAULT_WIDTH 100
+#define DEFAULT_HEIGHT 100
+
+#define RGA_TIMEOUT 500
+
+/* Registers address */
+#define RGA_SYS_CTRL 0x0000
+#define RGA_CMD_CTRL 0x0004
+#define RGA_CMD_BASE 0x0008
+#define RGA_INT 0x0010
+#define RGA_MMU_CTRL0 0x0014
+#define RGA_VERSION_INFO 0x0028
+
+#define RGA_MODE_BASE_REG 0x0100
+#define RGA_MODE_MAX_REG 0x017C
+
+#define RGA_MODE_CTRL 0x0100
+#define RGA_SRC_INFO 0x0104
+#define RGA_SRC_Y_RGB_BASE_ADDR 0x0108
+#define RGA_SRC_CB_BASE_ADDR 0x010c
+#define RGA_SRC_CR_BASE_ADDR 0x0110
+#define RGA_SRC1_RGB_BASE_ADDR 0x0114
+#define RGA_SRC_VIR_INFO 0x0118
+#define RGA_SRC_ACT_INFO 0x011c
+#define RGA_SRC_X_FACTOR 0x0120
+#define RGA_SRC_Y_FACTOR 0x0124
+#define RGA_SRC_BG_COLOR 0x0128
+#define RGA_SRC_FG_COLOR 0x012c
+#define RGA_SRC_TR_COLOR0 0x0130
+#define RGA_SRC_TR_COLOR1 0x0134
+
+#define RGA_DST_INFO 0x0138
+#define RGA_DST_Y_RGB_BASE_ADDR 0x013c
+#define RGA_DST_CB_BASE_ADDR 0x0140
+#define RGA_DST_CR_BASE_ADDR 0x0144
+#define RGA_DST_VIR_INFO 0x0148
+#define RGA_DST_ACT_INFO 0x014c
+
+#define RGA_ALPHA_CTRL0 0x0150
+#define RGA_ALPHA_CTRL1 0x0154
+#define RGA_FADING_CTRL 0x0158
+#define RGA_PAT_CON 0x015c
+#define RGA_ROP_CON0 0x0160
+#define RGA_ROP_CON1 0x0164
+#define RGA_MASK_BASE 0x0168
+
+#define RGA_MMU_CTRL1 0x016C
+#define RGA_MMU_SRC_BASE 0x0170
+#define RGA_MMU_SRC1_BASE 0x0174
+#define RGA_MMU_DST_BASE 0x0178
+
+/* Registers value */
+#define RGA_MODE_RENDER_BITBLT 0
+#define RGA_MODE_RENDER_COLOR_PALETTE 1
+#define RGA_MODE_RENDER_RECTANGLE_FILL 2
+#define RGA_MODE_RENDER_UPDATE_PALETTE_LUT_RAM 3
+
+#define RGA_MODE_BITBLT_MODE_SRC_TO_DST 0
+#define RGA_MODE_BITBLT_MODE_SRC_SRC1_TO_DST 1
+
+#define RGA_MODE_CF_ROP4_SOLID 0
+#define RGA_MODE_CF_ROP4_PATTERN 1
+
+#define RGA_COLOR_FMT_ABGR8888 0
+#define RGA_COLOR_FMT_XBGR8888 1
+#define RGA_COLOR_FMT_RGB888 2
+#define RGA_COLOR_FMT_BGR565 4
+#define RGA_COLOR_FMT_ABGR1555 5
+#define RGA_COLOR_FMT_ABGR4444 6
+#define RGA_COLOR_FMT_YUV422SP 8
+#define RGA_COLOR_FMT_YUV422P 9
+#define RGA_COLOR_FMT_YUV420SP 10
+#define RGA_COLOR_FMT_YUV420P 11
+/* SRC_COLOR Palette */
+#define RGA_COLOR_FMT_CP_1BPP 12
+#define RGA_COLOR_FMT_CP_2BPP 13
+#define RGA_COLOR_FMT_CP_4BPP 14
+#define RGA_COLOR_FMT_CP_8BPP 15
+#define RGA_COLOR_FMT_MASK 15
+
+#define RGA_COLOR_NONE_SWAP 0
+#define RGA_COLOR_RB_SWAP 1
+#define RGA_COLOR_ALPHA_SWAP 2
+#define RGA_COLOR_UV_SWAP 4
+
+#define RGA_SRC_CSC_MODE_BYPASS 0
+#define RGA_SRC_CSC_MODE_BT601_R0 1
+#define RGA_SRC_CSC_MODE_BT601_R1 2
+#define RGA_SRC_CSC_MODE_BT709_R0 3
+#define RGA_SRC_CSC_MODE_BT709_R1 4
+
+#define RGA_SRC_ROT_MODE_0_DEGREE 0
+#define RGA_SRC_ROT_MODE_90_DEGREE 1
+#define RGA_SRC_ROT_MODE_180_DEGREE 2
+#define RGA_SRC_ROT_MODE_270_DEGREE 3
+
+#define RGA_SRC_MIRR_MODE_NO 0
+#define RGA_SRC_MIRR_MODE_X 1
+#define RGA_SRC_MIRR_MODE_Y 2
+#define RGA_SRC_MIRR_MODE_X_Y 3
+
+#define RGA_SRC_HSCL_MODE_NO 0
+#define RGA_SRC_HSCL_MODE_DOWN 1
+#define RGA_SRC_HSCL_MODE_UP 2
+
+#define RGA_SRC_VSCL_MODE_NO 0
+#define RGA_SRC_VSCL_MODE_DOWN 1
+#define RGA_SRC_VSCL_MODE_UP 2
+
+#define RGA_SRC_TRANS_ENABLE_R 1
+#define RGA_SRC_TRANS_ENABLE_G 2
+#define RGA_SRC_TRANS_ENABLE_B 4
+#define RGA_SRC_TRANS_ENABLE_A 8
+
+#define RGA_SRC_BIC_COE_SELEC_CATROM 0
+#define RGA_SRC_BIC_COE_SELEC_MITCHELL 1
+#define RGA_SRC_BIC_COE_SELEC_HERMITE 2
+#define RGA_SRC_BIC_COE_SELEC_BSPLINE 3
+
+#define RGA_DST_DITHER_MODE_888_TO_666 0
+#define RGA_DST_DITHER_MODE_888_TO_565 1
+#define RGA_DST_DITHER_MODE_888_TO_555 2
+#define RGA_DST_DITHER_MODE_888_TO_444 3
+
+#define RGA_DST_CSC_MODE_BYPASS 0
+#define RGA_DST_CSC_MODE_BT601_R0 1
+#define RGA_DST_CSC_MODE_BT601_R1 2
+#define RGA_DST_CSC_MODE_BT709_R0 3
+
+#define RGA_ALPHA_ROP_MODE_2 0
+#define RGA_ALPHA_ROP_MODE_3 1
+#define RGA_ALPHA_ROP_MODE_4 2
+
+#define RGA_ALPHA_SELECT_ALPHA 0
+#define RGA_ALPHA_SELECT_ROP 1
+
+#define RGA_ALPHA_MASK_BIG_ENDIAN 0
+#define RGA_ALPHA_MASK_LITTLE_ENDIAN 1
+
+#define RGA_ALPHA_NORMAL 0
+#define RGA_ALPHA_REVERSE 1
+
+#define RGA_ALPHA_BLEND_GLOBAL 0
+#define RGA_ALPHA_BLEND_NORMAL 1
+#define RGA_ALPHA_BLEND_MULTIPLY 2
+
+#define RGA_ALPHA_CAL_CUT 0
+#define RGA_ALPHA_CAL_NORMAL 1
+
+#define RGA_ALPHA_FACTOR_ZERO 0
+#define RGA_ALPHA_FACTOR_ONE 1
+#define RGA_ALPHA_FACTOR_OTHER 2
+#define RGA_ALPHA_FACTOR_OTHER_REVERSE 3
+#define RGA_ALPHA_FACTOR_SELF 4
+
+#define RGA_ALPHA_COLOR_NORMAL 0
+#define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
+
+/* Registers union */
+union rga_mode_ctrl {
+	unsigned int val;
+	struct {
+		/* [0:2] */
+		unsigned int render:3;
+		/* [3:6] */
+		unsigned int bitblt:1;
+		unsigned int cf_rop4_pat:1;
+		unsigned int alpha_zero_key:1;
+		unsigned int gradient_sat:1;
+		/* [7:31] */
+		unsigned int reserved:25;
+	} data;
+};
+
+union rga_src_info {
+	unsigned int val;
+	struct {
+		/* [0:3] */
+		unsigned int format:4;
+		/* [4:7] */
+		unsigned int swap:3;
+		unsigned int cp_endian:1;
+		/* [8:17] */
+		unsigned int csc_mode:2;
+		unsigned int rot_mode:2;
+		unsigned int mir_mode:2;
+		unsigned int hscl_mode:2;
+		unsigned int vscl_mode:2;
+		/* [18:22] */
+		unsigned int trans_mode:1;
+		unsigned int trans_enable:4;
+		/* [23:25] */
+		unsigned int dither_up_en:1;
+		unsigned int bic_coe_sel:2;
+		/* [26:31] */
+		unsigned int reserved:6;
+	} data;
+};
+
+union rga_src_vir_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int vir_width:15;
+		unsigned int reserved:1;
+		/* [16:25] */
+		unsigned int vir_stride:10;
+		/* [26:31] */
+		unsigned int reserved1:6;
+	} data;
+};
+
+union rga_src_act_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int act_width:13;
+		unsigned int reserved:3;
+		/* [16:31] */
+		unsigned int act_height:13;
+		unsigned int reserved1:3;
+	} data;
+};
+
+union rga_src_x_factor {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int down_scale_factor:16;
+		/* [16:31] */
+		unsigned int up_scale_factor:16;
+	} data;
+};
+
+union rga_src_y_factor {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int down_scale_factor:16;
+		/* [16:31] */
+		unsigned int up_scale_factor:16;
+	} data;
+};
+
+/* Alpha / Red / Green / Blue */
+union rga_src_cp_gr_color {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int gradient_x:16;
+		/* [16:31] */
+		unsigned int gradient_y:16;
+	} data;
+};
+
+union rga_src_transparency_color0 {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int trans_rmin:8;
+		/* [8:15] */
+		unsigned int trans_gmin:8;
+		/* [16:23] */
+		unsigned int trans_bmin:8;
+		/* [24:31] */
+		unsigned int trans_amin:8;
+	} data;
+};
+
+union rga_src_transparency_color1 {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int trans_rmax:8;
+		/* [8:15] */
+		unsigned int trans_gmax:8;
+		/* [16:23] */
+		unsigned int trans_bmax:8;
+		/* [24:31] */
+		unsigned int trans_amax:8;
+	} data;
+};
+
+union rga_dst_info {
+	unsigned int val;
+	struct {
+		/* [0:3] */
+		unsigned int format:4;
+		/* [4:6] */
+		unsigned int swap:3;
+		/* [7:9] */
+		unsigned int src1_format:3;
+		/* [10:11] */
+		unsigned int src1_swap:2;
+		/* [12:15] */
+		unsigned int dither_up_en:1;
+		unsigned int dither_down_en:1;
+		unsigned int dither_down_mode:2;
+		/* [16:18] */
+		unsigned int csc_mode:2;
+		unsigned int csc_clip:1;
+		/* [19:31] */
+		unsigned int reserved:13;
+	} data;
+};
+
+union rga_dst_vir_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int vir_stride:15;
+		unsigned int reserved:1;
+		/* [16:31] */
+		unsigned int src1_vir_stride:15;
+		unsigned int reserved1:1;
+	} data;
+};
+
+union rga_dst_act_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int act_width:12;
+		unsigned int reserved:4;
+		/* [16:31] */
+		unsigned int act_height:12;
+		unsigned int reserved1:4;
+	} data;
+};
+
+union rga_alpha_ctrl0 {
+	unsigned int val;
+	struct {
+		/* [0:3] */
+		unsigned int rop_en:1;
+		unsigned int rop_select:1;
+		unsigned int rop_mode:2;
+		/* [4:11] */
+		unsigned int src_fading_val:8;
+		/* [12:20] */
+		unsigned int dst_fading_val:8;
+		unsigned int mask_endian:1;
+		/* [21:31] */
+		unsigned int reserved:11;
+	} data;
+};
+
+union rga_alpha_ctrl1 {
+	unsigned int val;
+	struct {
+		/* [0:1] */
+		unsigned int dst_color_m0:1;
+		unsigned int src_color_m0:1;
+		/* [2:7] */
+		unsigned int dst_factor_m0:3;
+		unsigned int src_factor_m0:3;
+		/* [8:9] */
+		unsigned int dst_alpha_cal_m0:1;
+		unsigned int src_alpha_cal_m0:1;
+		/* [10:13] */
+		unsigned int dst_blend_m0:2;
+		unsigned int src_blend_m0:2;
+		/* [14:15] */
+		unsigned int dst_alpha_m0:1;
+		unsigned int src_alpha_m0:1;
+		/* [16:21] */
+		unsigned int dst_factor_m1:3;
+		unsigned int src_factor_m1:3;
+		/* [22:23] */
+		unsigned int dst_alpha_cal_m1:1;
+		unsigned int src_alpha_cal_m1:1;
+		/* [24:27] */
+		unsigned int dst_blend_m1:2;
+		unsigned int src_blend_m1:2;
+		/* [28:29] */
+		unsigned int dst_alpha_m1:1;
+		unsigned int src_alpha_m1:1;
+		/* [30:31] */
+		unsigned int reserved:2;
+	} data;
+};
+
+union rga_fading_ctrl {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int fading_offset_r:8;
+		/* [8:15] */
+		unsigned int fading_offset_g:8;
+		/* [16:23] */
+		unsigned int fading_offset_b:8;
+		/* [24:31] */
+		unsigned int fading_en:1;
+		unsigned int reserved:7;
+	} data;
+};
+
+union rga_pat_con {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int width:8;
+		/* [8:15] */
+		unsigned int height:8;
+		/* [16:23] */
+		unsigned int offset_x:8;
+		/* [24:31] */
+		unsigned int offset_y:8;
+	} data;
+};
+
+#endif
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
new file mode 100644
index 000000000000..9424458a3c85
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "rga-hw.h"
+#include "rga.h"
+
+static int debug;
+module_param(debug, int, 0644);
+
+static void job_abort(void *prv)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+
+	if (!rga->curr)	/* No job currently running */
+		return;
+
+	wait_event_timeout(rga->irq_queue,
+			   !rga->curr, msecs_to_jiffies(RGA_TIMEOUT));
+}
+
+static void device_run(void *prv)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+	struct vb2_buffer *src, *dst;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rga->ctrl_lock, flags);
+
+	rga->curr = ctx;
+
+	src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+	rga_buf_map(src);
+	rga_buf_map(dst);
+
+	rga_hw_start(rga);
+
+	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
+}
+
+static irqreturn_t rga_isr(int irq, void *prv)
+{
+	struct rockchip_rga *rga = prv;
+	int intr;
+
+	intr = rga_read(rga, RGA_INT) & 0xf;
+
+	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
+
+	if (intr & 0x04) {
+		struct vb2_v4l2_buffer *src, *dst;
+		struct rga_ctx *ctx = rga->curr;
+
+		BUG_ON(!ctx);
+
+		rga->curr = NULL;
+
+		src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+		BUG_ON(!src);
+		BUG_ON(!dst);
+
+		dst->timecode = src->timecode;
+		dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
+		dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+		dst->flags |= src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+
+		v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
+		v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
+		v4l2_m2m_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx);
+
+		wake_up(&rga->irq_queue);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct v4l2_m2m_ops rga_m2m_ops = {
+	.device_run = device_run,
+	.job_abort = job_abort,
+};
+
+static int
+queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+	struct rga_ctx *ctx = priv;
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	src_vq->drv_priv = ctx;
+	src_vq->ops = &rga_qops;
+	src_vq->mem_ops = &vb2_dma_sg_memops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->lock = &ctx->rga->mutex;
+	src_vq->dev = ctx->rga->v4l2_dev.dev;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->ops = &rga_qops;
+	dst_vq->mem_ops = &vb2_dma_sg_memops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->lock = &ctx->rga->mutex;
+	dst_vq->dev = ctx->rga->v4l2_dev.dev;
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int rga_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct rga_ctx *ctx = container_of(ctrl->handler, struct rga_ctx,
+					   ctrl_handler);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->rga->ctrl_lock, flags);
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		ctx->hflip = ctrl->val;
+		break;
+	case V4L2_CID_VFLIP:
+		ctx->vflip = ctrl->val;
+		break;
+	case V4L2_CID_ROTATE:
+		ctx->rotate = ctrl->val;
+		break;
+	case V4L2_CID_BG_COLOR:
+		ctx->fill_color = ctrl->val;
+		break;
+	}
+	spin_unlock_irqrestore(&ctx->rga->ctrl_lock, flags);
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops rga_ctrl_ops = {
+	.s_ctrl = rga_s_ctrl,
+};
+
+static int rga_setup_ctrls(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_ROTATE, 0, 270, 90, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
+
+	if (ctx->ctrl_handler.error) {
+		int err = ctx->ctrl_handler.error;
+
+		v4l2_err(&rga->v4l2_dev, "%s failed\n", __func__);
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+		return err;
+	}
+
+	return 0;
+}
+
+struct rga_fmt formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XRGB32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_XBGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XBGR32,
+		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.hw_format = RGA_COLOR_FMT_XBGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB444,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR4444,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB555,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR1555,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_BGR565,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV422P,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422P,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YVU420,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+struct rga_fmt *rga_fmt_find(struct v4l2_format *f)
+{
+	unsigned int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].fourcc == f->fmt.pix.pixelformat)
+			return &formats[i];
+	}
+	return NULL;
+}
+
+static struct rga_frame def_frame = {
+	.width = DEFAULT_WIDTH,
+	.height = DEFAULT_HEIGHT,
+	.colorspace = V4L2_COLORSPACE_DEFAULT,
+	.crop.left = 0,
+	.crop.top = 0,
+	.crop.width = DEFAULT_WIDTH,
+	.crop.height = DEFAULT_HEIGHT,
+	.fmt = &formats[0],
+};
+
+struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &ctx->in;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &ctx->out;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+static int rga_open(struct file *file)
+{
+	struct rockchip_rga *rga = video_drvdata(file);
+	struct rga_ctx *ctx = NULL;
+	int ret = 0;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+	ctx->rga = rga;
+	/* Set default formats */
+	ctx->in = def_frame;
+	ctx->out = def_frame;
+
+	if (mutex_lock_interruptible(&rga->mutex)) {
+		kfree(ctx);
+		return -ERESTARTSYS;
+	}
+	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init);
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+		mutex_unlock(&rga->mutex);
+		kfree(ctx);
+		return ret;
+	}
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	rga_setup_ctrls(ctx);
+
+	/* Write the default values to the ctx struct */
+	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	mutex_unlock(&rga->mutex);
+
+	return 0;
+}
+
+static int rga_release(struct file *file)
+{
+	struct rga_ctx *ctx =
+		container_of(file->private_data, struct rga_ctx, fh);
+	struct rockchip_rga *rga = ctx->rga;
+
+	mutex_lock(&rga->mutex);
+
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+
+	mutex_unlock(&rga->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations rga_fops = {
+	.owner = THIS_MODULE,
+	.open = rga_open,
+	.release = rga_release,
+	.poll = v4l2_m2m_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = v4l2_m2m_fop_mmap,
+};
+
+static int
+vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+	strlcpy(cap->driver, RGA_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, "rockchip-rga", sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
+
+	return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
+{
+	struct rga_fmt *fmt;
+
+	if (f->index >= NUM_FORMATS)
+		return -EINVAL;
+
+	fmt = &formats[f->index];
+	f->pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct rga_ctx *ctx = prv;
+	struct vb2_queue *vq;
+	struct rga_frame *frm;
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+	frm = rga_get_frame(ctx, f->type);
+	if (IS_ERR(frm))
+		return PTR_ERR(frm);
+
+	f->fmt.pix.width = frm->width;
+	f->fmt.pix.height = frm->height;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat = frm->fmt->fourcc;
+	f->fmt.pix.bytesperline = frm->stride;
+	f->fmt.pix.sizeimage = frm->size;
+	f->fmt.pix.colorspace = frm->colorspace;
+
+	return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct rga_fmt *fmt;
+
+	fmt = rga_fmt_find(f);
+	if (!fmt) {
+		fmt = &formats[0];
+		f->fmt.pix.pixelformat = fmt->fourcc;
+	}
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+
+	if (f->fmt.pix.width > MAX_WIDTH)
+		f->fmt.pix.width = MAX_WIDTH;
+	if (f->fmt.pix.height > MAX_HEIGHT)
+		f->fmt.pix.height = MAX_HEIGHT;
+
+	if (f->fmt.pix.width < MIN_WIDTH)
+		f->fmt.pix.width = MIN_WIDTH;
+	if (f->fmt.pix.height < MIN_HEIGHT)
+		f->fmt.pix.height = MIN_HEIGHT;
+
+	if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP)
+		f->fmt.pix.bytesperline = f->fmt.pix.width;
+	else
+		f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * (f->fmt.pix.width * fmt->depth) >> 3;
+
+	return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+	struct vb2_queue *vq;
+	struct rga_frame *frm;
+	struct rga_fmt *fmt;
+	int ret = 0;
+
+	/* Adjust all values accordingly to the hardware capabilities
+	 * and chosen format.
+	 */
+	ret = vidioc_try_fmt(file, prv, f);
+	if (ret)
+		return ret;
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&rga->v4l2_dev, "queue (%d) bust\n", f->type);
+		return -EBUSY;
+	}
+	frm = rga_get_frame(ctx, f->type);
+	if (IS_ERR(frm))
+		return PTR_ERR(frm);
+	fmt = rga_fmt_find(f);
+	if (!fmt)
+		return -EINVAL;
+	frm->width = f->fmt.pix.width;
+	frm->height = f->fmt.pix.height;
+	frm->size = f->fmt.pix.sizeimage;
+	frm->fmt = fmt;
+	frm->stride = f->fmt.pix.bytesperline;
+	frm->colorspace = f->fmt.pix.colorspace;
+
+	/* Reset crop settings */
+	frm->crop.left = 0;
+	frm->crop.top = 0;
+	frm->crop.width = frm->width;
+	frm->crop.height = frm->height;
+
+	return 0;
+}
+
+static int vidioc_g_selection(struct file *file, void *prv,
+			      struct v4l2_selection *s)
+{
+	struct rga_ctx *ctx = prv;
+	struct rga_frame *f;
+	bool use_frame = false;
+
+	f = rga_get_frame(ctx, s->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		use_frame = true;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		use_frame = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (use_frame) {
+		s->r = f->crop;
+	} else {
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = f->width;
+		s->r.height = f->height;
+	}
+
+	return 0;
+}
+
+static int vidioc_s_selection(struct file *file, void *prv,
+			      struct v4l2_selection *s)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+	struct rga_frame *f;
+	int ret = 0;
+
+	f = rga_get_frame(ctx, s->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:
+		/*
+		 * COMPOSE target is only valid for capture buffer type, return
+		 * error for output buffer type
+		 */
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		/*
+		 * CROP target is only valid for output buffer type, return
+		 * error for capture buffer type
+		 */
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		break;
+	/*
+	 * bound and default crop/compose targets are invalid targets to
+	 * try/set
+	 */
+	default:
+		return -EINVAL;
+	}
+
+	if (s->r.top < 0 || s->r.left < 0) {
+		v4l2_dbg(debug, 1, &rga->v4l2_dev,
+			 "doesn't support negative values for top & left.\n");
+		return -EINVAL;
+	}
+
+	if (s->r.left + s->r.width > f->width ||
+	    s->r.top + s->r.height > f->height ||
+	    s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
+		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
+		return -EINVAL;
+	}
+
+	f->crop = s->r;
+
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops rga_ioctl_ops = {
+	.vidioc_querycap = vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_cap = vidioc_g_fmt,
+	.vidioc_try_fmt_vid_cap = vidioc_try_fmt,
+	.vidioc_s_fmt_vid_cap = vidioc_s_fmt,
+
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_out = vidioc_g_fmt,
+	.vidioc_try_fmt_vid_out = vidioc_try_fmt,
+	.vidioc_s_fmt_vid_out = vidioc_s_fmt,
+
+	.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+	.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+	.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+	.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+	.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+	.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+	.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
+	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+	.vidioc_g_selection = vidioc_g_selection,
+	.vidioc_s_selection = vidioc_s_selection,
+};
+
+static struct video_device rga_videodev = {
+	.name = "rockchip-rga",
+	.fops = &rga_fops,
+	.ioctl_ops = &rga_ioctl_ops,
+	.minor = -1,
+	.release = video_device_release,
+	.vfl_dir = VFL_DIR_M2M,
+	.device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+static int rga_enable_clocks(struct rockchip_rga *rga)
+{
+	int ret;
+
+	ret = clk_prepare_enable(rga->sclk);
+	if (ret) {
+		dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(rga->aclk);
+	if (ret) {
+		dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret);
+		goto err_disable_sclk;
+	}
+
+	ret = clk_prepare_enable(rga->hclk);
+	if (ret) {
+		dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret);
+		goto err_disable_aclk;
+	}
+
+	return 0;
+
+err_disable_sclk:
+	clk_disable_unprepare(rga->sclk);
+err_disable_aclk:
+	clk_disable_unprepare(rga->aclk);
+
+	return ret;
+}
+
+static void rga_disable_clocks(struct rockchip_rga *rga)
+{
+	clk_disable_unprepare(rga->sclk);
+	clk_disable_unprepare(rga->hclk);
+	clk_disable_unprepare(rga->aclk);
+}
+
+static int rga_parse_dt(struct rockchip_rga *rga)
+{
+	struct reset_control *core_rst, *axi_rst, *ahb_rst;
+
+	core_rst = devm_reset_control_get(rga->dev, "core");
+	if (IS_ERR(core_rst)) {
+		dev_err(rga->dev, "failed to get core reset controller\n");
+		return PTR_ERR(core_rst);
+	}
+
+	axi_rst = devm_reset_control_get(rga->dev, "axi");
+	if (IS_ERR(axi_rst)) {
+		dev_err(rga->dev, "failed to get axi reset controller\n");
+		return PTR_ERR(axi_rst);
+	}
+
+	ahb_rst = devm_reset_control_get(rga->dev, "ahb");
+	if (IS_ERR(ahb_rst)) {
+		dev_err(rga->dev, "failed to get ahb reset controller\n");
+		return PTR_ERR(ahb_rst);
+	}
+
+	reset_control_assert(core_rst);
+	udelay(1);
+	reset_control_deassert(core_rst);
+
+	reset_control_assert(axi_rst);
+	udelay(1);
+	reset_control_deassert(axi_rst);
+
+	reset_control_assert(ahb_rst);
+	udelay(1);
+	reset_control_deassert(ahb_rst);
+
+	rga->sclk = devm_clk_get(rga->dev, "sclk");
+	if (IS_ERR(rga->sclk)) {
+		dev_err(rga->dev, "failed to get sclk clock\n");
+		return PTR_ERR(rga->sclk);
+	}
+
+	rga->aclk = devm_clk_get(rga->dev, "aclk");
+	if (IS_ERR(rga->aclk)) {
+		dev_err(rga->dev, "failed to get aclk clock\n");
+		return PTR_ERR(rga->aclk);
+	}
+
+	rga->hclk = devm_clk_get(rga->dev, "hclk");
+	if (IS_ERR(rga->hclk)) {
+		dev_err(rga->dev, "failed to get hclk clock\n");
+		return PTR_ERR(rga->hclk);
+	}
+
+	return 0;
+}
+
+static int rga_probe(struct platform_device *pdev)
+{
+	struct rockchip_rga *rga;
+	struct video_device *vfd;
+	struct resource *res;
+	int ret = 0;
+	int irq;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
+	if (!rga)
+		return -ENOMEM;
+
+	rga->dev = &pdev->dev;
+	spin_lock_init(&rga->ctrl_lock);
+	mutex_init(&rga->mutex);
+
+	init_waitqueue_head(&rga->irq_queue);
+
+	ret = rga_parse_dt(rga);
+	if (ret)
+		dev_err(&pdev->dev, "Unable to parse OF data\n");
+
+	pm_runtime_enable(rga->dev);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	rga->regs = devm_ioremap_resource(rga->dev, res);
+	if (IS_ERR(rga->regs)) {
+		ret = PTR_ERR(rga->regs);
+		goto err_put_clk;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(rga->dev, "failed to get irq\n");
+		ret = irq;
+		goto err_put_clk;
+	}
+
+	ret = devm_request_irq(rga->dev, irq, rga_isr, 0,
+			       dev_name(rga->dev), rga);
+	if (ret < 0) {
+		dev_err(rga->dev, "failed to request irq\n");
+		goto err_put_clk;
+	}
+
+	ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev);
+	if (ret)
+		goto err_put_clk;
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&rga->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_v4l2_dev;
+	}
+	*vfd = rga_videodev;
+	vfd->lock = &rga->mutex;
+	vfd->v4l2_dev = &rga->v4l2_dev;
+
+	video_set_drvdata(vfd, rga);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", rga_videodev.name);
+	rga->vfd = vfd;
+
+	platform_set_drvdata(pdev, rga);
+	rga->m2m_dev = v4l2_m2m_init(&rga_m2m_ops);
+	if (IS_ERR(rga->m2m_dev)) {
+		v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(rga->m2m_dev);
+		goto unreg_video_dev;
+	}
+
+	pm_runtime_get_sync(rga->dev);
+
+	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
+	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
+
+	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
+		  rga->version.major, rga->version.minor);
+
+	pm_runtime_put(rga->dev);
+
+	/* Create CMD buffer */
+	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
+					   &rga->cmdbuf_phy, GFP_KERNEL,
+					   DMA_ATTR_WRITE_COMBINE);
+
+	rga->src_mmu_pages =
+		(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
+	rga->dst_mmu_pages =
+		(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
+
+	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
+	def_frame.size = def_frame.stride * def_frame.height;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret) {
+		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
+		goto rel_vdev;
+	}
+
+	v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+
+	return 0;
+
+rel_vdev:
+	video_device_release(vfd);
+unreg_video_dev:
+	video_unregister_device(rga->vfd);
+unreg_v4l2_dev:
+	v4l2_device_unregister(&rga->v4l2_dev);
+err_put_clk:
+	pm_runtime_disable(rga->dev);
+
+	return ret;
+}
+
+static int rga_remove(struct platform_device *pdev)
+{
+	struct rockchip_rga *rga = platform_get_drvdata(pdev);
+
+	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, &rga->cmdbuf_virt,
+		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
+
+	free_pages((unsigned long)rga->src_mmu_pages, 3);
+	free_pages((unsigned long)rga->dst_mmu_pages, 3);
+
+	v4l2_info(&rga->v4l2_dev, "Removing\n");
+
+	v4l2_m2m_release(rga->m2m_dev);
+	video_unregister_device(rga->vfd);
+	v4l2_device_unregister(&rga->v4l2_dev);
+
+	pm_runtime_disable(rga->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rga_runtime_suspend(struct device *dev)
+{
+	struct rockchip_rga *rga = dev_get_drvdata(dev);
+
+	rga_disable_clocks(rga);
+
+	return 0;
+}
+
+static int rga_runtime_resume(struct device *dev)
+{
+	struct rockchip_rga *rga = dev_get_drvdata(dev);
+
+	return rga_enable_clocks(rga);
+}
+#endif
+
+static const struct dev_pm_ops rga_pm = {
+	SET_RUNTIME_PM_OPS(rga_runtime_suspend,
+			   rga_runtime_resume, NULL)
+};
+
+static const struct of_device_id rockchip_rga_match[] = {
+	{
+		.compatible = "rockchip,rk3288-rga",
+	},
+	{
+		.compatible = "rockchip,rk3399-rga",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_rga_match);
+
+static struct platform_driver rga_pdrv = {
+	.probe = rga_probe,
+	.remove = rga_remove,
+	.driver = {
+		.name = RGA_NAME,
+		.pm = &rga_pm,
+		.of_match_table = rockchip_rga_match,
+	},
+};
+
+module_platform_driver(rga_pdrv);
+
+MODULE_AUTHOR("Jacob Chen <jacob-chen at iotwrt.com>");
+MODULE_DESCRIPTION("Rockchip Raster 2d Graphic Acceleration Unit");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
new file mode 100644
index 000000000000..cf7003647112
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __RGA_H__
+#define __RGA_H__
+
+#include <linux/platform_device.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#define RGA_NAME "rockchip-rga"
+
+struct rga_fmt {
+	u32 fourcc;
+	int depth;
+	u8 uv_factor;
+	u8 y_div;
+	u8 x_div;
+	u8 color_swap;
+	u8 hw_format;
+};
+
+struct rga_frame {
+	/* Original dimensions */
+	u32 width;
+	u32 height;
+	u32 colorspace;
+
+	/* Crop */
+	struct v4l2_rect crop;
+
+	/* Image format */
+	struct rga_fmt *fmt;
+
+	/* Variables that can calculated once and reused */
+	u32 stride;
+	u32 size;
+};
+
+struct rockchip_rga_version {
+	u32 major;
+	u32 minor;
+};
+
+struct rga_ctx {
+	struct v4l2_fh fh;
+	struct rockchip_rga *rga;
+	struct rga_frame in;
+	struct rga_frame out;
+	struct v4l2_ctrl_handler ctrl_handler;
+
+	/* Control values */
+	u32 op;
+	u32 hflip;
+	u32 vflip;
+	u32 rotate;
+	u32 fill_color;
+};
+
+struct rockchip_rga {
+	struct v4l2_device v4l2_dev;
+	struct v4l2_m2m_dev *m2m_dev;
+	struct video_device *vfd;
+
+	struct device *dev;
+	struct regmap *grf;
+	void __iomem *regs;
+	struct clk *sclk;
+	struct clk *aclk;
+	struct clk *hclk;
+	struct rockchip_rga_version version;
+
+	struct mutex mutex;
+	spinlock_t ctrl_lock;
+
+	wait_queue_head_t irq_queue;
+
+	struct rga_ctx *curr;
+	dma_addr_t cmdbuf_phy;
+	void *cmdbuf_virt;
+	unsigned int *src_mmu_pages;
+	unsigned int *dst_mmu_pages;
+};
+
+struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type);
+
+/* RGA Buffers Manage */
+extern const struct vb2_ops rga_qops;
+void rga_buf_map(struct vb2_buffer *vb);
+
+/* RGA Hardware */
+static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value)
+{
+	writel(value, rga->regs + reg);
+};
+
+static inline u32 rga_read(struct rockchip_rga *rga, u32 reg)
+{
+	return readl(rga->regs + reg);
+};
+
+static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
+{
+	u32 temp = rga_read(rga, reg) & ~(mask);
+
+	temp |= val & mask;
+	rga_write(rga, reg, temp);
+};
+
+void rga_hw_start(struct rockchip_rga *rga);
+
+#endif
-- 
2.14.1



From hverkuil at xs4all.nl  Mon Oct  9 05:43:23 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Mon, 9 Oct 2017 14:43:23 +0200
Subject: [PATCH v11 0/4] Add Rockchip RGA V4l2 support
In-Reply-To: <20171009090424.15292-1-jacob-chen@iotwrt.com>
References: <20171009090424.15292-1-jacob-chen@iotwrt.com>
Message-ID: <2b5c0479-0836-9e03-dfd7-75ed77f39512@xs4all.nl>

Hi Jacob,

A patch adding an entry to MAINTAINERS is still missing.

Just post a separate patch for that.

Regards,

	Hans

On 09/10/17 11:04, Jacob Chen wrote:
> change in V11:
> - fix compile warning
> 
> change in V10:
> - move to rockchip/rga
> - changes according to comments
> - some style changes
> 
> change in V9:
> - remove protduff things
> - test with the latest v4l2-compliance
> 
> change in V8:
> - remove protduff things
> 
> change in V6,V7:
> - correct warning in checkpatch.pl
> 
> change in V5:
> - v4l2-compliance: handle invalid pxielformat
> - v4l2-compliance: add subscribe_event
> - add colorspace support
> 
> change in V4:
> - document the controls.
> - change according to Hans's comments
> 
> change in V3:
> - rename the controls.
> - add pm_runtime support.
> - enable node by default.
> - correct spelling in documents.
> 
> change in V2:
> - generalize the controls.
> - map buffers (10-50 us) in every cmd-run rather than in buffer-import to avoid get_free_pages failed on
> actively used systems.
> - remove status in dt-bindings examples.
> 
> Jacob Chen (4):
>   rockchip/rga: v4l2 m2m support
>   ARM: dts: rockchip: add RGA device node for RK3288
>   arm64: dts: rockchip: add RGA device node for RK3399
>   dt-bindings: Document the Rockchip RGA bindings
> 
>  .../devicetree/bindings/media/rockchip-rga.txt     |   33 +
>  arch/arm/boot/dts/rk3288.dtsi                      |   11 +
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi           |   11 +
>  drivers/media/platform/Kconfig                     |   15 +
>  drivers/media/platform/Makefile                    |    2 +
>  drivers/media/platform/rockchip/rga/Makefile       |    3 +
>  drivers/media/platform/rockchip/rga/rga-buf.c      |  154 +++
>  drivers/media/platform/rockchip/rga/rga-hw.c       |  421 ++++++++
>  drivers/media/platform/rockchip/rga/rga-hw.h       |  437 +++++++++
>  drivers/media/platform/rockchip/rga/rga.c          | 1012 ++++++++++++++++++++
>  drivers/media/platform/rockchip/rga/rga.h          |  123 +++
>  11 files changed, 2222 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/rockchip-rga.txt
>  create mode 100644 drivers/media/platform/rockchip/rga/Makefile
>  create mode 100644 drivers/media/platform/rockchip/rga/rga-buf.c
>  create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.c
>  create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.h
>  create mode 100644 drivers/media/platform/rockchip/rga/rga.c
>  create mode 100644 drivers/media/platform/rockchip/rga/rga.h
> 



From hverkuil at xs4all.nl  Mon Oct  9 05:48:13 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Mon, 9 Oct 2017 14:48:13 +0200
Subject: [PATCH v11 1/4] rockchip/rga: v4l2 m2m support
In-Reply-To: <20171009090424.15292-2-jacob-chen@iotwrt.com>
References: <20171009090424.15292-1-jacob-chen@iotwrt.com>
 <20171009090424.15292-2-jacob-chen@iotwrt.com>
Message-ID: <39318451-a078-3451-47f8-9205a31cadb5@xs4all.nl>

On 09/10/17 11:04, Jacob Chen wrote:
> Rockchip RGA is a separate 2D raster graphic acceleration unit. It
> accelerates 2D graphics operations, such as point/line drawing, image
> scaling, rotation, BitBLT, alpha blending and image blur/sharpness
> 
> The driver supports various operations from the rendering pipeline.
>  - copy
>  - fast solid color fill
>  - rotation
>  - flip
>  - alpha blending
> 
> The code in rga-hw.c is used to configure regs according to operations
> The code in rga-buf.c is used to create private mmu table for RGA.
> 
> Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>

I ran checkpatch --strict on this patch and I found a few small issues:

WARNING: Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()
#1222: FILE: drivers/media/platform/rockchip/rga/rga.c:89:
+               BUG_ON(!ctx);

WARNING: Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()
#1229: FILE: drivers/media/platform/rockchip/rga/rga.c:96:
+               BUG_ON(!src);

WARNING: Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()
#1230: FILE: drivers/media/platform/rockchip/rga/rga.c:97:
+               BUG_ON(!dst);

I think you can use WARN_ON here and just return.

CHECK: struct mutex definition without comment
#2235: FILE: drivers/media/platform/rockchip/rga/rga.h:84:
+       struct mutex mutex;

CHECK: spinlock_t definition without comment
#2236: FILE: drivers/media/platform/rockchip/rga/rga.h:85:
+       spinlock_t ctrl_lock;

These two fields need a comment describing what the locks protect.

Also move patch 4/4 to the beginning of the patch series. The bindings
patch should come before the driver.

If I have a v12 with these issues fixed and a MAINTAINERS patch, then
I'll take it on Friday.

Do you want me to take the dts patches or will they go through another tree?

Regards,

	Hans


From heiko at sntech.de  Mon Oct  9 05:52:06 2017
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Mon, 09 Oct 2017 14:52:06 +0200
Subject: [PATCH v11 1/4] rockchip/rga: v4l2 m2m support
In-Reply-To: <39318451-a078-3451-47f8-9205a31cadb5@xs4all.nl>
References: <20171009090424.15292-1-jacob-chen@iotwrt.com>
 <20171009090424.15292-2-jacob-chen@iotwrt.com>
 <39318451-a078-3451-47f8-9205a31cadb5@xs4all.nl>
Message-ID: <1723232.PDSGHSTtIa@diego>

Hi Hans,

Am Montag, 9. Oktober 2017, 14:48:13 CEST schrieb Hans Verkuil:
> On 09/10/17 11:04, Jacob Chen wrote:
> > Rockchip RGA is a separate 2D raster graphic acceleration unit. It
> > accelerates 2D graphics operations, such as point/line drawing, image
> > scaling, rotation, BitBLT, alpha blending and image blur/sharpness
> > 
> > The driver supports various operations from the rendering pipeline.
> > 
> >  - copy
> >  - fast solid color fill
> >  - rotation
> >  - flip
> >  - alpha blending
> > 
> > The code in rga-hw.c is used to configure regs according to operations
> > The code in rga-buf.c is used to create private mmu table for RGA.
> > 
> > Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
> 
> I ran checkpatch --strict on this patch and I found a few small issues:
> 
> WARNING: Avoid crashing the kernel - try using WARN_ON & recovery code
> rather than BUG() or BUG_ON() #1222: FILE:
> drivers/media/platform/rockchip/rga/rga.c:89:
> +               BUG_ON(!ctx);
> 
> WARNING: Avoid crashing the kernel - try using WARN_ON & recovery code
> rather than BUG() or BUG_ON() #1229: FILE:
> drivers/media/platform/rockchip/rga/rga.c:96:
> +               BUG_ON(!src);
> 
> WARNING: Avoid crashing the kernel - try using WARN_ON & recovery code
> rather than BUG() or BUG_ON() #1230: FILE:
> drivers/media/platform/rockchip/rga/rga.c:97:
> +               BUG_ON(!dst);
> 
> I think you can use WARN_ON here and just return.
> 
> CHECK: struct mutex definition without comment
> #2235: FILE: drivers/media/platform/rockchip/rga/rga.h:84:
> +       struct mutex mutex;
> 
> CHECK: spinlock_t definition without comment
> #2236: FILE: drivers/media/platform/rockchip/rga/rga.h:85:
> +       spinlock_t ctrl_lock;
> 
> These two fields need a comment describing what the locks protect.
> 
> Also move patch 4/4 to the beginning of the patch series. The bindings
> patch should come before the driver.
> 
> If I have a v12 with these issues fixed and a MAINTAINERS patch, then
> I'll take it on Friday.
> 
> Do you want me to take the dts patches or will they go through another tree?

I'd prefer for me to pick up the dts patches ("ARM: dts" and "arm64: dts:"), 
as otherwise we always get conflicts and confusion :-)

I'm monitoring this series, so after you pick the binding + driver, I can
just pick the other two.


Thanks
Heiko


From robh at kernel.org  Mon Oct  9 06:05:44 2017
From: robh at kernel.org (Rob Herring)
Date: Mon, 9 Oct 2017 08:05:44 -0500
Subject: [PATCH v2 1/3] dt-bindings: Add document for rockchip RGB output
 interface
In-Reply-To: <2d502a9d-e952-8afb-d2d7-45c21c36da7e@rock-chips.com>
References: <1506049221-117283-1-git-send-email-hjc@rock-chips.com>
 <1506049229-117376-1-git-send-email-hjc@rock-chips.com>
 <20171003215631.rc2jsf2m3qgoltsb@rob-hp-laptop>
 <2d502a9d-e952-8afb-d2d7-45c21c36da7e@rock-chips.com>
Message-ID: <CAL_JsqJcO6VtgYBzby+gjerODT9n6fE0aMNJXNejvvhF1nqM-Q@mail.gmail.com>

On Mon, Oct 9, 2017 at 3:06 AM, Sandy Huang <hjc at rock-chips.com> wrote:
> Hi rob,
>     Thanks for your reply.
>
> ? 2017/10/4 5:56, Rob Herring ??:
>>
>> On Fri, Sep 22, 2017 at 11:00:26AM +0800, Sandy Huang wrote:
>>>
>>> This path add support rv1108 rgb output interface driver.
>>>
>>> Signed-off-by: Sandy Huang <hjc at rock-chips.com>
>>> ---
>>> Changes in v2:
>>>   1. rename rockchip,rgb-mode to rgb-mode;
>>
>>
>> You can't just drop the vendor. This needs to be documented in a common
>> place that others will find and use. See panel-common.txt or
>> panel-dpi.txt.
>>
>> Alternatively, you could just drop it and let the panel compatible imply
>> what the mode is.
>>
>>
> ok, get it, i will move the rgb-mode to panel and describe it at
> panel-rgb.txt. the patches will be send soon later.

Don't create yet another common panel file. We already have
panel-dpi.txt which is for digital parallel interface.

Rob


From kernel at esmil.dk  Mon Oct  9 11:40:28 2017
From: kernel at esmil.dk (Emil Renner Berthing)
Date: Mon,  9 Oct 2017 20:40:28 +0200
Subject: [PATCH] arm64: dts: rockchip: enable touchpad button for
 rk3399-gru-kevin
Message-ID: <20171009184028.11829-1-kernel@esmil.dk>

Adding the linux,gpio-keymap entry also has
the side-effect of making the driver register
the touchpad as a touchpad rather than another
touchscreen.

The index for BTN_LEFT was found by trial and error.

Signed-off-by: Emil Renner Berthing <kernel at esmil.dk>
---
 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index 5c8621766908..1c58d12551f5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -278,6 +278,10 @@ ap_i2c_dig: &i2c2 {
 		pinctrl-0 = <&trackpad_int_l>;
 		interrupt-parent = <&gpio1>;
 		interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
+		linux,gpio-keymap = <KEY_RESERVED
+				     KEY_RESERVED
+				     KEY_RESERVED
+				     BTN_LEFT>;
 		wakeup-source;
 	};
 };
-- 
2.14.2



From hjc at rock-chips.com  Mon Oct  9 18:59:24 2017
From: hjc at rock-chips.com (Sandy Huang)
Date: Tue, 10 Oct 2017 09:59:24 +0800
Subject: [PATCH v2 1/3] dt-bindings: Add document for rockchip RGB output
 interface
In-Reply-To: <CAL_JsqJcO6VtgYBzby+gjerODT9n6fE0aMNJXNejvvhF1nqM-Q@mail.gmail.com>
References: <1506049221-117283-1-git-send-email-hjc@rock-chips.com>
 <1506049229-117376-1-git-send-email-hjc@rock-chips.com>
 <20171003215631.rc2jsf2m3qgoltsb@rob-hp-laptop>
 <2d502a9d-e952-8afb-d2d7-45c21c36da7e@rock-chips.com>
 <CAL_JsqJcO6VtgYBzby+gjerODT9n6fE0aMNJXNejvvhF1nqM-Q@mail.gmail.com>
Message-ID: <e877b1d6-9365-6c26-fbca-8d307610c94a@rock-chips.com>



? 2017/10/9 21:05, Rob Herring ??:
> On Mon, Oct 9, 2017 at 3:06 AM, Sandy Huang <hjc at rock-chips.com> wrote:
>> Hi rob,
>>      Thanks for your reply.
>>
>> ? 2017/10/4 5:56, Rob Herring ??:
>>>
>>> On Fri, Sep 22, 2017 at 11:00:26AM +0800, Sandy Huang wrote:
>>>>
>>>> This path add support rv1108 rgb output interface driver.
>>>>
>>>> Signed-off-by: Sandy Huang <hjc at rock-chips.com>
>>>> ---
>>>> Changes in v2:
>>>>    1. rename rockchip,rgb-mode to rgb-mode;
>>>
>>>
>>> You can't just drop the vendor. This needs to be documented in a common
>>> place that others will find and use. See panel-common.txt or
>>> panel-dpi.txt.
>>>
>>> Alternatively, you could just drop it and let the panel compatible imply
>>> what the mode is.
>>>
>>>
>> ok, get it, i will move the rgb-mode to panel and describe it at
>> panel-rgb.txt. the patches will be send soon later.
> 
> Don't create yet another common panel file. We already have
> panel-dpi.txt which is for digital parallel interface.
> The panel-rgb.txt define different rgb output format and timing, this is 
the detail info: https://patchwork.kernel.org/patch/9992241/
do you think this need move to panel-dpi.txt?
> Rob
> 
> 
> 



From arnd at arndb.de  Tue Oct 10 01:56:01 2017
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 10 Oct 2017 10:56:01 +0200
Subject: [PATCH] arm64: dts: rockchip: fix typo in iommu nodes
Message-ID: <20171010085648.1339605-1-arnd@arndb.de>

The latest dtc warns about an extraneous cell in the interrupt
property of two of the iommu device nodes:

Warning (interrupts_property): interrupts size is (16), expected multiple of 12 in /iommu at ff373f00
Warning (interrupts_property): interrupts size is (16), expected multiple of 12 in /iommu at ff900800

This removes the typo.

Fixes: cede4c79de28 ("arm64: dts: rockchip: add rk3368 iommu nodes")
Fixes: 49c82f2b7c5d ("arm64: dts: rockchip: add rk3328 iommu nodes")
Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 arch/arm64/boot/dts/rockchip/rk3328.dtsi | 2 +-
 arch/arm64/boot/dts/rockchip/rk3368.dtsi | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index 6d615cb6e64d..41d61840fb99 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -582,7 +582,7 @@
 	vop_mmu: iommu at ff373f00 {
 		compatible = "rockchip,iommu";
 		reg = <0x0 0xff373f00 0x0 0x100>;
-		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH 0>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-names = "vop_mmu";
 		#iommu-cells = <0>;
 		status = "disabled";
diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
index 19fbaa5e7bdd..1070c8264c13 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -740,7 +740,7 @@
 	iep_mmu: iommu at ff900800 {
 		compatible = "rockchip,iommu";
 		reg = <0x0 0xff900800 0x0 0x100>;
-		interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH 0>;
+		interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
 		interrupt-names = "iep_mmu";
 		#iommu-cells = <0>;
 		status = "disabled";
-- 
2.9.0



From heiko at sntech.de  Tue Oct 10 02:25:49 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 10 Oct 2017 11:25:49 +0200
Subject: [PATCH] ARM: dts: rockchip: fix mali400 ppmmu interrupt names
Message-ID: <20171010092549.13895-1-heiko@sntech.de>

The interrupts were wrongly named as ppXmmu while the binding
specifies them as ppmmuX.
Fix that for the recently added Utgard mali nodes on Rockchip socs.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
Already applied for 4.15

 arch/arm/boot/dts/rk3036.dtsi  | 2 +-
 arch/arm/boot/dts/rk3066a.dtsi | 8 ++++----
 arch/arm/boot/dts/rk3188.dtsi  | 8 ++++----
 arch/arm/boot/dts/rk322x.dtsi  | 4 ++--
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
index 5b084c0143ce..3b704cfed69a 100644
--- a/arch/arm/boot/dts/rk3036.dtsi
+++ b/arch/arm/boot/dts/rk3036.dtsi
@@ -162,7 +162,7 @@
 		interrupt-names = "gp",
 				  "gpmmu",
 				  "pp0",
-				  "pp0mmu";
+				  "ppmmu0";
 		assigned-clocks = <&cru SCLK_GPU>;
 		assigned-clock-rates = <100000000>;
 		clocks = <&cru SCLK_GPU>, <&cru SCLK_GPU>;
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
index b76119dd5733..06523caca27d 100644
--- a/arch/arm/boot/dts/rk3066a.dtsi
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -625,13 +625,13 @@
 	interrupt-names = "gp",
 			  "gpmmu",
 			  "pp0",
-			  "pp0mmu",
+			  "ppmmu0",
 			  "pp1",
-			  "pp1mmu",
+			  "ppmmu1",
 			  "pp2",
-			  "pp2mmu",
+			  "ppmmu2",
 			  "pp3",
-			  "pp3mmu";
+			  "ppmmu3";
 };
 
 &i2c0 {
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index 9e24d0ffadac..aa10caae51c3 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -568,13 +568,13 @@
 	interrupt-names = "gp",
 			  "gpmmu",
 			  "pp0",
-			  "pp0mmu",
+			  "ppmmu0",
 			  "pp1",
-			  "pp1mmu",
+			  "ppmmu1",
 			  "pp2",
-			  "pp2mmu",
+			  "ppmmu2",
 			  "pp3",
-			  "pp3mmu";
+			  "ppmmu3";
 };
 
 &i2c0 {
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
index c97287ebb0ea..780ec3a99b21 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -570,9 +570,9 @@
 		interrupt-names = "gp",
 				  "gpmmu",
 				  "pp0",
-				  "pp0mmu",
+				  "ppmmu0",
 				  "pp1",
-				  "pp1mmu";
+				  "ppmmu1";
 		clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>;
 		clock-names = "core", "bus";
 		resets = <&cru SRST_GPU_A>;
-- 
2.14.1



From heiko at sntech.de  Tue Oct 10 02:33:49 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 10 Oct 2017 11:33:49 +0200
Subject: [PATCH] arm64: dts: rockchip: enable touchpad button for
 rk3399-gru-kevin
In-Reply-To: <20171009184028.11829-1-kernel@esmil.dk>
References: <20171009184028.11829-1-kernel@esmil.dk>
Message-ID: <4174027.Z5MyPRUDcj@phil>

Hi Emil,

Am Montag, 9. Oktober 2017, 20:40:28 CEST schrieb Emil Renner Berthing:
> Adding the linux,gpio-keymap entry also has
> the side-effect of making the driver register
> the touchpad as a touchpad rather than another
> touchscreen.
> 
> The index for BTN_LEFT was found by trial and error.
> 
> Signed-off-by: Emil Renner Berthing <kernel at esmil.dk>

looks good to me. I'll just give the ChromeOS people a chance to
respond before applying [maybe they can even tell what the other
keys are :-) ]


Heiko

> ---
>  arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
> index 5c8621766908..1c58d12551f5 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
> @@ -278,6 +278,10 @@ ap_i2c_dig: &i2c2 {
>  		pinctrl-0 = <&trackpad_int_l>;
>  		interrupt-parent = <&gpio1>;
>  		interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
> +		linux,gpio-keymap = <KEY_RESERVED
> +				     KEY_RESERVED
> +				     KEY_RESERVED
> +				     BTN_LEFT>;
>  		wakeup-source;
>  	};
>  };
> 




From heiko at sntech.de  Tue Oct 10 02:48:25 2017
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Tue, 10 Oct 2017 11:48:25 +0200
Subject: [PATCH] arm64: dts: rockchip: fix typo in iommu nodes
In-Reply-To: <20171010085648.1339605-1-arnd@arndb.de>
References: <20171010085648.1339605-1-arnd@arndb.de>
Message-ID: <4123717.0VmPnCpUOn@diego>

Hi Arnd,

Am Dienstag, 10. Oktober 2017, 10:56:01 CEST schrieb Arnd Bergmann:
> The latest dtc warns about an extraneous cell in the interrupt
> property of two of the iommu device nodes:
> 
> Warning (interrupts_property): interrupts size is (16), expected multiple of
> 12 in /iommu at ff373f00 Warning (interrupts_property): interrupts size is
> (16), expected multiple of 12 in /iommu at ff900800
> 
> This removes the typo.
> 
> Fixes: cede4c79de28 ("arm64: dts: rockchip: add rk3368 iommu nodes")
> Fixes: 49c82f2b7c5d ("arm64: dts: rockchip: add rk3328 iommu nodes")
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>

looks like that got copy-pasted from rk3399 where we have 4 elements per irq.
In any case the change looks good, so if you want to apply it directly to 
armsoc-fixes here is a

Acked-by: Heiko Stuebner <heiko at sntech.de>

Depending on how you want to handle it I can also merge it, but
Olof already picked up my 2 fixes for 4.14, so you applying it might
save us the round-trip for a further 1-patch pull request :-)


Heiko

> ---
>  arch/arm64/boot/dts/rockchip/rk3328.dtsi | 2 +-
>  arch/arm64/boot/dts/rockchip/rk3368.dtsi | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
> b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index 6d615cb6e64d..41d61840fb99
> 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
> @@ -582,7 +582,7 @@
>  	vop_mmu: iommu at ff373f00 {
>  		compatible = "rockchip,iommu";
>  		reg = <0x0 0xff373f00 0x0 0x100>;
> -		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH 0>;
> +		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
>  		interrupt-names = "vop_mmu";
>  		#iommu-cells = <0>;
>  		status = "disabled";
> diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
> b/arch/arm64/boot/dts/rockchip/rk3368.dtsi index 19fbaa5e7bdd..1070c8264c13
> 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
> @@ -740,7 +740,7 @@
>  	iep_mmu: iommu at ff900800 {
>  		compatible = "rockchip,iommu";
>  		reg = <0x0 0xff900800 0x0 0x100>;
> -		interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH 0>;
> +		interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
>  		interrupt-names = "iep_mmu";
>  		#iommu-cells = <0>;
>  		status = "disabled";




From cw00.choi at samsung.com  Tue Oct 10 03:17:51 2017
From: cw00.choi at samsung.com (Chanwoo Choi)
Date: Tue, 10 Oct 2017 19:17:51 +0900
Subject: [PATCH v2] extcon: Split out extcon header file for consumer and
 provider device
References: <CGME20171010101758epcas2p3b3f379076f5be5e81edee2bd00354c28@epcas2p3.samsung.com>
Message-ID: <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>

The extcon has two type of extcon devices as following.
- 'extcon provider deivce' adds new extcon device and detect the
   state/properties of external connector. Also, it notifies the
   state/properties to the extcon consumer device.
- 'extcon consumer device' gets the change state/properties
   from extcon provider device.
Prior to that, include/linux/extcon.h contains all exported API for
both provider and consumer device driver. To clarify the meaning of
header file and to remove the wrong use-case on consumer device,
this patch separates into extcon.h and extcon-provider.h.

[Description for include/linux/{extcon.h|extcon-provider.h}]
- extcon.h includes the extcon API and data structure for extcon consumer
  device driver. This header file contains the following APIs:
  : Register/unregister the notifier to catch the change of extcon device
  : Get the extcon device instance
  : Get the extcon device name
  : Get the state of each external connector
  : Get the property value of each external connector
  : Get the property capability of each external connector

- extcon-provider.h includes the extcon API and data structure for extcon
  provider device driver. This header file contains the following APIs:
  : Include 'include/linux/extcon.h'
  : Allocate the memory for extcon device instance
  : Register/unregister extcon device
  : Set the state of each external connector
  : Set the property value of each external connector
  : Set the property capability of each external connector

Cc: Felipe Balbi <balbi at kernel.org>
Cc: Kishon Vijay Abraham I <kishon at ti.com>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Acked-by: Sebastian Reichel <sebastian.reichel at collabora.co.uk>
Acked-by: Chen-Yu Tsai <wens at csie.org>
Acked-by: Charles Keepax <ckeepax at opensource.cirrus.com>
Acked-by: Lee Jones <lee.jones at linaro.org>
Signed-off-by: Chanwoo Choi <cw00.choi at samsung.com>
---
Changes from v1:
- Don't touch drivers/usb/renesas_usbhs/common.h.
- Add acked-by from Sebastian Reichel (for drivers/power/supply/)
- Add acked-by from Chen-Yu Tsai (for phy-sun4i-usb.c & extcon-axp288.c)
- Add acked-by from Charles Keepax (for drivers/extcon/extcon-arizona.c)
- Add acked-by from Lee Jones (fo include/linux/mfd/palmas.h)

 drivers/extcon/extcon-adc-jack.c              |   2 +-
 drivers/extcon/extcon-arizona.c               |   2 +-
 drivers/extcon/extcon-axp288.c                |   2 +-
 drivers/extcon/extcon-gpio.c                  |   2 +-
 drivers/extcon/extcon-intel-cht-wc.c          |   2 +-
 drivers/extcon/extcon-intel-int3496.c         |   2 +-
 drivers/extcon/extcon-max14577.c              |   2 +-
 drivers/extcon/extcon-max3355.c               |   2 +-
 drivers/extcon/extcon-max77693.c              |   2 +-
 drivers/extcon/extcon-max77843.c              |   2 +-
 drivers/extcon/extcon-max8997.c               |   2 +-
 drivers/extcon/extcon-qcom-spmi-misc.c        |   2 +-
 drivers/extcon/extcon-rt8973a.c               |   2 +-
 drivers/extcon/extcon-sm5502.c                |   2 +-
 drivers/extcon/extcon-usb-gpio.c              |   2 +-
 drivers/extcon/extcon-usbc-cros-ec.c          |   2 +-
 drivers/extcon/extcon.h                       |   2 +-
 drivers/phy/allwinner/phy-sun4i-usb.c         |   2 +-
 drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c     |   2 +-
 drivers/phy/renesas/phy-rcar-gen3-usb2.c      |   2 +-
 drivers/phy/rockchip/phy-rockchip-inno-usb2.c |   2 +-
 drivers/power/supply/qcom_smbb.c              |   2 +-
 drivers/usb/gadget/udc/renesas_usb3.c         |   2 +-
 drivers/usb/phy/phy-tahvo.c                   |   2 +-
 include/linux/extcon-provider.h               | 142 ++++++++++++++++++++++++++
 include/linux/extcon.h                        | 109 +-------------------
 include/linux/mfd/palmas.h                    |   2 +-
 27 files changed, 172 insertions(+), 129 deletions(-)
 create mode 100644 include/linux/extcon-provider.h

diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index 6f6537ab0a79..3877d86c746a 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -26,7 +26,7 @@
 #include <linux/workqueue.h>
 #include <linux/iio/consumer.h>
 #include <linux/extcon/extcon-adc-jack.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 
 /**
  * struct adc_jack_data - internal data for adc_jack device driver
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index f84da4a17724..da0e9bc4262f 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -27,7 +27,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/regulator/consumer.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 
 #include <sound/soc.h>
 
diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c
index f4fd03e58e37..981fba56bc18 100644
--- a/drivers/extcon/extcon-axp288.c
+++ b/drivers/extcon/extcon-axp288.c
@@ -22,7 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/notifier.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/regmap.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index ebed22f22d75..ab770adcca7e 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -17,7 +17,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/extcon/extcon-gpio.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c
index 91a0023074af..7c4bc8c44c3f 100644
--- a/drivers/extcon/extcon-intel-cht-wc.c
+++ b/drivers/extcon/extcon-intel-cht-wc.c
@@ -15,7 +15,7 @@
  * more details.
  */
 
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mfd/intel_soc_pmic.h>
diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
index 1a45e745717d..c8691b5a9cb0 100644
--- a/drivers/extcon/extcon-intel-int3496.c
+++ b/drivers/extcon/extcon-intel-int3496.c
@@ -19,7 +19,7 @@
  */
 
 #include <linux/acpi.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
index f6414b7fa5bc..6c2c9996eb71 100644
--- a/drivers/extcon/extcon-max14577.c
+++ b/drivers/extcon/extcon-max14577.c
@@ -23,7 +23,7 @@
 #include <linux/platform_device.h>
 #include <linux/mfd/max14577.h>
 #include <linux/mfd/max14577-private.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 
 #define	DELAY_MS_DEFAULT		17000		/* unit: millisecond */
 
diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c
index 533e16a952b8..0aa410836f4e 100644
--- a/drivers/extcon/extcon-max3355.c
+++ b/drivers/extcon/extcon-max3355.c
@@ -9,7 +9,7 @@
  * may be copied, distributed, and modified under those terms.
  */
 
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 7a5856809047..643411066ad9 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -26,7 +26,7 @@
 #include <linux/mfd/max77693.h>
 #include <linux/mfd/max77693-common.h>
 #include <linux/mfd/max77693-private.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/regmap.h>
 #include <linux/irqdomain.h>
 
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index 6e722d552cf1..28f251ff0fa2 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -11,7 +11,7 @@
  * (at your option) any later version.
  */
 
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
index 4a0612fb9c07..8152790d72e1 100644
--- a/drivers/extcon/extcon-max8997.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -25,7 +25,7 @@
 #include <linux/kobject.h>
 #include <linux/mfd/max8997.h>
 #include <linux/mfd/max8997-private.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/irqdomain.h>
 
 #define	DEV_NAME			"max8997-muic"
diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c
index b8cde096a808..660bbf163bf5 100644
--- a/drivers/extcon/extcon-qcom-spmi-misc.c
+++ b/drivers/extcon/extcon-qcom-spmi-misc.c
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
index eaa355e7d9e4..e059bd5f2041 100644
--- a/drivers/extcon/extcon-rt8973a.c
+++ b/drivers/extcon/extcon-rt8973a.c
@@ -20,7 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 
 #include "extcon-rt8973a.h"
 
diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
index 106ef0297b53..0cfb5a3efdf6 100644
--- a/drivers/extcon/extcon-sm5502.c
+++ b/drivers/extcon/extcon-sm5502.c
@@ -19,7 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 
 #include "extcon-sm5502.h"
 
diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
index 9c925b05b7aa..53762864a9f7 100644
--- a/drivers/extcon/extcon-usb-gpio.c
+++ b/drivers/extcon/extcon-usb-gpio.c
@@ -14,7 +14,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/init.h>
diff --git a/drivers/extcon/extcon-usbc-cros-ec.c b/drivers/extcon/extcon-usbc-cros-ec.c
index 598956f1dcae..6187f731b29d 100644
--- a/drivers/extcon/extcon-usbc-cros-ec.c
+++ b/drivers/extcon/extcon-usbc-cros-ec.c
@@ -14,7 +14,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/kernel.h>
 #include <linux/mfd/cros_ec.h>
 #include <linux/module.h>
diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h
index dddddcfa0587..cc1b436eb66a 100644
--- a/drivers/extcon/extcon.h
+++ b/drivers/extcon/extcon.h
@@ -1,7 +1,7 @@
 #ifndef __LINUX_EXTCON_INTERNAL_H__
 #define __LINUX_EXTCON_INTERNAL_H__
 
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 
 /**
  * struct extcon_dev - An extcon device represents one external connector.
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index 1161e11fb3cf..ef34f97f214b 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -24,7 +24,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
diff --git a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
index d099a0c8cee5..7ceea5ae2704 100644
--- a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
+++ b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
@@ -12,7 +12,7 @@
  */
 
 #include <linux/delay.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/init.h>
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index 54c34298a000..b33e2994ccce 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -12,7 +12,7 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index ee7ce5ee53f9..5049dac79bd0 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -17,7 +17,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/gpio/consumer.h>
diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c
index f6a0d245731d..11de691b9a71 100644
--- a/drivers/power/supply/qcom_smbb.c
+++ b/drivers/power/supply/qcom_smbb.c
@@ -34,7 +34,7 @@
 #include <linux/power_supply.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/regulator/driver.h>
 
 #define SMBB_CHG_VMAX		0x040
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index df37c1e6e9d5..8b4d051fdbed 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -12,7 +12,7 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c
index 8babd318c0ed..354e8c98af05 100644
--- a/drivers/usb/phy/phy-tahvo.c
+++ b/drivers/usb/phy/phy-tahvo.c
@@ -23,7 +23,7 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/usb.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb/otg.h>
diff --git a/include/linux/extcon-provider.h b/include/linux/extcon-provider.h
new file mode 100644
index 000000000000..2feca5881fa7
--- /dev/null
+++ b/include/linux/extcon-provider.h
@@ -0,0 +1,142 @@
+/*
+ * External Connector (extcon) framework
+ * - linux/include/linux/extcon-provider.h for extcon provider device driver.
+ *
+ * Copyright (C) 2017 Samsung Electronics
+ * Author: Chanwoo Choi <cw00.choi at samsung.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __LINUX_EXTCON_PROVIDER_H__
+#define __LINUX_EXTCON_PROVIDER_H__
+
+#include <linux/extcon.h>
+
+struct extcon_dev;
+
+#if IS_ENABLED(CONFIG_EXTCON)
+
+/* Following APIs register/unregister the extcon device. */
+extern int extcon_dev_register(struct extcon_dev *edev);
+extern void extcon_dev_unregister(struct extcon_dev *edev);
+extern int devm_extcon_dev_register(struct device *dev,
+				struct extcon_dev *edev);
+extern void devm_extcon_dev_unregister(struct device *dev,
+				struct extcon_dev *edev);
+
+/* Following APIs allocate/free the memory of the extcon device. */
+extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable);
+extern void extcon_dev_free(struct extcon_dev *edev);
+extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
+				const unsigned int *cable);
+extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
+
+/* Synchronize the state and property value for each external connector. */
+extern int extcon_sync(struct extcon_dev *edev, unsigned int id);
+
+/*
+ * Following APIs set the connected state of each external connector.
+ * The 'id' argument indicates the defined external connector.
+ */
+extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
+				bool state);
+extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
+				bool state);
+
+/*
+ * Following APIs set the property of each external connector.
+ * The 'id' argument indicates the defined external connector
+ * and the 'prop' indicates the extcon property.
+ *
+ * And extcon_set_property_capability() set the capability of the property
+ * for each external connector. They are used to set the capability of the
+ * property of each external connector based on the id and property.
+ */
+extern int extcon_set_property(struct extcon_dev *edev, unsigned int id,
+				unsigned int prop,
+				union extcon_property_value prop_val);
+extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
+				unsigned int prop,
+				union extcon_property_value prop_val);
+extern int extcon_set_property_capability(struct extcon_dev *edev,
+				unsigned int id, unsigned int prop);
+
+#else /* CONFIG_EXTCON */
+static inline int extcon_dev_register(struct extcon_dev *edev)
+{
+	return 0;
+}
+
+static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
+
+static inline int devm_extcon_dev_register(struct device *dev,
+				struct extcon_dev *edev)
+{
+	return -EINVAL;
+}
+
+static inline void devm_extcon_dev_unregister(struct device *dev,
+				struct extcon_dev *edev) { }
+
+static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline void extcon_dev_free(struct extcon_dev *edev) { }
+
+static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
+				const unsigned int *cable)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline void devm_extcon_dev_free(struct extcon_dev *edev) { }
+
+
+static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id,
+				bool state)
+{
+	return 0;
+}
+
+static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
+				bool state)
+{
+	return 0;
+}
+
+static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
+{
+	return 0;
+}
+
+static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
+				unsigned int prop,
+				union extcon_property_value prop_val)
+{
+	return 0;
+}
+
+static inline int extcon_set_property_sync(struct extcon_dev *edev,
+				unsigned int id, unsigned int prop,
+				union extcon_property_value prop_val)
+{
+	return 0;
+}
+
+static inline int extcon_set_property_capability(struct extcon_dev *edev,
+				unsigned int id, unsigned int prop)
+{
+	return 0;
+}
+#endif /* CONFIG_EXTCON */
+#endif /* __LINUX_EXTCON_PROVIDER_H__ */
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
index 744d60ca80c3..6d94e82c8ad9 100644
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -1,5 +1,6 @@
 /*
  * External Connector (extcon) framework
+ * - linux/include/linux/extcon.h for extcon consumer device driver.
  *
  * Copyright (C) 2015 Samsung Electronics
  * Author: Chanwoo Choi <cw00.choi at samsung.com>
@@ -170,61 +171,29 @@
 	int intval;	/* type : integer (intval) */
 };
 
-struct extcon_cable;
 struct extcon_dev;
 
 #if IS_ENABLED(CONFIG_EXTCON)
-
-/* Following APIs register/unregister the extcon device. */
-extern int extcon_dev_register(struct extcon_dev *edev);
-extern void extcon_dev_unregister(struct extcon_dev *edev);
-extern int devm_extcon_dev_register(struct device *dev,
-				struct extcon_dev *edev);
-extern void devm_extcon_dev_unregister(struct device *dev,
-				struct extcon_dev *edev);
-
-/* Following APIs allocate/free the memory of the extcon device. */
-extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable);
-extern void extcon_dev_free(struct extcon_dev *edev);
-extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
-				const unsigned int *cable);
-extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
-
-/* Synchronize the state and property value for each external connector. */
-extern int extcon_sync(struct extcon_dev *edev, unsigned int id);
-
 /*
- * Following APIs get/set the connected state of each external connector.
+ * Following APIs get the connected state of each external connector.
  * The 'id' argument indicates the defined external connector.
  */
 extern int extcon_get_state(struct extcon_dev *edev, unsigned int id);
-extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
-				bool state);
-extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
-				bool state);
 
 /*
- * Following APIs get/set the property of each external connector.
+ * Following APIs get the property of each external connector.
  * The 'id' argument indicates the defined external connector
  * and the 'prop' indicates the extcon property.
  *
- * And extcon_get/set_property_capability() set the capability of the property
- * for each external connector. They are used to set the capability of the
+ * And extcon_get_property_capability() get the capability of the property
+ * for each external connector. They are used to get the capability of the
  * property of each external connector based on the id and property.
  */
 extern int extcon_get_property(struct extcon_dev *edev, unsigned int id,
 				unsigned int prop,
 				union extcon_property_value *prop_val);
-extern int extcon_set_property(struct extcon_dev *edev, unsigned int id,
-				unsigned int prop,
-				union extcon_property_value prop_val);
-extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
-				unsigned int prop,
-				union extcon_property_value prop_val);
 extern int extcon_get_property_capability(struct extcon_dev *edev,
 				unsigned int id, unsigned int prop);
-extern int extcon_set_property_capability(struct extcon_dev *edev,
-				unsigned int id, unsigned int prop);
 
 /*
  * Following APIs register the notifier block in order to detect
@@ -268,79 +237,17 @@ extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
 extern const char *extcon_get_edev_name(struct extcon_dev *edev);
 
 #else /* CONFIG_EXTCON */
-static inline int extcon_dev_register(struct extcon_dev *edev)
-{
-	return 0;
-}
-
-static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
-
-static inline int devm_extcon_dev_register(struct device *dev,
-				struct extcon_dev *edev)
-{
-	return -EINVAL;
-}
-
-static inline void devm_extcon_dev_unregister(struct device *dev,
-				struct extcon_dev *edev) { }
-
-static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable)
-{
-	return ERR_PTR(-ENOSYS);
-}
-
-static inline void extcon_dev_free(struct extcon_dev *edev) { }
-
-static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
-				const unsigned int *cable)
-{
-	return ERR_PTR(-ENOSYS);
-}
-
-static inline void devm_extcon_dev_free(struct extcon_dev *edev) { }
-
-
 static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id)
 {
 	return 0;
 }
 
-static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id,
-				bool state)
-{
-	return 0;
-}
-
-static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
-				bool state)
-{
-	return 0;
-}
-
-static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
-{
-	return 0;
-}
-
 static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id,
 				unsigned int prop,
 				union extcon_property_value *prop_val)
 {
 	return 0;
 }
-static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
-				unsigned int prop,
-				union extcon_property_value prop_val)
-{
-	return 0;
-}
-
-static inline int extcon_set_property_sync(struct extcon_dev *edev,
-				unsigned int id, unsigned int prop,
-				union extcon_property_value prop_val)
-{
-	return 0;
-}
 
 static inline int extcon_get_property_capability(struct extcon_dev *edev,
 				unsigned int id, unsigned int prop)
@@ -348,12 +255,6 @@ static inline int extcon_get_property_capability(struct extcon_dev *edev,
 	return 0;
 }
 
-static inline int extcon_set_property_capability(struct extcon_dev *edev,
-				unsigned int id, unsigned int prop)
-{
-	return 0;
-}
-
 static inline int extcon_register_notifier(struct extcon_dev *edev,
 				unsigned int id, struct notifier_block *nb)
 {
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index 6dec43826303..3c8568aa82a5 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -20,7 +20,7 @@
 #include <linux/leds.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
-#include <linux/extcon.h>
+#include <linux/extcon-provider.h>
 #include <linux/of_gpio.h>
 #include <linux/usb/phy_companion.h>
 
-- 
1.9.1



From balbi at kernel.org  Tue Oct 10 03:26:44 2017
From: balbi at kernel.org (Felipe Balbi)
Date: Tue, 10 Oct 2017 13:26:44 +0300
Subject: [PATCH v2] extcon: Split out extcon header file for consumer and
 provider device
In-Reply-To: <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>
References: <CGME20171010101758epcas2p3b3f379076f5be5e81edee2bd00354c28@epcas2p3.samsung.com>
 <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>
Message-ID: <87efqbmh7f.fsf@linux.intel.com>


Hi,

Chanwoo Choi <cw00.choi at samsung.com> writes:
> The extcon has two type of extcon devices as following.
> - 'extcon provider deivce' adds new extcon device and detect the
>    state/properties of external connector. Also, it notifies the
>    state/properties to the extcon consumer device.
> - 'extcon consumer device' gets the change state/properties
>    from extcon provider device.
> Prior to that, include/linux/extcon.h contains all exported API for
> both provider and consumer device driver. To clarify the meaning of
> header file and to remove the wrong use-case on consumer device,
> this patch separates into extcon.h and extcon-provider.h.
>
> [Description for include/linux/{extcon.h|extcon-provider.h}]
> - extcon.h includes the extcon API and data structure for extcon consumer
>   device driver. This header file contains the following APIs:
>   : Register/unregister the notifier to catch the change of extcon device
>   : Get the extcon device instance
>   : Get the extcon device name
>   : Get the state of each external connector
>   : Get the property value of each external connector
>   : Get the property capability of each external connector
>
> - extcon-provider.h includes the extcon API and data structure for extcon
>   provider device driver. This header file contains the following APIs:
>   : Include 'include/linux/extcon.h'
>   : Allocate the memory for extcon device instance
>   : Register/unregister extcon device
>   : Set the state of each external connector
>   : Set the property value of each external connector
>   : Set the property capability of each external connector
>
> Cc: Felipe Balbi <balbi at kernel.org>

Acked-by: Felipe Balbi <felipe.balbi at linux.intel.com>

-- 
balbi


From kernel at esmil.dk  Tue Oct 10 04:04:20 2017
From: kernel at esmil.dk (Emil Renner Berthing)
Date: Tue, 10 Oct 2017 13:04:20 +0200
Subject: [PATCH] arm64: dts: rockchip: enable touchpad button for
 rk3399-gru-kevin
In-Reply-To: <4174027.Z5MyPRUDcj@phil>
References: <20171009184028.11829-1-kernel@esmil.dk> <4174027.Z5MyPRUDcj@phil>
Message-ID: <CANBLGcx187QrX3pgUAjvBmPbyJsX7ZiYdWXhamM-atEe+Mqe3A@mail.gmail.com>

On 10 October 2017 at 11:33, Heiko Stuebner <heiko at sntech.de> wrote:
> Am Montag, 9. Oktober 2017, 20:40:28 CEST schrieb Emil Renner Berthing:
>> Adding the linux,gpio-keymap entry also has
>> the side-effect of making the driver register
>> the touchpad as a touchpad rather than another
>> touchscreen.
>>
>> The index for BTN_LEFT was found by trial and error.
>>
>> Signed-off-by: Emil Renner Berthing <kernel at esmil.dk>
>
> looks good to me. I'll just give the ChromeOS people a chance to
> respond before applying [maybe they can even tell what the other
> keys are :-) ]

Good plan. As far as I can tell their kernel doesn't send anything but
BTN_LEFT either. It's just that the controller supports multiple
buttons, but not all are necessarily connected to any button.
Their version of the driver has logic to detect the proper keymap
whereas the mainline driver gets it from this devicetree entry.

/Emil


From yoshihiro.shimoda.uh at renesas.com  Tue Oct 10 03:36:42 2017
From: yoshihiro.shimoda.uh at renesas.com (Yoshihiro Shimoda)
Date: Tue, 10 Oct 2017 10:36:42 +0000
Subject: [PATCH v2] extcon: Split out extcon header file for consumer and
 provider device
In-Reply-To: <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>
References: <CGME20171010101758epcas2p3b3f379076f5be5e81edee2bd00354c28@epcas2p3.samsung.com>
 <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>
Message-ID: <TY1PR06MB09928903CD7F333B35C2C17DD8750@TY1PR06MB0992.apcprd06.prod.outlook.com>

Hi,

> From: Chanwoo Choi, Sent: Tuesday, October 10, 2017 7:18 PM
> 
> The extcon has two type of extcon devices as following.
> - 'extcon provider deivce' adds new extcon device and detect the
>    state/properties of external connector. Also, it notifies the
>    state/properties to the extcon consumer device.
> - 'extcon consumer device' gets the change state/properties
>    from extcon provider device.
> Prior to that, include/linux/extcon.h contains all exported API for
> both provider and consumer device driver. To clarify the meaning of
> header file and to remove the wrong use-case on consumer device,
> this patch separates into extcon.h and extcon-provider.h.
> 
> [Description for include/linux/{extcon.h|extcon-provider.h}]
> - extcon.h includes the extcon API and data structure for extcon consumer
>   device driver. This header file contains the following APIs:
>   : Register/unregister the notifier to catch the change of extcon device
>   : Get the extcon device instance
>   : Get the extcon device name
>   : Get the state of each external connector
>   : Get the property value of each external connector
>   : Get the property capability of each external connector
> 
> - extcon-provider.h includes the extcon API and data structure for extcon
>   provider device driver. This header file contains the following APIs:
>   : Include 'include/linux/extcon.h'
>   : Allocate the memory for extcon device instance
>   : Register/unregister extcon device
>   : Set the state of each external connector
>   : Set the property value of each external connector
>   : Set the property capability of each external connector
> 
> Cc: Felipe Balbi <balbi at kernel.org>
> Cc: Kishon Vijay Abraham I <kishon at ti.com>
> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> Acked-by: Sebastian Reichel <sebastian.reichel at collabora.co.uk>
> Acked-by: Chen-Yu Tsai <wens at csie.org>
> Acked-by: Charles Keepax <ckeepax at opensource.cirrus.com>
> Acked-by: Lee Jones <lee.jones at linaro.org>
> Signed-off-by: Chanwoo Choi <cw00.choi at samsung.com>
> ---
> Changes from v1:
> - Don't touch drivers/usb/renesas_usbhs/common.h.
> - Add acked-by from Sebastian Reichel (for drivers/power/supply/)
> - Add acked-by from Chen-Yu Tsai (for phy-sun4i-usb.c & extcon-axp288.c)
> - Add acked-by from Charles Keepax (for drivers/extcon/extcon-arizona.c)
> - Add acked-by from Lee Jones (fo include/linux/mfd/palmas.h)
< snip >
>  drivers/phy/renesas/phy-rcar-gen3-usb2.c      |   2 +-

and

< snip >
>  drivers/usb/gadget/udc/renesas_usb3.c         |   2 +-

Acked-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh at renesas.com>

Best regards,
Yoshihiro Shimoda



From briannorris at chromium.org  Tue Oct 10 10:03:57 2017
From: briannorris at chromium.org (Brian Norris)
Date: Tue, 10 Oct 2017 10:03:57 -0700
Subject: [PATCH] arm64: dts: rockchip: enable touchpad button for
 rk3399-gru-kevin
In-Reply-To: <CANBLGcx187QrX3pgUAjvBmPbyJsX7ZiYdWXhamM-atEe+Mqe3A@mail.gmail.com>
References: <20171009184028.11829-1-kernel@esmil.dk> <4174027.Z5MyPRUDcj@phil>
 <CANBLGcx187QrX3pgUAjvBmPbyJsX7ZiYdWXhamM-atEe+Mqe3A@mail.gmail.com>
Message-ID: <20171010170355.GA136735@google.com>

+ Dmitry, who can probably answer better than I can

On Tue, Oct 10, 2017 at 01:04:20PM +0200, Emil Renner Berthing wrote:
> On 10 October 2017 at 11:33, Heiko Stuebner <heiko at sntech.de> wrote:
> > Am Montag, 9. Oktober 2017, 20:40:28 CEST schrieb Emil Renner Berthing:
> >> Adding the linux,gpio-keymap entry also has
> >> the side-effect of making the driver register
> >> the touchpad as a touchpad rather than another
> >> touchscreen.
> >>
> >> The index for BTN_LEFT was found by trial and error.
> >>
> >> Signed-off-by: Emil Renner Berthing <kernel at esmil.dk>
> >
> > looks good to me. I'll just give the ChromeOS people a chance to
> > respond before applying [maybe they can even tell what the other
> > keys are :-) ]
> 
> Good plan. As far as I can tell their kernel doesn't send anything but
> BTN_LEFT either. It's just that the controller supports multiple
> buttons, but not all are necessarily connected to any button.
> Their version of the driver has logic to detect the proper keymap
> whereas the mainline driver gets it from this devicetree entry.

I believe Emil is mostly correct. We only are using a BTN_LEFT in our
copy of the driver, and I'm not sure the others are connected to
anything. As Dmitry has explained to me (when I also wondered about
"detect[ing] the proper keymap"), we don't exactly "auto"discover
things; we just heuristically determine the configurations we know are
used on Chrome devices.

So from the sound of it, this keymap property is reasonable. I haven't
actually checked what our driver "auto" detects on gru-kevin, but if
this works then I'll bet it's correct :)

IOW, I don't know enough to ACK this patch, but I'm certainly not going
to NAK it.

Brian


From dmitry.torokhov at gmail.com  Tue Oct 10 10:25:16 2017
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Tue, 10 Oct 2017 10:25:16 -0700
Subject: [PATCH] arm64: dts: rockchip: enable touchpad button for
 rk3399-gru-kevin
In-Reply-To: <20171010170355.GA136735@google.com>
References: <20171009184028.11829-1-kernel@esmil.dk> <4174027.Z5MyPRUDcj@phil>
 <CANBLGcx187QrX3pgUAjvBmPbyJsX7ZiYdWXhamM-atEe+Mqe3A@mail.gmail.com>
 <20171010170355.GA136735@google.com>
Message-ID: <20171010172516.GA1681@dtor-ws>

On Tue, Oct 10, 2017 at 10:03:57AM -0700, Brian Norris wrote:
> + Dmitry, who can probably answer better than I can
> 
> On Tue, Oct 10, 2017 at 01:04:20PM +0200, Emil Renner Berthing wrote:
> > On 10 October 2017 at 11:33, Heiko Stuebner <heiko at sntech.de> wrote:
> > > Am Montag, 9. Oktober 2017, 20:40:28 CEST schrieb Emil Renner Berthing:
> > >> Adding the linux,gpio-keymap entry also has
> > >> the side-effect of making the driver register
> > >> the touchpad as a touchpad rather than another
> > >> touchscreen.
> > >>
> > >> The index for BTN_LEFT was found by trial and error.
> > >>
> > >> Signed-off-by: Emil Renner Berthing <kernel at esmil.dk>
> > >
> > > looks good to me. I'll just give the ChromeOS people a chance to
> > > respond before applying [maybe they can even tell what the other
> > > keys are :-) ]

They are not connected.

> > 
> > Good plan. As far as I can tell their kernel doesn't send anything but
> > BTN_LEFT either. It's just that the controller supports multiple
> > buttons, but not all are necessarily connected to any button.
> > Their version of the driver has logic to detect the proper keymap
> > whereas the mainline driver gets it from this devicetree entry.
> 
> I believe Emil is mostly correct. We only are using a BTN_LEFT in our
> copy of the driver, and I'm not sure the others are connected to
> anything. As Dmitry has explained to me (when I also wondered about
> "detect[ing] the proper keymap"), we don't exactly "auto"discover
> things; we just heuristically determine the configurations we know are
> used on Chrome devices.

Right, we had a "legacy" GPIO/button mapping on original Pixels that
used T9 multitouch reports, then we switched to a bit different mapping
for newer devices that use T100 multitouch reports.

We should really have explicit map, like we have in upstream driver.

> 
> So from the sound of it, this keymap property is reasonable. I haven't
> actually checked what our driver "auto" detects on gru-kevin, but if
> this works then I'll bet it's correct :)
> 
> IOW, I don't know enough to ACK this patch, but I'm certainly not going
> to NAK it.

I think I can ACK it:

Acked-by: Dmitry Torokhov <dmitry.torokhov at gmail.com>

Thanks.

-- 
Dmitry


From jacob-chen at iotwrt.com  Wed Oct 11 00:29:33 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Wed, 11 Oct 2017 15:29:33 +0800
Subject: [PATCH v12 0/5] Add Rockchip RGA V4l2 support
Message-ID: <20171011072938.383-1-jacob-chen@iotwrt.com>

change in V12:
- adding an entry to MAINTAINERS 
- fix checkpatch

change in V11:
- fix compile warning

change in V10:
- move to rockchip/rga
- changes according to comments
- some style changes

change in V9:
- remove protduff things
- test with the latest v4l2-compliance

change in V8:
- remove protduff things

change in V6,V7:
- correct warning in checkpatch.pl

change in V5:
- v4l2-compliance: handle invalid pxielformat
- v4l2-compliance: add subscribe_event
- add colorspace support

change in V4:
- document the controls.
- change according to Hans's comments

change in V3:
- rename the controls.
- add pm_runtime support.
- enable node by default.
- correct spelling in documents.

change in V2:
- generalize the controls.
- map buffers (10-50 us) in every cmd-run rather than in buffer-import to avoid get_free_pages failed on
actively used systems.
- remove status in dt-bindings examples.

Jacob Chen (5):
  dt-bindings: Document the Rockchip RGA bindings
  rockchip/rga: v4l2 m2m support
  MAINTAINERS: add entry for Rockchip RGA driver
  ARM: dts: rockchip: add RGA device node for RK3288
  arm64: dts: rockchip: add RGA device node for RK3399

 .../devicetree/bindings/media/rockchip-rga.txt     |   33 +
 MAINTAINERS                                        |    7 +
 arch/arm/boot/dts/rk3288.dtsi                      |   11 +
 arch/arm64/boot/dts/rockchip/rk3399.dtsi           |   11 +
 drivers/media/platform/Kconfig                     |   15 +
 drivers/media/platform/Makefile                    |    2 +
 drivers/media/platform/rockchip/rga/Makefile       |    3 +
 drivers/media/platform/rockchip/rga/rga-buf.c      |  154 +++
 drivers/media/platform/rockchip/rga/rga-hw.c       |  421 ++++++++
 drivers/media/platform/rockchip/rga/rga-hw.h       |  437 +++++++++
 drivers/media/platform/rockchip/rga/rga.c          | 1012 ++++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga.h          |  125 +++
 12 files changed, 2231 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/rockchip-rga.txt
 create mode 100644 drivers/media/platform/rockchip/rga/Makefile
 create mode 100644 drivers/media/platform/rockchip/rga/rga-buf.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.h
 create mode 100644 drivers/media/platform/rockchip/rga/rga.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga.h

-- 
2.14.1



From jacob-chen at iotwrt.com  Wed Oct 11 00:29:34 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Wed, 11 Oct 2017 15:29:34 +0800
Subject: [PATCH v12 1/5] dt-bindings: Document the Rockchip RGA bindings
In-Reply-To: <20171011072938.383-1-jacob-chen@iotwrt.com>
References: <20171011072938.383-1-jacob-chen@iotwrt.com>
Message-ID: <20171011072938.383-2-jacob-chen@iotwrt.com>

Add DT bindings documentation for Rockchip RGA

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
Acked-by: Rob Herring <robh at kernel.org>
---
 .../devicetree/bindings/media/rockchip-rga.txt     | 33 ++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/rockchip-rga.txt

diff --git a/Documentation/devicetree/bindings/media/rockchip-rga.txt b/Documentation/devicetree/bindings/media/rockchip-rga.txt
new file mode 100644
index 000000000000..fd5276abfad6
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/rockchip-rga.txt
@@ -0,0 +1,33 @@
+device-tree bindings for rockchip 2D raster graphic acceleration controller (RGA)
+
+RGA is a standalone 2D raster graphic acceleration unit. It accelerates 2D
+graphics operations, such as point/line drawing, image scaling, rotation,
+BitBLT, alpha blending and image blur/sharpness.
+
+Required properties:
+- compatible: value should be one of the following
+		"rockchip,rk3288-rga";
+		"rockchip,rk3399-rga";
+
+- interrupts: RGA interrupt specifier.
+
+- clocks: phandle to RGA sclk/hclk/aclk clocks
+
+- clock-names: should be "aclk", "hclk" and "sclk"
+
+- resets: Must contain an entry for each entry in reset-names.
+  See ../reset/reset.txt for details.
+- reset-names: should be "core", "axi" and "ahb"
+
+Example:
+SoC-specific DT entry:
+	rga: rga at ff680000 {
+		compatible = "rockchip,rk3399-rga";
+		reg = <0xff680000 0x10000>;
+		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+
+		resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>;
+		reset-names = "core, "axi", "ahb";
+	};
-- 
2.14.1



From jacob-chen at iotwrt.com  Wed Oct 11 00:29:36 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Wed, 11 Oct 2017 15:29:36 +0800
Subject: [PATCH v12 3/5] MAINTAINERS: add entry for Rockchip RGA driver
In-Reply-To: <20171011072938.383-1-jacob-chen@iotwrt.com>
References: <20171011072938.383-1-jacob-chen@iotwrt.com>
Message-ID: <20171011072938.383-4-jacob-chen@iotwrt.com>

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6671f375f7fc..335497bbc3f3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11509,6 +11509,13 @@ F:	drivers/hid/hid-roccat*
 F:	include/linux/hid-roccat*
 F:	Documentation/ABI/*/sysfs-driver-hid-roccat*
 
+ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER
+M:	Jacob chen <jacob-chen at iotwrt.com>
+L:	linux-media at vger.kernel.org
+S:	Maintained
+F:	drivers/media/platform/rockchip/rga/
+F:	Documentation/devicetree/bindings/media/rockchip-rga.txt
+
 ROCKER DRIVER
 M:	Jiri Pirko <jiri at resnulli.us>
 L:	netdev at vger.kernel.org
-- 
2.14.1



From jacob-chen at iotwrt.com  Wed Oct 11 00:29:37 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Wed, 11 Oct 2017 15:29:37 +0800
Subject: [PATCH v12 4/5] ARM: dts: rockchip: add RGA device node for RK3288
In-Reply-To: <20171011072938.383-1-jacob-chen@iotwrt.com>
References: <20171011072938.383-1-jacob-chen@iotwrt.com>
Message-ID: <20171011072938.383-5-jacob-chen@iotwrt.com>

This patch add the RGA dt config of rk3288 SoC.

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm/boot/dts/rk3288.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index a0a0b08bff74..8c6dfc0abc42 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -972,6 +972,17 @@
 		status = "disabled";
 	};
 
+	rga: rga at ff920000 {
+		compatible = "rockchip,rk3288-rga";
+		reg = <0x0 0xff920000 0x0 0x180>;
+		interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA>;
+		clock-names = "aclk", "hclk", "sclk";
+		power-domains = <&power RK3288_PD_VIO>;
+		resets = <&cru SRST_RGA_CORE>, <&cru SRST_RGA_AXI>, <&cru SRST_RGA_AHB>;
+		reset-names = "core", "axi", "ahb";
+	};
+
 	vopb: vop at ff930000 {
 		compatible = "rockchip,rk3288-vop";
 		reg = <0x0 0xff930000 0x0 0x19c>;
-- 
2.14.1



From jacob-chen at iotwrt.com  Wed Oct 11 00:29:38 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Wed, 11 Oct 2017 15:29:38 +0800
Subject: [PATCH v12 5/5] arm64: dts: rockchip: add RGA device node for RK3399
In-Reply-To: <20171011072938.383-1-jacob-chen@iotwrt.com>
References: <20171011072938.383-1-jacob-chen@iotwrt.com>
Message-ID: <20171011072938.383-6-jacob-chen@iotwrt.com>

This patch add the RGA dt config of RK3399 SoC.

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d79e9b3265b9..a3fab6af5a17 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1204,6 +1204,17 @@
 		status = "disabled";
 	};
 
+	rga: rga at ff680000 {
+		compatible = "rockchip,rk3399-rga";
+		reg = <0x0 0xff680000 0x0 0x10000>;
+		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>;
+		clock-names = "aclk", "hclk", "sclk";
+		resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>;
+		reset-names = "core", "axi", "ahb";
+		power-domains = <&power RK3399_PD_RGA>;
+	};
+
 	efuse0: efuse at ff690000 {
 		compatible = "rockchip,rk3399-efuse";
 		reg = <0x0 0xff690000 0x0 0x80>;
-- 
2.14.1



From jacob-chen at iotwrt.com  Wed Oct 11 00:29:35 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Wed, 11 Oct 2017 15:29:35 +0800
Subject: [PATCH v12 2/5] rockchip/rga: v4l2 m2m support
In-Reply-To: <20171011072938.383-1-jacob-chen@iotwrt.com>
References: <20171011072938.383-1-jacob-chen@iotwrt.com>
Message-ID: <20171011072938.383-3-jacob-chen@iotwrt.com>

Rockchip RGA is a separate 2D raster graphic acceleration unit. It
accelerates 2D graphics operations, such as point/line drawing, image
scaling, rotation, BitBLT, alpha blending and image blur/sharpness

The driver supports various operations from the rendering pipeline.
 - copy
 - fast solid color fill
 - rotation
 - flip
 - alpha blending

The code in rga-hw.c is used to configure regs according to operations
The code in rga-buf.c is used to create private mmu table for RGA.

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
---
 drivers/media/platform/Kconfig                |   15 +
 drivers/media/platform/Makefile               |    2 +
 drivers/media/platform/rockchip/rga/Makefile  |    3 +
 drivers/media/platform/rockchip/rga/rga-buf.c |  154 ++++
 drivers/media/platform/rockchip/rga/rga-hw.c  |  421 ++++++++++
 drivers/media/platform/rockchip/rga/rga-hw.h  |  437 +++++++++++
 drivers/media/platform/rockchip/rga/rga.c     | 1012 +++++++++++++++++++++++++
 drivers/media/platform/rockchip/rga/rga.h     |  125 +++
 8 files changed, 2169 insertions(+)
 create mode 100644 drivers/media/platform/rockchip/rga/Makefile
 create mode 100644 drivers/media/platform/rockchip/rga/rga-buf.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.h
 create mode 100644 drivers/media/platform/rockchip/rga/rga.c
 create mode 100644 drivers/media/platform/rockchip/rga/rga.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 7e7cc49b8674..3c6074ece15a 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -458,6 +458,21 @@ config VIDEO_RENESAS_VSP1
 	  To compile this driver as a module, choose M here: the module
 	  will be called vsp1.
 
+config VIDEO_ROCKCHIP_RGA
+	tristate "Rockchip Raster 2d Graphic Acceleration Unit"
+	depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	select VIDEOBUF2_DMA_SG
+	select V4L2_MEM2MEM_DEV
+	default n
+	---help---
+	  This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator.
+	  Rockchip RGA is a separate 2D raster graphic acceleration unit.
+	  It accelerates 2D graphics operations, such as point/line drawing,
+	  image scaling, rotation, BitBLT, alpha blending and image blur/sharpness.
+
+	  To compile this driver as a module choose m here.
+
 config VIDEO_TI_VPE
 	tristate "TI VPE (Video Processing Engine) driver"
 	depends on VIDEO_DEV && VIDEO_V4L2
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index c1ef946bf032..c179de1c98c3 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -62,6 +62,8 @@ obj-$(CONFIG_VIDEO_RENESAS_FDP1)	+= rcar_fdp1.o
 obj-$(CONFIG_VIDEO_RENESAS_JPU) 	+= rcar_jpu.o
 obj-$(CONFIG_VIDEO_RENESAS_VSP1)	+= vsp1/
 
+obj-$(CONFIG_VIDEO_ROCKCHIP_RGA)	+= rockchip/rga/
+
 obj-y	+= omap/
 
 obj-$(CONFIG_VIDEO_AM437X_VPFE)		+= am437x/
diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile
new file mode 100644
index 000000000000..92fe25490ccd
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/Makefile
@@ -0,0 +1,3 @@
+rockchip-rga-objs := rga.o rga-hw.o rga-buf.o
+
+obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
new file mode 100644
index 000000000000..49cacc7a48d1
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/pm_runtime.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "rga-hw.h"
+#include "rga.h"
+
+static int
+rga_queue_setup(struct vb2_queue *vq,
+		unsigned int *nbuffers, unsigned int *nplanes,
+		unsigned int sizes[], struct device *alloc_devs[])
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(vq);
+	struct rga_frame *f = rga_get_frame(ctx, vq->type);
+
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	if (*nplanes)
+		return sizes[0] < f->size ? -EINVAL : 0;
+
+	sizes[0] = f->size;
+	*nplanes = 1;
+
+	return 0;
+}
+
+static int rga_buf_prepare(struct vb2_buffer *vb)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
+
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	vb2_set_plane_payload(vb, 0, f->size);
+
+	return 0;
+}
+
+static void rga_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(q);
+	struct rockchip_rga *rga = ctx->rga;
+	int ret, i;
+
+	ret = pm_runtime_get_sync(rga->dev);
+
+	if (!ret)
+		return 0;
+
+	for (i = 0; i < q->num_buffers; ++i) {
+		if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
+			v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]),
+					  VB2_BUF_STATE_QUEUED);
+		}
+	}
+
+	return ret;
+}
+
+static void rga_buf_stop_streaming(struct vb2_queue *q)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(q);
+	struct rockchip_rga *rga = ctx->rga;
+	struct vb2_v4l2_buffer *vbuf;
+
+	for (;;) {
+		if (V4L2_TYPE_IS_OUTPUT(q->type))
+			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		else
+			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+		if (!vbuf)
+			break;
+		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+	}
+
+	pm_runtime_put(rga->dev);
+}
+
+const struct vb2_ops rga_qops = {
+	.queue_setup = rga_queue_setup,
+	.buf_prepare = rga_buf_prepare,
+	.buf_queue = rga_buf_queue,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+	.start_streaming = rga_buf_start_streaming,
+	.stop_streaming = rga_buf_stop_streaming,
+};
+
+/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API.
+ * We use it more like a scatter-gather list.
+ */
+void rga_buf_map(struct vb2_buffer *vb)
+{
+	struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct rockchip_rga *rga = ctx->rga;
+	struct sg_table *sgt;
+	struct scatterlist *sgl;
+	unsigned int *pages;
+	unsigned int address, len, i, p;
+	unsigned int mapped_size = 0;
+
+	if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		pages = rga->src_mmu_pages;
+	else
+		pages = rga->dst_mmu_pages;
+
+	/* Create local MMU table for RGA */
+	sgt = vb2_plane_cookie(vb, 0);
+
+	for_each_sg(sgt->sgl, sgl, sgt->nents, i) {
+		len = sg_dma_len(sgl) >> PAGE_SHIFT;
+		address = sg_phys(sgl);
+
+		for (p = 0; p < len; p++) {
+			dma_addr_t phys = address + (p << PAGE_SHIFT);
+
+			pages[mapped_size + p] = phys;
+		}
+
+		mapped_size += len;
+	}
+
+	/* sync local MMU table for RGA */
+	dma_sync_single_for_device(rga->dev, virt_to_phys(pages),
+				   8 * PAGE_SIZE, DMA_BIDIRECTIONAL);
+}
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
new file mode 100644
index 000000000000..0645481c9a5e
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/pm_runtime.h>
+
+#include "rga-hw.h"
+#include "rga.h"
+
+enum e_rga_start_pos {
+	LT = 0,
+	LB = 1,
+	RT = 2,
+	RB = 3,
+};
+
+struct rga_addr_offset {
+	unsigned int y_off;
+	unsigned int u_off;
+	unsigned int v_off;
+};
+
+struct rga_corners_addr_offset {
+	struct rga_addr_offset left_top;
+	struct rga_addr_offset right_top;
+	struct rga_addr_offset left_bottom;
+	struct rga_addr_offset right_bottom;
+};
+
+static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
+{
+	/*
+	 * The rga hw scaling factor is a normalized inverse of the
+	 * scaling factor.
+	 * For example: When source width is 100 and destination width is 200
+	 * (scaling of 2x), then the hw factor is NC * 100 / 200.
+	 * The normalization factor (NC) is 2^16 = 0x10000.
+	 */
+
+	return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst);
+}
+
+static struct rga_corners_addr_offset
+rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y,
+		    unsigned int w, unsigned int h)
+{
+	struct rga_corners_addr_offset offsets;
+	struct rga_addr_offset *lt, *lb, *rt, *rb;
+	unsigned int x_div = 0,
+		     y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0;
+
+	lt = &offsets.left_top;
+	lb = &offsets.left_bottom;
+	rt = &offsets.right_top;
+	rb = &offsets.right_bottom;
+
+	x_div = frm->fmt->x_div;
+	y_div = frm->fmt->y_div;
+	uv_factor = frm->fmt->uv_factor;
+	uv_stride = frm->stride / x_div;
+	pixel_width = frm->stride / frm->width;
+
+	lt->y_off = y * frm->stride + x * pixel_width;
+	lt->u_off =
+		frm->width * frm->height + (y / y_div) * uv_stride + x / x_div;
+	lt->v_off = lt->u_off + frm->width * frm->height / uv_factor;
+
+	lb->y_off = lt->y_off + (h - 1) * frm->stride;
+	lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
+	lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride;
+
+	rt->y_off = lt->y_off + (w - 1) * pixel_width;
+	rt->u_off = lt->u_off + w / x_div - 1;
+	rt->v_off = lt->v_off + w / x_div - 1;
+
+	rb->y_off = lb->y_off + (w - 1) * pixel_width;
+	rb->u_off = lb->u_off + w / x_div - 1;
+	rb->v_off = lb->v_off + w / x_div - 1;
+
+	return offsets;
+}
+
+static struct rga_addr_offset *rga_lookup_draw_pos(struct
+		rga_corners_addr_offset
+		* offsets, u32 rotate_mode,
+		u32 mirr_mode)
+{
+	static enum e_rga_start_pos rot_mir_point_matrix[4][4] = {
+		{
+			LT, RT, LB, RB,
+		},
+		{
+			RT, LT, RB, LB,
+		},
+		{
+			RB, LB, RT, LT,
+		},
+		{
+			LB, RB, LT, RT,
+		},
+	};
+
+	if (!offsets)
+		return NULL;
+
+	switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) {
+	case LT:
+		return &offsets->left_top;
+	case LB:
+		return &offsets->left_bottom;
+	case RT:
+		return &offsets->right_top;
+	case RB:
+		return &offsets->right_bottom;
+	}
+
+	return NULL;
+}
+
+static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
+	dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+
+	reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
+	dest[reg >> 2] |= 0x7;
+}
+
+static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
+	dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+
+	reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
+	dest[reg >> 2] |= 0x7 << 4;
+}
+
+static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int reg;
+
+	reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
+	dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+
+	reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
+	dest[reg >> 2] |= 0x7 << 8;
+}
+
+static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	unsigned int scale_dst_w, scale_dst_h;
+	unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y;
+	union rga_src_info src_info;
+	union rga_dst_info dst_info;
+	union rga_src_x_factor x_factor;
+	union rga_src_y_factor y_factor;
+	union rga_src_vir_info src_vir_info;
+	union rga_src_act_info src_act_info;
+	union rga_dst_vir_info dst_vir_info;
+	union rga_dst_act_info dst_act_info;
+
+	struct rga_addr_offset *dst_offset;
+	struct rga_corners_addr_offset offsets;
+	struct rga_corners_addr_offset src_offsets;
+
+	src_h = ctx->in.crop.height;
+	src_w = ctx->in.crop.width;
+	src_x = ctx->in.crop.left;
+	src_y = ctx->in.crop.top;
+	dst_h = ctx->out.crop.height;
+	dst_w = ctx->out.crop.width;
+	dst_x = ctx->out.crop.left;
+	dst_y = ctx->out.crop.top;
+
+	src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2];
+	dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2];
+	x_factor.val = dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2];
+	y_factor.val = dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2];
+	src_vir_info.val = dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
+	src_act_info.val = dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
+	dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2];
+	dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2];
+
+	src_info.data.format = ctx->in.fmt->hw_format;
+	src_info.data.swap = ctx->in.fmt->color_swap;
+	dst_info.data.format = ctx->out.fmt->hw_format;
+	dst_info.data.swap = ctx->out.fmt->color_swap;
+
+	if (ctx->in.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
+		if (ctx->out.fmt->hw_format < RGA_COLOR_FMT_YUV422SP) {
+			switch (ctx->in.colorspace) {
+			case V4L2_COLORSPACE_REC709:
+				src_info.data.csc_mode =
+					RGA_SRC_CSC_MODE_BT709_R0;
+				break;
+			default:
+				src_info.data.csc_mode =
+					RGA_SRC_CSC_MODE_BT601_R0;
+				break;
+			}
+		}
+	}
+
+	if (ctx->out.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) {
+		switch (ctx->out.colorspace) {
+		case V4L2_COLORSPACE_REC709:
+			dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0;
+			break;
+		default:
+			dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0;
+			break;
+		}
+	}
+
+	if (ctx->vflip)
+		src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X;
+
+	if (ctx->hflip)
+		src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y;
+
+	switch (ctx->rotate) {
+	case 90:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_90_DEGREE;
+		break;
+	case 180:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_180_DEGREE;
+		break;
+	case 270:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_270_DEGREE;
+		break;
+	default:
+		src_info.data.rot_mode = RGA_SRC_ROT_MODE_0_DEGREE;
+		break;
+	}
+
+	/*
+	 * Cacluate the up/down scaling mode/factor.
+	 *
+	 * RGA used to scale the picture first, and then rotate second,
+	 * so we need to swap the w/h when rotate degree is 90/270.
+	 */
+	if (src_info.data.rot_mode == RGA_SRC_ROT_MODE_90_DEGREE ||
+	    src_info.data.rot_mode == RGA_SRC_ROT_MODE_270_DEGREE) {
+		if (rga->version.major == 0 || rga->version.minor == 0) {
+			if (dst_w == src_h)
+				src_h -= 8;
+			if (abs(src_w - dst_h) < 16)
+				src_w -= 16;
+		}
+
+		scale_dst_h = dst_w;
+		scale_dst_w = dst_h;
+	} else {
+		scale_dst_w = dst_w;
+		scale_dst_h = dst_h;
+	}
+
+	if (src_w == scale_dst_w) {
+		src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_NO;
+		x_factor.val = 0;
+	} else if (src_w > scale_dst_w) {
+		src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN;
+		x_factor.data.down_scale_factor =
+			rga_get_scaling(src_w, scale_dst_w) + 1;
+	} else {
+		src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_UP;
+		x_factor.data.up_scale_factor =
+			rga_get_scaling(src_w - 1, scale_dst_w - 1);
+	}
+
+	if (src_h == scale_dst_h) {
+		src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_NO;
+		y_factor.val = 0;
+	} else if (src_h > scale_dst_h) {
+		src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN;
+		y_factor.data.down_scale_factor =
+			rga_get_scaling(src_h, scale_dst_h) + 1;
+	} else {
+		src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_UP;
+		y_factor.data.up_scale_factor =
+			rga_get_scaling(src_h - 1, scale_dst_h - 1);
+	}
+
+	/*
+	 * Cacluate the framebuffer virtual strides and active size,
+	 * note that the step of vir_stride / vir_width is 4 byte words
+	 */
+	src_vir_info.data.vir_stride = ctx->in.stride >> 2;
+	src_vir_info.data.vir_width = ctx->in.stride >> 2;
+
+	src_act_info.data.act_height = src_h - 1;
+	src_act_info.data.act_width = src_w - 1;
+
+	dst_vir_info.data.vir_stride = ctx->out.stride >> 2;
+	dst_act_info.data.act_height = dst_h - 1;
+	dst_act_info.data.act_width = dst_w - 1;
+
+	/*
+	 * Cacluate the source framebuffer base address with offset pixel.
+	 */
+	src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y,
+					  src_w, src_h);
+
+	/*
+	 * Configure the dest framebuffer base address with pixel offset.
+	 */
+	offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h);
+	dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode,
+					 src_info.data.mir_mode);
+
+	dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		src_offsets.left_top.y_off;
+	dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		src_offsets.left_top.u_off;
+	dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		src_offsets.left_top.v_off;
+
+	dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;
+	dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;
+	dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;
+	dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;
+
+	dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;
+
+	dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		dst_offset->y_off;
+	dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		dst_offset->u_off;
+	dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
+		dst_offset->v_off;
+
+	dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;
+	dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;
+
+	dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;
+}
+
+static void rga_cmd_set_mode(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+	u32 *dest = rga->cmdbuf_virt;
+	union rga_mode_ctrl mode;
+	union rga_alpha_ctrl0 alpha_ctrl0;
+	union rga_alpha_ctrl1 alpha_ctrl1;
+
+	mode.val = 0;
+	alpha_ctrl0.val = 0;
+	alpha_ctrl1.val = 0;
+
+	mode.data.gradient_sat = 1;
+	mode.data.render = RGA_MODE_RENDER_BITBLT;
+	mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST;
+
+	/* disable alpha blending */
+	dest[(RGA_ALPHA_CTRL0 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl0.val;
+	dest[(RGA_ALPHA_CTRL1 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl1.val;
+
+	dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;
+}
+
+void rga_cmd_set(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+
+	memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
+
+	rga_cmd_set_src_addr(ctx, rga->src_mmu_pages);
+	/*
+	 * Due to hardware bug,
+	 * src1 mmu also should be configured when using alpha blending.
+	 */
+	rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages);
+
+	rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages);
+	rga_cmd_set_mode(ctx);
+
+	rga_cmd_set_trans_info(ctx);
+
+	rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
+
+	/* sync CMD buf for RGA */
+	dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy,
+		PAGE_SIZE, DMA_BIDIRECTIONAL);
+}
+
+void rga_hw_start(struct rockchip_rga *rga)
+{
+	struct rga_ctx *ctx = rga->curr;
+
+	rga_cmd_set(ctx);
+
+	rga_write(rga, RGA_SYS_CTRL, 0x00);
+
+	rga_write(rga, RGA_SYS_CTRL, 0x22);
+
+	rga_write(rga, RGA_INT, 0x600);
+
+	rga_write(rga, RGA_CMD_CTRL, 0x1);
+}
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h
new file mode 100644
index 000000000000..ca3c204abe42
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __RGA_HW_H__
+#define __RGA_HW_H__
+
+#define RGA_CMDBUF_SIZE 0x20
+
+/* Hardware limits */
+#define MAX_WIDTH 8192
+#define MAX_HEIGHT 8192
+
+#define MIN_WIDTH 34
+#define MIN_HEIGHT 34
+
+#define DEFAULT_WIDTH 100
+#define DEFAULT_HEIGHT 100
+
+#define RGA_TIMEOUT 500
+
+/* Registers address */
+#define RGA_SYS_CTRL 0x0000
+#define RGA_CMD_CTRL 0x0004
+#define RGA_CMD_BASE 0x0008
+#define RGA_INT 0x0010
+#define RGA_MMU_CTRL0 0x0014
+#define RGA_VERSION_INFO 0x0028
+
+#define RGA_MODE_BASE_REG 0x0100
+#define RGA_MODE_MAX_REG 0x017C
+
+#define RGA_MODE_CTRL 0x0100
+#define RGA_SRC_INFO 0x0104
+#define RGA_SRC_Y_RGB_BASE_ADDR 0x0108
+#define RGA_SRC_CB_BASE_ADDR 0x010c
+#define RGA_SRC_CR_BASE_ADDR 0x0110
+#define RGA_SRC1_RGB_BASE_ADDR 0x0114
+#define RGA_SRC_VIR_INFO 0x0118
+#define RGA_SRC_ACT_INFO 0x011c
+#define RGA_SRC_X_FACTOR 0x0120
+#define RGA_SRC_Y_FACTOR 0x0124
+#define RGA_SRC_BG_COLOR 0x0128
+#define RGA_SRC_FG_COLOR 0x012c
+#define RGA_SRC_TR_COLOR0 0x0130
+#define RGA_SRC_TR_COLOR1 0x0134
+
+#define RGA_DST_INFO 0x0138
+#define RGA_DST_Y_RGB_BASE_ADDR 0x013c
+#define RGA_DST_CB_BASE_ADDR 0x0140
+#define RGA_DST_CR_BASE_ADDR 0x0144
+#define RGA_DST_VIR_INFO 0x0148
+#define RGA_DST_ACT_INFO 0x014c
+
+#define RGA_ALPHA_CTRL0 0x0150
+#define RGA_ALPHA_CTRL1 0x0154
+#define RGA_FADING_CTRL 0x0158
+#define RGA_PAT_CON 0x015c
+#define RGA_ROP_CON0 0x0160
+#define RGA_ROP_CON1 0x0164
+#define RGA_MASK_BASE 0x0168
+
+#define RGA_MMU_CTRL1 0x016C
+#define RGA_MMU_SRC_BASE 0x0170
+#define RGA_MMU_SRC1_BASE 0x0174
+#define RGA_MMU_DST_BASE 0x0178
+
+/* Registers value */
+#define RGA_MODE_RENDER_BITBLT 0
+#define RGA_MODE_RENDER_COLOR_PALETTE 1
+#define RGA_MODE_RENDER_RECTANGLE_FILL 2
+#define RGA_MODE_RENDER_UPDATE_PALETTE_LUT_RAM 3
+
+#define RGA_MODE_BITBLT_MODE_SRC_TO_DST 0
+#define RGA_MODE_BITBLT_MODE_SRC_SRC1_TO_DST 1
+
+#define RGA_MODE_CF_ROP4_SOLID 0
+#define RGA_MODE_CF_ROP4_PATTERN 1
+
+#define RGA_COLOR_FMT_ABGR8888 0
+#define RGA_COLOR_FMT_XBGR8888 1
+#define RGA_COLOR_FMT_RGB888 2
+#define RGA_COLOR_FMT_BGR565 4
+#define RGA_COLOR_FMT_ABGR1555 5
+#define RGA_COLOR_FMT_ABGR4444 6
+#define RGA_COLOR_FMT_YUV422SP 8
+#define RGA_COLOR_FMT_YUV422P 9
+#define RGA_COLOR_FMT_YUV420SP 10
+#define RGA_COLOR_FMT_YUV420P 11
+/* SRC_COLOR Palette */
+#define RGA_COLOR_FMT_CP_1BPP 12
+#define RGA_COLOR_FMT_CP_2BPP 13
+#define RGA_COLOR_FMT_CP_4BPP 14
+#define RGA_COLOR_FMT_CP_8BPP 15
+#define RGA_COLOR_FMT_MASK 15
+
+#define RGA_COLOR_NONE_SWAP 0
+#define RGA_COLOR_RB_SWAP 1
+#define RGA_COLOR_ALPHA_SWAP 2
+#define RGA_COLOR_UV_SWAP 4
+
+#define RGA_SRC_CSC_MODE_BYPASS 0
+#define RGA_SRC_CSC_MODE_BT601_R0 1
+#define RGA_SRC_CSC_MODE_BT601_R1 2
+#define RGA_SRC_CSC_MODE_BT709_R0 3
+#define RGA_SRC_CSC_MODE_BT709_R1 4
+
+#define RGA_SRC_ROT_MODE_0_DEGREE 0
+#define RGA_SRC_ROT_MODE_90_DEGREE 1
+#define RGA_SRC_ROT_MODE_180_DEGREE 2
+#define RGA_SRC_ROT_MODE_270_DEGREE 3
+
+#define RGA_SRC_MIRR_MODE_NO 0
+#define RGA_SRC_MIRR_MODE_X 1
+#define RGA_SRC_MIRR_MODE_Y 2
+#define RGA_SRC_MIRR_MODE_X_Y 3
+
+#define RGA_SRC_HSCL_MODE_NO 0
+#define RGA_SRC_HSCL_MODE_DOWN 1
+#define RGA_SRC_HSCL_MODE_UP 2
+
+#define RGA_SRC_VSCL_MODE_NO 0
+#define RGA_SRC_VSCL_MODE_DOWN 1
+#define RGA_SRC_VSCL_MODE_UP 2
+
+#define RGA_SRC_TRANS_ENABLE_R 1
+#define RGA_SRC_TRANS_ENABLE_G 2
+#define RGA_SRC_TRANS_ENABLE_B 4
+#define RGA_SRC_TRANS_ENABLE_A 8
+
+#define RGA_SRC_BIC_COE_SELEC_CATROM 0
+#define RGA_SRC_BIC_COE_SELEC_MITCHELL 1
+#define RGA_SRC_BIC_COE_SELEC_HERMITE 2
+#define RGA_SRC_BIC_COE_SELEC_BSPLINE 3
+
+#define RGA_DST_DITHER_MODE_888_TO_666 0
+#define RGA_DST_DITHER_MODE_888_TO_565 1
+#define RGA_DST_DITHER_MODE_888_TO_555 2
+#define RGA_DST_DITHER_MODE_888_TO_444 3
+
+#define RGA_DST_CSC_MODE_BYPASS 0
+#define RGA_DST_CSC_MODE_BT601_R0 1
+#define RGA_DST_CSC_MODE_BT601_R1 2
+#define RGA_DST_CSC_MODE_BT709_R0 3
+
+#define RGA_ALPHA_ROP_MODE_2 0
+#define RGA_ALPHA_ROP_MODE_3 1
+#define RGA_ALPHA_ROP_MODE_4 2
+
+#define RGA_ALPHA_SELECT_ALPHA 0
+#define RGA_ALPHA_SELECT_ROP 1
+
+#define RGA_ALPHA_MASK_BIG_ENDIAN 0
+#define RGA_ALPHA_MASK_LITTLE_ENDIAN 1
+
+#define RGA_ALPHA_NORMAL 0
+#define RGA_ALPHA_REVERSE 1
+
+#define RGA_ALPHA_BLEND_GLOBAL 0
+#define RGA_ALPHA_BLEND_NORMAL 1
+#define RGA_ALPHA_BLEND_MULTIPLY 2
+
+#define RGA_ALPHA_CAL_CUT 0
+#define RGA_ALPHA_CAL_NORMAL 1
+
+#define RGA_ALPHA_FACTOR_ZERO 0
+#define RGA_ALPHA_FACTOR_ONE 1
+#define RGA_ALPHA_FACTOR_OTHER 2
+#define RGA_ALPHA_FACTOR_OTHER_REVERSE 3
+#define RGA_ALPHA_FACTOR_SELF 4
+
+#define RGA_ALPHA_COLOR_NORMAL 0
+#define RGA_ALPHA_COLOR_MULTIPLY_CAL 1
+
+/* Registers union */
+union rga_mode_ctrl {
+	unsigned int val;
+	struct {
+		/* [0:2] */
+		unsigned int render:3;
+		/* [3:6] */
+		unsigned int bitblt:1;
+		unsigned int cf_rop4_pat:1;
+		unsigned int alpha_zero_key:1;
+		unsigned int gradient_sat:1;
+		/* [7:31] */
+		unsigned int reserved:25;
+	} data;
+};
+
+union rga_src_info {
+	unsigned int val;
+	struct {
+		/* [0:3] */
+		unsigned int format:4;
+		/* [4:7] */
+		unsigned int swap:3;
+		unsigned int cp_endian:1;
+		/* [8:17] */
+		unsigned int csc_mode:2;
+		unsigned int rot_mode:2;
+		unsigned int mir_mode:2;
+		unsigned int hscl_mode:2;
+		unsigned int vscl_mode:2;
+		/* [18:22] */
+		unsigned int trans_mode:1;
+		unsigned int trans_enable:4;
+		/* [23:25] */
+		unsigned int dither_up_en:1;
+		unsigned int bic_coe_sel:2;
+		/* [26:31] */
+		unsigned int reserved:6;
+	} data;
+};
+
+union rga_src_vir_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int vir_width:15;
+		unsigned int reserved:1;
+		/* [16:25] */
+		unsigned int vir_stride:10;
+		/* [26:31] */
+		unsigned int reserved1:6;
+	} data;
+};
+
+union rga_src_act_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int act_width:13;
+		unsigned int reserved:3;
+		/* [16:31] */
+		unsigned int act_height:13;
+		unsigned int reserved1:3;
+	} data;
+};
+
+union rga_src_x_factor {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int down_scale_factor:16;
+		/* [16:31] */
+		unsigned int up_scale_factor:16;
+	} data;
+};
+
+union rga_src_y_factor {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int down_scale_factor:16;
+		/* [16:31] */
+		unsigned int up_scale_factor:16;
+	} data;
+};
+
+/* Alpha / Red / Green / Blue */
+union rga_src_cp_gr_color {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int gradient_x:16;
+		/* [16:31] */
+		unsigned int gradient_y:16;
+	} data;
+};
+
+union rga_src_transparency_color0 {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int trans_rmin:8;
+		/* [8:15] */
+		unsigned int trans_gmin:8;
+		/* [16:23] */
+		unsigned int trans_bmin:8;
+		/* [24:31] */
+		unsigned int trans_amin:8;
+	} data;
+};
+
+union rga_src_transparency_color1 {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int trans_rmax:8;
+		/* [8:15] */
+		unsigned int trans_gmax:8;
+		/* [16:23] */
+		unsigned int trans_bmax:8;
+		/* [24:31] */
+		unsigned int trans_amax:8;
+	} data;
+};
+
+union rga_dst_info {
+	unsigned int val;
+	struct {
+		/* [0:3] */
+		unsigned int format:4;
+		/* [4:6] */
+		unsigned int swap:3;
+		/* [7:9] */
+		unsigned int src1_format:3;
+		/* [10:11] */
+		unsigned int src1_swap:2;
+		/* [12:15] */
+		unsigned int dither_up_en:1;
+		unsigned int dither_down_en:1;
+		unsigned int dither_down_mode:2;
+		/* [16:18] */
+		unsigned int csc_mode:2;
+		unsigned int csc_clip:1;
+		/* [19:31] */
+		unsigned int reserved:13;
+	} data;
+};
+
+union rga_dst_vir_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int vir_stride:15;
+		unsigned int reserved:1;
+		/* [16:31] */
+		unsigned int src1_vir_stride:15;
+		unsigned int reserved1:1;
+	} data;
+};
+
+union rga_dst_act_info {
+	unsigned int val;
+	struct {
+		/* [0:15] */
+		unsigned int act_width:12;
+		unsigned int reserved:4;
+		/* [16:31] */
+		unsigned int act_height:12;
+		unsigned int reserved1:4;
+	} data;
+};
+
+union rga_alpha_ctrl0 {
+	unsigned int val;
+	struct {
+		/* [0:3] */
+		unsigned int rop_en:1;
+		unsigned int rop_select:1;
+		unsigned int rop_mode:2;
+		/* [4:11] */
+		unsigned int src_fading_val:8;
+		/* [12:20] */
+		unsigned int dst_fading_val:8;
+		unsigned int mask_endian:1;
+		/* [21:31] */
+		unsigned int reserved:11;
+	} data;
+};
+
+union rga_alpha_ctrl1 {
+	unsigned int val;
+	struct {
+		/* [0:1] */
+		unsigned int dst_color_m0:1;
+		unsigned int src_color_m0:1;
+		/* [2:7] */
+		unsigned int dst_factor_m0:3;
+		unsigned int src_factor_m0:3;
+		/* [8:9] */
+		unsigned int dst_alpha_cal_m0:1;
+		unsigned int src_alpha_cal_m0:1;
+		/* [10:13] */
+		unsigned int dst_blend_m0:2;
+		unsigned int src_blend_m0:2;
+		/* [14:15] */
+		unsigned int dst_alpha_m0:1;
+		unsigned int src_alpha_m0:1;
+		/* [16:21] */
+		unsigned int dst_factor_m1:3;
+		unsigned int src_factor_m1:3;
+		/* [22:23] */
+		unsigned int dst_alpha_cal_m1:1;
+		unsigned int src_alpha_cal_m1:1;
+		/* [24:27] */
+		unsigned int dst_blend_m1:2;
+		unsigned int src_blend_m1:2;
+		/* [28:29] */
+		unsigned int dst_alpha_m1:1;
+		unsigned int src_alpha_m1:1;
+		/* [30:31] */
+		unsigned int reserved:2;
+	} data;
+};
+
+union rga_fading_ctrl {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int fading_offset_r:8;
+		/* [8:15] */
+		unsigned int fading_offset_g:8;
+		/* [16:23] */
+		unsigned int fading_offset_b:8;
+		/* [24:31] */
+		unsigned int fading_en:1;
+		unsigned int reserved:7;
+	} data;
+};
+
+union rga_pat_con {
+	unsigned int val;
+	struct {
+		/* [0:7] */
+		unsigned int width:8;
+		/* [8:15] */
+		unsigned int height:8;
+		/* [16:23] */
+		unsigned int offset_x:8;
+		/* [24:31] */
+		unsigned int offset_y:8;
+	} data;
+};
+
+#endif
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
new file mode 100644
index 000000000000..2cf3bb29a2b3
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "rga-hw.h"
+#include "rga.h"
+
+static int debug;
+module_param(debug, int, 0644);
+
+static void job_abort(void *prv)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+
+	if (!rga->curr)	/* No job currently running */
+		return;
+
+	wait_event_timeout(rga->irq_queue,
+			   !rga->curr, msecs_to_jiffies(RGA_TIMEOUT));
+}
+
+static void device_run(void *prv)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+	struct vb2_buffer *src, *dst;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rga->ctrl_lock, flags);
+
+	rga->curr = ctx;
+
+	src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+	rga_buf_map(src);
+	rga_buf_map(dst);
+
+	rga_hw_start(rga);
+
+	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
+}
+
+static irqreturn_t rga_isr(int irq, void *prv)
+{
+	struct rockchip_rga *rga = prv;
+	int intr;
+
+	intr = rga_read(rga, RGA_INT) & 0xf;
+
+	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
+
+	if (intr & 0x04) {
+		struct vb2_v4l2_buffer *src, *dst;
+		struct rga_ctx *ctx = rga->curr;
+
+		WARN_ON(!ctx);
+
+		rga->curr = NULL;
+
+		src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+		WARN_ON(!src);
+		WARN_ON(!dst);
+
+		dst->timecode = src->timecode;
+		dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
+		dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+		dst->flags |= src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+
+		v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
+		v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
+		v4l2_m2m_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx);
+
+		wake_up(&rga->irq_queue);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct v4l2_m2m_ops rga_m2m_ops = {
+	.device_run = device_run,
+	.job_abort = job_abort,
+};
+
+static int
+queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+	struct rga_ctx *ctx = priv;
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	src_vq->drv_priv = ctx;
+	src_vq->ops = &rga_qops;
+	src_vq->mem_ops = &vb2_dma_sg_memops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->lock = &ctx->rga->mutex;
+	src_vq->dev = ctx->rga->v4l2_dev.dev;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->ops = &rga_qops;
+	dst_vq->mem_ops = &vb2_dma_sg_memops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->lock = &ctx->rga->mutex;
+	dst_vq->dev = ctx->rga->v4l2_dev.dev;
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int rga_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct rga_ctx *ctx = container_of(ctrl->handler, struct rga_ctx,
+					   ctrl_handler);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->rga->ctrl_lock, flags);
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		ctx->hflip = ctrl->val;
+		break;
+	case V4L2_CID_VFLIP:
+		ctx->vflip = ctrl->val;
+		break;
+	case V4L2_CID_ROTATE:
+		ctx->rotate = ctrl->val;
+		break;
+	case V4L2_CID_BG_COLOR:
+		ctx->fill_color = ctrl->val;
+		break;
+	}
+	spin_unlock_irqrestore(&ctx->rga->ctrl_lock, flags);
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops rga_ctrl_ops = {
+	.s_ctrl = rga_s_ctrl,
+};
+
+static int rga_setup_ctrls(struct rga_ctx *ctx)
+{
+	struct rockchip_rga *rga = ctx->rga;
+
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_ROTATE, 0, 270, 90, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops,
+			  V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0);
+
+	if (ctx->ctrl_handler.error) {
+		int err = ctx->ctrl_handler.error;
+
+		v4l2_err(&rga->v4l2_dev, "%s failed\n", __func__);
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+		return err;
+	}
+
+	return 0;
+}
+
+struct rga_fmt formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XRGB32,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_XBGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_XBGR32,
+		.color_swap = RGA_COLOR_ALPHA_SWAP,
+		.hw_format = RGA_COLOR_FMT_XBGR8888,
+		.depth = 32,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_RGB888,
+		.depth = 24,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB444,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR4444,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB555,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_ABGR1555,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.color_swap = RGA_COLOR_RB_SWAP,
+		.hw_format = RGA_COLOR_FMT_BGR565,
+		.depth = 16,
+		.uv_factor = 1,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420SP,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422SP,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 1,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YUV422P,
+		.color_swap = RGA_COLOR_NONE_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV422P,
+		.depth = 16,
+		.uv_factor = 2,
+		.y_div = 1,
+		.x_div = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_YVU420,
+		.color_swap = RGA_COLOR_UV_SWAP,
+		.hw_format = RGA_COLOR_FMT_YUV420P,
+		.depth = 12,
+		.uv_factor = 4,
+		.y_div = 2,
+		.x_div = 2,
+	},
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+struct rga_fmt *rga_fmt_find(struct v4l2_format *f)
+{
+	unsigned int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (formats[i].fourcc == f->fmt.pix.pixelformat)
+			return &formats[i];
+	}
+	return NULL;
+}
+
+static struct rga_frame def_frame = {
+	.width = DEFAULT_WIDTH,
+	.height = DEFAULT_HEIGHT,
+	.colorspace = V4L2_COLORSPACE_DEFAULT,
+	.crop.left = 0,
+	.crop.top = 0,
+	.crop.width = DEFAULT_WIDTH,
+	.crop.height = DEFAULT_HEIGHT,
+	.fmt = &formats[0],
+};
+
+struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
+{
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		return &ctx->in;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &ctx->out;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+}
+
+static int rga_open(struct file *file)
+{
+	struct rockchip_rga *rga = video_drvdata(file);
+	struct rga_ctx *ctx = NULL;
+	int ret = 0;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+	ctx->rga = rga;
+	/* Set default formats */
+	ctx->in = def_frame;
+	ctx->out = def_frame;
+
+	if (mutex_lock_interruptible(&rga->mutex)) {
+		kfree(ctx);
+		return -ERESTARTSYS;
+	}
+	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init);
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+		mutex_unlock(&rga->mutex);
+		kfree(ctx);
+		return ret;
+	}
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	rga_setup_ctrls(ctx);
+
+	/* Write the default values to the ctx struct */
+	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+	mutex_unlock(&rga->mutex);
+
+	return 0;
+}
+
+static int rga_release(struct file *file)
+{
+	struct rga_ctx *ctx =
+		container_of(file->private_data, struct rga_ctx, fh);
+	struct rockchip_rga *rga = ctx->rga;
+
+	mutex_lock(&rga->mutex);
+
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+
+	mutex_unlock(&rga->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations rga_fops = {
+	.owner = THIS_MODULE,
+	.open = rga_open,
+	.release = rga_release,
+	.poll = v4l2_m2m_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = v4l2_m2m_fop_mmap,
+};
+
+static int
+vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+	strlcpy(cap->driver, RGA_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, "rockchip-rga", sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info));
+
+	return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
+{
+	struct rga_fmt *fmt;
+
+	if (f->index >= NUM_FORMATS)
+		return -EINVAL;
+
+	fmt = &formats[f->index];
+	f->pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct rga_ctx *ctx = prv;
+	struct vb2_queue *vq;
+	struct rga_frame *frm;
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (!vq)
+		return -EINVAL;
+	frm = rga_get_frame(ctx, f->type);
+	if (IS_ERR(frm))
+		return PTR_ERR(frm);
+
+	f->fmt.pix.width = frm->width;
+	f->fmt.pix.height = frm->height;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat = frm->fmt->fourcc;
+	f->fmt.pix.bytesperline = frm->stride;
+	f->fmt.pix.sizeimage = frm->size;
+	f->fmt.pix.colorspace = frm->colorspace;
+
+	return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct rga_fmt *fmt;
+
+	fmt = rga_fmt_find(f);
+	if (!fmt) {
+		fmt = &formats[0];
+		f->fmt.pix.pixelformat = fmt->fourcc;
+	}
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+
+	if (f->fmt.pix.width > MAX_WIDTH)
+		f->fmt.pix.width = MAX_WIDTH;
+	if (f->fmt.pix.height > MAX_HEIGHT)
+		f->fmt.pix.height = MAX_HEIGHT;
+
+	if (f->fmt.pix.width < MIN_WIDTH)
+		f->fmt.pix.width = MIN_WIDTH;
+	if (f->fmt.pix.height < MIN_HEIGHT)
+		f->fmt.pix.height = MIN_HEIGHT;
+
+	if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP)
+		f->fmt.pix.bytesperline = f->fmt.pix.width;
+	else
+		f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * (f->fmt.pix.width * fmt->depth) >> 3;
+
+	return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+	struct vb2_queue *vq;
+	struct rga_frame *frm;
+	struct rga_fmt *fmt;
+	int ret = 0;
+
+	/* Adjust all values accordingly to the hardware capabilities
+	 * and chosen format.
+	 */
+	ret = vidioc_try_fmt(file, prv, f);
+	if (ret)
+		return ret;
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (vb2_is_busy(vq)) {
+		v4l2_err(&rga->v4l2_dev, "queue (%d) bust\n", f->type);
+		return -EBUSY;
+	}
+	frm = rga_get_frame(ctx, f->type);
+	if (IS_ERR(frm))
+		return PTR_ERR(frm);
+	fmt = rga_fmt_find(f);
+	if (!fmt)
+		return -EINVAL;
+	frm->width = f->fmt.pix.width;
+	frm->height = f->fmt.pix.height;
+	frm->size = f->fmt.pix.sizeimage;
+	frm->fmt = fmt;
+	frm->stride = f->fmt.pix.bytesperline;
+	frm->colorspace = f->fmt.pix.colorspace;
+
+	/* Reset crop settings */
+	frm->crop.left = 0;
+	frm->crop.top = 0;
+	frm->crop.width = frm->width;
+	frm->crop.height = frm->height;
+
+	return 0;
+}
+
+static int vidioc_g_selection(struct file *file, void *prv,
+			      struct v4l2_selection *s)
+{
+	struct rga_ctx *ctx = prv;
+	struct rga_frame *f;
+	bool use_frame = false;
+
+	f = rga_get_frame(ctx, s->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		use_frame = true;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		use_frame = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (use_frame) {
+		s->r = f->crop;
+	} else {
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = f->width;
+		s->r.height = f->height;
+	}
+
+	return 0;
+}
+
+static int vidioc_s_selection(struct file *file, void *prv,
+			      struct v4l2_selection *s)
+{
+	struct rga_ctx *ctx = prv;
+	struct rockchip_rga *rga = ctx->rga;
+	struct rga_frame *f;
+	int ret = 0;
+
+	f = rga_get_frame(ctx, s->type);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE:
+		/*
+		 * COMPOSE target is only valid for capture buffer type, return
+		 * error for output buffer type
+		 */
+		if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		break;
+	case V4L2_SEL_TGT_CROP:
+		/*
+		 * CROP target is only valid for output buffer type, return
+		 * error for capture buffer type
+		 */
+		if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		break;
+	/*
+	 * bound and default crop/compose targets are invalid targets to
+	 * try/set
+	 */
+	default:
+		return -EINVAL;
+	}
+
+	if (s->r.top < 0 || s->r.left < 0) {
+		v4l2_dbg(debug, 1, &rga->v4l2_dev,
+			 "doesn't support negative values for top & left.\n");
+		return -EINVAL;
+	}
+
+	if (s->r.left + s->r.width > f->width ||
+	    s->r.top + s->r.height > f->height ||
+	    s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) {
+		v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n");
+		return -EINVAL;
+	}
+
+	f->crop = s->r;
+
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops rga_ioctl_ops = {
+	.vidioc_querycap = vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_cap = vidioc_g_fmt,
+	.vidioc_try_fmt_vid_cap = vidioc_try_fmt,
+	.vidioc_s_fmt_vid_cap = vidioc_s_fmt,
+
+	.vidioc_enum_fmt_vid_out = vidioc_enum_fmt,
+	.vidioc_g_fmt_vid_out = vidioc_g_fmt,
+	.vidioc_try_fmt_vid_out = vidioc_try_fmt,
+	.vidioc_s_fmt_vid_out = vidioc_s_fmt,
+
+	.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+	.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+	.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+	.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+	.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+	.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+	.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
+	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+	.vidioc_g_selection = vidioc_g_selection,
+	.vidioc_s_selection = vidioc_s_selection,
+};
+
+static struct video_device rga_videodev = {
+	.name = "rockchip-rga",
+	.fops = &rga_fops,
+	.ioctl_ops = &rga_ioctl_ops,
+	.minor = -1,
+	.release = video_device_release,
+	.vfl_dir = VFL_DIR_M2M,
+	.device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+static int rga_enable_clocks(struct rockchip_rga *rga)
+{
+	int ret;
+
+	ret = clk_prepare_enable(rga->sclk);
+	if (ret) {
+		dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(rga->aclk);
+	if (ret) {
+		dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret);
+		goto err_disable_sclk;
+	}
+
+	ret = clk_prepare_enable(rga->hclk);
+	if (ret) {
+		dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret);
+		goto err_disable_aclk;
+	}
+
+	return 0;
+
+err_disable_sclk:
+	clk_disable_unprepare(rga->sclk);
+err_disable_aclk:
+	clk_disable_unprepare(rga->aclk);
+
+	return ret;
+}
+
+static void rga_disable_clocks(struct rockchip_rga *rga)
+{
+	clk_disable_unprepare(rga->sclk);
+	clk_disable_unprepare(rga->hclk);
+	clk_disable_unprepare(rga->aclk);
+}
+
+static int rga_parse_dt(struct rockchip_rga *rga)
+{
+	struct reset_control *core_rst, *axi_rst, *ahb_rst;
+
+	core_rst = devm_reset_control_get(rga->dev, "core");
+	if (IS_ERR(core_rst)) {
+		dev_err(rga->dev, "failed to get core reset controller\n");
+		return PTR_ERR(core_rst);
+	}
+
+	axi_rst = devm_reset_control_get(rga->dev, "axi");
+	if (IS_ERR(axi_rst)) {
+		dev_err(rga->dev, "failed to get axi reset controller\n");
+		return PTR_ERR(axi_rst);
+	}
+
+	ahb_rst = devm_reset_control_get(rga->dev, "ahb");
+	if (IS_ERR(ahb_rst)) {
+		dev_err(rga->dev, "failed to get ahb reset controller\n");
+		return PTR_ERR(ahb_rst);
+	}
+
+	reset_control_assert(core_rst);
+	udelay(1);
+	reset_control_deassert(core_rst);
+
+	reset_control_assert(axi_rst);
+	udelay(1);
+	reset_control_deassert(axi_rst);
+
+	reset_control_assert(ahb_rst);
+	udelay(1);
+	reset_control_deassert(ahb_rst);
+
+	rga->sclk = devm_clk_get(rga->dev, "sclk");
+	if (IS_ERR(rga->sclk)) {
+		dev_err(rga->dev, "failed to get sclk clock\n");
+		return PTR_ERR(rga->sclk);
+	}
+
+	rga->aclk = devm_clk_get(rga->dev, "aclk");
+	if (IS_ERR(rga->aclk)) {
+		dev_err(rga->dev, "failed to get aclk clock\n");
+		return PTR_ERR(rga->aclk);
+	}
+
+	rga->hclk = devm_clk_get(rga->dev, "hclk");
+	if (IS_ERR(rga->hclk)) {
+		dev_err(rga->dev, "failed to get hclk clock\n");
+		return PTR_ERR(rga->hclk);
+	}
+
+	return 0;
+}
+
+static int rga_probe(struct platform_device *pdev)
+{
+	struct rockchip_rga *rga;
+	struct video_device *vfd;
+	struct resource *res;
+	int ret = 0;
+	int irq;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
+	if (!rga)
+		return -ENOMEM;
+
+	rga->dev = &pdev->dev;
+	spin_lock_init(&rga->ctrl_lock);
+	mutex_init(&rga->mutex);
+
+	init_waitqueue_head(&rga->irq_queue);
+
+	ret = rga_parse_dt(rga);
+	if (ret)
+		dev_err(&pdev->dev, "Unable to parse OF data\n");
+
+	pm_runtime_enable(rga->dev);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	rga->regs = devm_ioremap_resource(rga->dev, res);
+	if (IS_ERR(rga->regs)) {
+		ret = PTR_ERR(rga->regs);
+		goto err_put_clk;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(rga->dev, "failed to get irq\n");
+		ret = irq;
+		goto err_put_clk;
+	}
+
+	ret = devm_request_irq(rga->dev, irq, rga_isr, 0,
+			       dev_name(rga->dev), rga);
+	if (ret < 0) {
+		dev_err(rga->dev, "failed to request irq\n");
+		goto err_put_clk;
+	}
+
+	ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev);
+	if (ret)
+		goto err_put_clk;
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&rga->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_v4l2_dev;
+	}
+	*vfd = rga_videodev;
+	vfd->lock = &rga->mutex;
+	vfd->v4l2_dev = &rga->v4l2_dev;
+
+	video_set_drvdata(vfd, rga);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", rga_videodev.name);
+	rga->vfd = vfd;
+
+	platform_set_drvdata(pdev, rga);
+	rga->m2m_dev = v4l2_m2m_init(&rga_m2m_ops);
+	if (IS_ERR(rga->m2m_dev)) {
+		v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(rga->m2m_dev);
+		goto unreg_video_dev;
+	}
+
+	pm_runtime_get_sync(rga->dev);
+
+	rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF;
+	rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F;
+
+	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
+		  rga->version.major, rga->version.minor);
+
+	pm_runtime_put(rga->dev);
+
+	/* Create CMD buffer */
+	rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE,
+					   &rga->cmdbuf_phy, GFP_KERNEL,
+					   DMA_ATTR_WRITE_COMBINE);
+
+	rga->src_mmu_pages =
+		(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
+	rga->dst_mmu_pages =
+		(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
+
+	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
+	def_frame.size = def_frame.stride * def_frame.height;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret) {
+		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
+		goto rel_vdev;
+	}
+
+	v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+
+	return 0;
+
+rel_vdev:
+	video_device_release(vfd);
+unreg_video_dev:
+	video_unregister_device(rga->vfd);
+unreg_v4l2_dev:
+	v4l2_device_unregister(&rga->v4l2_dev);
+err_put_clk:
+	pm_runtime_disable(rga->dev);
+
+	return ret;
+}
+
+static int rga_remove(struct platform_device *pdev)
+{
+	struct rockchip_rga *rga = platform_get_drvdata(pdev);
+
+	dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, &rga->cmdbuf_virt,
+		       rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
+
+	free_pages((unsigned long)rga->src_mmu_pages, 3);
+	free_pages((unsigned long)rga->dst_mmu_pages, 3);
+
+	v4l2_info(&rga->v4l2_dev, "Removing\n");
+
+	v4l2_m2m_release(rga->m2m_dev);
+	video_unregister_device(rga->vfd);
+	v4l2_device_unregister(&rga->v4l2_dev);
+
+	pm_runtime_disable(rga->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int rga_runtime_suspend(struct device *dev)
+{
+	struct rockchip_rga *rga = dev_get_drvdata(dev);
+
+	rga_disable_clocks(rga);
+
+	return 0;
+}
+
+static int rga_runtime_resume(struct device *dev)
+{
+	struct rockchip_rga *rga = dev_get_drvdata(dev);
+
+	return rga_enable_clocks(rga);
+}
+#endif
+
+static const struct dev_pm_ops rga_pm = {
+	SET_RUNTIME_PM_OPS(rga_runtime_suspend,
+			   rga_runtime_resume, NULL)
+};
+
+static const struct of_device_id rockchip_rga_match[] = {
+	{
+		.compatible = "rockchip,rk3288-rga",
+	},
+	{
+		.compatible = "rockchip,rk3399-rga",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_rga_match);
+
+static struct platform_driver rga_pdrv = {
+	.probe = rga_probe,
+	.remove = rga_remove,
+	.driver = {
+		.name = RGA_NAME,
+		.pm = &rga_pm,
+		.of_match_table = rockchip_rga_match,
+	},
+};
+
+module_platform_driver(rga_pdrv);
+
+MODULE_AUTHOR("Jacob Chen <jacob-chen at iotwrt.com>");
+MODULE_DESCRIPTION("Rockchip Raster 2d Graphic Acceleration Unit");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
new file mode 100644
index 000000000000..5d43e7ea88af
--- /dev/null
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Jacob Chen <jacob-chen at iotwrt.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __RGA_H__
+#define __RGA_H__
+
+#include <linux/platform_device.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#define RGA_NAME "rockchip-rga"
+
+struct rga_fmt {
+	u32 fourcc;
+	int depth;
+	u8 uv_factor;
+	u8 y_div;
+	u8 x_div;
+	u8 color_swap;
+	u8 hw_format;
+};
+
+struct rga_frame {
+	/* Original dimensions */
+	u32 width;
+	u32 height;
+	u32 colorspace;
+
+	/* Crop */
+	struct v4l2_rect crop;
+
+	/* Image format */
+	struct rga_fmt *fmt;
+
+	/* Variables that can calculated once and reused */
+	u32 stride;
+	u32 size;
+};
+
+struct rockchip_rga_version {
+	u32 major;
+	u32 minor;
+};
+
+struct rga_ctx {
+	struct v4l2_fh fh;
+	struct rockchip_rga *rga;
+	struct rga_frame in;
+	struct rga_frame out;
+	struct v4l2_ctrl_handler ctrl_handler;
+
+	/* Control values */
+	u32 op;
+	u32 hflip;
+	u32 vflip;
+	u32 rotate;
+	u32 fill_color;
+};
+
+struct rockchip_rga {
+	struct v4l2_device v4l2_dev;
+	struct v4l2_m2m_dev *m2m_dev;
+	struct video_device *vfd;
+
+	struct device *dev;
+	struct regmap *grf;
+	void __iomem *regs;
+	struct clk *sclk;
+	struct clk *aclk;
+	struct clk *hclk;
+	struct rockchip_rga_version version;
+
+	/* vfd lock */
+	struct mutex mutex;
+	/* ctrl parm lock */
+	spinlock_t ctrl_lock;
+
+	wait_queue_head_t irq_queue;
+
+	struct rga_ctx *curr;
+	dma_addr_t cmdbuf_phy;
+	void *cmdbuf_virt;
+	unsigned int *src_mmu_pages;
+	unsigned int *dst_mmu_pages;
+};
+
+struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type);
+
+/* RGA Buffers Manage */
+extern const struct vb2_ops rga_qops;
+void rga_buf_map(struct vb2_buffer *vb);
+
+/* RGA Hardware */
+static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value)
+{
+	writel(value, rga->regs + reg);
+};
+
+static inline u32 rga_read(struct rockchip_rga *rga, u32 reg)
+{
+	return readl(rga->regs + reg);
+};
+
+static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
+{
+	u32 temp = rga_read(rga, reg) & ~(mask);
+
+	temp |= val & mask;
+	rga_write(rga, reg, temp);
+};
+
+void rga_hw_start(struct rockchip_rga *rga);
+
+#endif
-- 
2.14.1



From hoegsberg at gmail.com  Wed Oct 11 14:26:50 2017
From: hoegsberg at gmail.com (Kristian Kristensen)
Date: Wed, 11 Oct 2017 14:26:50 -0700
Subject: [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting
In-Reply-To: <1506412523-1766-1-git-send-email-nickey.yang@rock-chips.com>
References: <1506412523-1766-1-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <rdisy3ohidet.fsf@hawkmoon.pdx.corp.google.com>

Nickey Yang <nickey.yang at rock-chips.com> writes:

> This patch correct Feedback divider setting:
> 1?Set Feedback divider [8:5] when HIGH_PROGRAM_EN
> 2?Due to the use of a "by 2 pre-scaler," the range of the
> feedback multiplication Feedback divider is limited to even
> division numbers, and Feedback divider must be greater than
> 12, less than 1000.
> 3?Make the previously configured Feedback divider(LSB)
> factors effective
> 4?Add the definition of the MIPI PHY register.

There's too much going on in this patch.  A good rule of thumb is that
if you have enumerate the changes in a list like above, you should
probably break it down it that many patches instead. Any of these
changes could be a regression and when we bisect to this commit, we'll
have split it by hand to see which of the four independent changes is
causing trouble.

As a minimum, the addition of the register #defines should be a separate
patch. As it is, it makes it really hard to review the functional
changes...

> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
> ---
>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 219 ++++++++++++++++++++++-----------
>  1 file changed, 146 insertions(+), 73 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 9a20b9d..c933a3a 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -228,7 +228,7 @@
>  #define LOW_PROGRAM_EN		0
>  #define HIGH_PROGRAM_EN		BIT(7)
>  #define LOOP_DIV_LOW_SEL(val)	(((val) - 1) & 0x1f)
> -#define LOOP_DIV_HIGH_SEL(val)	((((val) - 1) >> 5) & 0x1f)
> +#define LOOP_DIV_HIGH_SEL(val)	((((val) - 1) >> 5) & 0xf)
>  #define PLL_LOOP_DIV_EN		BIT(5)
>  #define PLL_INPUT_DIV_EN	BIT(4)
>  
> @@ -254,6 +254,28 @@
>  #define DW_MIPI_NEEDS_PHY_CFG_CLK	BIT(0)
>  #define DW_MIPI_NEEDS_GRF_CLK		BIT(1)
>  
> +#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10
> +#define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11
> +#define PLL_LPF_AND_CP_CONTROL 0x12
> +#define PLL_INPUT_DIVIDER_RATIO 0x17
> +#define PLL_LOOP_DIVIDER_RATIO 0x18
> +#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19
> +#define BANDGAP_AND_BIAS_CONTROL 0x20
> +#define TERMINATION_RESISTER_CONTROL 0x21
> +#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22
> +#define HS_RX_CONTROL_OF_LANE_0 0x44
> +#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60
> +#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61
> +#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62
> +#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL 0x63
> +#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL 0x64
> +#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL 0x65
> +#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL 0x70
> +#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL 0x71
> +#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72
> +#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73
> +#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74
> +
>  enum {
>  	BANDGAP_97_07,
>  	BANDGAP_98_05,
> @@ -447,53 +469,79 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>  		return ret;
>  	}
>  
> -	dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
> -					 VCO_RANGE_CON_SEL(vco) |
> -					 VCO_IN_CAP_CON_LOW |
> -					 REF_BIAS_CUR_SEL);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
> -	dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
> -					 LPF_RESISTORS_20_KOHM);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
> -	dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> -					 LOW_PROGRAM_EN);
> -	dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> -					 HIGH_PROGRAM_EN);
> -	dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
> -					 BIASEXTR_SEL(BIASEXTR_127_7));
> -	dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
> -					 BANDGAP_SEL(BANDGAP_96_10));
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
> -					 BIAS_BLOCK_ON | BANDGAP_ON);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
> -					 SETRD_MAX | TER_RESISTORS_ON);
> -	dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> -					 SETRD_MAX | POWER_MANAGE |
> -					 TER_RESISTORS_ON);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> -	dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> -	dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> -	dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> -	dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
> -	dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> -	dw_mipi_dsi_phy_write(dsi, 0x71,
> +	dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
> +			      BYPASS_VCO_RANGE |
> +			      VCO_RANGE_CON_SEL(vco) |
> +			      VCO_IN_CAP_CON_LOW |
> +			      REF_BIAS_CUR_SEL);
> +
> +	dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> +			      CP_CURRENT_3MA);
> +	dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
> +			      CP_PROGRAM_EN | LPF_PROGRAM_EN |
> +			      LPF_RESISTORS_20_KOHM);
> +
> +	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> +			      HSFREQRANGE_SEL(testdin));
> +
> +	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
> +			      INPUT_DIVIDER(dsi->input_div));
> +	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> +			      LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> +			      LOW_PROGRAM_EN);
> +	/*
> +	 * we need set 0x19 immediately to make the configrued LSB
> +	 * effective according to IP simulation and lab test results.
> +	 * Only in this way can we get correct mipi phy pll frequency.
> +	 */

In particular, here's a functional change that adds an extra write to
PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL, after programming
LOW_PROGRAM_EN, and it's obscured by the renaming noise.

> +	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> +			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> +	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> +			      LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> +			      HIGH_PROGRAM_EN);
> +	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> +			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> +
> +	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> +			      LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
> +	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> +			      HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
> +
> +	dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
> +			      POWER_CONTROL | INTERNAL_REG_CURRENT |
> +			      BIAS_BLOCK_ON | BANDGAP_ON);
> +
> +	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> +			      TER_RESISTOR_LOW | TER_CAL_DONE |
> +			      SETRD_MAX | TER_RESISTORS_ON);
> +	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> +			      TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> +			      SETRD_MAX | POWER_MANAGE |
> +			      TER_RESISTORS_ON);
> +
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
> +			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
> +			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
> +			      THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
> +			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
> +			      BIT(5) | ns2bc(dsi, 100));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
> +			      BIT(5) | (ns2bc(dsi, 60) + 7));
> +
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
> +			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
>  			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
> -	dw_mipi_dsi_phy_write(dsi, 0x72,
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
>  			      THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
> -	dw_mipi_dsi_phy_write(dsi, 0x73,
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
>  			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
> -	dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
> +			      BIT(5) | ns2bc(dsi, 100));
>  
>  	dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
>  				     PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
> @@ -521,11 +569,16 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>  static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>  				    struct drm_display_mode *mode)
>  {
> -	unsigned int i, pre;
> -	unsigned long mpclk, pllref, tmp;
> -	unsigned int m = 1, n = 1, target_mbps = 1000;
> +	unsigned long mpclk, tmp;
> +	unsigned int target_mbps = 1000;
>  	unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
>  	int bpp;
> +	unsigned long best_freq = 0;
> +	unsigned long fvco_min, fvco_max, fin, fout;
> +	unsigned int min_prediv, max_prediv;
> +	unsigned int _prediv, uninitialized_var(best_prediv);
> +	unsigned long _fbdiv, uninitialized_var(best_fbdiv);
> +	unsigned long min_delta = ULONG_MAX;
>  
>  	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
>  	if (bpp < 0) {
> @@ -544,34 +597,54 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>  			dev_err(dsi->dev, "DPHY clock frequency is out of range\n");
>  	}
>  
> -	pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
> -	tmp = pllref;
> -
> -	/*
> -	 * The limits on the PLL divisor are:
> -	 *
> -	 *	5MHz <= (pllref / n) <= 40MHz
> -	 *
> -	 * we walk over these values in descreasing order so that if we hit
> -	 * an exact match for target_mbps it is more likely that "m" will be
> -	 * even.
> -	 *
> -	 * TODO: ensure that "m" is even after this loop.
> -	 */
> -	for (i = pllref / 5; i > (pllref / 40); i--) {
> -		pre = pllref / i;
> -		if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
> -			tmp = target_mbps % pre;
> -			n = i;
> -			m = target_mbps / pre;
> +	fin = clk_get_rate(dsi->pllref_clk);
> +	fout = target_mbps * USEC_PER_SEC;
> +
> +	/* constraint: 5Mhz <= Fref / N <= 40MHz */
> +	min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
> +	max_prediv = fin / (5 * USEC_PER_SEC);
> +
> +	/* constraint: 80MHz <= Fvco <= 1500Mhz */
> +	fvco_min = 80 * USEC_PER_SEC;
> +	fvco_max = 1500 * USEC_PER_SEC;
> +
> +	for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
> +		u64 tmp;
> +		u32 delta;
> +		/* Fvco = Fref * M / N */
> +		tmp = (u64)fout * _prediv;
> +		do_div(tmp, fin);
> +		_fbdiv = tmp;
> +		/*
> +		 * Due to the use of a "by 2 pre-scaler," the range of the
> +		 * feedback multiplication value M is limited to even division
> +		 * numbers, and m must be greater than 12, less than 1000.
> +		 */
> +		if (_fbdiv <= 12 || _fbdiv >= 1000)
> +			continue;
> +
> +		_fbdiv += _fbdiv % 2;
> +
> +		tmp = (u64)_fbdiv * fin;
> +		do_div(tmp, _prediv);
> +		if (tmp < fvco_min || tmp > fvco_max)
> +			continue;
> +
> +		delta = abs(fout - tmp);
> +		if (delta < min_delta) {
> +			best_prediv = _prediv;
> +			best_fbdiv = _fbdiv;
> +			min_delta = delta;
> +			best_freq = tmp;
>  		}
> -		if (tmp == 0)
> -			break;
>  	}
>  
> -	dsi->lane_mbps = pllref / n * m;
> -	dsi->input_div = n;
> -	dsi->feedback_div = m;
> +	if (best_freq) {
> +		dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
> +		dsi->input_div = best_prediv;
> +		dsi->feedback_div = best_fbdiv;
> +	} else
> +		dev_err(dsi->dev, "Can not find best_freq for DPHY\n");
>  
>  	return 0;
>  }
> -- 
> 1.9.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


From jacob-chen at iotwrt.com  Wed Oct 11 20:33:09 2017
From: jacob-chen at iotwrt.com (Jacob Chen)
Date: Thu, 12 Oct 2017 11:33:09 +0800
Subject: [PATCH v13] MAINTAINERS: add entry for Rockchip RGA driver
Message-ID: <20171012033309.2062-1-jacob-chen@iotwrt.com>

Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6671f375f7fc..b13dae0cbf42 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11509,6 +11509,13 @@ F:	drivers/hid/hid-roccat*
 F:	include/linux/hid-roccat*
 F:	Documentation/ABI/*/sysfs-driver-hid-roccat*
 
+ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER
+M:	Jacob chen <jacob2.chen at rock-chips.com>
+L:	linux-media at vger.kernel.org
+S:	Maintained
+F:	drivers/media/platform/rockchip/rga/
+F:	Documentation/devicetree/bindings/media/rockchip-rga.txt
+
 ROCKER DRIVER
 M:	Jiri Pirko <jiri at resnulli.us>
 L:	netdev at vger.kernel.org
-- 
2.14.1



From cw00.choi at samsung.com  Wed Oct 11 20:40:25 2017
From: cw00.choi at samsung.com (Chanwoo Choi)
Date: Thu, 12 Oct 2017 12:40:25 +0900
Subject: [PATCH v2] extcon: Split out extcon header file for consumer
 and provider device
In-Reply-To: <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>
References: <CGME20171010101758epcas2p3b3f379076f5be5e81edee2bd00354c28@epcas2p3.samsung.com>
 <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>
Message-ID: <59DEE429.2000608@samsung.com>

Dear Kishon,

Could you please review this patch?
After that, I'll make the immutable brand and then send the pull request
for power_supply, mfd, phy, usb and extcon framework.

On 2017? 10? 10? 19:17, Chanwoo Choi wrote:
> The extcon has two type of extcon devices as following.
> - 'extcon provider deivce' adds new extcon device and detect the
>    state/properties of external connector. Also, it notifies the
>    state/properties to the extcon consumer device.
> - 'extcon consumer device' gets the change state/properties
>    from extcon provider device.
> Prior to that, include/linux/extcon.h contains all exported API for
> both provider and consumer device driver. To clarify the meaning of
> header file and to remove the wrong use-case on consumer device,
> this patch separates into extcon.h and extcon-provider.h.
> 
> [Description for include/linux/{extcon.h|extcon-provider.h}]
> - extcon.h includes the extcon API and data structure for extcon consumer
>   device driver. This header file contains the following APIs:
>   : Register/unregister the notifier to catch the change of extcon device
>   : Get the extcon device instance
>   : Get the extcon device name
>   : Get the state of each external connector
>   : Get the property value of each external connector
>   : Get the property capability of each external connector
> 
> - extcon-provider.h includes the extcon API and data structure for extcon
>   provider device driver. This header file contains the following APIs:
>   : Include 'include/linux/extcon.h'
>   : Allocate the memory for extcon device instance
>   : Register/unregister extcon device
>   : Set the state of each external connector
>   : Set the property value of each external connector
>   : Set the property capability of each external connector
> 
> Cc: Felipe Balbi <balbi at kernel.org>
> Cc: Kishon Vijay Abraham I <kishon at ti.com>
> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> Acked-by: Sebastian Reichel <sebastian.reichel at collabora.co.uk>
> Acked-by: Chen-Yu Tsai <wens at csie.org>
> Acked-by: Charles Keepax <ckeepax at opensource.cirrus.com>
> Acked-by: Lee Jones <lee.jones at linaro.org>
> Signed-off-by: Chanwoo Choi <cw00.choi at samsung.com>
> ---
> Changes from v1:
> - Don't touch drivers/usb/renesas_usbhs/common.h.
> - Add acked-by from Sebastian Reichel (for drivers/power/supply/)
> - Add acked-by from Chen-Yu Tsai (for phy-sun4i-usb.c & extcon-axp288.c)
> - Add acked-by from Charles Keepax (for drivers/extcon/extcon-arizona.c)
> - Add acked-by from Lee Jones (fo include/linux/mfd/palmas.h)
> 
>  drivers/extcon/extcon-adc-jack.c              |   2 +-
>  drivers/extcon/extcon-arizona.c               |   2 +-
>  drivers/extcon/extcon-axp288.c                |   2 +-
>  drivers/extcon/extcon-gpio.c                  |   2 +-
>  drivers/extcon/extcon-intel-cht-wc.c          |   2 +-
>  drivers/extcon/extcon-intel-int3496.c         |   2 +-
>  drivers/extcon/extcon-max14577.c              |   2 +-
>  drivers/extcon/extcon-max3355.c               |   2 +-
>  drivers/extcon/extcon-max77693.c              |   2 +-
>  drivers/extcon/extcon-max77843.c              |   2 +-
>  drivers/extcon/extcon-max8997.c               |   2 +-
>  drivers/extcon/extcon-qcom-spmi-misc.c        |   2 +-
>  drivers/extcon/extcon-rt8973a.c               |   2 +-
>  drivers/extcon/extcon-sm5502.c                |   2 +-
>  drivers/extcon/extcon-usb-gpio.c              |   2 +-
>  drivers/extcon/extcon-usbc-cros-ec.c          |   2 +-
>  drivers/extcon/extcon.h                       |   2 +-
>  drivers/phy/allwinner/phy-sun4i-usb.c         |   2 +-
>  drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c     |   2 +-
>  drivers/phy/renesas/phy-rcar-gen3-usb2.c      |   2 +-
>  drivers/phy/rockchip/phy-rockchip-inno-usb2.c |   2 +-
>  drivers/power/supply/qcom_smbb.c              |   2 +-
>  drivers/usb/gadget/udc/renesas_usb3.c         |   2 +-
>  drivers/usb/phy/phy-tahvo.c                   |   2 +-
>  include/linux/extcon-provider.h               | 142 ++++++++++++++++++++++++++
>  include/linux/extcon.h                        | 109 +-------------------
>  include/linux/mfd/palmas.h                    |   2 +-
>  27 files changed, 172 insertions(+), 129 deletions(-)
>  create mode 100644 include/linux/extcon-provider.h
> 
> diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
> index 6f6537ab0a79..3877d86c746a 100644
> --- a/drivers/extcon/extcon-adc-jack.c
> +++ b/drivers/extcon/extcon-adc-jack.c
> @@ -26,7 +26,7 @@
>  #include <linux/workqueue.h>
>  #include <linux/iio/consumer.h>
>  #include <linux/extcon/extcon-adc-jack.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  
>  /**
>   * struct adc_jack_data - internal data for adc_jack device driver
> diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
> index f84da4a17724..da0e9bc4262f 100644
> --- a/drivers/extcon/extcon-arizona.c
> +++ b/drivers/extcon/extcon-arizona.c
> @@ -27,7 +27,7 @@
>  #include <linux/pm_runtime.h>
>  #include <linux/property.h>
>  #include <linux/regulator/consumer.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  
>  #include <sound/soc.h>
>  
> diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c
> index f4fd03e58e37..981fba56bc18 100644
> --- a/drivers/extcon/extcon-axp288.c
> +++ b/drivers/extcon/extcon-axp288.c
> @@ -22,7 +22,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/property.h>
>  #include <linux/notifier.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/regmap.h>
>  #include <linux/gpio.h>
>  #include <linux/gpio/consumer.h>
> diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
> index ebed22f22d75..ab770adcca7e 100644
> --- a/drivers/extcon/extcon-gpio.c
> +++ b/drivers/extcon/extcon-gpio.c
> @@ -17,7 +17,7 @@
>   * GNU General Public License for more details.
>   */
>  
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/extcon/extcon-gpio.h>
>  #include <linux/gpio.h>
>  #include <linux/gpio/consumer.h>
> diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c
> index 91a0023074af..7c4bc8c44c3f 100644
> --- a/drivers/extcon/extcon-intel-cht-wc.c
> +++ b/drivers/extcon/extcon-intel-cht-wc.c
> @@ -15,7 +15,7 @@
>   * more details.
>   */
>  
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/mfd/intel_soc_pmic.h>
> diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
> index 1a45e745717d..c8691b5a9cb0 100644
> --- a/drivers/extcon/extcon-intel-int3496.c
> +++ b/drivers/extcon/extcon-intel-int3496.c
> @@ -19,7 +19,7 @@
>   */
>  
>  #include <linux/acpi.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/gpio.h>
>  #include <linux/interrupt.h>
>  #include <linux/module.h>
> diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
> index f6414b7fa5bc..6c2c9996eb71 100644
> --- a/drivers/extcon/extcon-max14577.c
> +++ b/drivers/extcon/extcon-max14577.c
> @@ -23,7 +23,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/mfd/max14577.h>
>  #include <linux/mfd/max14577-private.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  
>  #define	DELAY_MS_DEFAULT		17000		/* unit: millisecond */
>  
> diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c
> index 533e16a952b8..0aa410836f4e 100644
> --- a/drivers/extcon/extcon-max3355.c
> +++ b/drivers/extcon/extcon-max3355.c
> @@ -9,7 +9,7 @@
>   * may be copied, distributed, and modified under those terms.
>   */
>  
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/gpio.h>
>  #include <linux/gpio/consumer.h>
>  #include <linux/interrupt.h>
> diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
> index 7a5856809047..643411066ad9 100644
> --- a/drivers/extcon/extcon-max77693.c
> +++ b/drivers/extcon/extcon-max77693.c
> @@ -26,7 +26,7 @@
>  #include <linux/mfd/max77693.h>
>  #include <linux/mfd/max77693-common.h>
>  #include <linux/mfd/max77693-private.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/regmap.h>
>  #include <linux/irqdomain.h>
>  
> diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
> index 6e722d552cf1..28f251ff0fa2 100644
> --- a/drivers/extcon/extcon-max77843.c
> +++ b/drivers/extcon/extcon-max77843.c
> @@ -11,7 +11,7 @@
>   * (at your option) any later version.
>   */
>  
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/i2c.h>
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
> diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
> index 4a0612fb9c07..8152790d72e1 100644
> --- a/drivers/extcon/extcon-max8997.c
> +++ b/drivers/extcon/extcon-max8997.c
> @@ -25,7 +25,7 @@
>  #include <linux/kobject.h>
>  #include <linux/mfd/max8997.h>
>  #include <linux/mfd/max8997-private.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/irqdomain.h>
>  
>  #define	DEV_NAME			"max8997-muic"
> diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c
> index b8cde096a808..660bbf163bf5 100644
> --- a/drivers/extcon/extcon-qcom-spmi-misc.c
> +++ b/drivers/extcon/extcon-qcom-spmi-misc.c
> @@ -15,7 +15,7 @@
>   * GNU General Public License for more details.
>   */
>  
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/init.h>
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
> diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
> index eaa355e7d9e4..e059bd5f2041 100644
> --- a/drivers/extcon/extcon-rt8973a.c
> +++ b/drivers/extcon/extcon-rt8973a.c
> @@ -20,7 +20,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/regmap.h>
>  #include <linux/slab.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  
>  #include "extcon-rt8973a.h"
>  
> diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
> index 106ef0297b53..0cfb5a3efdf6 100644
> --- a/drivers/extcon/extcon-sm5502.c
> +++ b/drivers/extcon/extcon-sm5502.c
> @@ -19,7 +19,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/regmap.h>
>  #include <linux/slab.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  
>  #include "extcon-sm5502.h"
>  
> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
> index 9c925b05b7aa..53762864a9f7 100644
> --- a/drivers/extcon/extcon-usb-gpio.c
> +++ b/drivers/extcon/extcon-usb-gpio.c
> @@ -14,7 +14,7 @@
>   * GNU General Public License for more details.
>   */
>  
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/gpio.h>
>  #include <linux/gpio/consumer.h>
>  #include <linux/init.h>
> diff --git a/drivers/extcon/extcon-usbc-cros-ec.c b/drivers/extcon/extcon-usbc-cros-ec.c
> index 598956f1dcae..6187f731b29d 100644
> --- a/drivers/extcon/extcon-usbc-cros-ec.c
> +++ b/drivers/extcon/extcon-usbc-cros-ec.c
> @@ -14,7 +14,7 @@
>   * GNU General Public License for more details.
>   */
>  
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/kernel.h>
>  #include <linux/mfd/cros_ec.h>
>  #include <linux/module.h>
> diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h
> index dddddcfa0587..cc1b436eb66a 100644
> --- a/drivers/extcon/extcon.h
> +++ b/drivers/extcon/extcon.h
> @@ -1,7 +1,7 @@
>  #ifndef __LINUX_EXTCON_INTERNAL_H__
>  #define __LINUX_EXTCON_INTERNAL_H__
>  
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  
>  /**
>   * struct extcon_dev - An extcon device represents one external connector.
> diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
> index 1161e11fb3cf..ef34f97f214b 100644
> --- a/drivers/phy/allwinner/phy-sun4i-usb.c
> +++ b/drivers/phy/allwinner/phy-sun4i-usb.c
> @@ -24,7 +24,7 @@
>  #include <linux/clk.h>
>  #include <linux/delay.h>
>  #include <linux/err.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/io.h>
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
> diff --git a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
> index d099a0c8cee5..7ceea5ae2704 100644
> --- a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
> +++ b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
> @@ -12,7 +12,7 @@
>   */
>  
>  #include <linux/delay.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/gpio.h>
>  #include <linux/gpio/consumer.h>
>  #include <linux/init.h>
> diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> index 54c34298a000..b33e2994ccce 100644
> --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
> @@ -12,7 +12,7 @@
>   * published by the Free Software Foundation.
>   */
>  
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
> diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
> index ee7ce5ee53f9..5049dac79bd0 100644
> --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
> +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
> @@ -17,7 +17,7 @@
>  #include <linux/clk.h>
>  #include <linux/clk-provider.h>
>  #include <linux/delay.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
>  #include <linux/gpio/consumer.h>
> diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c
> index f6a0d245731d..11de691b9a71 100644
> --- a/drivers/power/supply/qcom_smbb.c
> +++ b/drivers/power/supply/qcom_smbb.c
> @@ -34,7 +34,7 @@
>  #include <linux/power_supply.h>
>  #include <linux/regmap.h>
>  #include <linux/slab.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/regulator/driver.h>
>  
>  #define SMBB_CHG_VMAX		0x040
> diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
> index df37c1e6e9d5..8b4d051fdbed 100644
> --- a/drivers/usb/gadget/udc/renesas_usb3.c
> +++ b/drivers/usb/gadget/udc/renesas_usb3.c
> @@ -12,7 +12,7 @@
>  #include <linux/delay.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/err.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
>  #include <linux/module.h>
> diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c
> index 8babd318c0ed..354e8c98af05 100644
> --- a/drivers/usb/phy/phy-tahvo.c
> +++ b/drivers/usb/phy/phy-tahvo.c
> @@ -23,7 +23,7 @@
>  #include <linux/io.h>
>  #include <linux/clk.h>
>  #include <linux/usb.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/usb/otg.h>
> diff --git a/include/linux/extcon-provider.h b/include/linux/extcon-provider.h
> new file mode 100644
> index 000000000000..2feca5881fa7
> --- /dev/null
> +++ b/include/linux/extcon-provider.h
> @@ -0,0 +1,142 @@
> +/*
> + * External Connector (extcon) framework
> + * - linux/include/linux/extcon-provider.h for extcon provider device driver.
> + *
> + * Copyright (C) 2017 Samsung Electronics
> + * Author: Chanwoo Choi <cw00.choi at samsung.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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 __LINUX_EXTCON_PROVIDER_H__
> +#define __LINUX_EXTCON_PROVIDER_H__
> +
> +#include <linux/extcon.h>
> +
> +struct extcon_dev;
> +
> +#if IS_ENABLED(CONFIG_EXTCON)
> +
> +/* Following APIs register/unregister the extcon device. */
> +extern int extcon_dev_register(struct extcon_dev *edev);
> +extern void extcon_dev_unregister(struct extcon_dev *edev);
> +extern int devm_extcon_dev_register(struct device *dev,
> +				struct extcon_dev *edev);
> +extern void devm_extcon_dev_unregister(struct device *dev,
> +				struct extcon_dev *edev);
> +
> +/* Following APIs allocate/free the memory of the extcon device. */
> +extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable);
> +extern void extcon_dev_free(struct extcon_dev *edev);
> +extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
> +				const unsigned int *cable);
> +extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
> +
> +/* Synchronize the state and property value for each external connector. */
> +extern int extcon_sync(struct extcon_dev *edev, unsigned int id);
> +
> +/*
> + * Following APIs set the connected state of each external connector.
> + * The 'id' argument indicates the defined external connector.
> + */
> +extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
> +				bool state);
> +extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
> +				bool state);
> +
> +/*
> + * Following APIs set the property of each external connector.
> + * The 'id' argument indicates the defined external connector
> + * and the 'prop' indicates the extcon property.
> + *
> + * And extcon_set_property_capability() set the capability of the property
> + * for each external connector. They are used to set the capability of the
> + * property of each external connector based on the id and property.
> + */
> +extern int extcon_set_property(struct extcon_dev *edev, unsigned int id,
> +				unsigned int prop,
> +				union extcon_property_value prop_val);
> +extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
> +				unsigned int prop,
> +				union extcon_property_value prop_val);
> +extern int extcon_set_property_capability(struct extcon_dev *edev,
> +				unsigned int id, unsigned int prop);
> +
> +#else /* CONFIG_EXTCON */
> +static inline int extcon_dev_register(struct extcon_dev *edev)
> +{
> +	return 0;
> +}
> +
> +static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
> +
> +static inline int devm_extcon_dev_register(struct device *dev,
> +				struct extcon_dev *edev)
> +{
> +	return -EINVAL;
> +}
> +
> +static inline void devm_extcon_dev_unregister(struct device *dev,
> +				struct extcon_dev *edev) { }
> +
> +static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable)
> +{
> +	return ERR_PTR(-ENOSYS);
> +}
> +
> +static inline void extcon_dev_free(struct extcon_dev *edev) { }
> +
> +static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
> +				const unsigned int *cable)
> +{
> +	return ERR_PTR(-ENOSYS);
> +}
> +
> +static inline void devm_extcon_dev_free(struct extcon_dev *edev) { }
> +
> +
> +static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id,
> +				bool state)
> +{
> +	return 0;
> +}
> +
> +static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
> +				bool state)
> +{
> +	return 0;
> +}
> +
> +static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
> +{
> +	return 0;
> +}
> +
> +static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
> +				unsigned int prop,
> +				union extcon_property_value prop_val)
> +{
> +	return 0;
> +}
> +
> +static inline int extcon_set_property_sync(struct extcon_dev *edev,
> +				unsigned int id, unsigned int prop,
> +				union extcon_property_value prop_val)
> +{
> +	return 0;
> +}
> +
> +static inline int extcon_set_property_capability(struct extcon_dev *edev,
> +				unsigned int id, unsigned int prop)
> +{
> +	return 0;
> +}
> +#endif /* CONFIG_EXTCON */
> +#endif /* __LINUX_EXTCON_PROVIDER_H__ */
> diff --git a/include/linux/extcon.h b/include/linux/extcon.h
> index 744d60ca80c3..6d94e82c8ad9 100644
> --- a/include/linux/extcon.h
> +++ b/include/linux/extcon.h
> @@ -1,5 +1,6 @@
>  /*
>   * External Connector (extcon) framework
> + * - linux/include/linux/extcon.h for extcon consumer device driver.
>   *
>   * Copyright (C) 2015 Samsung Electronics
>   * Author: Chanwoo Choi <cw00.choi at samsung.com>
> @@ -170,61 +171,29 @@
>  	int intval;	/* type : integer (intval) */
>  };
>  
> -struct extcon_cable;
>  struct extcon_dev;
>  
>  #if IS_ENABLED(CONFIG_EXTCON)
> -
> -/* Following APIs register/unregister the extcon device. */
> -extern int extcon_dev_register(struct extcon_dev *edev);
> -extern void extcon_dev_unregister(struct extcon_dev *edev);
> -extern int devm_extcon_dev_register(struct device *dev,
> -				struct extcon_dev *edev);
> -extern void devm_extcon_dev_unregister(struct device *dev,
> -				struct extcon_dev *edev);
> -
> -/* Following APIs allocate/free the memory of the extcon device. */
> -extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable);
> -extern void extcon_dev_free(struct extcon_dev *edev);
> -extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
> -				const unsigned int *cable);
> -extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
> -
> -/* Synchronize the state and property value for each external connector. */
> -extern int extcon_sync(struct extcon_dev *edev, unsigned int id);
> -
>  /*
> - * Following APIs get/set the connected state of each external connector.
> + * Following APIs get the connected state of each external connector.
>   * The 'id' argument indicates the defined external connector.
>   */
>  extern int extcon_get_state(struct extcon_dev *edev, unsigned int id);
> -extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
> -				bool state);
> -extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
> -				bool state);
>  
>  /*
> - * Following APIs get/set the property of each external connector.
> + * Following APIs get the property of each external connector.
>   * The 'id' argument indicates the defined external connector
>   * and the 'prop' indicates the extcon property.
>   *
> - * And extcon_get/set_property_capability() set the capability of the property
> - * for each external connector. They are used to set the capability of the
> + * And extcon_get_property_capability() get the capability of the property
> + * for each external connector. They are used to get the capability of the
>   * property of each external connector based on the id and property.
>   */
>  extern int extcon_get_property(struct extcon_dev *edev, unsigned int id,
>  				unsigned int prop,
>  				union extcon_property_value *prop_val);
> -extern int extcon_set_property(struct extcon_dev *edev, unsigned int id,
> -				unsigned int prop,
> -				union extcon_property_value prop_val);
> -extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
> -				unsigned int prop,
> -				union extcon_property_value prop_val);
>  extern int extcon_get_property_capability(struct extcon_dev *edev,
>  				unsigned int id, unsigned int prop);
> -extern int extcon_set_property_capability(struct extcon_dev *edev,
> -				unsigned int id, unsigned int prop);
>  
>  /*
>   * Following APIs register the notifier block in order to detect
> @@ -268,79 +237,17 @@ extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
>  extern const char *extcon_get_edev_name(struct extcon_dev *edev);
>  
>  #else /* CONFIG_EXTCON */
> -static inline int extcon_dev_register(struct extcon_dev *edev)
> -{
> -	return 0;
> -}
> -
> -static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
> -
> -static inline int devm_extcon_dev_register(struct device *dev,
> -				struct extcon_dev *edev)
> -{
> -	return -EINVAL;
> -}
> -
> -static inline void devm_extcon_dev_unregister(struct device *dev,
> -				struct extcon_dev *edev) { }
> -
> -static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable)
> -{
> -	return ERR_PTR(-ENOSYS);
> -}
> -
> -static inline void extcon_dev_free(struct extcon_dev *edev) { }
> -
> -static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
> -				const unsigned int *cable)
> -{
> -	return ERR_PTR(-ENOSYS);
> -}
> -
> -static inline void devm_extcon_dev_free(struct extcon_dev *edev) { }
> -
> -
>  static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id)
>  {
>  	return 0;
>  }
>  
> -static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id,
> -				bool state)
> -{
> -	return 0;
> -}
> -
> -static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
> -				bool state)
> -{
> -	return 0;
> -}
> -
> -static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
> -{
> -	return 0;
> -}
> -
>  static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id,
>  				unsigned int prop,
>  				union extcon_property_value *prop_val)
>  {
>  	return 0;
>  }
> -static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
> -				unsigned int prop,
> -				union extcon_property_value prop_val)
> -{
> -	return 0;
> -}
> -
> -static inline int extcon_set_property_sync(struct extcon_dev *edev,
> -				unsigned int id, unsigned int prop,
> -				union extcon_property_value prop_val)
> -{
> -	return 0;
> -}
>  
>  static inline int extcon_get_property_capability(struct extcon_dev *edev,
>  				unsigned int id, unsigned int prop)
> @@ -348,12 +255,6 @@ static inline int extcon_get_property_capability(struct extcon_dev *edev,
>  	return 0;
>  }
>  
> -static inline int extcon_set_property_capability(struct extcon_dev *edev,
> -				unsigned int id, unsigned int prop)
> -{
> -	return 0;
> -}
> -
>  static inline int extcon_register_notifier(struct extcon_dev *edev,
>  				unsigned int id, struct notifier_block *nb)
>  {
> diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
> index 6dec43826303..3c8568aa82a5 100644
> --- a/include/linux/mfd/palmas.h
> +++ b/include/linux/mfd/palmas.h
> @@ -20,7 +20,7 @@
>  #include <linux/leds.h>
>  #include <linux/regmap.h>
>  #include <linux/regulator/driver.h>
> -#include <linux/extcon.h>
> +#include <linux/extcon-provider.h>
>  #include <linux/of_gpio.h>
>  #include <linux/usb/phy_companion.h>
>  
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics


From seanpaul at chromium.org  Thu Oct 12 06:53:40 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Thu, 12 Oct 2017 09:53:40 -0400
Subject: [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support
In-Reply-To: <1506412523-1766-2-git-send-email-nickey.yang@rock-chips.com>
References: <1506412523-1766-1-git-send-email-nickey.yang@rock-chips.com>
 <1506412523-1766-2-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <20171012135340.ys6djpmr4vq4g3yw@art_vandelay>

On Tue, Sep 26, 2017 at 03:55:17PM +0800, Nickey Yang wrote:
> This patch add dual mipi channel support:
> 1.add definition of dsi1 register and grf operation.
> 2.dsi0 and dsi1 will work in master and slave mode
> when driving dual mipi panel.
> 
> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
> ---

Hi Nickey,
Please add patch changelogs to make reviewers' lives easier.


>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c      | 390 ++++++++++++++++++++--------
>  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   1 +
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.c |   2 +
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   3 +
>  4 files changed, 292 insertions(+), 104 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index c933a3a..191037c 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -39,8 +39,58 @@
>  #define RK3399_DSI1_SEL_VOP_LIT		BIT(4)
>  
>  /* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
> -#define RK3399_GRF_SOC_CON22		0x6258
> -#define RK3399_GRF_DSI_MODE		0xffff0000
> +#define RK3399_GRF_SOC_CON22			0x6258
> +#define DPHY_TX0_TURNREQUEST_SET		((0xf << 12) << 16)

This is a confusing way of doing this. How about moving this below
TURNREQUEST_ENABLE and doing

+#define DPHY_TX0_TURNREQUEST_SET		(DPHY_TX0_TURNREQUEST_ENABLE << 16)

The same goes for all instances of *_SET


> +#define DPHY_TX0_TURNREQUEST_DISABLE		(0x0 << 12)

No need to define all of these *_DISABLE values to 0, just leave them out.


> +#define DPHY_TX0_TURNREQUEST_ENABLE		(0xf << 12)
> +#define DPHY_TX0_TURNDISABLE_SET		((0xf << 8) << 16)
> +#define DPHY_TX0_TURNDISABLE_DISABLE		(0x0 << 8)
> +#define DPHY_TX0_TURNDISABLE_ENABLE		(0xf << 8)
> +#define DPHY_TX0_FORCETXSTOPMODE_SET		((0xf << 4) << 16)
> +#define DPHY_TX0_FORCETXSTOPMODE_DISABLE	(0x0 << 4)
> +#define DPHY_TX0_FORCETXSTOPMODE_ENABLE		(0xf << 4)
> +#define DPHY_TX0_FORCETRXMODE_SET		((0xf << 0) << 16)
> +#define DPHY_TX0_FORCETRXMODE_DISABLE		0x0
> +#define DPHY_TX0_FORCETRXMODE_ENABLE		0xf
> +#define RK3399_GRF_DSI_MODE			((DPHY_TX0_TURNREQUEST_SET | \
> +						 DPHY_TX0_TURNDISABLE_SET | \
> +						 DPHY_TX0_FORCETXSTOPMODE_SET | \
> +						 DPHY_TX0_FORCETRXMODE_SET) | \
> +						 (DPHY_TX0_TURNREQUEST_DISABLE | \
> +						 DPHY_TX0_TURNDISABLE_DISABLE | \
> +						 DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
> +						 DPHY_TX0_FORCETRXMODE_DISABLE))
> +
> +
> +/* disable turndisable, forcetxstopmode, forcerxmode, enable */
> +#define RK3399_GRF_SOC_CON23			0x625c
> +#define DPHY_TX1RX1_TURNDISABLE_SET		((0xf << 12) << 16)
> +#define DPHY_TX1RX1_TURNDISABLE_DISABLE		(0x0 << 12)
> +#define DPHY_TX1RX1_TURNDISABLE_ENABLE		(0xf << 12)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_SET		((0xf << 8) << 16)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_DISABLE	(0x0 << 8)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_ENABLE	(0xf << 8)
> +#define DPHY_TX1RX1_FORCERXMODE_SET		((0xf << 4) << 16)
> +#define DPHY_TX1RX1_FORCERXMODE_DISABLE		(0x0 << 4)
> +#define DPHY_TX1RX1_FORCERXMODE_ENABLE		(0xf << 4)
> +#define DPHY_TX1RX1_ENABLE_SET			((0xf << 0) << 16)
> +#define DPHY_TX1RX1_ENABLE_DISABLE		0x0
> +#define DPHY_TX1RX1_ENABLE_ENABLE		0xf

Seems like you can share a number of these DPHY bit masks between the TX0 and TX1RX1.

> +#define RK3399_GRF_DSI1_MODE			((DPHY_TX1RX1_TURNDISABLE_SET | \
> +						 DPHY_TX1RX1_FORCETXSTOPMODE_SET | \
> +						 DPHY_TX1RX1_FORCERXMODE_SET | \
> +						 DPHY_TX1RX1_ENABLE_SET) | \
> +						 (DPHY_TX0_TURNREQUEST_DISABLE | \
> +						 DPHY_TX0_TURNDISABLE_DISABLE | \
> +						 DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
> +						 DPHY_TX0_FORCETRXMODE_DISABLE))
> +#define RK3399_GRF_DSI1_ENABLE			((DPHY_TX1RX1_ENABLE_SET | \
> +						  DPHY_TX1RX1_ENABLE_ENABLE))
> +
> +#define RK3399_GRF_SOC_CON24		0x6260
> +#define RK3399_TXRX_MASTERSLAVEZ	BIT(7)
> +#define RK3399_TXRX_ENABLECLK		BIT(6)
> +#define RK3399_TXRX_BASEDIR		BIT(5)
>  
>  #define DSI_VERSION			0x00
>  #define DSI_PWR_UP			0x04
> @@ -304,6 +354,13 @@ struct dw_mipi_dsi_plat_data {
>  	u32 grf_switch_reg;
>  	u32 grf_dsi0_mode;
>  	u32 grf_dsi0_mode_reg;
> +	u32 grf_dsi1_mode;
> +	u32 grf_dsi1_enable;
> +	u32 grf_dsi1_mode_reg1;
> +	u32 dsi1_basedir;
> +	u32 dsi1_masterslavez;
> +	u32 dsi1_enableclk;
> +	u32 grf_dsi1_mode_reg2;
>  	unsigned int flags;
>  	unsigned int max_data_lanes;
>  };
> @@ -322,6 +379,10 @@ struct dw_mipi_dsi {
>  	struct clk *pclk;
>  	struct clk *phy_cfg_clk;
>  
> +	/* dual-channel */
> +	struct dw_mipi_dsi *master;
> +	struct dw_mipi_dsi *slave;
> +
>  	int dpms_mode;
>  	unsigned int lane_mbps; /* per lane */
>  	u32 channel;
> @@ -574,6 +635,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>  	unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
>  	int bpp;
>  	unsigned long best_freq = 0;
> +	int lanes = dsi->lanes;
>  	unsigned long fvco_min, fvco_max, fin, fout;
>  	unsigned int min_prediv, max_prediv;
>  	unsigned int _prediv, uninitialized_var(best_prediv);
> @@ -587,10 +649,13 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>  		return bpp;
>  	}
>  
> +	if (dsi->slave || dsi->master)
> +		lanes = dsi->lanes * 2;
> +
>  	mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
>  	if (mpclk) {
>  		/* take 1 / 0.8, since mbps must big than bandwidth of RGB */
> -		tmp = mpclk * (bpp / dsi->lanes) * 10 / 8;
> +		tmp = mpclk * (bpp / lanes) * 10 / 8;
>  		if (tmp < max_mbps)
>  			target_mbps = tmp;
>  		else
> @@ -653,17 +718,26 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
>  				   struct mipi_dsi_device *device)
>  {
>  	struct dw_mipi_dsi *dsi = host_to_dsi(host);
> +	int lanes = dsi->slave ? device->lanes / 2 : device->lanes;
>  
> -	if (device->lanes > dsi->pdata->max_data_lanes) {
> +	if (lanes > dsi->pdata->max_data_lanes) {
>  		dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
> -			device->lanes);
> +			lanes);
>  		return -EINVAL;
>  	}
>  
> -	dsi->lanes = device->lanes;
> +	dsi->lanes = lanes;
>  	dsi->channel = device->channel;
>  	dsi->format = device->format;
>  	dsi->mode_flags = device->mode_flags;
> +
> +	if (dsi->slave) {
> +		dsi->slave->lanes = lanes;
> +		dsi->slave->channel = device->channel;
> +		dsi->slave->format = device->format;
> +		dsi->slave->mode_flags = device->mode_flags;
> +	}
> +
>  	dsi->panel = of_drm_find_panel(device->dev.of_node);
>  	if (dsi->panel)
>  		return drm_panel_attach(dsi->panel, &dsi->connector);
> @@ -793,15 +867,22 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
>  	int ret;
>  
>  	dw_mipi_message_config(dsi, msg);
> +	if (dsi->slave)
> +		dw_mipi_message_config(dsi->slave, msg);
>  
>  	switch (msg->type) {
>  	case MIPI_DSI_DCS_SHORT_WRITE:
>  	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
>  	case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
> +	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
>  		ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
> +		if (dsi->slave)
> +			ret = dw_mipi_dsi_dcs_short_write(dsi->slave, msg);
>  		break;
>  	case MIPI_DSI_DCS_LONG_WRITE:
>  		ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
> +		if (dsi->slave)
> +			ret = dw_mipi_dsi_dcs_long_write(dsi->slave, msg);
>  		break;
>  	default:
>  		dev_err(dsi->dev, "unsupported message type 0x%02x\n",
> @@ -875,6 +956,55 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
>  		  TX_ESC_CLK_DIVIDSION(esc_clk_division));
>  }
>  
> +static void rockchip_dsi_grf_config(struct dw_mipi_dsi *dsi, int vop_id)
> +{
> +	const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
> +	int val = 0;
> +	int ret;
> +
> +	/*
> +	 * For the RK3399, the clk of grf must be enabled before writing grf
> +	 * register. And for RK3288 or other soc, this grf_clk must be NULL,
> +	 * the clk_prepare_enable return true directly.
> +	 */
> +	ret = clk_prepare_enable(dsi->grf_clk);
> +	if (ret) {
> +		dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
> +		return;
> +	}
> +
> +	val = pdata->dsi0_en_bit << 16;
> +	if (dsi->slave)
> +		val |= pdata->dsi1_en_bit << 16;
> +	if (vop_id) {
> +		val |= pdata->dsi0_en_bit;
> +		if (dsi->slave)
> +			val |= pdata->dsi1_en_bit;
> +	}
> +	regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
> +
> +	if (pdata->grf_dsi0_mode_reg)
> +		regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
> +			     pdata->grf_dsi0_mode);
> +
> +	if (dsi->slave) {
> +		if (pdata->grf_dsi1_mode_reg1)
> +			regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
> +				     pdata->grf_dsi1_mode);
> +		val = pdata->dsi1_masterslavez |
> +		      (pdata->dsi1_masterslavez << 16) |
> +		      (pdata->dsi1_basedir << 16);
> +		if (pdata->grf_dsi1_mode_reg2)
> +			regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg2,
> +				     val);

I don't think the val assignment above gains you anything. IMO, the following
would be better:

                if (pdata->grf_dsi1_mode_reg2)
			regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg2,
                                     pdata->dsi1_masterslavez |
                                     (pdata->dsi1_masterslavez << 16) |
                                     (pdata->dsi1_basedir << 16));


> +		if (pdata->grf_dsi1_mode_reg1)
> +			regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
> +				     pdata->grf_dsi1_enable);
> +	}
> +
> +	clk_disable_unprepare(dsi->grf_clk);
> +}
> +
>  static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
>  				   struct drm_display_mode *mode)
>  {
> @@ -915,7 +1045,14 @@ static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
>  static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
>  					    struct drm_display_mode *mode)
>  {
> -	dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
> +	int pkt_size;
> +
> +	if (dsi->slave || dsi->master)
> +		pkt_size = VID_PKT_SIZE(mode->hdisplay / 2);
> +	else
> +		pkt_size = VID_PKT_SIZE(mode->hdisplay);
> +
> +	dsi_write(dsi, DSI_VID_PKT_SIZE, pkt_size);
>  }
>  
>  static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
> @@ -1020,24 +1157,26 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
>  	dw_mipi_dsi_disable(dsi);
>  	pm_runtime_put(dsi->dev);
>  	clk_disable_unprepare(dsi->pclk);
> +
> +	if (dsi->slave) {
> +		if (clk_prepare_enable(dsi->slave->pclk)) {
> +			dev_err(dsi->slave->dev, "%s: Failed to enable pclk\n", __func__);

My comment from v1 still applies, please use DRM_DEV_* messages

> +			return;
> +		}
> +		dw_mipi_dsi_disable(dsi->slave);
> +		pm_runtime_put(dsi->slave->dev);
> +		clk_disable_unprepare(dsi->slave->pclk);
> +	}
> +
>  	dsi->dpms_mode = DRM_MODE_DPMS_OFF;
>  }
>  
> -static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> +static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi, struct drm_display_mode *mode)
>  {
> -	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
> -	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> -	const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
> -	int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
> -	u32 val;
> -	int ret;
> -
> -	ret = dw_mipi_dsi_get_lane_bps(dsi, mode);
> -	if (ret < 0)
> -		return;
> -
> -	if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
> +	if (dw_mipi_dsi_get_lane_bps(dsi, mode) < 0) {
> +		dev_err(dsi->dev, "%s: Failed to get lane bps\n", __func__);
>  		return;
> +	}
>  
>  	if (clk_prepare_enable(dsi->pclk)) {
>  		dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
> @@ -1057,43 +1196,42 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
>  	dw_mipi_dsi_dphy_interface_config(dsi);
>  	dw_mipi_dsi_clear_err(dsi);
>  
> -	/*
> -	 * For the RK3399, the clk of grf must be enabled before writing grf
> -	 * register. And for RK3288 or other soc, this grf_clk must be NULL,
> -	 * the clk_prepare_enable return true directly.
> -	 */
> -	ret = clk_prepare_enable(dsi->grf_clk);
> -	if (ret) {
> -		dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
> -		return;
> -	}
> -
> -	if (pdata->grf_dsi0_mode_reg)
> -		regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
> -			     pdata->grf_dsi0_mode);
> -
>  	dw_mipi_dsi_phy_init(dsi);
>  	dw_mipi_dsi_wait_for_two_frames(mode);
>  
>  	dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
> +}
> +
> +static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> +{
> +	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
> +	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> +	int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
> +
> +	if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
> +		return;
> +
> +	rockchip_dsi_grf_config(dsi, mux);
> +	dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
> +
> +	dw_mipi_dsi_enable(dsi, mode);
> +	if (dsi->slave)
> +		dw_mipi_dsi_enable(dsi->slave, mode);
> +
>  	if (drm_panel_prepare(dsi->panel))
>  		dev_err(dsi->dev, "failed to prepare panel\n");
>  
>  	dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
> +	if (dsi->slave)
> +		dw_mipi_dsi_set_mode(dsi->slave, DW_MIPI_DSI_VID_MODE);
> +
>  	drm_panel_enable(dsi->panel);
>  
>  	clk_disable_unprepare(dsi->pclk);
> +	if (dsi->slave)
> +		clk_disable_unprepare(dsi->slave->pclk);
>  
> -	if (mux)
> -		val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
> -	else
> -		val = pdata->dsi0_en_bit << 16;
> -
> -	regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
> -	dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
>  	dsi->dpms_mode = DRM_MODE_DPMS_ON;
> -
> -	clk_disable_unprepare(dsi->grf_clk);
>  }
>  
>  static int
> @@ -1121,6 +1259,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
>  
>  	s->output_type = DRM_MODE_CONNECTOR_DSI;
>  
> +	if (dsi->slave)
> +		s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL;
> +
>  	return 0;
>  }
>  
> @@ -1226,6 +1367,13 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
>  	.grf_switch_reg = RK3399_GRF_SOC_CON20,
>  	.grf_dsi0_mode = RK3399_GRF_DSI_MODE,
>  	.grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
> +	.grf_dsi1_mode = RK3399_GRF_DSI1_MODE,
> +	.grf_dsi1_enable = RK3399_GRF_DSI1_ENABLE,
> +	.grf_dsi1_mode_reg1 = RK3399_GRF_SOC_CON23,
> +	.dsi1_basedir = RK3399_TXRX_BASEDIR,
> +	.dsi1_masterslavez = RK3399_TXRX_MASTERSLAVEZ,
> +	.dsi1_enableclk = RK3399_TXRX_ENABLECLK,
> +	.grf_dsi1_mode_reg2 = RK3399_GRF_SOC_CON24,
>  	.flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
>  	.max_data_lanes = 4,
>  };
> @@ -1242,17 +1390,107 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
>  };
>  MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
>  
> +
> +static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
> +{
> +	struct device_node *np;
> +	struct platform_device *secondary;
> +
> +	np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
> +	if (np) {
> +		secondary = of_find_device_by_node(np);
> +		dsi->slave = platform_get_drvdata(secondary);
> +		of_node_put(np);
> +
> +		if (!dsi->slave)
> +			return -EPROBE_DEFER;
> +
> +		dsi->slave->master = dsi;
> +	}
> +
> +	return 0;
> +}
> +
>  static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
>  			    void *data)
>  {
> +	struct drm_device *drm = data;
> +	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = rockchip_dsi_dual_channel_probe(dsi);
> +	if (ret)
> +		return ret;
> +
> +	ret = clk_prepare_enable(dsi->pllref_clk);
> +	if (ret) {
> +		dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
> +		return ret;
> +	}
> +
> +	pm_runtime_enable(dev);
> +
> +	if (dsi->master)
> +		return 0;
> +
> +	ret = dw_mipi_dsi_register(drm, dsi);
> +	if (ret) {
> +		dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
> +		goto err_pllref;
> +	}
> +
> +	dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
> +	dsi->dsi_host.dev = dev;
> +	ret = mipi_dsi_host_register(&dsi->dsi_host);
> +	if (ret) {
> +		dev_err(dev, "Failed to register MIPI host: %d\n", ret);
> +		goto err_cleanup;
> +	}
> +
> +	if (!dsi->panel) {
> +		ret = -EPROBE_DEFER;
> +		goto err_mipi_dsi_host;
> +	}
> +
> +	return 0;
> +
> +err_mipi_dsi_host:
> +	mipi_dsi_host_unregister(&dsi->dsi_host);
> +err_cleanup:
> +	drm_encoder_cleanup(&dsi->encoder);
> +	drm_connector_cleanup(&dsi->connector);
> +err_pllref:
> +	pm_runtime_disable(dev);
> +	clk_disable_unprepare(dsi->pllref_clk);
> +	return ret;
> +}
> +
> +static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
> +			       void *data)
> +{
> +	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> +
> +	mipi_dsi_host_unregister(&dsi->dsi_host);
> +	pm_runtime_disable(dev);
> +	if (dsi->slave)
> +		pm_runtime_disable(dsi->slave->dev);
> +	clk_disable_unprepare(dsi->pllref_clk);
> +}
> +
> +static const struct component_ops dw_mipi_dsi_ops = {
> +	.bind	= dw_mipi_dsi_bind,
> +	.unbind	= dw_mipi_dsi_unbind,
> +};
> +
> +static int dw_mipi_dsi_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
>  	const struct of_device_id *of_id =
>  			of_match_device(dw_mipi_dsi_dt_ids, dev);
>  	const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
> -	struct platform_device *pdev = to_platform_device(dev);
> -	struct reset_control *apb_rst;
> -	struct drm_device *drm = data;
>  	struct dw_mipi_dsi *dsi;
>  	struct resource *res;
> +	struct reset_control *apb_rst;
>  	int ret;
>  
>  	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
> @@ -1262,6 +1500,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
>  	dsi->dev = dev;
>  	dsi->pdata = pdata;
>  	dsi->dpms_mode = DRM_MODE_DPMS_OFF;
> +	dev_set_drvdata(dev, dsi);
>  
>  	ret = rockchip_mipi_parse_dt(dsi);
>  	if (ret)
> @@ -1336,63 +1575,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
>  		}
>  	}
>  
> -	ret = clk_prepare_enable(dsi->pllref_clk);
> -	if (ret) {
> -		dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
> -		return ret;
> -	}
> -
> -	ret = dw_mipi_dsi_register(drm, dsi);
> -	if (ret) {
> -		dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
> -		goto err_pllref;
> -	}
> -
> -	pm_runtime_enable(dev);
> -
> -	dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
> -	dsi->dsi_host.dev = dev;
> -	ret = mipi_dsi_host_register(&dsi->dsi_host);
> -	if (ret) {
> -		dev_err(dev, "Failed to register MIPI host: %d\n", ret);
> -		goto err_cleanup;
> -	}
> -
> -	if (!dsi->panel) {
> -		ret = -EPROBE_DEFER;
> -		goto err_mipi_dsi_host;
> -	}
> -
> -	dev_set_drvdata(dev, dsi);
> -	return 0;
> -
> -err_mipi_dsi_host:
> -	mipi_dsi_host_unregister(&dsi->dsi_host);
> -err_cleanup:
> -	drm_encoder_cleanup(&dsi->encoder);
> -	drm_connector_cleanup(&dsi->connector);
> -err_pllref:
> -	clk_disable_unprepare(dsi->pllref_clk);
> -	return ret;
> -}
> -
> -static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
> -			       void *data)
> -{
> -	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> -
> -	mipi_dsi_host_unregister(&dsi->dsi_host);
> -	pm_runtime_disable(dev);
> -	clk_disable_unprepare(dsi->pllref_clk);
> -}
> -
> -static const struct component_ops dw_mipi_dsi_ops = {
> -	.bind	= dw_mipi_dsi_bind,
> -	.unbind	= dw_mipi_dsi_unbind,
> -};
> -
> -static int dw_mipi_dsi_probe(struct platform_device *pdev)
> -{
>  	return component_add(&pdev->dev, &dw_mipi_dsi_ops);
>  }
>  
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> index c7e96b8..51ad1c2 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> @@ -36,6 +36,7 @@ struct rockchip_crtc_state {
>  	struct drm_crtc_state base;
>  	int output_type;
>  	int output_mode;
> +	int output_flags;
>  };
>  #define to_rockchip_crtc_state(s) \
>  		container_of(s, struct rockchip_crtc_state, base)
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> index bf9ed0e..cb40cdd 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> @@ -917,6 +917,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
>  	case DRM_MODE_CONNECTOR_DSI:
>  		VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
>  		VOP_REG_SET(vop, output, mipi_en, 1);
> +		VOP_REG_SET(vop, output, mipi_dual_channel_en,
> +			!!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL));
>  		break;
>  	case DRM_MODE_CONNECTOR_DisplayPort:
>  		pin_pol &= ~BIT(DCLK_INVERT);
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> index 56bbd2e..d184531 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> @@ -60,6 +60,7 @@ struct vop_output {
>  	struct vop_reg edp_en;
>  	struct vop_reg hdmi_en;
>  	struct vop_reg mipi_en;
> +	struct vop_reg mipi_dual_channel_en;
>  	struct vop_reg rgb_en;
>  };
>  
> @@ -212,6 +213,8 @@ struct vop_data {
>  /* for use special outface */
>  #define ROCKCHIP_OUT_MODE_AAAA	15
>  
> +#define ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL	BIT(0)
> +
>  enum alpha_mode {
>  	ALPHA_STRAIGHT,
>  	ALPHA_INVERSE,
> -- 
> 1.9.1
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Thu Oct 12 06:58:51 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Thu, 12 Oct 2017 09:58:51 -0400
Subject: [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting
In-Reply-To: <1506412523-1766-4-git-send-email-nickey.yang@rock-chips.com>
References: <1506412523-1766-1-git-send-email-nickey.yang@rock-chips.com>
 <1506412523-1766-4-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <20171012135851.qpyi772awlueuetg@art_vandelay>

On Tue, Sep 26, 2017 at 03:55:19PM +0800, Nickey Yang wrote:
> As MIPI PHY document show, icpctrl<3..0> and lpfctrl<5..0>
> should depend on frequency,so fix it.
> 
> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>

With the improvements to max_mbps that Matthias suggested,

Reviewed-by: Sean Paul <seanpaul at chromium.org>

> ---
>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 98 ++++++++++++++++++++++++----------
>  1 file changed, 70 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 191037c..20d3f36 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -267,10 +267,21 @@
>  #define VCO_IN_CAP_CON_HIGH	(0x2 << 1)
>  #define REF_BIAS_CUR_SEL	BIT(0)
>  
> -#define CP_CURRENT_3MA		BIT(3)
> +#define CP_CURRENT_1_5UA	0x1
> +#define CP_CURRENT_4_5UA	0x2
> +#define CP_CURRENT_7_5UA	0x6
> +#define CP_CURRENT_6UA	0x9
> +#define CP_CURRENT_12UA	0xb
> +#define CP_CURRENT_SEL(val)	((val) & 0xf)
>  #define CP_PROGRAM_EN		BIT(7)
> +
> +#define LPF_RESISTORS_15_5KOHM	0x1
> +#define LPF_RESISTORS_13KOHM	0x2
> +#define LPF_RESISTORS_11_5KOHM	0x4
> +#define LPF_RESISTORS_10_5KOHM	0x8
> +#define LPF_RESISTORS_8KOHM	0x10
>  #define LPF_PROGRAM_EN		BIT(6)
> -#define LPF_RESISTORS_20_KOHM	0
> +#define LPF_RESISTORS_SEL(val)	((val) & 0x3f)
>  
>  #define HSFREQRANGE_SEL(val)	(((val) & 0x3f) << 1)
>  
> @@ -400,32 +411,63 @@ enum dw_mipi_dsi_mode {
>  	DW_MIPI_DSI_VID_MODE,
>  };
>  
> -struct dphy_pll_testdin_map {
> +struct dphy_pll_parameter_map {
>  	unsigned int max_mbps;
> -	u8 testdin;
> +	u8 hsfreqrange;
> +	u8 icpctrl;
> +	u8 lpfctrl;
>  };
>  
>  /* The table is based on 27MHz DPHY pll reference clock. */
> -static const struct dphy_pll_testdin_map dptdin_map[] = {
> -	{  90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
> -	{ 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
> -	{ 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
> -	{ 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
> -	{ 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
> -	{ 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
> -	{ 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
> -	{1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
> -	{1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
> -	{1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
> +static const struct dphy_pll_parameter_map dppa_map[] = {
> +	{  90, 0x00, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> +	{ 100, 0x10, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> +	{ 110, 0x20, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> +	{ 130, 0x01, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 140, 0x11, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 150, 0x21, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 170, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> +	{ 180, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> +	{ 200, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> +	{ 220, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> +	{ 240, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> +	{ 250, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> +	{ 270, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
> +	{ 300, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
> +	{ 330, 0x05, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 360, 0x15, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 400, 0x25, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 450, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 500, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 550, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
> +	{ 600, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
> +	{ 650, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 700, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 750, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 800, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 850, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 900, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 950, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> +	{1000, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> +	{1050, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> +	{1100, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> +	{1150, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1200, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1250, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1300, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1350, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1400, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1450, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM}
>  };
>  
> -static int max_mbps_to_testdin(unsigned int max_mbps)
> +static int max_mbps_to_parameter(unsigned int max_mbps)
>  {
>  	int i;
>  
> -	for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
> -		if (dptdin_map[i].max_mbps > max_mbps)
> -			return dptdin_map[i].testdin;
> +	for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
> +		if (dppa_map[i].max_mbps > max_mbps)
> +			return i;
>  
>  	return -EINVAL;
>  }
> @@ -507,16 +549,16 @@ static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns)
>  
>  static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>  {
> -	int ret, testdin, vco, val;
> +	int ret, i, vco, val;
>  
>  	vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
>  
> -	testdin = max_mbps_to_testdin(dsi->lane_mbps);
> -	if (testdin < 0) {
> +	i = max_mbps_to_parameter(dsi->lane_mbps);
> +	if (i < 0) {
>  		dev_err(dsi->dev,
> -			"failed to get testdin for %dmbps lane clock\n",
> +			"failed to get parameter for %dmbps lane clock\n",
>  			dsi->lane_mbps);
> -		return testdin;
> +		return i;
>  	}
>  
>  	/* Start by clearing PHY state */
> @@ -537,13 +579,13 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>  			      REF_BIAS_CUR_SEL);
>  
>  	dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> -			      CP_CURRENT_3MA);
> +			      CP_CURRENT_SEL(dppa_map[i].icpctrl));
>  	dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
>  			      CP_PROGRAM_EN | LPF_PROGRAM_EN |
> -			      LPF_RESISTORS_20_KOHM);
> +			      LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
>  
>  	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> -			      HSFREQRANGE_SEL(testdin));
> +			      HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
>  
>  	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
>  			      INPUT_DIVIDER(dsi->input_div));
> @@ -632,7 +674,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>  {
>  	unsigned long mpclk, tmp;
>  	unsigned int target_mbps = 1000;
> -	unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> +	unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
>  	int bpp;
>  	unsigned long best_freq = 0;
>  	int lanes = dsi->lanes;
> -- 
> 1.9.1
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From dianders at chromium.org  Thu Oct 12 13:11:13 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 12 Oct 2017 13:11:13 -0700
Subject: [PATCH v2 0/5] mmc: dw_mmc: Fix the CTO timer patch,
 plus the DTO timer
Message-ID: <20171012201118.23570-1-dianders@chromium.org>

Recently we landed 03de19212ea3 ("mmc: dw_mmc: introduce timer for
broken command transfer over scheme").  I found a bunch of problems
with that patch, so this series attempts to solve some of them.

This also fixes the DTO timer in some of the same ways even though I
haven't personally seen problems with the DTO timer.

NOTE: this series has only been lighly tested so far.  I can at least
reproduce the need for the CTO timer on one of my devices and so I can
confirm that part still works.  As mentioned in the 3rd patch I also
ran the mmc_test kernel module on this and did manage to see the 3rd
patch doing something useful.

Changes in v2:
- Removed extra "int i"
- Fix the DTO timeout calculation new for v2
- Cleanup the DTO timer new for v2

Douglas Anderson (5):
  mmc: dw_mmc: cancel the CTO timer after a voltage switch
  mmc: dw_mmc: Fix the CTO timeout calculation
  mmc: dw_mmc: Add locking to the CTO timer
  mmc: dw_mmc: Fix the DTO timeout calculation
  mmc: dw_mmc: Cleanup the DTO timer like the CTO one

 drivers/mmc/host/dw_mmc.c | 162 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 146 insertions(+), 16 deletions(-)

-- 
2.15.0.rc0.271.g36b669edcc-goog



From dianders at chromium.org  Thu Oct 12 13:11:14 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 12 Oct 2017 13:11:14 -0700
Subject: [PATCH v2 1/5] mmc: dw_mmc: cancel the CTO timer after a voltage
 switch
In-Reply-To: <20171012201118.23570-1-dianders@chromium.org>
References: <20171012201118.23570-1-dianders@chromium.org>
Message-ID: <20171012201118.23570-2-dianders@chromium.org>

When running with the commit 03de19212ea3 ("mmc: dw_mmc: introduce
timer for broken command transfer over scheme") I found this message
in the log:
  Unexpected command timeout, state 7

It turns out that we weren't properly cancelling the new CTO timer in
the case that a voltage switch was done.  Let's promote the cancel
into the dw_mci_cmd_interrupt() function to fix this.

Fixes: 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command transfer over scheme")
Tested-by: Emil Renner Berthing <kernel at esmil.dk>
Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>
Signed-off-by: Douglas Anderson <dianders at chromium.org>
---

Changes in v2: None

 drivers/mmc/host/dw_mmc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 860313bd952a..f5b2bb4b4d98 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2570,6 +2570,8 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
 
 static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
 {
+	del_timer(&host->cto_timer);
+
 	if (!host->cmd_status)
 		host->cmd_status = status;
 
@@ -2662,7 +2664,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 		}
 
 		if (pending & SDMMC_INT_CMD_DONE) {
-			del_timer(&host->cto_timer);
 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
 			dw_mci_cmd_interrupt(host, pending);
 		}
-- 
2.15.0.rc0.271.g36b669edcc-goog



From dianders at chromium.org  Thu Oct 12 13:11:15 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 12 Oct 2017 13:11:15 -0700
Subject: [PATCH v2 2/5] mmc: dw_mmc: Fix the CTO timeout calculation
In-Reply-To: <20171012201118.23570-1-dianders@chromium.org>
References: <20171012201118.23570-1-dianders@chromium.org>
Message-ID: <20171012201118.23570-3-dianders@chromium.org>

In the commit 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken
command transfer over scheme") we tried to calculate the expected
hardware command timeout value.  Unfortunately that calculation isn't
quite correct in all cases.  It used "bus_hz" but, as far as I can
tell, it's supposed to use the card clock.  Let's account for the div
value, which is documented as 2x the value stored in the register, or
1 if the register is 0.

NOTE: It's not expected that this will actually fix anything important
since the 10 ms margin added by the function will pretty much dwarf
any calculations.  The card clock should be 100 kHz at minimum and:
  1000 ms/s * (255 * 2) / 100000 Hz.
Gives us 5.1 ms.

...so really the point of this patch is just to make the code more
"correct" in case anyone ever tries to remove the 10 ms buffer.

Fixes: 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command transfer over scheme")
Tested-by: Emil Renner Berthing <kernel at esmil.dk>
Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>
Signed-off-by: Douglas Anderson <dianders at chromium.org>
---

Changes in v2: None

 drivers/mmc/host/dw_mmc.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index f5b2bb4b4d98..16516c528a88 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -401,10 +401,14 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
 static inline void dw_mci_set_cto(struct dw_mci *host)
 {
 	unsigned int cto_clks;
+	unsigned int cto_div;
 	unsigned int cto_ms;
 
 	cto_clks = mci_readl(host, TMOUT) & 0xff;
-	cto_ms = DIV_ROUND_UP(cto_clks, host->bus_hz / 1000);
+	cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
+	if (cto_div == 0)
+		cto_div = 1;
+	cto_ms = DIV_ROUND_UP(MSEC_PER_SEC * cto_clks * cto_div, host->bus_hz);
 
 	/* add a bit spare time */
 	cto_ms += 10;
-- 
2.15.0.rc0.271.g36b669edcc-goog



From dianders at chromium.org  Thu Oct 12 13:11:16 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 12 Oct 2017 13:11:16 -0700
Subject: [PATCH v2 3/5] mmc: dw_mmc: Add locking to the CTO timer
In-Reply-To: <20171012201118.23570-1-dianders@chromium.org>
References: <20171012201118.23570-1-dianders@chromium.org>
Message-ID: <20171012201118.23570-4-dianders@chromium.org>

This attempts to instill a bit of paranoia to the code dealing with
the CTO timer.  It's believed that this will make the CTO timer more
robust in the case that we're having very long interrupt latencies.

Note that I originally thought that perhaps this patch was being
overly paranoid and wasn't really needed, but then while I was running
mmc_test on an rk3399 board I saw one instance of the message:
  dwmmc_rockchip fe320000.dwmmc: Unexpected interrupt latency

I had debug prints in the CTO timer code and I found that it was
running CMD 13 at the time.

...so even though this patch seems like it might be overly paranoid,
maybe it really isn't?

Presumably the bad interrupt latency experienced was due to the fact
that I had serial console enabled as serial console is typically where
I place blame when I see absurdly large interrupt latencies.  In this
particular case there was an (unrelated) printout to the serial
console just before I saw the "Unexpected interrupt latency" printout.

...and actually, I managed to even reproduce the problems by running
"iw mlan0 scan > /dev/null" while mmc_test was running.  That not only
does a bunch of PCIe traffic but it also (on my system) outputs some
SELinux log spam.

Fixes: 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command transfer over scheme")
Tested-by: Emil Renner Berthing <kernel at esmil.dk>
Signed-off-by: Douglas Anderson <dianders at chromium.org>
---

Changes in v2:
- Removed extra "int i"

 drivers/mmc/host/dw_mmc.c | 91 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 81 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 16516c528a88..50148991f30e 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -403,6 +403,7 @@ static inline void dw_mci_set_cto(struct dw_mci *host)
 	unsigned int cto_clks;
 	unsigned int cto_div;
 	unsigned int cto_ms;
+	unsigned long irqflags;
 
 	cto_clks = mci_readl(host, TMOUT) & 0xff;
 	cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
@@ -413,8 +414,24 @@ static inline void dw_mci_set_cto(struct dw_mci *host)
 	/* add a bit spare time */
 	cto_ms += 10;
 
-	mod_timer(&host->cto_timer,
-		  jiffies + msecs_to_jiffies(cto_ms) + 1);
+	/*
+	 * The durations we're working with are fairly short so we have to be
+	 * extra careful about synchronization here.  Specifically in hardware a
+	 * command timeout is _at most_ 5.1 ms, so that means we expect an
+	 * interrupt (either command done or timeout) to come rather quickly
+	 * after the mci_writel.  ...but just in case we have a long interrupt
+	 * latency let's add a bit of paranoia.
+	 *
+	 * In general we'll assume that at least an interrupt will be asserted
+	 * in hardware by the time the cto_timer runs.  ...and if it hasn't
+	 * been asserted in hardware by that time then we'll assume it'll never
+	 * come.
+	 */
+	spin_lock_irqsave(&host->irq_lock, irqflags);
+	if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events))
+		mod_timer(&host->cto_timer,
+			jiffies + msecs_to_jiffies(cto_ms) + 1);
+	spin_unlock_irqrestore(&host->irq_lock, irqflags);
 }
 
 static void dw_mci_start_command(struct dw_mci *host,
@@ -429,11 +446,11 @@ static void dw_mci_start_command(struct dw_mci *host,
 	wmb(); /* drain writebuffer */
 	dw_mci_wait_while_busy(host, cmd_flags);
 
+	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
+
 	/* response expected command only */
 	if (cmd_flags & SDMMC_CMD_RESP_EXP)
 		dw_mci_set_cto(host);
-
-	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
 }
 
 static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
@@ -1930,6 +1947,24 @@ static void dw_mci_set_drto(struct dw_mci *host)
 	mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));
 }
 
+static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
+{
+	if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events))
+		return false;
+
+	/*
+	 * Really be certain that the timer has stopped.  This is a bit of
+	 * paranoia and could only really happen if we had really bad
+	 * interrupt latency and the interrupt routine and timeout were
+	 * running concurrently so that the del_timer() in the interrupt
+	 * handler couldn't run.
+	 */
+	WARN_ON(del_timer_sync(&host->cto_timer));
+	clear_bit(EVENT_CMD_COMPLETE, &host->pending_events);
+
+	return true;
+}
+
 static void dw_mci_tasklet_func(unsigned long priv)
 {
 	struct dw_mci *host = (struct dw_mci *)priv;
@@ -1956,8 +1991,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
 		case STATE_SENDING_CMD11:
 		case STATE_SENDING_CMD:
-			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
-						&host->pending_events))
+			if (!dw_mci_clear_pending_cmd_complete(host))
 				break;
 
 			cmd = host->cmd;
@@ -2126,8 +2160,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
 			/* fall through */
 
 		case STATE_SENDING_STOP:
-			if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
-						&host->pending_events))
+			if (!dw_mci_clear_pending_cmd_complete(host))
 				break;
 
 			/* CMD error in data command */
@@ -2600,6 +2633,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 	struct dw_mci *host = dev_id;
 	u32 pending;
 	struct dw_mci_slot *slot = host->slot;
+	unsigned long irqflags;
 
 	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
 
@@ -2607,8 +2641,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 		/* Check volt switch first, since it can look like an error */
 		if ((host->state == STATE_SENDING_CMD11) &&
 		    (pending & SDMMC_INT_VOLT_SWITCH)) {
-			unsigned long irqflags;
-
 			mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);
 			pending &= ~SDMMC_INT_VOLT_SWITCH;
 
@@ -2624,11 +2656,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 		}
 
 		if (pending & DW_MCI_CMD_ERROR_FLAGS) {
+			spin_lock_irqsave(&host->irq_lock, irqflags);
+
 			del_timer(&host->cto_timer);
 			mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
 			host->cmd_status = pending;
 			smp_wmb(); /* drain writebuffer */
 			set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
+
+			spin_unlock_irqrestore(&host->irq_lock, irqflags);
 		}
 
 		if (pending & DW_MCI_DATA_ERROR_FLAGS) {
@@ -2668,8 +2704,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 		}
 
 		if (pending & SDMMC_INT_CMD_DONE) {
+			spin_lock_irqsave(&host->irq_lock, irqflags);
+
 			mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
 			dw_mci_cmd_interrupt(host, pending);
+
+			spin_unlock_irqrestore(&host->irq_lock, irqflags);
 		}
 
 		if (pending & SDMMC_INT_CD) {
@@ -2943,7 +2983,35 @@ static void dw_mci_cmd11_timer(unsigned long arg)
 static void dw_mci_cto_timer(unsigned long arg)
 {
 	struct dw_mci *host = (struct dw_mci *)arg;
+	unsigned long irqflags;
+	u32 pending;
+
+	spin_lock_irqsave(&host->irq_lock, irqflags);
 
+	/*
+	 * If somehow we have very bad interrupt latency it's remotely possible
+	 * that the timer could fire while the interrupt is still pending or
+	 * while the interrupt is midway through running.  Let's be paranoid
+	 * and detect those two cases.  Note that this is paranoia is somewhat
+	 * justified because in this function we don't actually cancel the
+	 * pending command in the controller--we just assume it will never come.
+	 */
+	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
+	if (pending & (DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_CMD_DONE)) {
+		/* The interrupt should fire; no need to act but we can warn */
+		dev_warn(host->dev, "Unexpected interrupt latency\n");
+		goto exit;
+	}
+	if (test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) {
+		/* Presumably interrupt handler couldn't delete the timer */
+		dev_warn(host->dev, "CTO timeout when already completed\n");
+		goto exit;
+	}
+
+	/*
+	 * Continued paranoia to make sure we're in the state we expect.
+	 * This paranoia isn't really justified but it seems good to be safe.
+	 */
 	switch (host->state) {
 	case STATE_SENDING_CMD11:
 	case STATE_SENDING_CMD:
@@ -2962,6 +3030,9 @@ static void dw_mci_cto_timer(unsigned long arg)
 			 host->state);
 		break;
 	}
+
+exit:
+	spin_unlock_irqrestore(&host->irq_lock, irqflags);
 }
 
 static void dw_mci_dto_timer(unsigned long arg)
-- 
2.15.0.rc0.271.g36b669edcc-goog



From dianders at chromium.org  Thu Oct 12 13:11:17 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 12 Oct 2017 13:11:17 -0700
Subject: [PATCH v2 4/5] mmc: dw_mmc: Fix the DTO timeout calculation
In-Reply-To: <20171012201118.23570-1-dianders@chromium.org>
References: <20171012201118.23570-1-dianders@chromium.org>
Message-ID: <20171012201118.23570-5-dianders@chromium.org>

Just like the CTO timeout calculation introduced recently, the DTO
timeout calculation was incorrect.  It used "bus_hz" but, as far as I
can tell, it's supposed to use the card clock.  Let's account for the
div value, which is documented as 2x the value stored in the register,
or 1 if the register is 0.

NOTE: This was likely not terribly important until commit 16a34574c6ca
("mmc: dw_mmc: remove the quirks flags") landed because "DIV" is
documented on Rockchip SoCs (the ones that used to define the quirk)
to always be 0 or 1.  ...and, in fact, it's documented to only be 1
with EMMC in 8-bit DDR52 mode.  Thus before the quirk was applied to
everyone it was mostly OK to ignore the DIV value.

I haven't personally observed any problems that are fixed by this
patch but I also haven't tested this anywhere with a DIV other an 0.
AKA: this problem was found simply by code inspection and I have no
failing test cases that are fixed by it.  Presumably this could fix
real bugs for someone out there, though.

Fixes: 16a34574c6ca ("mmc: dw_mmc: remove the quirks flags")
Signed-off-by: Douglas Anderson <dianders at chromium.org>
---

Changes in v2:
- Fix the DTO timeout calculation new for v2

 drivers/mmc/host/dw_mmc.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 50148991f30e..6bc87b1385a9 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1936,10 +1936,16 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
 static void dw_mci_set_drto(struct dw_mci *host)
 {
 	unsigned int drto_clks;
+	unsigned int drto_div;
 	unsigned int drto_ms;
+	unsigned long irqflags;
 
 	drto_clks = mci_readl(host, TMOUT) >> 8;
-	drto_ms = DIV_ROUND_UP(drto_clks, host->bus_hz / 1000);
+	drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
+	if (drto_div == 0)
+		drto_div = 1;
+	drto_ms = DIV_ROUND_UP(MSEC_PER_SEC * drto_clks * drto_div,
+			       host->bus_hz);
 
 	/* add a bit spare time */
 	drto_ms += 10;
-- 
2.15.0.rc0.271.g36b669edcc-goog



From dianders at chromium.org  Thu Oct 12 13:11:18 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 12 Oct 2017 13:11:18 -0700
Subject: [PATCH v2 5/5] mmc: dw_mmc: Cleanup the DTO timer like the CTO one
In-Reply-To: <20171012201118.23570-1-dianders@chromium.org>
References: <20171012201118.23570-1-dianders@chromium.org>
Message-ID: <20171012201118.23570-6-dianders@chromium.org>

The recent CTO timer introduced in commit 03de19212ea3 ("mmc: dw_mmc:
introduce timer for broken command transfer over scheme") was causing
observable problems due to race conditions.  Previous patches have
fixed those race conditions.

It can be observed that these same race conditions ought to be
theoretically possible with the DTO timer too though they are
massively less likely to happen because the data timeout is always set
to 0xffffff right now.  That means even at a 200 MHz card clock we
were arming the DTO timer for 94 ms:
  >>> (0xffffff * 1000. / 200000000) + 10
  93.886075

We always also were setting the DTO timer _after_ starting the
transfer, unlike how the old code was seting the CTO timer.

In any case, even though the DTO timer is much less likely to have
races, it still makes sense to add code to handle it _just in case_.

Signed-off-by: Douglas Anderson <dianders at chromium.org>
---

Changes in v2:
- Cleanup the DTO timer new for v2

 drivers/mmc/host/dw_mmc.c | 54 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 51 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 6bc87b1385a9..bc0808615431 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1950,7 +1950,11 @@ static void dw_mci_set_drto(struct dw_mci *host)
 	/* add a bit spare time */
 	drto_ms += 10;
 
-	mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));
+	spin_lock_irqsave(&host->irq_lock, irqflags);
+	if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
+		mod_timer(&host->dto_timer,
+			  jiffies + msecs_to_jiffies(drto_ms));
+	spin_unlock_irqrestore(&host->irq_lock, irqflags);
 }
 
 static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
@@ -1971,6 +1975,18 @@ static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
 	return true;
 }
 
+static bool dw_mci_clear_pending_data_complete(struct dw_mci *host)
+{
+	if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
+		return false;
+
+	/* Extra paranoia just like dw_mci_clear_pending_cmd_complete() */
+	WARN_ON(del_timer_sync(&host->dto_timer));
+	clear_bit(EVENT_DATA_COMPLETE, &host->pending_events);
+
+	return true;
+}
+
 static void dw_mci_tasklet_func(unsigned long priv)
 {
 	struct dw_mci *host = (struct dw_mci *)priv;
@@ -2112,8 +2128,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
 			/* fall through */
 
 		case STATE_DATA_BUSY:
-			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
-						&host->pending_events)) {
+			if (!dw_mci_clear_pending_data_complete(host)) {
 				/*
 				 * If data error interrupt comes but data over
 				 * interrupt doesn't come within the given time.
@@ -2683,6 +2698,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 		}
 
 		if (pending & SDMMC_INT_DATA_OVER) {
+			spin_lock_irqsave(&host->irq_lock, irqflags);
+
 			del_timer(&host->dto_timer);
 
 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
@@ -2695,6 +2712,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 			}
 			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
 			tasklet_schedule(&host->tasklet);
+
+			spin_unlock_irqrestore(&host->irq_lock, irqflags);
 		}
 
 		if (pending & SDMMC_INT_RXDR) {
@@ -3044,7 +3063,31 @@ static void dw_mci_cto_timer(unsigned long arg)
 static void dw_mci_dto_timer(unsigned long arg)
 {
 	struct dw_mci *host = (struct dw_mci *)arg;
+	unsigned long irqflags;
+	u32 pending;
+
+	spin_lock_irqsave(&host->irq_lock, irqflags);
 
+	/*
+	 * The DTO timer is much longer than the CTO timer, so it's even less
+	 * likely that we'll these cases, but it pays to be paranoid.
+	 */
+	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
+	if (pending & SDMMC_INT_DATA_OVER) {
+		/* The interrupt should fire; no need to act but we can warn */
+		dev_warn(host->dev, "Unexpected data interrupt latency\n");
+		goto exit;
+	}
+	if (test_bit(EVENT_DATA_COMPLETE, &host->pending_events)) {
+		/* Presumably interrupt handler couldn't delete the timer */
+		dev_warn(host->dev, "DTO timeout when already completed\n");
+		goto exit;
+	}
+
+	/*
+	 * Continued paranoia to make sure we're in the state we expect.
+	 * This paranoia isn't really justified but it seems good to be safe.
+	 */
 	switch (host->state) {
 	case STATE_SENDING_DATA:
 	case STATE_DATA_BUSY:
@@ -3059,8 +3102,13 @@ static void dw_mci_dto_timer(unsigned long arg)
 		tasklet_schedule(&host->tasklet);
 		break;
 	default:
+		dev_warn(host->dev, "Unexpected data timeout, state %d\n",
+			 host->state);
 		break;
 	}
+
+exit:
+	spin_unlock_irqrestore(&host->irq_lock, irqflags);
 }
 
 #ifdef CONFIG_OF
-- 
2.15.0.rc0.271.g36b669edcc-goog



From briannorris at chromium.org  Thu Oct 12 13:52:17 2017
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 Oct 2017 13:52:17 -0700
Subject: [PATCH 0/3] PCI: rockchip: assert PERST# in S3
Message-ID: <20171012205220.130048-1-briannorris@chromium.org>

Hi,

This patch series should mostly be self-descriptive, but it's motivated by the
fact that I've found differing requirements from PCIe endpoint makers regarding
the state of PERST# when in system suspend (S3). Additionally, some existing
boards are not especially well suited for holding PERST# low in S3 (e.g., the
pin is driven by a non-PMU GPIO, so it's hard or impossible to keep it
asserted). So the solution is...give it a device tree property!

Brian

Brian Norris (3):
  Documentation/devicetree: Add pcie-reset-suspend property
  of/pci: Add of_pci_get_pcie_reset_suspend() to parse
    pcie-reset-suspend
  PCI: rockchip: Support configuring PERST# state via DT

 Documentation/devicetree/bindings/pci/pci.txt | 11 +++++++++++
 drivers/of/of_pci.c                           | 25 +++++++++++++++++++++++++
 drivers/pci/host/pcie-rockchip.c              |  7 +++++++
 include/linux/of_pci.h                        |  7 +++++++
 4 files changed, 50 insertions(+)

-- 
2.15.0.rc0.271.g36b669edcc-goog



From briannorris at chromium.org  Thu Oct 12 13:52:20 2017
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 Oct 2017 13:52:20 -0700
Subject: [PATCH 3/3] PCI: rockchip: Support configuring PERST# state via DT
In-Reply-To: <20171012205220.130048-1-briannorris@chromium.org>
References: <20171012205220.130048-1-briannorris@chromium.org>
Message-ID: <20171012205220.130048-4-briannorris@chromium.org>

I've found that different endpoints and board configurations have
required different behavior from the PCIe Reset (PERST#) signal when in
low-power system suspend (e.g., S3). Use the new of_pci helper to
request this state and assert (active low) PERST# before suspending.

Note that we reinitialize the link (including reconfiguring PERST#) at
resume time.

This requires that the board and system firmware supports driving this
signal low when the system is suspended, since PERST# may be pulled up
by the endpoint, and some GPIO banks are not active in S3.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 drivers/pci/host/pcie-rockchip.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
index 9051c6c8fea4..1ab58c1abb34 100644
--- a/drivers/pci/host/pcie-rockchip.c
+++ b/drivers/pci/host/pcie-rockchip.c
@@ -233,6 +233,7 @@ struct rockchip_pcie {
 	struct	regulator *vpcie1v8; /* 1.8V power supply */
 	struct	regulator *vpcie0v9; /* 0.9V power supply */
 	struct	gpio_desc *ep_gpio;
+	bool	suspend_reset;
 	u32	lanes;
 	u8      lanes_map;
 	u8	root_bus_nr;
@@ -1155,6 +1156,9 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
 		dev_info(dev, "no vpcie0v9 regulator found\n");
 	}
 
+	/* Default not-asserted, to retain backward compatibility. */
+	rockchip->suspend_reset = of_pci_get_pcie_reset_suspend(node) > 0;
+
 	return 0;
 }
 
@@ -1463,6 +1467,9 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev)
 		return ret;
 	}
 
+	if (rockchip->suspend_reset)
+		gpiod_set_value(rockchip->ep_gpio, 0);
+
 	rockchip_pcie_deinit_phys(rockchip);
 
 	rockchip_pcie_disable_clocks(rockchip);
-- 
2.15.0.rc0.271.g36b669edcc-goog



From briannorris at chromium.org  Thu Oct 12 13:52:18 2017
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 Oct 2017 13:52:18 -0700
Subject: [PATCH 1/3] Documentation/devicetree: Add pcie-reset-suspend property
In-Reply-To: <20171012205220.130048-1-briannorris@chromium.org>
References: <20171012205220.130048-1-briannorris@chromium.org>
Message-ID: <20171012205220.130048-2-briannorris@chromium.org>

The patch is self-descriptive. I've found that we may need
platform-specific behavior for the PERST# signal in system suspend,
depending on the type of PCIe endpoints are attached.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 Documentation/devicetree/bindings/pci/pci.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt
index c77981c5dd18..91339b6d0652 100644
--- a/Documentation/devicetree/bindings/pci/pci.txt
+++ b/Documentation/devicetree/bindings/pci/pci.txt
@@ -24,3 +24,14 @@ driver implementation may support the following properties:
    unsupported link speed, for instance, trying to do training for
    unsupported link speed, etc.  Must be '4' for gen4, '3' for gen3, '2'
    for gen2, and '1' for gen1. Any other values are invalid.
+- pcie-reset-suspend:
+   If present this property defines whether the PCIe Reset signal (referred to
+   as PERST#) should be asserted when the system enters low-power suspend modes
+   (e.g., S3). Depending on the form factor, the associated PCIe
+   electromechanical specification may specify a particular behavior (e.g.,
+   "PERST# is asserted in advance of the power being switched off in a
+   power-managed state like S3") or it may be less clear. The net result is
+   that some endpoints perform better (e.g., lower power consumption) with
+   PERST# asserted, and others prefer PERST# deasserted. The value must be '0'
+   or '1', where '0' means do not assert PERST# and '1' means assert PERST#.
+   When absent, behavior may be platform-specific.
-- 
2.15.0.rc0.271.g36b669edcc-goog



From briannorris at chromium.org  Thu Oct 12 13:52:19 2017
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 Oct 2017 13:52:19 -0700
Subject: [PATCH 2/3] of/pci: Add of_pci_get_pcie_reset_suspend() to parse
 pcie-reset-suspend
In-Reply-To: <20171012205220.130048-1-briannorris@chromium.org>
References: <20171012205220.130048-1-briannorris@chromium.org>
Message-ID: <20171012205220.130048-3-briannorris@chromium.org>

This helper can be used by drivers to determine the expected PERST#
behavior when in low-power system suspend (e.g., S3). I've found the
expected behavior to vary across a few different endpoint
implementations.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 drivers/of/of_pci.c    | 25 +++++++++++++++++++++++++
 include/linux/of_pci.h |  7 +++++++
 2 files changed, 32 insertions(+)

diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index e9ec931f5b9a..ab2586f86094 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -137,6 +137,31 @@ int of_pci_get_max_link_speed(struct device_node *node)
 }
 EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);
 
+/**
+ * This function returns true if the PCIe controller should assert PCIe Reset
+ * (PERST#) when entering system suspend (e.g., S3).
+ *
+ * @node: device tree node with the reset property
+ *
+ * Returns 1 (meaning "assert reset") or 0 ("don't assert reset"), if the DT
+ * defined a valid behavior. Otherwise, returns a negative error code.
+ */
+int of_pci_get_pcie_reset_suspend(struct device_node *node)
+{
+	int ret;
+	u32 val;
+
+	ret = of_property_read_u32(node, "pcie-reset-suspend", &val);
+	if (ret)
+		return ret;
+
+	if (val > 1)
+		return -EINVAL;
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(of_pci_get_pcie_reset_suspend);
+
 /**
  * of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only
  *                           is present and valid
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 518c8d20647a..df453893080b 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -17,6 +17,7 @@ int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
 int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
 int of_get_pci_domain_nr(struct device_node *node);
 int of_pci_get_max_link_speed(struct device_node *node);
+int of_pci_get_pcie_reset_suspend(struct device_node *node);
 void of_pci_check_probe_only(void);
 int of_pci_map_rid(struct device_node *np, u32 rid,
 		   const char *map_name, const char *map_mask_name,
@@ -69,6 +70,12 @@ of_pci_get_max_link_speed(struct device_node *node)
 	return -EINVAL;
 }
 
+static inline int
+of_pci_get_pcie_reset_suspend(struct device_node *node)
+{
+	return -EINVAL;
+}
+
 static inline void of_pci_check_probe_only(void) { }
 #endif
 
-- 
2.15.0.rc0.271.g36b669edcc-goog



From dianders at chromium.org  Thu Oct 12 15:27:16 2017
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 12 Oct 2017 15:27:16 -0700
Subject: [PATCH 0/3] PCI: rockchip: assert PERST# in S3
In-Reply-To: <20171012205220.130048-1-briannorris@chromium.org>
References: <20171012205220.130048-1-briannorris@chromium.org>
Message-ID: <CAD=FV=VyERPq9yGE27Uvj6bs4Mru81gZAiqCOP=yQv3ai6-YDQ@mail.gmail.com>

Hi,

On Thu, Oct 12, 2017 at 1:52 PM, Brian Norris <briannorris at chromium.org> wrote:
> Hi,
>
> This patch series should mostly be self-descriptive, but it's motivated by the
> fact that I've found differing requirements from PCIe endpoint makers regarding
> the state of PERST# when in system suspend (S3). Additionally, some existing
> boards are not especially well suited for holding PERST# low in S3 (e.g., the
> pin is driven by a non-PMU GPIO, so it's hard or impossible to keep it
> asserted). So the solution is...give it a device tree property!
>
> Brian
>
> Brian Norris (3):
>   Documentation/devicetree: Add pcie-reset-suspend property
>   of/pci: Add of_pci_get_pcie_reset_suspend() to parse
>     pcie-reset-suspend
>   PCI: rockchip: Support configuring PERST# state via DT
>
>  Documentation/devicetree/bindings/pci/pci.txt | 11 +++++++++++
>  drivers/of/of_pci.c                           | 25 +++++++++++++++++++++++++
>  drivers/pci/host/pcie-rockchip.c              |  7 +++++++
>  include/linux/of_pci.h                        |  7 +++++++
>  4 files changed, 50 insertions(+)

I'm nowhere near an expert on PCIe, but overall the series seems sane
to me.  ...and I'd agree that the discussions I've seen from different
vendors seem to have different opinions about what we should do with
this line in S3.  ...so FWIW:

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From briannorris at chromium.org  Thu Oct 12 18:56:22 2017
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 Oct 2017 18:56:22 -0700
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20170911151029.25185-2-jeffy.chen@rock-chips.com>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
Message-ID: <20171013015620.GA94568@google.com>

Hi,

On Mon, Sep 11, 2017 at 11:10:27PM +0800, Jeffy Chen wrote:
> Add support for PCIE_WAKE pin in rockchip pcie driver.
> 
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v5:
> Rebase
> 
> Changes in v3:
> Fix error handling
> 
> Changes in v2:
> Use dev_pm_set_dedicated_wake_irq
>         -- Suggested by Brian Norris <briannorris at chromium.com>
> 
>  drivers/pci/host/pcie-rockchip.c | 19 +++++++++++++++++--
>  1 file changed, 17 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> index 9051c6c8fea4..a8b7272597a7 100644
> --- a/drivers/pci/host/pcie-rockchip.c
> +++ b/drivers/pci/host/pcie-rockchip.c
> @@ -37,6 +37,7 @@
>  #include <linux/pci_ids.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_wakeirq.h>
>  #include <linux/reset.h>
>  #include <linux/regmap.h>
>  
> @@ -995,6 +996,15 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
>  		return err;
>  	}
>  
> +	/* Must init wakeup before setting dedicated wakeup irq. */
> +	device_init_wakeup(dev, true);

Am I crazy, or should this go inside the 'irq >= 0' conditional?
Otherwise, for the whole series:

Reviewed-by: Brian Norris <briannorris at chromium.org>
Tested-by: Brian Norris <briannorris at chromium.org>

Bjorn, were you planning to pick this up?

Also, the DT binding change conflicts (just simple context) with the
PERST# series I just sent out. Would be good if we could land one or
both :)

Thanks,
Brian

> +	irq = platform_get_irq_byname(pdev, "wakeup");
> +	if (irq >= 0) {
> +		err = dev_pm_set_dedicated_wake_irq(dev, irq);
> +		if (err)
> +			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
> +	}
> +
>  	return 0;
>  }
>  
> @@ -1542,11 +1552,11 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
>  
>  	err = rockchip_pcie_parse_dt(rockchip);
>  	if (err)
> -		return err;
> +		goto err_disable_wake;
>  
>  	err = rockchip_pcie_enable_clocks(rockchip);
>  	if (err)
> -		return err;
> +		goto err_disable_wake;
>  
>  	err = rockchip_pcie_set_vpcie(rockchip);
>  	if (err) {
> @@ -1656,6 +1666,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
>  		regulator_disable(rockchip->vpcie0v9);
>  err_set_vpcie:
>  	rockchip_pcie_disable_clocks(rockchip);
> +err_disable_wake:
> +	dev_pm_clear_wake_irq(dev);
> +	device_init_wakeup(dev, false);
>  	return err;
>  }
>  
> @@ -1682,6 +1695,8 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
>  	if (!IS_ERR(rockchip->vpcie0v9))
>  		regulator_disable(rockchip->vpcie0v9);
>  
> +	dev_pm_clear_wake_irq(dev);
> +	device_init_wakeup(dev, false);
>  	return 0;
>  }
>  
> -- 
> 2.11.0
> 
> 


From mark.yao at rock-chips.com  Thu Oct 12 19:28:07 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Fri, 13 Oct 2017 10:28:07 +0800
Subject: [PATCH] drm/rockchip: add PINCTRL dependency for LVDS
In-Reply-To: <20171005120957.485433-1-arnd@arndb.de>
References: <20171005120957.485433-1-arnd@arndb.de>
Message-ID: <c0d08177-00b6-7d20-5fd0-5d4a9b3c2b7b@rock-chips.com>

On 2017?10?05? 20:09, Arnd Bergmann wrote:
> The new driver fails to build when CONFIG_PINCTRL is disabled:
>
> drivers/gpu/drm/rockchip/rockchip_lvds.c: In function 'rockchip_lvds_grf_config':
> drivers/gpu/drm/rockchip/rockchip_lvds.c:229:39: error: dereferencing pointer to incomplete type 'struct dev_pin_info'
>     if (lvds->pins && !IS_ERR(lvds->pins->default_state))
>
> This adds the respective Kconfig dependency.
>
> Fixes: 34cc0aa25456 ("drm/rockchip: Add support for Rockchip Soc LVDS")
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>

Pushed to drm-misc-next

Thanks
Mark



From helgaas at kernel.org  Thu Oct 12 19:32:47 2017
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Thu, 12 Oct 2017 21:32:47 -0500
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171013015620.GA94568@google.com>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
 <20171013015620.GA94568@google.com>
Message-ID: <20171013023246.GZ25517@bhelgaas-glaptop.roam.corp.google.com>

On Thu, Oct 12, 2017 at 06:56:22PM -0700, Brian Norris wrote:
> Hi,
> 
> On Mon, Sep 11, 2017 at 11:10:27PM +0800, Jeffy Chen wrote:
> > Add support for PCIE_WAKE pin in rockchip pcie driver.
> > 
> > Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> > ---
> > 
> > Changes in v5:
> > Rebase
> > 
> > Changes in v3:
> > Fix error handling
> > 
> > Changes in v2:
> > Use dev_pm_set_dedicated_wake_irq
> >         -- Suggested by Brian Norris <briannorris at chromium.com>
> > 
> >  drivers/pci/host/pcie-rockchip.c | 19 +++++++++++++++++--
> >  1 file changed, 17 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> > index 9051c6c8fea4..a8b7272597a7 100644
> > --- a/drivers/pci/host/pcie-rockchip.c
> > +++ b/drivers/pci/host/pcie-rockchip.c
> > @@ -37,6 +37,7 @@
> >  #include <linux/pci_ids.h>
> >  #include <linux/phy/phy.h>
> >  #include <linux/platform_device.h>
> > +#include <linux/pm_wakeirq.h>
> >  #include <linux/reset.h>
> >  #include <linux/regmap.h>
> >  
> > @@ -995,6 +996,15 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
> >  		return err;
> >  	}
> >  
> > +	/* Must init wakeup before setting dedicated wakeup irq. */
> > +	device_init_wakeup(dev, true);
> 
> Am I crazy, or should this go inside the 'irq >= 0' conditional?
> Otherwise, for the whole series:
> 
> Reviewed-by: Brian Norris <briannorris at chromium.org>
> Tested-by: Brian Norris <briannorris at chromium.org>
> 
> Bjorn, were you planning to pick this up?

I had already applied this to pci/host-rockchip, but I must have gotten
interrupted before sending the email.

But now that you mention it, I looked at this again and have some
questions.  I'll respond to the original patch.

> Also, the DT binding change conflicts (just simple context) with the
> PERST# series I just sent out. Would be good if we could land one or
> both :)
> 
> Thanks,
> Brian
> 
> > +	irq = platform_get_irq_byname(pdev, "wakeup");
> > +	if (irq >= 0) {
> > +		err = dev_pm_set_dedicated_wake_irq(dev, irq);
> > +		if (err)
> > +			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
> > +	}
> > +
> >  	return 0;
> >  }
> >  
> > @@ -1542,11 +1552,11 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
> >  
> >  	err = rockchip_pcie_parse_dt(rockchip);
> >  	if (err)
> > -		return err;
> > +		goto err_disable_wake;
> >  
> >  	err = rockchip_pcie_enable_clocks(rockchip);
> >  	if (err)
> > -		return err;
> > +		goto err_disable_wake;
> >  
> >  	err = rockchip_pcie_set_vpcie(rockchip);
> >  	if (err) {
> > @@ -1656,6 +1666,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
> >  		regulator_disable(rockchip->vpcie0v9);
> >  err_set_vpcie:
> >  	rockchip_pcie_disable_clocks(rockchip);
> > +err_disable_wake:
> > +	dev_pm_clear_wake_irq(dev);
> > +	device_init_wakeup(dev, false);
> >  	return err;
> >  }
> >  
> > @@ -1682,6 +1695,8 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
> >  	if (!IS_ERR(rockchip->vpcie0v9))
> >  		regulator_disable(rockchip->vpcie0v9);
> >  
> > +	dev_pm_clear_wake_irq(dev);
> > +	device_init_wakeup(dev, false);
> >  	return 0;
> >  }
> >  
> > -- 
> > 2.11.0
> > 
> > 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


From helgaas at kernel.org  Thu Oct 12 20:04:41 2017
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Thu, 12 Oct 2017 22:04:41 -0500
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20170911151029.25185-2-jeffy.chen@rock-chips.com>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
Message-ID: <20171013030441.GA25517@bhelgaas-glaptop.roam.corp.google.com>

[+cc Rafael, linux-pm]

On Mon, Sep 11, 2017 at 11:10:27PM +0800, Jeffy Chen wrote:
> Add support for PCIE_WAKE pin in rockchip pcie driver.
> 
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v5:
> Rebase
> 
> Changes in v3:
> Fix error handling
> 
> Changes in v2:
> Use dev_pm_set_dedicated_wake_irq
>         -- Suggested by Brian Norris <briannorris at chromium.com>
> 
>  drivers/pci/host/pcie-rockchip.c | 19 +++++++++++++++++--
>  1 file changed, 17 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> index 9051c6c8fea4..a8b7272597a7 100644
> --- a/drivers/pci/host/pcie-rockchip.c
> +++ b/drivers/pci/host/pcie-rockchip.c
> @@ -37,6 +37,7 @@
>  #include <linux/pci_ids.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_wakeirq.h>
>  #include <linux/reset.h>
>  #include <linux/regmap.h>
>  
> @@ -995,6 +996,15 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
>  		return err;
>  	}
>  
> +	/* Must init wakeup before setting dedicated wakeup irq. */
> +	device_init_wakeup(dev, true);
> +	irq = platform_get_irq_byname(pdev, "wakeup");
> +	if (irq >= 0) {
> +		err = dev_pm_set_dedicated_wake_irq(dev, irq);

I'm a little skeptical about dev_pm_set_dedicated_wake_irq(), not
because I know anything at all about it, but because there are only
five callers in the whole tree, three of which are in UART code, and
none in anything resembling PCI code.

Is Rockchip really that special, or are we going about this the wrong
way?

> +		if (err)
> +			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
> +	}
> +
>  	return 0;

The above could be structured as:

  irq = platform_get_irq_byname(pdev, "wakeup");
  if (irq < 0)
    return 0;

  device_init_wakeup(dev, true);
  err = dev_pm_set_dedicated_wake_irq(dev, irq);
  if (err) {
    dev_pm_clear_wake_irq(dev);
    device_init_wakeup(dev, false);
  }

  return 0;

to unindent the mainline non-error code.

>  }
>  
> @@ -1542,11 +1552,11 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
>  
>  	err = rockchip_pcie_parse_dt(rockchip);
>  	if (err)
> -		return err;
> +		goto err_disable_wake;
>  
>  	err = rockchip_pcie_enable_clocks(rockchip);
>  	if (err)
> -		return err;
> +		goto err_disable_wake;
>  
>  	err = rockchip_pcie_set_vpcie(rockchip);
>  	if (err) {
> @@ -1656,6 +1666,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
>  		regulator_disable(rockchip->vpcie0v9);
>  err_set_vpcie:
>  	rockchip_pcie_disable_clocks(rockchip);
> +err_disable_wake:
> +	dev_pm_clear_wake_irq(dev);
> +	device_init_wakeup(dev, false);

I think this error cleanup should be done in rockchip_pcie_setup_irq()
as shown above.  There's no real connection between
rockchip_pcie_probe() and the wake setup.

>  	return err;
>  }
>  
> @@ -1682,6 +1695,8 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
>  	if (!IS_ERR(rockchip->vpcie0v9))
>  		regulator_disable(rockchip->vpcie0v9);
>  
> +	dev_pm_clear_wake_irq(dev);
> +	device_init_wakeup(dev, false);
>  	return 0;
>  }
>  
> -- 
> 2.11.0
> 
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


From helgaas at kernel.org  Thu Oct 12 20:15:23 2017
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Thu, 12 Oct 2017 22:15:23 -0500
Subject: [PATCH 0/3] PCI: rockchip: assert PERST# in S3
In-Reply-To: <20171012205220.130048-1-briannorris@chromium.org>
References: <20171012205220.130048-1-briannorris@chromium.org>
Message-ID: <20171013031523.GB25517@bhelgaas-glaptop.roam.corp.google.com>

On Thu, Oct 12, 2017 at 01:52:17PM -0700, Brian Norris wrote:
> Hi,
> 
> This patch series should mostly be self-descriptive, but it's motivated by the
> fact that I've found differing requirements from PCIe endpoint makers regarding
> the state of PERST# when in system suspend (S3). Additionally, some existing
> boards are not especially well suited for holding PERST# low in S3 (e.g., the
> pin is driven by a non-PMU GPIO, so it's hard or impossible to keep it
> asserted). So the solution is...give it a device tree property!

How do ACPI systems solve this problem?

Can you point to any relevant sections in the PCI specs?

Is this a hole in those specs?  Is this something that needs to be
clarified by the PCI-SIG to improve interoperability?

Why is this problem only showing up now?

> Brian Norris (3):
>   Documentation/devicetree: Add pcie-reset-suspend property
>   of/pci: Add of_pci_get_pcie_reset_suspend() to parse
>     pcie-reset-suspend
>   PCI: rockchip: Support configuring PERST# state via DT
> 
>  Documentation/devicetree/bindings/pci/pci.txt | 11 +++++++++++
>  drivers/of/of_pci.c                           | 25 +++++++++++++++++++++++++
>  drivers/pci/host/pcie-rockchip.c              |  7 +++++++
>  include/linux/of_pci.h                        |  7 +++++++
>  4 files changed, 50 insertions(+)
> 
> -- 
> 2.15.0.rc0.271.g36b669edcc-goog
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


From dianders at chromium.org  Thu Oct 12 21:20:09 2017
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 12 Oct 2017 21:20:09 -0700
Subject: [PATCH v2 3/5] mmc: dw_mmc: Add locking to the CTO timer
In-Reply-To: <41ae1571-4723-2700-1f03-7215e874c42e@rock-chips.com>
References: <20171012201118.23570-1-dianders@chromium.org>
 <20171012201118.23570-4-dianders@chromium.org>
 <41ae1571-4723-2700-1f03-7215e874c42e@rock-chips.com>
Message-ID: <CAD=FV=UMuJBKV2-pNo4yiyfxXxYJo_tX6RkxCCzm_UFg9XyjyQ@mail.gmail.com>

Shawn,

On Thu, Oct 12, 2017 at 6:32 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>
> On 2017/10/13 4:11, Douglas Anderson wrote:
>>
>> This attempts to instill a bit of paranoia to the code dealing with
>> the CTO timer.  It's believed that this will make the CTO timer more
>> robust in the case that we're having very long interrupt latencies.
>>
>
> Ack. It could help fix some problems observed.
>
>
>> Note that I originally thought that perhaps this patch was being
>> overly paranoid and wasn't really needed, but then while I was running
>> mmc_test on an rk3399 board I saw one instance of the message:
>>    dwmmc_rockchip fe320000.dwmmc: Unexpected interrupt latency
>>
>> I had debug prints in the CTO timer code and I found that it was
>> running CMD 13 at the time.
>>
>> ...so even though this patch seems like it might be overly paranoid,
>> maybe it really isn't?
>>
>> Presumably the bad interrupt latency experienced was due to the fact
>> that I had serial console enabled as serial console is typically where
>> I place blame when I see absurdly large interrupt latencies.  In this
>> particular case there was an (unrelated) printout to the serial
>> console just before I saw the "Unexpected interrupt latency" printout.
>>
>> ...and actually, I managed to even reproduce the problems by running
>> "iw mlan0 scan > /dev/null" while mmc_test was running.  That not only
>> does a bunch of PCIe traffic but it also (on my system) outputs some
>> SELinux log spam.
>> > Fixes: 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command
>
> transfer over scheme")
>>
>> Tested-by: Emil Renner Berthing <kernel at esmil.dk>
>> Signed-off-by: Douglas Anderson <dianders at chromium.org>
>> ---
>>
>> Changes in v2:
>> - Removed extra "int i"
>>
>>   drivers/mmc/host/dw_mmc.c | 91
>> +++++++++++++++++++++++++++++++++++++++++------
>>   1 file changed, 81 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 16516c528a88..50148991f30e 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -403,6 +403,7 @@ static inline void dw_mci_set_cto(struct dw_mci *host)
>>         unsigned int cto_clks;
>>         unsigned int cto_div;
>>         unsigned int cto_ms;
>> +       unsigned long irqflags;
>>         cto_clks = mci_readl(host, TMOUT) & 0xff;
>>         cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
>> @@ -413,8 +414,24 @@ static inline void dw_mci_set_cto(struct dw_mci
>> *host)
>>         /* add a bit spare time */
>>         cto_ms += 10;
>>   -     mod_timer(&host->cto_timer,
>> -                 jiffies + msecs_to_jiffies(cto_ms) + 1);
>> +       /*
>> +        * The durations we're working with are fairly short so we have to
>> be
>> +        * extra careful about synchronization here.  Specifically in
>> hardware a
>> +        * command timeout is _at most_ 5.1 ms, so that means we expect an
>> +        * interrupt (either command done or timeout) to come rather
>> quickly
>> +        * after the mci_writel.  ...but just in case we have a long
>> interrupt
>> +        * latency let's add a bit of paranoia.
>> +        *
>> +        * In general we'll assume that at least an interrupt will be
>> asserted
>> +        * in hardware by the time the cto_timer runs.  ...and if it
>> hasn't
>> +        * been asserted in hardware by that time then we'll assume it'll
>> never
>> +        * come.
>> +        */
>> +       spin_lock_irqsave(&host->irq_lock, irqflags);
>> +       if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events))
>> +               mod_timer(&host->cto_timer,
>> +                       jiffies + msecs_to_jiffies(cto_ms) + 1);
>> +       spin_unlock_irqrestore(&host->irq_lock, irqflags);
>
>
> IIUC, this change is beacuse you move
> mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START) before
> setting up the timer, so there is a timing gap that the cmd_done
> already comes and handled by dw_mci_interrupt->dw_mci_cmd_interrupt.
> At this point, we don't need the cto timer at all.

As per below, if I don't move the mci_writel() before setting up the
timer then there's still a race.  ...and actually that race was harder
for me to write code for, but I invite you to try to see if it's
somehow cleaner.


>>   }
>>     static void dw_mci_start_command(struct dw_mci *host,
>> @@ -429,11 +446,11 @@ static void dw_mci_start_command(struct dw_mci
>> *host,
>>         wmb(); /* drain writebuffer */
>>         dw_mci_wait_while_busy(host, cmd_flags);
>>   +     mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
>> +
>>         /* response expected command only */
>>         if (cmd_flags & SDMMC_CMD_RESP_EXP)
>>                 dw_mci_set_cto(host);
>> -
>> -       mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
>
>
>
> But why? If we still keep the original logic, it's always correct
> that cmd_done comes after setting up the cto timer. So could you
> eleborate a bit more to help me understand the real intention here?

No matter which order you put things, there's a race one way or the
other.  You need a lock.

Let's think about the old code you wrote.  You did this:
1. Start the CTO timer.
2. Start the command.

Now if you (somehow) take 20 ms to handle the interrupt, then this happens:

1. Start the CTO timer.
2. Start the command.
3. Interrupt is pending, but interrupt handler doesn't run yet.
4. CTO timer fires and enqueues CTO timeout.
5. Interrupt finally fires.


Now normally things are pretty bad if you've got an interrupt latency
of 20 ms.  ...and, in fact, I originally wrote up a commit that simply
explained why the race didn't matter and was thinking of posting that
instead of this one.  I wrote up:

     * Start a timer to detect missing cmd timeout if we expect a response.
     *
     * Note that we need to be a little careful about race conditions here
     * since our timer will be racing with the actual hardware interrupt
     * and things would get confused if both of them happened.
     *
     * We end up avoiding races here mostly because of our 10 ms "spare
     * time" buffer above.  That's probably reliable enough because:
     * - There's "guaranteed" "very little" time between setting the timer
     *   and starting the command.  We're holding a spinlock (host->lock)
     *   in all calls to this function so we won't get preempted.  Possibly
     *   we could get interrupts still, but that shouldn't add up to
     *   anything like the 10 ms spare time.
     * - We expect that when the actual interrupt fires that our interrupt
     *   routine should get called "relatively quickly" (compared to the
     *   10 ms buffer) and will be able to cancel this timer.

...but then I ran a whole bunch of tests and I found that, as far as I
could tell, we actually _were_ getting a super long interrupt latency.
Specifically I saw the printout "Unexpected interrupt latency" in my
patch.  In order to see that printout in my patch (which even starts
the command _before_ the CTO timer), the only explanation is bad
interrupt latency, right?  Also: based on my past experience I believe
it is possible to get upwards of 100 ms interrupt latency if you've
got serial console enabled.  printk, especially printk from an
interrupt context, can do some funny things.


...but this stuff is always hard to get right, so if I messed up the
above please let me know!  I tried to think of all of the cases so it
would work no matter if delays happened in any random place but
concurrency is hard.


-Doug


From briannorris at chromium.org  Thu Oct 12 23:27:29 2017
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 Oct 2017 23:27:29 -0700
Subject: [PATCH 0/3] PCI: rockchip: assert PERST# in S3
In-Reply-To: <20171013031523.GB25517@bhelgaas-glaptop.roam.corp.google.com>
References: <20171012205220.130048-1-briannorris@chromium.org>
 <20171013031523.GB25517@bhelgaas-glaptop.roam.corp.google.com>
Message-ID: <20171013062728.GA56763@google.com>

Hi Bjorn,

On Thu, Oct 12, 2017 at 10:15:23PM -0500, Bjorn Helgaas wrote:
> On Thu, Oct 12, 2017 at 01:52:17PM -0700, Brian Norris wrote:
> > Hi,
> > 
> > This patch series should mostly be self-descriptive, but it's motivated by the
> > fact that I've found differing requirements from PCIe endpoint makers regarding
> > the state of PERST# when in system suspend (S3). Additionally, some existing
> > boards are not especially well suited for holding PERST# low in S3 (e.g., the
> > pin is driven by a non-PMU GPIO, so it's hard or impossible to keep it
> > asserted). So the solution is...give it a device tree property!
> 
> How do ACPI systems solve this problem?

I don't really know, because by design ACPI is rather opaque. And I
expect people like it that way.

But from the very little experience I've had looking at ACPI
configuration, this is done on a case-by-case basis. I've heard of cases
where an Intel-based S0ix suspend-to-idle can't reinitialize PCIe
devices reliably if PERST# was asserted and so...the firmware designers
just hacked around it by not asserting PERST# (there was no difference
in power consumption for this endpoint).

For the case I'm particularly looking at (the Wifi card vendor that
suggests not to assert PERST#)...I haven't tested them on an ACPI-based
system. But they claimed that their Windows/ACPI systems don't enter L2
or assert PERST# at all -- they stay in L1.x. But then, I'm not sure
this vendor has been very successful in the desktop/laptop market, where
ACPI is common.

But I'll elaborate a little on my problems on this non-ACPI system,
where apparently I have to defend things in the open, since they're not
hidden behind an opaque BIOS :)

I'm looking at 2 different Wifi card vendors, both in M.2-compliant
packages, and using them on Rockchip RK3399. We want to support
Wake-on-WLAN, and these cards do not have an "auxiliary" power, so we
leave them fully powered in system suspend (S3) and expect them to enter
low power states when prompted. Rockchip supports L0, L0s, L1, and L2/3
link states, but no L1.1 or L1.2. Its PCIe reference clock is driven off
a clock which powers off in S3, and so by my understanding, the only
legal transition is to enter L2/L3 link state before suspend.

Now, one of these 2 Wifi vendors claims higher power consumption with
PERST# asserted, because they exit L2 and go into a detect state. They
also seem to claim that on some Windows/ACPI systems leave their link in
L1.x states in system suspend, and PERST# is not involved there either.

The other vendor is the opposite: when PERST# is not asserted, power
consumption in L2 link state is higher, and (because device is not in D3
cold?) PCIE WAKE# will not activate. After a closer reading of the PCIe
specs, this seems to be a more correct reading of the specs.

> Can you point to any relevant sections in the PCI specs?

Sure, I can try.

Per the above discussion, we expect to enter L2 link state when
suspending. The PCIe Base Specification 3.1 section 5.3.2.3 (Entry into
the L2/L3 Ready State) describes the L2/L3 transition sequence,
involving the PME_Turn_Off and PME_TO_Ack messages. It doesn't describe
what to do with PERST#.

Separately, the PCI Express Card Electromechanical Specification
Revision 3.0 talks about PERST#. Its main description is in section 2:

"PERST# (required): indicates when the applied main power is within the
specified tolerance and stable."

Considering we always keep main power on for the endpoint, this doesn't
appear to suggest anything.

There is more language in 2.2, but it's less clear:

"PERST# is asserted in advance of the power being switched off in a
power-managed state like S3."

Again, no power is switched off. And what is a "state like S3"? Rather
vague. The "S3" I refer to for RK3399 is not determined by an ACPI spec.

The PCIe M.2 specification is even lighter on details. It describes
PERST# but only in the context of powering off. Although it does refer
to the above PCIe Card EM Spec at times.

> Is this a hole in those specs?  Is this something that needs to be
> clarified by the PCI-SIG to improve interoperability?

After re-re-reading the specifications, I'm more convinced that the
first Wifi vendor got it wrong. I also don't trust them to get many
things right in general, so this is pretty much par for the course.

The only things I can suggest:
* "main power" is never defined, as far as I can tell. So "main" and
  "auxiliary" power don't have much meaning for many M.2 cards, and so
  I end up reading much of the spec with a grain of salt
* S3 is never defined in the PCIe Card EM spec, but it's thrown around a
  few times
* if possible, the PCIe base spec should mention something about the
  fundamental reset which is expected with an L2 transition. It's not
  clear what to do if you don't want to switch off power completely (and
  so enter L3), but you also don't have "auxiliary" power

> Why is this problem only showing up now?

Because initial work on RK3399 (and most upstreaming efforts) was done
on boards using the first Wifi vendor as the sole PCIe device on the
bus, and now we're introducing a second Wifi vendor, which is more
closely aligned with the PCIe Card EM spec.

Also, even if the first vendors' chips could handle PERST# OK, the first
boards may not be able to drive PERST# low in S3, as they'll get pulled
up when the GPIO bank shuts off. (It's unclear if just toggling PERST#
is enough to satisfy the spec.)

As to why no one else ran into this, I can only speculate. Maybe our 1st
Wifi vendor is the only vendor that got this wrong. Or maybe anyone who
has handled this stuff just handles it in custom BIOS code that nobody
ever reviewed.

Brian

> > Brian Norris (3):
> >   Documentation/devicetree: Add pcie-reset-suspend property
> >   of/pci: Add of_pci_get_pcie_reset_suspend() to parse
> >     pcie-reset-suspend
> >   PCI: rockchip: Support configuring PERST# state via DT
> > 
> >  Documentation/devicetree/bindings/pci/pci.txt | 11 +++++++++++
> >  drivers/of/of_pci.c                           | 25 +++++++++++++++++++++++++
> >  drivers/pci/host/pcie-rockchip.c              |  7 +++++++
> >  include/linux/of_pci.h                        |  7 +++++++
> >  4 files changed, 50 insertions(+)
> > 
> > -- 
> > 2.15.0.rc0.271.g36b669edcc-goog
> > 
> > 
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


From briannorris at chromium.org  Thu Oct 12 23:31:00 2017
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 Oct 2017 23:31:00 -0700
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171013023246.GZ25517@bhelgaas-glaptop.roam.corp.google.com>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
 <20171013015620.GA94568@google.com>
 <20171013023246.GZ25517@bhelgaas-glaptop.roam.corp.google.com>
Message-ID: <20171013063100.GB56763@google.com>

On Thu, Oct 12, 2017 at 09:32:47PM -0500, Bjorn Helgaas wrote:
> On Thu, Oct 12, 2017 at 06:56:22PM -0700, Brian Norris wrote:
> > Bjorn, were you planning to pick this up?
> 
> I had already applied this to pci/host-rockchip, but I must have gotten
> interrupted before sending the email.

You also hadn't merged it into your /next branch either, which is where
I was looking (and basing my other patch set).

> But now that you mention it, I looked at this again and have some
> questions.  I'll respond to the original patch.

Brian


From architt at codeaurora.org  Fri Oct 13 01:09:23 2017
From: architt at codeaurora.org (Archit Taneja)
Date: Fri, 13 Oct 2017 13:39:23 +0530
Subject: [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting
In-Reply-To: <1506412523-1766-1-git-send-email-nickey.yang@rock-chips.com>
References: <1506412523-1766-1-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <6633e1e8-3188-16f5-7b40-545b5ad97aac@codeaurora.org>

Hi,

On 09/26/2017 01:25 PM, Nickey Yang wrote:
> This patch correct Feedback divider setting:
> 1?Set Feedback divider [8:5] when HIGH_PROGRAM_EN
> 2?Due to the use of a "by 2 pre-scaler," the range of the
> feedback multiplication Feedback divider is limited to even
> division numbers, and Feedback divider must be greater than
> 12, less than 1000.
> 3?Make the previously configured Feedback divider(LSB)
> factors effective
> 4?Add the definition of the MIPI PHY register.

Slightly unrelated topic: We now have a generic dw-mipi-dsi bridge
driver. Can we consider moving to that instead of adding new features
within the rockchip kms driver?

Thanks,
Archit

> 
> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
> ---
>   drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 219 ++++++++++++++++++++++-----------
>   1 file changed, 146 insertions(+), 73 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 9a20b9d..c933a3a 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -228,7 +228,7 @@
>   #define LOW_PROGRAM_EN		0
>   #define HIGH_PROGRAM_EN		BIT(7)
>   #define LOOP_DIV_LOW_SEL(val)	(((val) - 1) & 0x1f)
> -#define LOOP_DIV_HIGH_SEL(val)	((((val) - 1) >> 5) & 0x1f)
> +#define LOOP_DIV_HIGH_SEL(val)	((((val) - 1) >> 5) & 0xf)
>   #define PLL_LOOP_DIV_EN		BIT(5)
>   #define PLL_INPUT_DIV_EN	BIT(4)
>   
> @@ -254,6 +254,28 @@
>   #define DW_MIPI_NEEDS_PHY_CFG_CLK	BIT(0)
>   #define DW_MIPI_NEEDS_GRF_CLK		BIT(1)
>   
> +#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10
> +#define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11
> +#define PLL_LPF_AND_CP_CONTROL 0x12
> +#define PLL_INPUT_DIVIDER_RATIO 0x17
> +#define PLL_LOOP_DIVIDER_RATIO 0x18
> +#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19
> +#define BANDGAP_AND_BIAS_CONTROL 0x20
> +#define TERMINATION_RESISTER_CONTROL 0x21
> +#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22
> +#define HS_RX_CONTROL_OF_LANE_0 0x44
> +#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60
> +#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61
> +#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62
> +#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL 0x63
> +#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL 0x64
> +#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL 0x65
> +#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL 0x70
> +#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL 0x71
> +#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72
> +#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73
> +#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74
> +
>   enum {
>   	BANDGAP_97_07,
>   	BANDGAP_98_05,
> @@ -447,53 +469,79 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>   		return ret;
>   	}
>   
> -	dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
> -					 VCO_RANGE_CON_SEL(vco) |
> -					 VCO_IN_CAP_CON_LOW |
> -					 REF_BIAS_CUR_SEL);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
> -	dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
> -					 LPF_RESISTORS_20_KOHM);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
> -	dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> -					 LOW_PROGRAM_EN);
> -	dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> -					 HIGH_PROGRAM_EN);
> -	dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
> -					 BIASEXTR_SEL(BIASEXTR_127_7));
> -	dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
> -					 BANDGAP_SEL(BANDGAP_96_10));
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
> -					 BIAS_BLOCK_ON | BANDGAP_ON);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
> -					 SETRD_MAX | TER_RESISTORS_ON);
> -	dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> -					 SETRD_MAX | POWER_MANAGE |
> -					 TER_RESISTORS_ON);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> -	dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> -	dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> -	dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> -	dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
> -	dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> -	dw_mipi_dsi_phy_write(dsi, 0x71,
> +	dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
> +			      BYPASS_VCO_RANGE |
> +			      VCO_RANGE_CON_SEL(vco) |
> +			      VCO_IN_CAP_CON_LOW |
> +			      REF_BIAS_CUR_SEL);
> +
> +	dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> +			      CP_CURRENT_3MA);
> +	dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
> +			      CP_PROGRAM_EN | LPF_PROGRAM_EN |
> +			      LPF_RESISTORS_20_KOHM);
> +
> +	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> +			      HSFREQRANGE_SEL(testdin));
> +
> +	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
> +			      INPUT_DIVIDER(dsi->input_div));
> +	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> +			      LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> +			      LOW_PROGRAM_EN);
> +	/*
> +	 * we need set 0x19 immediately to make the configrued LSB
> +	 * effective according to IP simulation and lab test results.
> +	 * Only in this way can we get correct mipi phy pll frequency.
> +	 */
> +	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> +			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> +	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> +			      LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> +			      HIGH_PROGRAM_EN);
> +	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> +			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> +
> +	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> +			      LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
> +	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> +			      HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
> +
> +	dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
> +			      POWER_CONTROL | INTERNAL_REG_CURRENT |
> +			      BIAS_BLOCK_ON | BANDGAP_ON);
> +
> +	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> +			      TER_RESISTOR_LOW | TER_CAL_DONE |
> +			      SETRD_MAX | TER_RESISTORS_ON);
> +	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> +			      TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> +			      SETRD_MAX | POWER_MANAGE |
> +			      TER_RESISTORS_ON);
> +
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
> +			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
> +			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
> +			      THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
> +			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
> +			      BIT(5) | ns2bc(dsi, 100));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
> +			      BIT(5) | (ns2bc(dsi, 60) + 7));
> +
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
> +			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
>   			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
> -	dw_mipi_dsi_phy_write(dsi, 0x72,
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
>   			      THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
> -	dw_mipi_dsi_phy_write(dsi, 0x73,
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
>   			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
> -	dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
> +			      BIT(5) | ns2bc(dsi, 100));
>   
>   	dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
>   				     PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
> @@ -521,11 +569,16 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>   static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>   				    struct drm_display_mode *mode)
>   {
> -	unsigned int i, pre;
> -	unsigned long mpclk, pllref, tmp;
> -	unsigned int m = 1, n = 1, target_mbps = 1000;
> +	unsigned long mpclk, tmp;
> +	unsigned int target_mbps = 1000;
>   	unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
>   	int bpp;
> +	unsigned long best_freq = 0;
> +	unsigned long fvco_min, fvco_max, fin, fout;
> +	unsigned int min_prediv, max_prediv;
> +	unsigned int _prediv, uninitialized_var(best_prediv);
> +	unsigned long _fbdiv, uninitialized_var(best_fbdiv);
> +	unsigned long min_delta = ULONG_MAX;
>   
>   	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
>   	if (bpp < 0) {
> @@ -544,34 +597,54 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>   			dev_err(dsi->dev, "DPHY clock frequency is out of range\n");
>   	}
>   
> -	pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
> -	tmp = pllref;
> -
> -	/*
> -	 * The limits on the PLL divisor are:
> -	 *
> -	 *	5MHz <= (pllref / n) <= 40MHz
> -	 *
> -	 * we walk over these values in descreasing order so that if we hit
> -	 * an exact match for target_mbps it is more likely that "m" will be
> -	 * even.
> -	 *
> -	 * TODO: ensure that "m" is even after this loop.
> -	 */
> -	for (i = pllref / 5; i > (pllref / 40); i--) {
> -		pre = pllref / i;
> -		if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
> -			tmp = target_mbps % pre;
> -			n = i;
> -			m = target_mbps / pre;
> +	fin = clk_get_rate(dsi->pllref_clk);
> +	fout = target_mbps * USEC_PER_SEC;
> +
> +	/* constraint: 5Mhz <= Fref / N <= 40MHz */
> +	min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
> +	max_prediv = fin / (5 * USEC_PER_SEC);
> +
> +	/* constraint: 80MHz <= Fvco <= 1500Mhz */
> +	fvco_min = 80 * USEC_PER_SEC;
> +	fvco_max = 1500 * USEC_PER_SEC;
> +
> +	for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
> +		u64 tmp;
> +		u32 delta;
> +		/* Fvco = Fref * M / N */
> +		tmp = (u64)fout * _prediv;
> +		do_div(tmp, fin);
> +		_fbdiv = tmp;
> +		/*
> +		 * Due to the use of a "by 2 pre-scaler," the range of the
> +		 * feedback multiplication value M is limited to even division
> +		 * numbers, and m must be greater than 12, less than 1000.
> +		 */
> +		if (_fbdiv <= 12 || _fbdiv >= 1000)
> +			continue;
> +
> +		_fbdiv += _fbdiv % 2;
> +
> +		tmp = (u64)_fbdiv * fin;
> +		do_div(tmp, _prediv);
> +		if (tmp < fvco_min || tmp > fvco_max)
> +			continue;
> +
> +		delta = abs(fout - tmp);
> +		if (delta < min_delta) {
> +			best_prediv = _prediv;
> +			best_fbdiv = _fbdiv;
> +			min_delta = delta;
> +			best_freq = tmp;
>   		}
> -		if (tmp == 0)
> -			break;
>   	}
>   
> -	dsi->lane_mbps = pllref / n * m;
> -	dsi->input_div = n;
> -	dsi->feedback_div = m;
> +	if (best_freq) {
> +		dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
> +		dsi->input_div = best_prediv;
> +		dsi->feedback_div = best_fbdiv;
> +	} else
> +		dev_err(dsi->dev, "Can not find best_freq for DPHY\n");
>   
>   	return 0;
>   }
> 

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From architt at codeaurora.org  Fri Oct 13 01:18:23 2017
From: architt at codeaurora.org (Archit Taneja)
Date: Fri, 13 Oct 2017 13:48:23 +0530
Subject: [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support
In-Reply-To: <1506412523-1766-2-git-send-email-nickey.yang@rock-chips.com>
References: <1506412523-1766-1-git-send-email-nickey.yang@rock-chips.com>
 <1506412523-1766-2-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <99994e8b-2698-77f0-9f56-c3aa5962a06a@codeaurora.org>

Hi,

Comment below.

On 09/26/2017 01:25 PM, Nickey Yang wrote:
> This patch add dual mipi channel support:
> 1.add definition of dsi1 register and grf operation.
> 2.dsi0 and dsi1 will work in master and slave mode
> when driving dual mipi panel.
> 
<snip>

>   
> @@ -1226,6 +1367,13 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
>   	.grf_switch_reg = RK3399_GRF_SOC_CON20,
>   	.grf_dsi0_mode = RK3399_GRF_DSI_MODE,
>   	.grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
> +	.grf_dsi1_mode = RK3399_GRF_DSI1_MODE,
> +	.grf_dsi1_enable = RK3399_GRF_DSI1_ENABLE,
> +	.grf_dsi1_mode_reg1 = RK3399_GRF_SOC_CON23,
> +	.dsi1_basedir = RK3399_TXRX_BASEDIR,
> +	.dsi1_masterslavez = RK3399_TXRX_MASTERSLAVEZ,
> +	.dsi1_enableclk = RK3399_TXRX_ENABLECLK,
> +	.grf_dsi1_mode_reg2 = RK3399_GRF_SOC_CON24,
>   	.flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
>   	.max_data_lanes = 4,
>   };
> @@ -1242,17 +1390,107 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
>   };
>   MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
>   
> +
> +static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
> +{
> +	struct device_node *np;
> +	struct platform_device *secondary;
> +
> +	np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
> +	if (np) {
> +		secondary = of_find_device_by_node(np);
> +		dsi->slave = platform_get_drvdata(secondary);
> +		of_node_put(np);
> +
> +		if (!dsi->slave)
> +			return -EPROBE_DEFER;
> +
> +		dsi->slave->master = dsi;

This is not a suitable DT binding. It doesn't really represent HW, it's more of
a configuration that allows 2 DSIs to work together.

You can use the of-graph bindings to figure out whether you are operating in dual
mode or not: If the output ports of both the DSIs are connected to the same DT
node (i.e, both DSIs driving the same bridge chip/panel), then you know that you
need to configure the DSIs in dual channel mode.

Thanks,
Archit

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From jeffy.chen at rock-chips.com  Fri Oct 13 03:01:15 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Fri, 13 Oct 2017 18:01:15 +0800
Subject: [PATCH 1/2] spi: rockchip: Convert to late and early system PM
 callbacks
Message-ID: <20171013100116.8271-1-jeffy.chen@rock-chips.com>

Currently we are suspending the spi master in it's ->suspend callback,
which is racy as some other drivers may still want to transmit messages
on the bus(e.g. spi based pwm backlight).

Convert to late and early system PM callbacks to avoid the race.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

 drivers/spi/spi-rockchip.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index fdcf3076681b..ae539c735ea6 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -914,7 +914,7 @@ static int rockchip_spi_runtime_resume(struct device *dev)
 #endif /* CONFIG_PM */
 
 static const struct dev_pm_ops rockchip_spi_pm = {
-	SET_SYSTEM_SLEEP_PM_OPS(rockchip_spi_suspend, rockchip_spi_resume)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(rockchip_spi_suspend, rockchip_spi_resume)
 	SET_RUNTIME_PM_OPS(rockchip_spi_runtime_suspend,
 			   rockchip_spi_runtime_resume, NULL)
 };
-- 
2.11.0




From jeffy.chen at rock-chips.com  Fri Oct 13 03:01:16 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Fri, 13 Oct 2017 18:01:16 +0800
Subject: [PATCH 2/2] arm64: dts: rockchip: Enable edp disaplay on kevin
In-Reply-To: <20171013100116.8271-1-jeffy.chen@rock-chips.com>
References: <20171013100116.8271-1-jeffy.chen@rock-chips.com>
Message-ID: <20171013100116.8271-2-jeffy.chen@rock-chips.com>

Add edp panel and enable related nodes on kevin.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index a3d3cea7dc4f..bc67b19f0af5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -93,6 +93,18 @@
 		pwm-delay-us = <10000>;
 	};
 
+	edp_panel: edp-panel {
+		compatible = "sharp,lq123p1jx31", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&pp3300_disp>;
+
+		ports {
+			panel_in_edp: endpoint {
+				remote-endpoint = <&edp_out_panel>;
+			};
+		};
+	};
+
 	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
 		compatible = "murata,ncp15wb473";
 		pullup-uv = <1800000>;
@@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
 	};
 };
 
+&edp {
+	status = "okay";
+
+	ports {
+		edp_out: port at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_out_panel: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&panel_in_edp>;
+			};
+		};
+	};
+};
+
 &ppvar_bigcpu_pwm {
 	regulator-min-microvolt = <798674>;
 	regulator-max-microvolt = <1302172>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..470105d651c2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
 	dr_mode = "host";
 };
 
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
 #include <arm/cros-ec-keyboard.dtsi>
 #include <arm/cros-ec-sbs.dtsi>
 
-- 
2.11.0




From broonie at kernel.org  Fri Oct 13 03:17:19 2017
From: broonie at kernel.org (Mark Brown)
Date: Fri, 13 Oct 2017 11:17:19 +0100
Subject: [PATCH 1/2] spi: rockchip: Convert to late and early system PM
 callbacks
In-Reply-To: <20171013100116.8271-1-jeffy.chen@rock-chips.com>
References: <20171013100116.8271-1-jeffy.chen@rock-chips.com>
Message-ID: <20171013101719.bophbiz7qb5wi7n2@sirena.co.uk>

On Fri, Oct 13, 2017 at 06:01:15PM +0800, Jeffy Chen wrote:
> Currently we are suspending the spi master in it's ->suspend callback,
> which is racy as some other drivers may still want to transmit messages
> on the bus(e.g. spi based pwm backlight).

I'm missing patch 2/2.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20171013/e0813609/attachment.sig>

From jeffy.chen at rock-chips.com  Fri Oct 13 03:41:36 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Fri, 13 Oct 2017 18:41:36 +0800
Subject: [RESEND PATCH 0/2] rockchip: kevin: Enable edp display
Message-ID: <20171013104138.3216-1-jeffy.chen@rock-chips.com>


Make edp display works on chromebook kevin.


Jeffy Chen (2):
  spi: rockchip: Convert to late and early system PM callbacks
  arm64: dts: rockchip: Enable edp disaplay on kevin

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
 drivers/spi/spi-rockchip.c                        |  2 +-
 3 files changed, 46 insertions(+), 1 deletion(-)

-- 
2.11.0




From jeffy.chen at rock-chips.com  Fri Oct 13 03:41:37 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Fri, 13 Oct 2017 18:41:37 +0800
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early system PM
 callbacks
In-Reply-To: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
Message-ID: <20171013104138.3216-2-jeffy.chen@rock-chips.com>

Currently we are suspending the spi master in it's ->suspend callback,
which is racy as some other drivers may still want to transmit messages
on the bus(e.g. spi based pwm backlight).

Convert to late and early system PM callbacks to avoid the race.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

 drivers/spi/spi-rockchip.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index fdcf3076681b..ae539c735ea6 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -914,7 +914,7 @@ static int rockchip_spi_runtime_resume(struct device *dev)
 #endif /* CONFIG_PM */
 
 static const struct dev_pm_ops rockchip_spi_pm = {
-	SET_SYSTEM_SLEEP_PM_OPS(rockchip_spi_suspend, rockchip_spi_resume)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(rockchip_spi_suspend, rockchip_spi_resume)
 	SET_RUNTIME_PM_OPS(rockchip_spi_runtime_suspend,
 			   rockchip_spi_runtime_resume, NULL)
 };
-- 
2.11.0




From jeffy.chen at rock-chips.com  Fri Oct 13 03:41:38 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Fri, 13 Oct 2017 18:41:38 +0800
Subject: [RESEND PATCH 2/2] arm64: dts: rockchip: Enable edp disaplay on kevin
In-Reply-To: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
Message-ID: <20171013104138.3216-3-jeffy.chen@rock-chips.com>

Add edp panel and enable related nodes on kevin.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index a3d3cea7dc4f..bc67b19f0af5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -93,6 +93,18 @@
 		pwm-delay-us = <10000>;
 	};
 
+	edp_panel: edp-panel {
+		compatible = "sharp,lq123p1jx31", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&pp3300_disp>;
+
+		ports {
+			panel_in_edp: endpoint {
+				remote-endpoint = <&edp_out_panel>;
+			};
+		};
+	};
+
 	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
 		compatible = "murata,ncp15wb473";
 		pullup-uv = <1800000>;
@@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
 	};
 };
 
+&edp {
+	status = "okay";
+
+	ports {
+		edp_out: port at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_out_panel: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&panel_in_edp>;
+			};
+		};
+	};
+};
+
 &ppvar_bigcpu_pwm {
 	regulator-min-microvolt = <798674>;
 	regulator-max-microvolt = <1302172>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..470105d651c2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
 	dr_mode = "host";
 };
 
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
 #include <arm/cros-ec-keyboard.dtsi>
 #include <arm/cros-ec-sbs.dtsi>
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Fri Oct 13 03:47:18 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Fri, 13 Oct 2017 18:47:18 +0800
Subject: [PATCH 1/2] spi: rockchip: Convert to late and early system PM
 callbacks
In-Reply-To: <20171013101719.bophbiz7qb5wi7n2@sirena.co.uk>
References: <20171013100116.8271-1-jeffy.chen@rock-chips.com>
 <20171013101719.bophbiz7qb5wi7n2@sirena.co.uk>
Message-ID: <59E099B6.1000804@rock-chips.com>

Hi Mark,

On 10/13/2017 06:17 PM, Mark Brown wrote:
> On Fri, Oct 13, 2017 at 06:01:15PM +0800, Jeffy Chen wrote:
>> Currently we are suspending the spi master in it's ->suspend callback,
>> which is racy as some other drivers may still want to transmit messages
>> on the bus(e.g. spi based pwm backlight).
>
> I'm missing patch 2/2.
>
Sorry, i'll resend them...

This patch is to defer suspend_spi_master to late suspend.

Since we put display-subsystem dt node above spi dt node, which makes 
spi suspend been called before display driver. Then the display driver 
would fail to set pwm backlight through spi in it's suspend/resume.



From heiko at sntech.de  Fri Oct 13 06:25:24 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 13 Oct 2017 15:25:24 +0200
Subject: [RESEND PATCH 2/2] arm64: dts: rockchip: Enable edp disaplay on
 kevin
In-Reply-To: <20171013104138.3216-3-jeffy.chen@rock-chips.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-3-jeffy.chen@rock-chips.com>
Message-ID: <3037285.0MAZvLKA4I@phil>

Hi Jeffy,

Am Freitag, 13. Oktober 2017, 18:41:38 CEST schrieb Jeffy Chen:
> Add edp panel and enable related nodes on kevin.
> 
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>

does this actually work with mainline kernel sources?

Sean Paul did look at making the edp work on Chromebooks recently,
but it seemed there were still parts missing to make it actually display
something.


Heiko

> ---
> 
>  arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
>  arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
>  2 files changed, 45 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
> index a3d3cea7dc4f..bc67b19f0af5 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
> @@ -93,6 +93,18 @@
>  		pwm-delay-us = <10000>;
>  	};
>  
> +	edp_panel: edp-panel {
> +		compatible = "sharp,lq123p1jx31", "simple-panel";
> +		backlight = <&backlight>;
> +		power-supply = <&pp3300_disp>;
> +
> +		ports {
> +			panel_in_edp: endpoint {
> +				remote-endpoint = <&edp_out_panel>;
> +			};
> +		};
> +	};
> +
>  	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
>  		compatible = "murata,ncp15wb473";
>  		pullup-uv = <1800000>;
> @@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
>  	};
>  };
>  
> +&edp {
> +	status = "okay";
> +
> +	ports {
> +		edp_out: port at 1 {
> +			reg = <1>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			edp_out_panel: endpoint at 0 {
> +				reg = <0>;
> +				remote-endpoint = <&panel_in_edp>;
> +			};
> +		};
> +	};
> +};
> +
>  &ppvar_bigcpu_pwm {
>  	regulator-min-microvolt = <798674>;
>  	regulator-max-microvolt = <1302172>;
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
> index 5772c52fbfd3..470105d651c2 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
> @@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
>  	dr_mode = "host";
>  };
>  
> +&vopb {
> +	status = "okay";
> +};
> +
> +&vopb_mmu {
> +	status = "okay";
> +};
> +
> +&vopl {
> +	status = "okay";
> +};
> +
> +&vopl_mmu {
> +	status = "okay";
> +};
> +
>  #include <arm/cros-ec-keyboard.dtsi>
>  #include <arm/cros-ec-sbs.dtsi>
>  
> 




From rjw at rjwysocki.net  Fri Oct 13 06:21:41 2017
From: rjw at rjwysocki.net (Rafael J. Wysocki)
Date: Fri, 13 Oct 2017 15:21:41 +0200
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171013030441.GA25517@bhelgaas-glaptop.roam.corp.google.com>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
 <20171013030441.GA25517@bhelgaas-glaptop.roam.corp.google.com>
Message-ID: <2453698.N4jfPaHx71@aspire.rjw.lan>

[+cc Tony]

On Friday, October 13, 2017 5:04:41 AM CEST Bjorn Helgaas wrote:
> [+cc Rafael, linux-pm]
> 
> On Mon, Sep 11, 2017 at 11:10:27PM +0800, Jeffy Chen wrote:
> > Add support for PCIE_WAKE pin in rockchip pcie driver.
> > 
> > Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> > ---
> > 
> > Changes in v5:
> > Rebase
> > 
> > Changes in v3:
> > Fix error handling
> > 
> > Changes in v2:
> > Use dev_pm_set_dedicated_wake_irq
> >         -- Suggested by Brian Norris <briannorris at chromium.com>
> > 
> >  drivers/pci/host/pcie-rockchip.c | 19 +++++++++++++++++--
> >  1 file changed, 17 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> > index 9051c6c8fea4..a8b7272597a7 100644
> > --- a/drivers/pci/host/pcie-rockchip.c
> > +++ b/drivers/pci/host/pcie-rockchip.c
> > @@ -37,6 +37,7 @@
> >  #include <linux/pci_ids.h>
> >  #include <linux/phy/phy.h>
> >  #include <linux/platform_device.h>
> > +#include <linux/pm_wakeirq.h>
> >  #include <linux/reset.h>
> >  #include <linux/regmap.h>
> >  
> > @@ -995,6 +996,15 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
> >  		return err;
> >  	}
> >  
> > +	/* Must init wakeup before setting dedicated wakeup irq. */
> > +	device_init_wakeup(dev, true);
> > +	irq = platform_get_irq_byname(pdev, "wakeup");
> > +	if (irq >= 0) {
> > +		err = dev_pm_set_dedicated_wake_irq(dev, irq);
> 
> I'm a little skeptical about dev_pm_set_dedicated_wake_irq(), not
> because I know anything at all about it, but because there are only
> five callers in the whole tree, three of which are in UART code, and
> none in anything resembling PCI code.
> 
> Is Rockchip really that special, or are we going about this the wrong
> way?
> 
> > +		if (err)
> > +			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
> > +	}
> > +
> >  	return 0;
> 
> The above could be structured as:
> 
>   irq = platform_get_irq_byname(pdev, "wakeup");
>   if (irq < 0)
>     return 0;
> 
>   device_init_wakeup(dev, true);
>   err = dev_pm_set_dedicated_wake_irq(dev, irq);
>   if (err) {
>     dev_pm_clear_wake_irq(dev);
>     device_init_wakeup(dev, false);
>   }
> 
>   return 0;
> 
> to unindent the mainline non-error code.
> 
> >  }
> >  
> > @@ -1542,11 +1552,11 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
> >  
> >  	err = rockchip_pcie_parse_dt(rockchip);
> >  	if (err)
> > -		return err;
> > +		goto err_disable_wake;
> >  
> >  	err = rockchip_pcie_enable_clocks(rockchip);
> >  	if (err)
> > -		return err;
> > +		goto err_disable_wake;
> >  
> >  	err = rockchip_pcie_set_vpcie(rockchip);
> >  	if (err) {
> > @@ -1656,6 +1666,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
> >  		regulator_disable(rockchip->vpcie0v9);
> >  err_set_vpcie:
> >  	rockchip_pcie_disable_clocks(rockchip);
> > +err_disable_wake:
> > +	dev_pm_clear_wake_irq(dev);
> > +	device_init_wakeup(dev, false);
> 
> I think this error cleanup should be done in rockchip_pcie_setup_irq()
> as shown above.  There's no real connection between
> rockchip_pcie_probe() and the wake setup.
> 
> >  	return err;
> >  }
> >  
> > @@ -1682,6 +1695,8 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
> >  	if (!IS_ERR(rockchip->vpcie0v9))
> >  		regulator_disable(rockchip->vpcie0v9);
> >  
> > +	dev_pm_clear_wake_irq(dev);
> > +	device_init_wakeup(dev, false);
> >  	return 0;
> >  }
> >  
> 




From emil.renner.berthing at gmail.com  Fri Oct 13 06:42:50 2017
From: emil.renner.berthing at gmail.com (Emil Renner Berthing)
Date: Fri, 13 Oct 2017 15:42:50 +0200
Subject: [RESEND PATCH 2/2] arm64: dts: rockchip: Enable edp disaplay on
 kevin
In-Reply-To: <3037285.0MAZvLKA4I@phil>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-3-jeffy.chen@rock-chips.com> <3037285.0MAZvLKA4I@phil>
Message-ID: <CANBLGcyqbfmVJ75Nu_RtVD2TUJs_pXZ+jZBhQ7J0E9U4DvwtSg@mail.gmail.com>

On 13 October 2017 at 15:25, Heiko Stuebner <heiko at sntech.de> wrote:
> Am Freitag, 13. Oktober 2017, 18:41:38 CEST schrieb Jeffy Chen:
>> Add edp panel and enable related nodes on kevin.
>>
>> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
>
> does this actually work with mainline kernel sources?
>
> Sean Paul did look at making the edp work on Chromebooks recently,
> but it seemed there were still parts missing to make it actually display
> something.

That's funny. I've been using your own similar patch on my Chromebook
Plus for a while now and it works "fine":
https://github.com/esmil/linux/commits/kevin

..where fine means I can't get the armsoc X11 driver to work, but
modesetting works and screenblank seems to freeze the kernel.

I'll test this version of the dts changes as soon as I'm near my
chrombook again.

/Emil

>> ---
>>
>>  arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
>>  arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
>>  2 files changed, 45 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
>> index a3d3cea7dc4f..bc67b19f0af5 100644
>> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
>> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
>> @@ -93,6 +93,18 @@
>>               pwm-delay-us = <10000>;
>>       };
>>
>> +     edp_panel: edp-panel {
>> +             compatible = "sharp,lq123p1jx31", "simple-panel";
>> +             backlight = <&backlight>;
>> +             power-supply = <&pp3300_disp>;
>> +
>> +             ports {
>> +                     panel_in_edp: endpoint {
>> +                             remote-endpoint = <&edp_out_panel>;
>> +                     };
>> +             };
>> +     };
>> +
>>       thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
>>               compatible = "murata,ncp15wb473";
>>               pullup-uv = <1800000>;
>> @@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
>>       };
>>  };
>>
>> +&edp {
>> +     status = "okay";
>> +
>> +     ports {
>> +             edp_out: port at 1 {
>> +                     reg = <1>;
>> +                     #address-cells = <1>;
>> +                     #size-cells = <0>;
>> +
>> +                     edp_out_panel: endpoint at 0 {
>> +                             reg = <0>;
>> +                             remote-endpoint = <&panel_in_edp>;
>> +                     };
>> +             };
>> +     };
>> +};
>> +
>>  &ppvar_bigcpu_pwm {
>>       regulator-min-microvolt = <798674>;
>>       regulator-max-microvolt = <1302172>;
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
>> index 5772c52fbfd3..470105d651c2 100644
>> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
>> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
>> @@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
>>       dr_mode = "host";
>>  };
>>
>> +&vopb {
>> +     status = "okay";
>> +};
>> +
>> +&vopb_mmu {
>> +     status = "okay";
>> +};
>> +
>> +&vopl {
>> +     status = "okay";
>> +};
>> +
>> +&vopl_mmu {
>> +     status = "okay";
>> +};
>> +
>>  #include <arm/cros-ec-keyboard.dtsi>
>>  #include <arm/cros-ec-sbs.dtsi>
>>
>>
>
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip


From emil.renner.berthing at gmail.com  Fri Oct 13 08:15:50 2017
From: emil.renner.berthing at gmail.com (Emil Renner Berthing)
Date: Fri, 13 Oct 2017 17:15:50 +0200
Subject: [RESEND PATCH 2/2] arm64: dts: rockchip: Enable edp disaplay on
 kevin
In-Reply-To: <CANBLGcyqbfmVJ75Nu_RtVD2TUJs_pXZ+jZBhQ7J0E9U4DvwtSg@mail.gmail.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-3-jeffy.chen@rock-chips.com> <3037285.0MAZvLKA4I@phil>
 <CANBLGcyqbfmVJ75Nu_RtVD2TUJs_pXZ+jZBhQ7J0E9U4DvwtSg@mail.gmail.com>
Message-ID: <CANBLGczVi9=+3um-jMmRxbtG+WsJNDXeKTFQYCZ=e=gnNj67gA@mail.gmail.com>

On 13 October 2017 at 15:42, Emil Renner Berthing
<emil.renner.berthing at gmail.com> wrote:
> On 13 October 2017 at 15:25, Heiko Stuebner <heiko at sntech.de> wrote:
>> Am Freitag, 13. Oktober 2017, 18:41:38 CEST schrieb Jeffy Chen:
>>> Add edp panel and enable related nodes on kevin.
>>>
>>> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
>>
>> does this actually work with mainline kernel sources?
>>
>> Sean Paul did look at making the edp work on Chromebooks recently,
>> but it seemed there were still parts missing to make it actually display
>> something.
>
> That's funny. I've been using your own similar patch on my Chromebook
> Plus for a while now and it works "fine":
> https://github.com/esmil/linux/commits/kevin
>
> ..where fine means I can't get the armsoc X11 driver to work, but
> modesetting works and screenblank seems to freeze the kernel.
>
> I'll test this version of the dts changes as soon as I'm near my
> chrombook again.

I've just tested this series and the internal screen works with this
too. Screenblank still seems to freeze the kernel though. Eg.
# setterm --powersave on
# setterm --blank 1
#  < wait 1 minute >

But getting output on the screen is progress ;)

As for the spi change suspend now works too, which it didn't before,
but the screen just didn't come up properly after the suspend. I could
still ssh into it after suspend though.

/Emil

>>>
>>>  arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
>>>  arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
>>>  2 files changed, 45 insertions(+)
>>>
>>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
>>> index a3d3cea7dc4f..bc67b19f0af5 100644
>>> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
>>> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
>>> @@ -93,6 +93,18 @@
>>>               pwm-delay-us = <10000>;
>>>       };
>>>
>>> +     edp_panel: edp-panel {
>>> +             compatible = "sharp,lq123p1jx31", "simple-panel";
>>> +             backlight = <&backlight>;
>>> +             power-supply = <&pp3300_disp>;
>>> +
>>> +             ports {
>>> +                     panel_in_edp: endpoint {
>>> +                             remote-endpoint = <&edp_out_panel>;
>>> +                     };
>>> +             };
>>> +     };
>>> +
>>>       thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
>>>               compatible = "murata,ncp15wb473";
>>>               pullup-uv = <1800000>;
>>> @@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
>>>       };
>>>  };
>>>
>>> +&edp {
>>> +     status = "okay";
>>> +
>>> +     ports {
>>> +             edp_out: port at 1 {
>>> +                     reg = <1>;
>>> +                     #address-cells = <1>;
>>> +                     #size-cells = <0>;
>>> +
>>> +                     edp_out_panel: endpoint at 0 {
>>> +                             reg = <0>;
>>> +                             remote-endpoint = <&panel_in_edp>;
>>> +                     };
>>> +             };
>>> +     };
>>> +};
>>> +
>>>  &ppvar_bigcpu_pwm {
>>>       regulator-min-microvolt = <798674>;
>>>       regulator-max-microvolt = <1302172>;
>>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
>>> index 5772c52fbfd3..470105d651c2 100644
>>> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
>>> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
>>> @@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
>>>       dr_mode = "host";
>>>  };
>>>
>>> +&vopb {
>>> +     status = "okay";
>>> +};
>>> +
>>> +&vopb_mmu {
>>> +     status = "okay";
>>> +};
>>> +
>>> +&vopl {
>>> +     status = "okay";
>>> +};
>>> +
>>> +&vopl_mmu {
>>> +     status = "okay";
>>> +};
>>> +
>>>  #include <arm/cros-ec-keyboard.dtsi>
>>>  #include <arm/cros-ec-sbs.dtsi>
>>>
>>>
>>
>>
>>
>> _______________________________________________
>> Linux-rockchip mailing list
>> Linux-rockchip at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-rockchip


From dianders at chromium.org  Fri Oct 13 08:32:12 2017
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 Oct 2017 08:32:12 -0700
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early
 system PM callbacks
In-Reply-To: <20171013104138.3216-2-jeffy.chen@rock-chips.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
Message-ID: <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>

Hi,

On Fri, Oct 13, 2017 at 3:41 AM, Jeffy Chen <jeffy.chen at rock-chips.com> wrote:
> Currently we are suspending the spi master in it's ->suspend callback,
> which is racy as some other drivers may still want to transmit messages
> on the bus(e.g. spi based pwm backlight).
>
> Convert to late and early system PM callbacks to avoid the race.
>
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
>
>  drivers/spi/spi-rockchip.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

It shouldn't hurt to do this, but I'm curious if you did any digging
about why this happens?  As I understood it suspend order is supposed
to be opposite of probe order.  Thus anything that was able to get a
reference to the cros-ec PWM at its probe time should get suspended
before cros-ec suspends.


-Doug


From dianders at chromium.org  Fri Oct 13 08:34:25 2017
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 Oct 2017 08:34:25 -0700
Subject: [RESEND PATCH 0/2] rockchip: kevin: Enable edp display
In-Reply-To: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
Message-ID: <CAD=FV=XieqJoXfurJZwayOmCSanaPr-4e2mp0g8Zf4pc_Tc0yQ@mail.gmail.com>

Hi,

On Fri, Oct 13, 2017 at 3:41 AM, Jeffy Chen <jeffy.chen at rock-chips.com> wrote:
>
> Make edp display works on chromebook kevin.
>
>
> Jeffy Chen (2):
>   spi: rockchip: Convert to late and early system PM callbacks
>   arm64: dts: rockchip: Enable edp disaplay on kevin
>
>  arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
>  arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
>  drivers/spi/spi-rockchip.c                        |  2 +-
>  3 files changed, 46 insertions(+), 1 deletion(-)

Presumably including Sean Paul would be a wise idea on future patches
trying to make eDP work well upstream since he's worked on supporting
rk3399 eDP in the past.  I think Alexandru has also expressed interest
in this area, too.

-Doug


From briannorris at chromium.org  Fri Oct 13 08:51:21 2017
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 Oct 2017 08:51:21 -0700
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early
 system PM callbacks
In-Reply-To: <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
Message-ID: <20171013155120.GA137489@google.com>

Hi,

On Fri, Oct 13, 2017 at 08:32:12AM -0700, Doug Anderson wrote:
> Hi,
> 
> On Fri, Oct 13, 2017 at 3:41 AM, Jeffy Chen <jeffy.chen at rock-chips.com> wrote:
> > Currently we are suspending the spi master in it's ->suspend callback,
> > which is racy as some other drivers may still want to transmit messages
> > on the bus(e.g. spi based pwm backlight).
> >
> > Convert to late and early system PM callbacks to avoid the race.
> >
> > Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> > ---
> >
> >  drivers/spi/spi-rockchip.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> It shouldn't hurt to do this, but I'm curious if you did any digging
> about why this happens?  As I understood it suspend order is supposed
> to be opposite of probe order.  Thus anything that was able to get a
> reference to the cros-ec PWM at its probe time should get suspended
> before cros-ec suspends.

Yes, this does seem odd to me too. This looks like an arms race hack
that should be avoided unless we know a legit root cause. Also,
"probe order implies suspend order" doesn't quite work for async suspend
anyway, so we'd probably want to express the dependency properly
anyway.

Any chance this is related? Seems like that might break the parent/child
relationship for master/slave:

commit d7e2ee257038baeb03baef602500368a51ee9eef
Author: Linus Walleij <linus.walleij at linaro.org>
Date:   Mon Apr 11 13:51:03 2016 +0200

    spi: let SPI masters ignore their children for PM

Brian


From broonie at kernel.org  Fri Oct 13 09:42:35 2017
From: broonie at kernel.org (Mark Brown)
Date: Fri, 13 Oct 2017 17:42:35 +0100
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early
 system PM callbacks
In-Reply-To: <20171013155120.GA137489@google.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
 <20171013155120.GA137489@google.com>
Message-ID: <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>

On Fri, Oct 13, 2017 at 08:51:21AM -0700, Brian Norris wrote:

> Yes, this does seem odd to me too. This looks like an arms race hack
> that should be avoided unless we know a legit root cause. Also,
> "probe order implies suspend order" doesn't quite work for async suspend
> anyway, so we'd probably want to express the dependency properly
> anyway.

Yeah, it's the same stuff as we get with initcall ordering.  This sort
of thing does happen with things like PMICs which tend to have hardware
that the system wants to manipulate in the IRQs off part of suspend.
Ideally the dependency annotation stuff would figure things out though
I'm not sure what the status of that is.

> Any chance this is related? Seems like that might break the parent/child
> relationship for master/slave:

> commit d7e2ee257038baeb03baef602500368a51ee9eef
> Author: Linus Walleij <linus.walleij at linaro.org>
> Date:   Mon Apr 11 13:51:03 2016 +0200

>     spi: let SPI masters ignore their children for PM

That's for runtime PM, I'd not expect it to affect system suspend.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20171013/5cd83500/attachment.sig>

From helgaas at kernel.org  Fri Oct 13 09:51:52 2017
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Fri, 13 Oct 2017 11:51:52 -0500
Subject: [PATCH 1/3] Documentation/devicetree: Add pcie-reset-suspend
 property
In-Reply-To: <20171012205220.130048-2-briannorris@chromium.org>
References: <20171012205220.130048-1-briannorris@chromium.org>
 <20171012205220.130048-2-briannorris@chromium.org>
Message-ID: <20171013165152.GE25517@bhelgaas-glaptop.roam.corp.google.com>

[+cc Doug]

On Thu, Oct 12, 2017 at 01:52:18PM -0700, Brian Norris wrote:
> The patch is self-descriptive. I've found that we may need
> platform-specific behavior for the PERST# signal in system suspend,
> depending on the type of PCIe endpoints are attached.
> 
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  Documentation/devicetree/bindings/pci/pci.txt | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt
> index c77981c5dd18..91339b6d0652 100644
> --- a/Documentation/devicetree/bindings/pci/pci.txt
> +++ b/Documentation/devicetree/bindings/pci/pci.txt
> @@ -24,3 +24,14 @@ driver implementation may support the following properties:
>     unsupported link speed, for instance, trying to do training for
>     unsupported link speed, etc.  Must be '4' for gen4, '3' for gen3, '2'
>     for gen2, and '1' for gen1. Any other values are invalid.
> +- pcie-reset-suspend:
> +   If present this property defines whether the PCIe Reset signal (referred to
> +   as PERST#) should be asserted when the system enters low-power suspend modes
> +   (e.g., S3). Depending on the form factor, the associated PCIe
> +   electromechanical specification may specify a particular behavior (e.g.,
> +   "PERST# is asserted in advance of the power being switched off in a
> +   power-managed state like S3") or it may be less clear. The net result is
> +   that some endpoints perform better (e.g., lower power consumption) with
> +   PERST# asserted, and others prefer PERST# deasserted. The value must be '0'
> +   or '1', where '0' means do not assert PERST# and '1' means assert PERST#.
> +   When absent, behavior may be platform-specific.

I don't understand this at all.  Are you suggesting that we need
different "pcie-reset-suspend" values based on what sort of endpoint
the user plugs in?

If so, I really don't want to get involved in that, because that's an
issue that needs to be resolved by the vendors and the PCI-SIG.  If we
put in a tweak like this, I think it would be a band-aid that only
delays getting a real solution figured out.

If you want a quirk to tune this based on specific devices, that might
make sense.  It would still sound like an interoperability issue and
an ongoing maintenance problem, but at least we would have specific
details about which devices are involved, and we'd have a chance to
make them work on more controllers than just Rockchip.

Bjorn


From jagannadh.teki at gmail.com  Fri Oct 13 10:33:32 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Fri, 13 Oct 2017 23:03:32 +0530
Subject: [PATCH] ARM: dts: rockchip: Enable thermal on rk3288-vyasa board
Message-ID: <1507916012-3980-1-git-send-email-jagan@amarulasolutions.com>

From: Michael Trimarchi <michael at amarulasolutions.com>

Enable thermal on rk3288-vyasa board, TSHUT is high active.

Signed-off-by: Michael Trimarchi <michael at amarulasolutions.com>
Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/boot/dts/rk3288-vyasa.dts | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index 932311c..3546eb8 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -302,6 +302,12 @@
 	status = "okay";
 };
 
+&tsadc {
+	rockchip,hw-tshut-mode = <1>; /* tshut mode 0:CRU 1:GPIO */
+	rockchip,hw-tshut-polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */
+	status = "okay";
+};
+
 &uart2 {
 	status = "okay";
 };
-- 
2.7.4



From tony at atomide.com  Fri Oct 13 10:58:26 2017
From: tony at atomide.com (Tony Lindgren)
Date: Fri, 13 Oct 2017 10:58:26 -0700
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <2453698.N4jfPaHx71@aspire.rjw.lan>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
 <20171013030441.GA25517@bhelgaas-glaptop.roam.corp.google.com>
 <2453698.N4jfPaHx71@aspire.rjw.lan>
Message-ID: <20171013175825.GR4394@atomide.com>

* Rafael J. Wysocki <rjw at rjwysocki.net> [171013 06:32]:
> [+cc Tony]
> 
> On Friday, October 13, 2017 5:04:41 AM CEST Bjorn Helgaas wrote:
> > [+cc Rafael, linux-pm]
> > On Mon, Sep 11, 2017 at 11:10:27PM +0800, Jeffy Chen wrote:
> > > Add support for PCIE_WAKE pin in rockchip pcie driver.
...
> > > @@ -995,6 +996,15 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
> > >  		return err;
> > >  	}
> > >  
> > > +	/* Must init wakeup before setting dedicated wakeup irq. */
> > > +	device_init_wakeup(dev, true);
> > > +	irq = platform_get_irq_byname(pdev, "wakeup");
> > > +	if (irq >= 0) {
> > > +		err = dev_pm_set_dedicated_wake_irq(dev, irq);
> > 
> > I'm a little skeptical about dev_pm_set_dedicated_wake_irq(), not
> > because I know anything at all about it, but because there are only
> > five callers in the whole tree, three of which are in UART code, and
> > none in anything resembling PCI code.

Well it should work for any device that can provide an out of band wakeup
interrupt such as a dedicated GPIO line.

> > Is Rockchip really that special, or are we going about this the wrong
> > way?

Maybe this can be set up in a generic way somewhere similar to what
the I2C bus is doing?

See i2c_device_probe() for dev_pm_set_dedicated_wake_irq() in
drivers/i2c/i2c-core-base.c.

Regards,

Tony


From jeffy.chen at rock-chips.com  Fri Oct 13 11:12:41 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Sat, 14 Oct 2017 02:12:41 +0800
Subject: [RESEND PATCH 2/2] arm64: dts: rockchip: Enable edp disaplay
 on kevin
In-Reply-To: <3037285.0MAZvLKA4I@phil>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-3-jeffy.chen@rock-chips.com> <3037285.0MAZvLKA4I@phil>
Message-ID: <59E10219.3060009@rock-chips.com>

Hi heiko,

On 10/13/2017 09:25 PM, Heiko Stuebner wrote:
> does this actually work with mainline kernel sources?
>
> Sean Paul did look at making the edp work on Chromebooks recently,
> but it seemed there were still parts missing to make it actually display
> something.

yes, it works, but only for boot-splash(boot animation). we still need 
mali gru stuff to bring chrome browser up...i think caesar tried that 
before(but i don't think he would submit that)
>
>
> Heiko




From jeffy.chen at rock-chips.com  Fri Oct 13 11:19:28 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Sat, 14 Oct 2017 02:19:28 +0800
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early system
 PM callbacks
In-Reply-To: <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
 <20171013155120.GA137489@google.com>
 <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>
Message-ID: <59E103B0.8060705@rock-chips.com>

Hi guys,

it looks like the suspend sequence depends on the dt node sequence, and 
we are putting display-subsystem dt node above spi dt node, so it would 
be earlier in the device list, then got suspended later than spi device.

the pwm backlight and cros_ec_spi pwm are very interesting, not only 
about suspend dependency... if we unbind cros_ec_spi pwm, the pwm 
backlight would still hold a reference to it, and crash the kernel later.

On 10/14/2017 12:42 AM, Mark Brown wrote:
> On Fri, Oct 13, 2017 at 08:51:21AM -0700, Brian Norris wrote:
>
>> Yes, this does seem odd to me too. This looks like an arms race hack
>> that should be avoided unless we know a legit root cause. Also,
>> "probe order implies suspend order" doesn't quite work for async suspend
>> anyway, so we'd probably want to express the dependency properly
>> anyway.
>
> Yeah, it's the same stuff as we get with initcall ordering.  This sort
> of thing does happen with things like PMICs which tend to have hardware
> that the system wants to manipulate in the IRQs off part of suspend.
> Ideally the dependency annotation stuff would figure things out though
> I'm not sure what the status of that is.
>
>> Any chance this is related? Seems like that might break the parent/child
>> relationship for master/slave:
>
>> commit d7e2ee257038baeb03baef602500368a51ee9eef
>> Author: Linus Walleij <linus.walleij at linaro.org>
>> Date:   Mon Apr 11 13:51:03 2016 +0200
>
>>      spi: let SPI masters ignore their children for PM
>
> That's for runtime PM, I'd not expect it to affect system suspend.
>




From dmitry.torokhov at gmail.com  Fri Oct 13 11:30:06 2017
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Fri, 13 Oct 2017 11:30:06 -0700
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early
 system PM callbacks
In-Reply-To: <59E103B0.8060705@rock-chips.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
 <20171013155120.GA137489@google.com>
 <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>
 <59E103B0.8060705@rock-chips.com>
Message-ID: <20171013183006.k6pzcr5tcwsxxtmp@dtor-ws>

On Sat, Oct 14, 2017 at 02:19:28AM +0800, jeffy wrote:
> Hi guys,
> 
> it looks like the suspend sequence depends on the dt node sequence, and we
> are putting display-subsystem dt node above spi dt node, so it would be
> earlier in the device list, then got suspended later than spi device.

Would it not get a deferral when trying to get resource reference, which
would cause it bumped down to the end of dpm list?

> 
> the pwm backlight and cros_ec_spi pwm are very interesting, not only about
> suspend dependency... if we unbind cros_ec_spi pwm, the pwm backlight would
> still hold a reference to it, and crash the kernel later.

That would be a bug in PWM/cors_ec and it should keep the PWM object
until last reference drops and simply error out on all requests.

> 
> On 10/14/2017 12:42 AM, Mark Brown wrote:
> > On Fri, Oct 13, 2017 at 08:51:21AM -0700, Brian Norris wrote:
> > 
> > > Yes, this does seem odd to me too. This looks like an arms race hack
> > > that should be avoided unless we know a legit root cause. Also,
> > > "probe order implies suspend order" doesn't quite work for async suspend
> > > anyway, so we'd probably want to express the dependency properly
> > > anyway.
> > 
> > Yeah, it's the same stuff as we get with initcall ordering.  This sort
> > of thing does happen with things like PMICs which tend to have hardware
> > that the system wants to manipulate in the IRQs off part of suspend.
> > Ideally the dependency annotation stuff would figure things out though
> > I'm not sure what the status of that is.

I'd say non-existent for resources such as regulators, pwms, clocks,
etc. I do not think many places call device_link_add()... I think adding
this to devm_* APIs might be easiest to get the ball going as they
naturally have consumer device and can easily figure out the supplier
side.

> > 
> > > Any chance this is related? Seems like that might break the parent/child
> > > relationship for master/slave:
> > 
> > > commit d7e2ee257038baeb03baef602500368a51ee9eef
> > > Author: Linus Walleij <linus.walleij at linaro.org>
> > > Date:   Mon Apr 11 13:51:03 2016 +0200
> > 
> > >      spi: let SPI masters ignore their children for PM
> > 
> > That's for runtime PM, I'd not expect it to affect system suspend.
> > 
> 
> 

Thanks.

-- 
Dmitry


From jeffy.chen at rock-chips.com  Fri Oct 13 11:33:45 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Sat, 14 Oct 2017 02:33:45 +0800
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <2453698.N4jfPaHx71@aspire.rjw.lan>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
 <20171013030441.GA25517@bhelgaas-glaptop.roam.corp.google.com>
 <2453698.N4jfPaHx71@aspire.rjw.lan>
Message-ID: <59E10709.4020300@rock-chips.com>

Hi Rafael,

On 10/13/2017 09:21 PM, Rafael J. Wysocki wrote:
>>
>>I'm a little skeptical about dev_pm_set_dedicated_wake_irq(), not
>>because I know anything at all about it, but because there are only
>>five callers in the whole tree, three of which are in UART code, and
>>none in anything resembling PCI code.
>>
>>Is Rockchip really that special, or are we going about this the wrong
>>way?

we used to put these codes in the wifi driver, but another wifi vendor 
suggests these should go into the pcie driver.

and as tony said, it could go into pcie common code :)
>>
>> > >+		if (err)
>> > >+			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
>> > >+	}
>> > >+
>> > >  	return 0;
>>
>>The above could be structured as:
>>
>>   irq = platform_get_irq_byname(pdev, "wakeup");
>>   if (irq < 0)
>>     return 0;
>>
>>   device_init_wakeup(dev, true);
>>   err = dev_pm_set_dedicated_wake_irq(dev, irq);
>>   if (err) {
>>     dev_pm_clear_wake_irq(dev);
>>     device_init_wakeup(dev, false);
>>   }
>>
there's no need to call dev_pm_clear_wake_irq when 
dev_pm_set_dedicated_wake_irq failed...and i agree the 
device_init_wakeup part, i'll add that in the next version(with brian's 
comment too)
>>   return 0;
>>
>>to unindent the mainline non-error code.
>>
>> > >  }
>> > >
>> > >@@ -1542,11 +1552,11 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
>> > >
>> > >  	err = rockchip_pcie_parse_dt(rockchip);
>> > >  	if (err)
>> > >-		return err;
>> > >+		goto err_disable_wake;
>> > >
>> > >  	err = rockchip_pcie_enable_clocks(rockchip);
>> > >  	if (err)
>> > >-		return err;
>> > >+		goto err_disable_wake;
>> > >
>> > >  	err = rockchip_pcie_set_vpcie(rockchip);
>> > >  	if (err) {
>> > >@@ -1656,6 +1666,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
>> > >  		regulator_disable(rockchip->vpcie0v9);
>> > >  err_set_vpcie:
>> > >  	rockchip_pcie_disable_clocks(rockchip);
>> > >+err_disable_wake:
>> > >+	dev_pm_clear_wake_irq(dev);
>> > >+	device_init_wakeup(dev, false);
>>
>>I think this error cleanup should be done in rockchip_pcie_setup_irq()
>>as shown above.  There's no real connection between
>>rockchip_pcie_probe() and the wake setup.

this error handling is like inline "rockchip_pcie_cleanup_irq()", and 
they are harmless to be called even if we don't have the wakeup irq :)




From broonie at kernel.org  Fri Oct 13 11:37:50 2017
From: broonie at kernel.org (Mark Brown)
Date: Fri, 13 Oct 2017 19:37:50 +0100
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early
 system PM callbacks
In-Reply-To: <20171013183006.k6pzcr5tcwsxxtmp@dtor-ws>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
 <20171013155120.GA137489@google.com>
 <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>
 <59E103B0.8060705@rock-chips.com>
 <20171013183006.k6pzcr5tcwsxxtmp@dtor-ws>
Message-ID: <20171013183750.piabs7m3dnpabnkm@sirena.co.uk>

On Fri, Oct 13, 2017 at 11:30:06AM -0700, Dmitry Torokhov wrote:
> On Sat, Oct 14, 2017 at 02:19:28AM +0800, jeffy wrote:

> > > Yeah, it's the same stuff as we get with initcall ordering.  This sort
> > > of thing does happen with things like PMICs which tend to have hardware
> > > that the system wants to manipulate in the IRQs off part of suspend.
> > > Ideally the dependency annotation stuff would figure things out though
> > > I'm not sure what the status of that is.

> I'd say non-existent for resources such as regulators, pwms, clocks,
> etc. I do not think many places call device_link_add()... I think adding
> this to devm_* APIs might be easiest to get the ball going as they
> naturally have consumer device and can easily figure out the supplier
> side.

Hrm, are things in a state where we're supposed to be doing that?  I've
not seen anyone even trying which is a bit odd, I'd thought there was
some core work still ongoing (and it wasn't clear to me if we were going
to try to do things like use DT/ACPI cross references to figure this
stuff out).
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20171013/15987c86/attachment.sig>

From jeffy.chen at rock-chips.com  Fri Oct 13 11:44:01 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Sat, 14 Oct 2017 02:44:01 +0800
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early system
 PM callbacks
In-Reply-To: <20171013183006.k6pzcr5tcwsxxtmp@dtor-ws>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
 <20171013155120.GA137489@google.com>
 <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>
 <59E103B0.8060705@rock-chips.com> <20171013183006.k6pzcr5tcwsxxtmp@dtor-ws>
Message-ID: <59E10971.6020200@rock-chips.com>

Hi Dmitry,

On 10/14/2017 02:30 AM, Dmitry Torokhov wrote:
> On Sat, Oct 14, 2017 at 02:19:28AM +0800, jeffy wrote:
>> Hi guys,
>>
>> it looks like the suspend sequence depends on the dt node sequence, and we
>> are putting display-subsystem dt node above spi dt node, so it would be
>> earlier in the device list, then got suspended later than spi device.
>
> Would it not get a deferral when trying to get resource reference, which
> would cause it bumped down to the end of dpm list?
hmm, right, check again, the rockchip drm would not depend on spi, but 
the edp driver does.

so the drm driver(display-subsystem) would probed before spi, but try to 
control the backlight in the suspend/resume...

so i was wrong in the commit message, will fix it in next version.
>
>>
>> the pwm backlight and cros_ec_spi pwm are very interesting, not only about
>> suspend dependency... if we unbind cros_ec_spi pwm, the pwm backlight would
>> still hold a reference to it, and crash the kernel later.
>
> That would be a bug in PWM/cors_ec and it should keep the PWM object
> until last reference drops and simply error out on all requests.
right, and maybe try to refresh the pwm reference when we bind it again
>
>>
>> On 10/14/2017 12:42 AM, Mark Brown wrote:
>>> On Fri, Oct 13, 2017 at 08:51:21AM -0700, Brian Norris wrote:
>>>
>>>> Yes, this does seem odd to me too. This looks like an arms race hack
>>>> that should be avoided unless we know a legit root cause. Also,
>>>> "probe order implies suspend order" doesn't quite work for async suspend
>>>> anyway, so we'd probably want to express the dependency properly
>>>> anyway.
>>>
>>> Yeah, it's the same stuff as we get with initcall ordering.  This sort
>>> of thing does happen with things like PMICs which tend to have hardware
>>> that the system wants to manipulate in the IRQs off part of suspend.
>>> Ideally the dependency annotation stuff would figure things out though
>>> I'm not sure what the status of that is.
>
> I'd say non-existent for resources such as regulators, pwms, clocks,
> etc. I do not think many places call device_link_add()... I think adding
> this to devm_* APIs might be easiest to get the ball going as they
> naturally have consumer device and can easily figure out the supplier
> side.
>
>>>
>>>> Any chance this is related? Seems like that might break the parent/child
>>>> relationship for master/slave:
>>>
>>>> commit d7e2ee257038baeb03baef602500368a51ee9eef
>>>> Author: Linus Walleij <linus.walleij at linaro.org>
>>>> Date:   Mon Apr 11 13:51:03 2016 +0200
>>>
>>>>       spi: let SPI masters ignore their children for PM
>>>
>>> That's for runtime PM, I'd not expect it to affect system suspend.
>>>
>>
>>
>
> Thanks.
>




From dmitry.torokhov at gmail.com  Fri Oct 13 11:30:48 2017
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Fri, 13 Oct 2017 11:30:48 -0700
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early
 system PM callbacks
In-Reply-To: <59E1052C.3000503@rock-chips.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
 <20171013155120.GA137489@google.com>
 <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>
 <59E103B0.8060705@rock-chips.com> <59E1052C.3000503@rock-chips.com>
Message-ID: <20171013183048.dg6wsabnz7qiviwy@dtor-ws>

On Sat, Oct 14, 2017 at 02:25:48AM +0800, jeffy wrote:
> On 10/14/2017 02:19 AM, jeffy wrote:
> > 
> > 
> > it looks like the suspend sequence depends on the dt node sequence, and
> > we are putting display-subsystem dt node above spi dt node, so it would
> > be earlier in the device list, then got suspended later than spi device.
> > 
> > the pwm backlight and cros_ec_spi pwm are very interesting, not only
> > about suspend dependency... if we unbind cros_ec_spi pwm, the pwm
> > backlight would still hold a reference to it, and crash the kernel later.
> 
> or maybe we should move device_pm_add() from device_add() to driver_bound()?

You do not necessarily need to have a driver to power the dveice on and
off.

-- 
Dmitry


From jeffy.chen at rock-chips.com  Fri Oct 13 11:25:48 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Sat, 14 Oct 2017 02:25:48 +0800
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early system
 PM callbacks
In-Reply-To: <59E103B0.8060705@rock-chips.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
 <20171013155120.GA137489@google.com>
 <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>
 <59E103B0.8060705@rock-chips.com>
Message-ID: <59E1052C.3000503@rock-chips.com>

On 10/14/2017 02:19 AM, jeffy wrote:
>
>
> it looks like the suspend sequence depends on the dt node sequence, and
> we are putting display-subsystem dt node above spi dt node, so it would
> be earlier in the device list, then got suspended later than spi device.
>
> the pwm backlight and cros_ec_spi pwm are very interesting, not only
> about suspend dependency... if we unbind cros_ec_spi pwm, the pwm
> backlight would still hold a reference to it, and crash the kernel later.

or maybe we should move device_pm_add() from device_add() to driver_bound()?



From jeffy.chen at rock-chips.com  Fri Oct 13 12:01:42 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Sat, 14 Oct 2017 03:01:42 +0800
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early system
 PM callbacks
In-Reply-To: <59E10971.6020200@rock-chips.com>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
 <20171013155120.GA137489@google.com>
 <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>
 <59E103B0.8060705@rock-chips.com> <20171013183006.k6pzcr5tcwsxxtmp@dtor-ws>
 <59E10971.6020200@rock-chips.com>
Message-ID: <59E10D96.90307@rock-chips.com>

Hi guys,

so what happens here is:
1/ we put display-subsystem dt node before spi node, which cause 
rockchip drm driver probed before spi(also before edp driver/vop driver...)

2/ rockchip drm driver bound after spi/edp/vop... drivers probed

3/ in rockchip drm driver's resume callback, it would try to enable edp 
panel backlight(through spi), but spi master is still suspended, then we 
got these errors:

1970-01-01T08:02:59.607315+08:00 ERR kernel: [  178.754005] cros-ec-spi 
spi2.0: spi
  transfer failed: -108
1970-01-01T08:02:59.607320+08:00 ERR kernel: [  178.760102] cros-ec-spi 
spi2.0: cs-
deassert spi transfer failed: -108
1970-01-01T08:02:59.607325+08:00 ERR kernel: [  178.767380] cros-ec-spi 
spi2.0: Com
mand xfer error (err:-108)
1970-01-01T08:02:59.607331+08:00 ERR kernel: [  178.773963] cros-ec-spi 
spi2.0: spi
  transfer failed: -108
1970-01-01T08:02:59.607336+08:00 ERR kernel: [  178.780066] cros-ec-spi 
spi2.0: cs-
deassert spi transfer failed: -108
1970-01-01T08:02:59.607341+08:00 ERR kernel: [  178.787359] cros-ec-spi 
spi2.0: Com
mand xfer error (err:-108)

so other than move spi master suspend to late suspend, maybe we could 
defer rockchip drm driver probe after it's component drivers somehow?



On 10/14/2017 02:44 AM, jeffy wrote:
> Hi Dmitry,
>
> On 10/14/2017 02:30 AM, Dmitry Torokhov wrote:
>> On Sat, Oct 14, 2017 at 02:19:28AM +0800, jeffy wrote:
>>> Hi guys,
>>>
>>> it looks like the suspend sequence depends on the dt node sequence,
>>> and we
>>> are putting display-subsystem dt node above spi dt node, so it would be
>>> earlier in the device list, then got suspended later than spi device.
>>
>> Would it not get a deferral when trying to get resource reference, which
>> would cause it bumped down to the end of dpm list?
> hmm, right, check again, the rockchip drm would not depend on spi, but
> the edp driver does.
>
> so the drm driver(display-subsystem) would probed before spi, but try to
> control the backlight in the suspend/resume...
>
> so i was wrong in the commit message, will fix it in next version.
>>
>>>
>>> the pwm backlight and cros_ec_spi pwm are very interesting, not only
>>> about
>>> suspend dependency... if we unbind cros_ec_spi pwm, the pwm backlight
>>> would
>>> still hold a reference to it, and crash the kernel later.
>>
>> That would be a bug in PWM/cors_ec and it should keep the PWM object
>> until last reference drops and simply error out on all requests.
> right, and maybe try to refresh the pwm reference when we bind it again
>>
>>>
>>> On 10/14/2017 12:42 AM, Mark Brown wrote:
>>>> On Fri, Oct 13, 2017 at 08:51:21AM -0700, Brian Norris wrote:
>>>>
>>>>> Yes, this does seem odd to me too. This looks like an arms race hack
>>>>> that should be avoided unless we know a legit root cause. Also,
>>>>> "probe order implies suspend order" doesn't quite work for async
>>>>> suspend
>>>>> anyway, so we'd probably want to express the dependency properly
>>>>> anyway.
>>>>
>>>> Yeah, it's the same stuff as we get with initcall ordering.  This sort
>>>> of thing does happen with things like PMICs which tend to have hardware
>>>> that the system wants to manipulate in the IRQs off part of suspend.
>>>> Ideally the dependency annotation stuff would figure things out though
>>>> I'm not sure what the status of that is.
>>
>> I'd say non-existent for resources such as regulators, pwms, clocks,
>> etc. I do not think many places call device_link_add()... I think adding
>> this to devm_* APIs might be easiest to get the ball going as they
>> naturally have consumer device and can easily figure out the supplier
>> side.
>>
>>>>
>>>>> Any chance this is related? Seems like that might break the
>>>>> parent/child
>>>>> relationship for master/slave:
>>>>
>>>>> commit d7e2ee257038baeb03baef602500368a51ee9eef
>>>>> Author: Linus Walleij <linus.walleij at linaro.org>
>>>>> Date:   Mon Apr 11 13:51:03 2016 +0200
>>>>
>>>>>       spi: let SPI masters ignore their children for PM
>>>>
>>>> That's for runtime PM, I'd not expect it to affect system suspend.
>>>>
>>>
>>>
>>
>> Thanks.
>>
>




From helgaas at kernel.org  Fri Oct 13 12:19:06 2017
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Fri, 13 Oct 2017 14:19:06 -0500
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <59E10709.4020300@rock-chips.com>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
 <20171013030441.GA25517@bhelgaas-glaptop.roam.corp.google.com>
 <2453698.N4jfPaHx71@aspire.rjw.lan>
 <59E10709.4020300@rock-chips.com>
Message-ID: <20171013191906.GF25517@bhelgaas-glaptop.roam.corp.google.com>

On Sat, Oct 14, 2017 at 02:33:45AM +0800, jeffy wrote:
> Hi Rafael,
> 
> On 10/13/2017 09:21 PM, Rafael J. Wysocki wrote:
> >>
> >>I'm a little skeptical about dev_pm_set_dedicated_wake_irq(), not
> >>because I know anything at all about it, but because there are only
> >>five callers in the whole tree, three of which are in UART code, and
> >>none in anything resembling PCI code.
> >>
> >>Is Rockchip really that special, or are we going about this the wrong
> >>way?
> 
> we used to put these codes in the wifi driver, but another wifi
> vendor suggests these should go into the pcie driver.
> 
> and as tony said, it could go into pcie common code :)

I guess the implication (I'm speculating here) is that in most
existing cases, the WAKE# signal is fielded by an ACPI BIOS, which
knows how it's connected.  I suppose that would end up being turned
into an SCI that Linux already knows how to handle generically.

And further, that the non-ACPI drivers are relatively new and you're
the first attempt to use WAKE# with a non-ACPI PCI host driver?

If this setup could be done somewhere in PCIe common code, that would
be great.  We have so much copy and pasted code already, it'd be nice
to avoid adding more.  I don't know if this would fit in
pci_scan_root_bus_bridge(), doing something like dma_configure() does
to get hold of a struct platform_device * or a struct device * so you
could lookup the IRQ?

> >>> >+		if (err)
> >>> >+			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
> >>> >+	}
> >>> >+
> >>> >  	return 0;
> >>
> >>The above could be structured as:
> >>
> >>  irq = platform_get_irq_byname(pdev, "wakeup");
> >>  if (irq < 0)
> >>    return 0;
> >>
> >>  device_init_wakeup(dev, true);
> >>  err = dev_pm_set_dedicated_wake_irq(dev, irq);
> >>  if (err) {
> >>    dev_pm_clear_wake_irq(dev);
> >>    device_init_wakeup(dev, false);
> >>  }
> >>
> there's no need to call dev_pm_clear_wake_irq when
> dev_pm_set_dedicated_wake_irq failed...and i agree the
> device_init_wakeup part, i'll add that in the next version(with
> brian's comment too)
> >>  return 0;
> >>
> >>to unindent the mainline non-error code.
> >>
> >>> >  }
> >>> >
> >>> >@@ -1542,11 +1552,11 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
> >>> >
> >>> >  	err = rockchip_pcie_parse_dt(rockchip);
> >>> >  	if (err)
> >>> >-		return err;
> >>> >+		goto err_disable_wake;
> >>> >
> >>> >  	err = rockchip_pcie_enable_clocks(rockchip);
> >>> >  	if (err)
> >>> >-		return err;
> >>> >+		goto err_disable_wake;
> >>> >
> >>> >  	err = rockchip_pcie_set_vpcie(rockchip);
> >>> >  	if (err) {
> >>> >@@ -1656,6 +1666,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
> >>> >  		regulator_disable(rockchip->vpcie0v9);
> >>> >  err_set_vpcie:
> >>> >  	rockchip_pcie_disable_clocks(rockchip);
> >>> >+err_disable_wake:
> >>> >+	dev_pm_clear_wake_irq(dev);
> >>> >+	device_init_wakeup(dev, false);
> >>
> >>I think this error cleanup should be done in rockchip_pcie_setup_irq()
> >>as shown above.  There's no real connection between
> >>rockchip_pcie_probe() and the wake setup.
> 
> this error handling is like inline "rockchip_pcie_cleanup_irq()",
> and they are harmless to be called even if we don't have the wakeup
> irq :)

I'm sure they're harmless.  The point is that the cleanup should be
done near the failure, not in the caller of the caller of the function
where the failure was detected.  You have:

  rockchip_pcie_probe
    rockchip_pcie_parse_dt
      rockchip_pcie_setup_irq
        err = dev_pm_set_dedicated_wake_irq
        if (err)
          dev_err(...)

So you detect the error in rockchip_pcie_setup_irq(), but you clean up
from it in rockchip_pcie_probe(), which doesn't make sense because
rockchip_pcie_probe() doesn't do anything related to wakeup interupts.

Bjorn


From jeffy.chen at rock-chips.com  Fri Oct 13 12:26:16 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Sat, 14 Oct 2017 03:26:16 +0800
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171013191906.GF25517@bhelgaas-glaptop.roam.corp.google.com>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
 <20171013030441.GA25517@bhelgaas-glaptop.roam.corp.google.com>
 <2453698.N4jfPaHx71@aspire.rjw.lan> <59E10709.4020300@rock-chips.com>
 <20171013191906.GF25517@bhelgaas-glaptop.roam.corp.google.com>
Message-ID: <59E11358.3090409@rock-chips.com>

Hi Bjorn,

On 10/14/2017 03:19 AM, Bjorn Helgaas wrote:
> I'm sure they're harmless.  The point is that the cleanup should be
> done near the failure, not in the caller of the caller of the function
> where the failure was detected.  You have:
>
>    rockchip_pcie_probe
>      rockchip_pcie_parse_dt
>        rockchip_pcie_setup_irq
>          err = dev_pm_set_dedicated_wake_irq
>          if (err)
>            dev_err(...)
>
> So you detect the error in rockchip_pcie_setup_irq(), but you clean up
> from it in rockchip_pcie_probe(), which doesn't make sense because
> rockchip_pcie_probe() doesn't do anything related to wakeup interupts.
>
right, but if something wrong happens in rockchip_pcie_probe() later 
than rockchip_pcie_setup_irq(), we may still need to clean it up ;)

i think the error handling is a little like what we do in the remove 
callback
> Bjorn
>
>
>




From jeffy.chen at rock-chips.com  Fri Oct 13 12:50:55 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Sat, 14 Oct 2017 03:50:55 +0800
Subject: [PATCH v6 0/3] PCI: rockchip: Move PCIE_WAKE handling into rockchip
 pcie driver
Message-ID: <20171013195059.23865-1-jeffy.chen@rock-chips.com>


Currently we are handling pcie wake in mrvl wifi driver. But Brian
suggests to move it into rockchip pcie driver.

Tested on my chromebook bob(with cros 4.4 kernel and mrvl wifi).


Changes in v6:
Fix device_init_wake error handling, and add some comments.

Changes in v5:
Rebase
Move to pci.txt
Use "wakeup" instead of "wake"

Changes in v3:
Fix error handling

Changes in v2:
Use dev_pm_set_dedicated_wake_irq
        -- Suggested by Brian Norris <briannorris at chromium.com>

Jeffy Chen (3):
  PCI: rockchip: Add support for pcie wake irq
  dt-bindings: PCI: Add definition of pcie wake irq
  arm64: dts: rockchip: Handle pcie wake in pcie driver for Gru

 Documentation/devicetree/bindings/pci/pci.txt |  2 ++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi  | 15 +++++++++------
 drivers/pci/host/pcie-rockchip.c              | 27 +++++++++++++++++++++------
 3 files changed, 32 insertions(+), 12 deletions(-)

-- 
2.11.0




From jeffy.chen at rock-chips.com  Fri Oct 13 12:50:56 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Sat, 14 Oct 2017 03:50:56 +0800
Subject: [PATCH v6 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171013195059.23865-1-jeffy.chen@rock-chips.com>
References: <20171013195059.23865-1-jeffy.chen@rock-chips.com>
Message-ID: <20171013195059.23865-2-jeffy.chen@rock-chips.com>

Add support for PCIE_WAKE pin in rockchip pcie driver.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v6:
Fix device_init_wake error handling, and add some comments.

Changes in v5:
Rebase

Changes in v3:
Fix error handling

Changes in v2:
Use dev_pm_set_dedicated_wake_irq
        -- Suggested by Brian Norris <briannorris at chromium.com>

 drivers/pci/host/pcie-rockchip.c | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
index 9051c6c8fea4..268513b6c9c4 100644
--- a/drivers/pci/host/pcie-rockchip.c
+++ b/drivers/pci/host/pcie-rockchip.c
@@ -37,6 +37,7 @@
 #include <linux/pci_ids.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
 #include <linux/reset.h>
 #include <linux/regmap.h>
 
@@ -995,6 +996,17 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
 		return err;
 	}
 
+	irq = platform_get_irq_byname(pdev, "wakeup");
+	if (irq >= 0) {
+		/* Must init wakeup before setting dedicated wakeup irq. */
+		device_init_wakeup(dev, true);
+		err = dev_pm_set_dedicated_wake_irq(dev, irq);
+		if (err) {
+			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
+			device_init_wakeup(dev, false);
+		}
+	}
+
 	return 0;
 }
 
@@ -1123,10 +1135,6 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
 		return PTR_ERR(rockchip->clk_pcie_pm);
 	}
 
-	err = rockchip_pcie_setup_irq(rockchip);
-	if (err)
-		return err;
-
 	rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v");
 	if (IS_ERR(rockchip->vpcie12v)) {
 		if (PTR_ERR(rockchip->vpcie12v) == -EPROBE_DEFER)
@@ -1155,7 +1163,7 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
 		dev_info(dev, "no vpcie0v9 regulator found\n");
 	}
 
-	return 0;
+	return rockchip_pcie_setup_irq(rockchip);
 }
 
 static int rockchip_pcie_set_vpcie(struct rockchip_pcie *rockchip)
@@ -1546,7 +1554,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
 
 	err = rockchip_pcie_enable_clocks(rockchip);
 	if (err)
-		return err;
+		/* Cleanup rockchip_pcie_parse_dt() */
+		goto err_disable_wake;
 
 	err = rockchip_pcie_set_vpcie(rockchip);
 	if (err) {
@@ -1656,6 +1665,10 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
 		regulator_disable(rockchip->vpcie0v9);
 err_set_vpcie:
 	rockchip_pcie_disable_clocks(rockchip);
+err_disable_wake:
+	/* It's harmless to disable wake even not enabled */
+	dev_pm_clear_wake_irq(dev);
+	device_init_wakeup(dev, false);
 	return err;
 }
 
@@ -1682,6 +1695,8 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
 	if (!IS_ERR(rockchip->vpcie0v9))
 		regulator_disable(rockchip->vpcie0v9);
 
+	dev_pm_clear_wake_irq(dev);
+	device_init_wakeup(dev, false);
 	return 0;
 }
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Fri Oct 13 12:50:58 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Sat, 14 Oct 2017 03:50:58 +0800
Subject: [PATCH v6 3/3] arm64: dts: rockchip: Handle pcie wake in pcie driver
 for Gru
In-Reply-To: <20171013195059.23865-1-jeffy.chen@rock-chips.com>
References: <20171013195059.23865-1-jeffy.chen@rock-chips.com>
Message-ID: <20171013195059.23865-4-jeffy.chen@rock-chips.com>

Currently we are handling pcie wake irq in mrvl wifi driver.
Move it to rockchip pcie driver for Gru boards.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v6: None
Changes in v5:
Use "wakeup" instead of "wake"

Changes in v3: None
Changes in v2: None

 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 199a5118b20d..9e0269a13ced 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -707,7 +707,15 @@ ap_i2c_audio: &i2c8 {
 
 	ep-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wifi_perst_l>;
+	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wlan_host_wake_l>, <&wifi_perst_l>;
+
+	interrupts-extended = <&gic GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gpio0 8 IRQ_TYPE_LEVEL_LOW>;
+	interrupt-names = "sys", "legacy", "client", "wakeup";
+	/delete-property/ interrupts;
+
 	vpcie3v3-supply = <&pp3300_wifi_bt>;
 	vpcie1v8-supply = <&wlan_pd_n>; /* HACK: see &wlan_pd_n */
 	vpcie0v9-supply = <&pp900_pcie>;
@@ -722,11 +730,6 @@ ap_i2c_audio: &i2c8 {
 			compatible = "pci1b4b,2b42";
 			reg = <0x83010000 0x0 0x00000000 0x0 0x00100000
 			       0x83010000 0x0 0x00100000 0x0 0x00100000>;
-			interrupt-parent = <&gpio0>;
-			interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
-			pinctrl-names = "default";
-			pinctrl-0 = <&wlan_host_wake_l>;
-			wakeup-source;
 		};
 	};
 };
-- 
2.11.0




From briannorris at chromium.org  Fri Oct 13 13:44:00 2017
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 Oct 2017 13:44:00 -0700
Subject: [PATCH v5 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171013191906.GF25517@bhelgaas-glaptop.roam.corp.google.com>
References: <20170911151029.25185-1-jeffy.chen@rock-chips.com>
 <20170911151029.25185-2-jeffy.chen@rock-chips.com>
 <20171013030441.GA25517@bhelgaas-glaptop.roam.corp.google.com>
 <2453698.N4jfPaHx71@aspire.rjw.lan>
 <59E10709.4020300@rock-chips.com>
 <20171013191906.GF25517@bhelgaas-glaptop.roam.corp.google.com>
Message-ID: <20171013204358.GA3585@google.com>

Hi,

On Fri, Oct 13, 2017 at 02:19:06PM -0500, Bjorn Helgaas wrote:
> On Sat, Oct 14, 2017 at 02:33:45AM +0800, jeffy wrote:
> > Hi Rafael,
> > 
> > On 10/13/2017 09:21 PM, Rafael J. Wysocki wrote:
> > >>
> > >>I'm a little skeptical about dev_pm_set_dedicated_wake_irq(), not
> > >>because I know anything at all about it, but because there are only
> > >>five callers in the whole tree, three of which are in UART code, and
> > >>none in anything resembling PCI code.
> > >>
> > >>Is Rockchip really that special, or are we going about this the wrong
> > >>way?
> > 
> > we used to put these codes in the wifi driver, but another wifi
> > vendor suggests these should go into the pcie driver.
> > 
> > and as tony said, it could go into pcie common code :)
> 
> I guess the implication (I'm speculating here) is that in most
> existing cases, the WAKE# signal is fielded by an ACPI BIOS, which
> knows how it's connected.  I suppose that would end up being turned
> into an SCI that Linux already knows how to handle generically.

I wasn't sure how ACPI did this when I first suggested Rockchip take
this approach, but since then I believe have figured it out. We have:

pci_prepare_to_sleep() -> pci_enable_wake()

where pci_enable_wake() will configure PME wakeup and/or "platform" wake
(which presumably is the WAKE# signal). pci-acpi.c has registered hooks
for the latter via pci_set_platform_pm().

This doesn't really make it any more generic for discovering this
platform-specific detail. We'd have to set up some kind of platform ops
that could be shared for any DT-based platforms.

But that *does* answer the question I had about conditionality: should
we always enable WAKE# for platforms that have the pin hooked up to the
host? Or is this configured on a per-device basis? IIUC, the intention
is that there's only a single open-drain WAKE# pin for the whole system,
and it's just pulled high for EPs that don't implement it.

> And further, that the non-ACPI drivers are relatively new and you're
> the first attempt to use WAKE# with a non-ACPI PCI host driver?

Quite possibly. Or everyone just sidestepped this an configured the pin
elsewhere (e.g., you could stick a GPIO like this into a gpio-keys
device and it would mostly work).

> If this setup could be done somewhere in PCIe common code, that would
> be great.  We have so much copy and pasted code already, it'd be nice
> to avoid adding more.  I don't know if this would fit in
> pci_scan_root_bus_bridge(), doing something like dma_configure() does
> to get hold of a struct platform_device * or a struct device * so you
> could lookup the IRQ?

It looks like the infrastructure is in pci_set_platform_pm(), sort of.
But that still doesn't help you for the repetition; you're just lucky
you only have 2 controller drivers that call this right now :)

Side note: there's some dissonance between this statement, in
Documentation/driver-api/pm/devices.rst:

"Device drivers, however, are not expected to call
:c:func:`device_set_wakeup_enable()` directly in any case."

Yet:

$ git grep -l device_set_wakeup_enable drivers/ | wc -l
69

And particularly, I believe that was necessary for Wifi drivers like
drivers/net/wireless/ath/ath10k/wow.c.

Brian


From phh at phh.me  Fri Oct 13 15:53:34 2017
From: phh at phh.me (Pierre-Hugues Husson)
Date: Sat, 14 Oct 2017 00:53:34 +0200
Subject: [PATCH 0/3] Enable CEC on rk3399
Message-ID: <20171013225337.5196-1-phh@phh.me>

Enable CEC on firefly-rk3399.
Tested on a TV with cec-ctl --playback; cec-ctl -S

Pierre-Hugues Husson (3):
  drm: bridge: synopsys/dw-hdmi: Enable cec clock
  arm64: dts: rockchip: add the cec clk for dw-mipi-hdmi on rk3399
  arm64: dts: rockchip: enable cec pin for rk3399 firefly

 arch/arm64/boot/dts/rockchip/rk3399-firefly.dts |  2 ++
 arch/arm64/boot/dts/rockchip/rk3399.dtsi        |  8 ++++++--
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c       | 16 ++++++++++++++++
 3 files changed, 24 insertions(+), 2 deletions(-)

-- 
2.14.1



From phh at phh.me  Fri Oct 13 15:53:37 2017
From: phh at phh.me (Pierre-Hugues Husson)
Date: Sat, 14 Oct 2017 00:53:37 +0200
Subject: [PATCH 3/3] arm64: dts: rockchip: enable cec pin for rk3399 firefly
In-Reply-To: <20171013225337.5196-1-phh@phh.me>
References: <20171013225337.5196-1-phh@phh.me>
Message-ID: <20171013225337.5196-4-phh@phh.me>

Signed-off-by: Pierre-Hugues Husson <phh at phh.me>
---
 arch/arm64/boot/dts/rockchip/rk3399-firefly.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
index f6fbcc05073e..431ff1bb3720 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
@@ -257,6 +257,8 @@
 
 &hdmi {
 	ddc-i2c-bus = <&i2c3>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_cec>;
 	status = "okay";
 };
 
-- 
2.14.1



From phh at phh.me  Fri Oct 13 15:53:35 2017
From: phh at phh.me (Pierre-Hugues Husson)
Date: Sat, 14 Oct 2017 00:53:35 +0200
Subject: [PATCH 1/3] drm: bridge: synopsys/dw-hdmi: Enable cec clock
In-Reply-To: <20171013225337.5196-1-phh@phh.me>
References: <20171013225337.5196-1-phh@phh.me>
Message-ID: <20171013225337.5196-2-phh@phh.me>

The documentation already mentions "cec" optional clock, but
currently the driver doesn't enable it.

Signed-off-by: Pierre-Hugues Husson <phh at phh.me>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index bf14214fa464..5007cdf43131 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -138,6 +138,7 @@ struct dw_hdmi {
 	struct device *dev;
 	struct clk *isfr_clk;
 	struct clk *iahb_clk;
+	struct clk *cec_clk;
 	struct dw_hdmi_i2c *i2c;
 
 	struct hdmi_data_info hdmi_data;
@@ -2382,6 +2383,18 @@ __dw_hdmi_probe(struct platform_device *pdev,
 		goto err_isfr;
 	}
 
+	hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec");
+	if (IS_ERR(hdmi->cec_clk)) {
+		hdmi->cec_clk = NULL;
+	} else {
+		ret = clk_prepare_enable(hdmi->cec_clk);
+		if (ret) {
+			dev_err(hdmi->dev, "Cannot enable HDMI cec clock: %d\n",
+					ret);
+			goto err_res;
+		}
+	}
+
 	/* Product and revision IDs */
 	hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
 		      | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
@@ -2518,6 +2531,8 @@ __dw_hdmi_probe(struct platform_device *pdev,
 		cec_notifier_put(hdmi->cec_notifier);
 
 	clk_disable_unprepare(hdmi->iahb_clk);
+	if (hdmi->cec_clk)
+		clk_disable_unprepare(hdmi->cec_clk);
 err_isfr:
 	clk_disable_unprepare(hdmi->isfr_clk);
 err_res:
@@ -2541,6 +2556,8 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
 
 	clk_disable_unprepare(hdmi->iahb_clk);
 	clk_disable_unprepare(hdmi->isfr_clk);
+	if (hdmi->cec_clk)
+		clk_disable_unprepare(hdmi->cec_clk);
 
 	if (hdmi->i2c)
 		i2c_del_adapter(&hdmi->i2c->adap);
-- 
2.14.1



From phh at phh.me  Fri Oct 13 15:53:36 2017
From: phh at phh.me (Pierre-Hugues Husson)
Date: Sat, 14 Oct 2017 00:53:36 +0200
Subject: [PATCH 2/3] arm64: dts: rockchip: add the cec clk for dw-mipi-hdmi on
 rk3399
In-Reply-To: <20171013225337.5196-1-phh@phh.me>
References: <20171013225337.5196-1-phh@phh.me>
Message-ID: <20171013225337.5196-3-phh@phh.me>

Signed-off-by: Pierre-Hugues Husson <phh at phh.me>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index ab7629c5b856..a65f7f744a40 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1601,8 +1601,12 @@
 		compatible = "rockchip,rk3399-dw-hdmi";
 		reg = <0x0 0xff940000 0x0 0x20000>;
 		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>;
-		clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_SFR>, <&cru PLL_VPLL>, <&cru PCLK_VIO_GRF>;
-		clock-names = "iahb", "isfr", "vpll", "grf";
+		clocks = <&cru PCLK_HDMI_CTRL>,
+			 <&cru SCLK_HDMI_SFR>,
+			 <&cru PLL_VPLL>,
+			 <&cru PCLK_VIO_GRF>,
+			 <&cru SCLK_HDMI_CEC>;
+		clock-names = "iahb", "isfr", "vpll", "grf", "cec";
 		power-domains = <&power RK3399_PD_HDCP>;
 		reg-io-width = <4>;
 		rockchip,grf = <&grf>;
-- 
2.14.1



From dmitry.torokhov at gmail.com  Fri Oct 13 16:45:11 2017
From: dmitry.torokhov at gmail.com (Dmitry Torokhov)
Date: Fri, 13 Oct 2017 16:45:11 -0700
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early
 system PM callbacks
In-Reply-To: <20171013183750.piabs7m3dnpabnkm@sirena.co.uk>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013104138.3216-2-jeffy.chen@rock-chips.com>
 <CAD=FV=X6pkaY3t=ceh3QEUws+_gqRGMN9zveW0fXR1noF1T6ew@mail.gmail.com>
 <20171013155120.GA137489@google.com>
 <20171013164235.thgqha7sl5tdptwv@sirena.co.uk>
 <59E103B0.8060705@rock-chips.com>
 <20171013183006.k6pzcr5tcwsxxtmp@dtor-ws>
 <20171013183750.piabs7m3dnpabnkm@sirena.co.uk>
Message-ID: <20171013234511.dxazu5wvvz7sjiiu@dtor-ws>

On Fri, Oct 13, 2017 at 07:37:50PM +0100, Mark Brown wrote:
> On Fri, Oct 13, 2017 at 11:30:06AM -0700, Dmitry Torokhov wrote:
> > On Sat, Oct 14, 2017 at 02:19:28AM +0800, jeffy wrote:
> 
> > > > Yeah, it's the same stuff as we get with initcall ordering.  This sort
> > > > of thing does happen with things like PMICs which tend to have hardware
> > > > that the system wants to manipulate in the IRQs off part of suspend.
> > > > Ideally the dependency annotation stuff would figure things out though
> > > > I'm not sure what the status of that is.
> 
> > I'd say non-existent for resources such as regulators, pwms, clocks,
> > etc. I do not think many places call device_link_add()... I think adding
> > this to devm_* APIs might be easiest to get the ball going as they
> > naturally have consumer device and can easily figure out the supplier
> > side.
> 
> Hrm, are things in a state where we're supposed to be doing that?  I've
> not seen anyone even trying which is a bit odd, I'd thought there was
> some core work still ongoing (and it wasn't clear to me if we were going
> to try to do things like use DT/ACPI cross references to figure this
> stuff out).

Not sure, adding Rafael...

-- 
Dmitry


From briannorris at chromium.org  Fri Oct 13 17:06:48 2017
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 Oct 2017 17:06:48 -0700
Subject: [PATCH 0/3] PCI: rockchip: assert PERST# in S3
In-Reply-To: <20171013062728.GA56763@google.com>
References: <20171012205220.130048-1-briannorris@chromium.org>
 <20171013031523.GB25517@bhelgaas-glaptop.roam.corp.google.com>
 <20171013062728.GA56763@google.com>
Message-ID: <CA+ASDXM2UnoGOkyVy=y3XToTvLZ1djLNaDESkB89mf-mzqGHRg@mail.gmail.com>

Hi Bjorn,

One piece of information to add:

On Thu, Oct 12, 2017 at 11:27 PM, Brian Norris <briannorris at chromium.org> wrote:
> On Thu, Oct 12, 2017 at 10:15:23PM -0500, Bjorn Helgaas wrote:
> > Is this a hole in those specs?  Is this something that needs to be
> > clarified by the PCI-SIG to improve interoperability?
>
> After re-re-reading the specifications, I'm more convinced that the
> first Wifi vendor got it wrong. I also don't trust them to get many
> things right in general, so this is pretty much par for the course.
>
> The only things I can suggest:
> * "main power" is never defined, as far as I can tell. So "main" and
>   "auxiliary" power don't have much meaning for many M.2 cards, and so
>   I end up reading much of the spec with a grain of salt

This part is where the first vendor seems to disagree. They claim that
because power is not switched off, PERST# can remain asserted or
deasserted -- whichever leads to least power consumption. (i.e., they
don't consider they need to follow the parts that describe "when
removing main power" (e.g., in S3) we must assert PERST#.

> * S3 is never defined in the PCIe Card EM spec, but it's thrown around a
>   few times
> * if possible, the PCIe base spec should mention something about the
>   fundamental reset which is expected with an L2 transition. It's not
>   clear what to do if you don't want to switch off power completely (and
>   so enter L3), but you also don't have "auxiliary" power

Brian


From festevam at gmail.com  Fri Oct 13 17:18:59 2017
From: festevam at gmail.com (Fabio Estevam)
Date: Fri, 13 Oct 2017 21:18:59 -0300
Subject: [PATCH 1/3] drm: bridge: synopsys/dw-hdmi: Enable cec clock
In-Reply-To: <20171013225337.5196-2-phh@phh.me>
References: <20171013225337.5196-1-phh@phh.me>
 <20171013225337.5196-2-phh@phh.me>
Message-ID: <CAOMZO5CtP=A0jF1FimScjSUvv-t6a2ua=ungr0LUHmQvUTKr3Q@mail.gmail.com>

Hi Pierre-Hugues,

On Fri, Oct 13, 2017 at 7:53 PM, Pierre-Hugues Husson <phh at phh.me> wrote:
> The documentation already mentions "cec" optional clock, but
> currently the driver doesn't enable it.

The cec clock is enabled at dw_hdmi_cec_enable().


From rjw at rjwysocki.net  Fri Oct 13 17:15:34 2017
From: rjw at rjwysocki.net (Rafael J. Wysocki)
Date: Sat, 14 Oct 2017 02:15:34 +0200
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early
 system PM callbacks
In-Reply-To: <20171013234511.dxazu5wvvz7sjiiu@dtor-ws>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013183750.piabs7m3dnpabnkm@sirena.co.uk>
 <20171013234511.dxazu5wvvz7sjiiu@dtor-ws>
Message-ID: <1617641.TtuYKIH8aZ@aspire.rjw.lan>

On Saturday, October 14, 2017 1:45:11 AM CEST Dmitry Torokhov wrote:
> On Fri, Oct 13, 2017 at 07:37:50PM +0100, Mark Brown wrote:
> > On Fri, Oct 13, 2017 at 11:30:06AM -0700, Dmitry Torokhov wrote:
> > > On Sat, Oct 14, 2017 at 02:19:28AM +0800, jeffy wrote:
> > 
> > > > > Yeah, it's the same stuff as we get with initcall ordering.  This sort
> > > > > of thing does happen with things like PMICs which tend to have hardware
> > > > > that the system wants to manipulate in the IRQs off part of suspend.
> > > > > Ideally the dependency annotation stuff would figure things out though
> > > > > I'm not sure what the status of that is.
> > 
> > > I'd say non-existent for resources such as regulators, pwms, clocks,
> > > etc. I do not think many places call device_link_add()... I think adding
> > > this to devm_* APIs might be easiest to get the ball going as they
> > > naturally have consumer device and can easily figure out the supplier
> > > side.
> > 
> > Hrm, are things in a state where we're supposed to be doing that?  I've
> > not seen anyone even trying which is a bit odd, I'd thought there was
> > some core work still ongoing (and it wasn't clear to me if we were going
> > to try to do things like use DT/ACPI cross references to figure this
> > stuff out).
> 
> Not sure, adding Rafael...

The infrastructure in the core is there, the part related to getting that
information from firmware is (mostly) missing.

Still, moving system suspend/resume callbacks to the late/early phases may
be a good idea anyway.

Thanks,
Rafael





From hverkuil at xs4all.nl  Sat Oct 14 01:16:07 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Sat, 14 Oct 2017 10:16:07 +0200
Subject: [PATCH 1/3] drm: bridge: synopsys/dw-hdmi: Enable cec clock
In-Reply-To: <20171013225337.5196-2-phh@phh.me>
References: <20171013225337.5196-1-phh@phh.me>
 <20171013225337.5196-2-phh@phh.me>
Message-ID: <35b9fbe3-9859-03e2-173e-8cff5a90efdd@xs4all.nl>

On 10/14/2017 12:53 AM, Pierre-Hugues Husson wrote:
> The documentation already mentions "cec" optional clock, but
> currently the driver doesn't enable it.
> 
> Signed-off-by: Pierre-Hugues Husson <phh at phh.me>

Acked-by: Hans Verkuil <hans.verkuil at cisco.com>

Thanks!

	Hans

> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index bf14214fa464..5007cdf43131 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -138,6 +138,7 @@ struct dw_hdmi {
>  	struct device *dev;
>  	struct clk *isfr_clk;
>  	struct clk *iahb_clk;
> +	struct clk *cec_clk;
>  	struct dw_hdmi_i2c *i2c;
>  
>  	struct hdmi_data_info hdmi_data;
> @@ -2382,6 +2383,18 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  		goto err_isfr;
>  	}
>  
> +	hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec");
> +	if (IS_ERR(hdmi->cec_clk)) {
> +		hdmi->cec_clk = NULL;
> +	} else {
> +		ret = clk_prepare_enable(hdmi->cec_clk);
> +		if (ret) {
> +			dev_err(hdmi->dev, "Cannot enable HDMI cec clock: %d\n",
> +					ret);
> +			goto err_res;
> +		}
> +	}
> +
>  	/* Product and revision IDs */
>  	hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
>  		      | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
> @@ -2518,6 +2531,8 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  		cec_notifier_put(hdmi->cec_notifier);
>  
>  	clk_disable_unprepare(hdmi->iahb_clk);
> +	if (hdmi->cec_clk)
> +		clk_disable_unprepare(hdmi->cec_clk);
>  err_isfr:
>  	clk_disable_unprepare(hdmi->isfr_clk);
>  err_res:
> @@ -2541,6 +2556,8 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
>  
>  	clk_disable_unprepare(hdmi->iahb_clk);
>  	clk_disable_unprepare(hdmi->isfr_clk);
> +	if (hdmi->cec_clk)
> +		clk_disable_unprepare(hdmi->cec_clk);
>  
>  	if (hdmi->i2c)
>  		i2c_del_adapter(&hdmi->i2c->adap);
> 



From hverkuil at xs4all.nl  Sat Oct 14 01:23:12 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Sat, 14 Oct 2017 10:23:12 +0200
Subject: [PATCH 0/3] Enable CEC on rk3399
In-Reply-To: <20171013225337.5196-1-phh@phh.me>
References: <20171013225337.5196-1-phh@phh.me>
Message-ID: <9833f103-769f-b9b9-05c7-4d75bd7e487c@xs4all.nl>

On 10/14/2017 12:53 AM, Pierre-Hugues Husson wrote:
> Enable CEC on firefly-rk3399.
> Tested on a TV with cec-ctl --playback; cec-ctl -S
> 
> Pierre-Hugues Husson (3):
>   drm: bridge: synopsys/dw-hdmi: Enable cec clock
>   arm64: dts: rockchip: add the cec clk for dw-mipi-hdmi on rk3399
>   arm64: dts: rockchip: enable cec pin for rk3399 firefly
> 
>  arch/arm64/boot/dts/rockchip/rk3399-firefly.dts |  2 ++
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi        |  8 ++++++--
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c       | 16 ++++++++++++++++
>  3 files changed, 24 insertions(+), 2 deletions(-)
> 

Nice! I had a similar dw-hdmi.c patch pending but got around to posting it.

I'll brush off my old rk3288 patches and see if I can get CEC enabled
for my firefly-reload. I was close to getting it work, but I guess
missed the "enable cec pin" change.

Regards,

	Hans


From broonie at kernel.org  Sat Oct 14 01:59:45 2017
From: broonie at kernel.org (Mark Brown)
Date: Sat, 14 Oct 2017 01:59:45 -0700
Subject: [RESEND PATCH 1/2] spi: rockchip: Convert to late and early
 system PM callbacks
In-Reply-To: <1617641.TtuYKIH8aZ@aspire.rjw.lan>
References: <20171013104138.3216-1-jeffy.chen@rock-chips.com>
 <20171013183750.piabs7m3dnpabnkm@sirena.co.uk>
 <20171013234511.dxazu5wvvz7sjiiu@dtor-ws>
 <1617641.TtuYKIH8aZ@aspire.rjw.lan>
Message-ID: <20171014085945.grm6gtdzuunogbwf@sirena.org.uk>

On Sat, Oct 14, 2017 at 02:15:34AM +0200, Rafael J. Wysocki wrote:

> The infrastructure in the core is there, the part related to getting that
> information from firmware is (mostly) missing.

Ah, yes - now I remember.  We want this for probe ordering so we don't
really want to be doing it in the subsystems when they request resources
as that's too late (though I guess duplication there won't hurt).  Fun.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20171014/6de47038/attachment.sig>

From phh at phh.me  Sat Oct 14 06:14:40 2017
From: phh at phh.me (Pierre-Hugues Husson)
Date: Sat, 14 Oct 2017 15:14:40 +0200
Subject: [PATCH 0/3] Enable CEC on rk3399
In-Reply-To: <9833f103-769f-b9b9-05c7-4d75bd7e487c@xs4all.nl>
References: <20171013225337.5196-1-phh@phh.me>
 <9833f103-769f-b9b9-05c7-4d75bd7e487c@xs4all.nl>
Message-ID: <CAJ-oXjQ3e1UHVGq=uV=yAK9Bu=ZoiNZaEbnHyvNtyc15RQQSKg@mail.gmail.com>

Hi Hans,

> Nice! I had a similar dw-hdmi.c patch pending but got around to posting it.
>
> I'll brush off my old rk3288 patches and see if I can get CEC enabled
> for my firefly-reload. I was close to getting it work, but I guess
> missed the "enable cec pin" change.
Please note that on rk3288, there are two CEC pins, and you must write
in RK3288_GRF_SOC_CON8 which pin you're using.
On the firefly-reload, the pin used is GPIO7C0, while the default pin
configuration is GPIO7C7.

Regards,


From phh at phh.me  Sat Oct 14 06:21:17 2017
From: phh at phh.me (Pierre-Hugues Husson)
Date: Sat, 14 Oct 2017 15:21:17 +0200
Subject: [PATCH 1/3] drm: bridge: synopsys/dw-hdmi: Enable cec clock
In-Reply-To: <CAOMZO5CtP=A0jF1FimScjSUvv-t6a2ua=ungr0LUHmQvUTKr3Q@mail.gmail.com>
References: <20171013225337.5196-1-phh@phh.me>
 <20171013225337.5196-2-phh@phh.me>
 <CAOMZO5CtP=A0jF1FimScjSUvv-t6a2ua=ungr0LUHmQvUTKr3Q@mail.gmail.com>
Message-ID: <CAJ-oXjQG9pbrXpTWyPWnJZ30DBkcQ1vjMG26rQunZq4V_-k8-w@mail.gmail.com>

Hi Fabio,

2017-10-14 2:18 GMT+02:00 Fabio Estevam <festevam at gmail.com>:
> Hi Pierre-Hugues,
>
> On Fri, Oct 13, 2017 at 7:53 PM, Pierre-Hugues Husson <phh at phh.me> wrote:
>> The documentation already mentions "cec" optional clock, but
>> currently the driver doesn't enable it.
>
> The cec clock is enabled at dw_hdmi_cec_enable().
As far as I understand, dw_hdmi_cec_enable only gates
the CEC clock inside the Synopsis IP,
but the SOC still has to provide a specific CEC clock to it.
To enable such an external CEC clock, the binding documentation [1]
mentions a "cec" optional clock, and I'm not seeing any code in dw-hdmi
to enable it.

Regards,

[1] On next-20170929
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt line 28


From festevam at gmail.com  Sat Oct 14 06:41:20 2017
From: festevam at gmail.com (Fabio Estevam)
Date: Sat, 14 Oct 2017 10:41:20 -0300
Subject: [PATCH 1/3] drm: bridge: synopsys/dw-hdmi: Enable cec clock
In-Reply-To: <CAJ-oXjQG9pbrXpTWyPWnJZ30DBkcQ1vjMG26rQunZq4V_-k8-w@mail.gmail.com>
References: <20171013225337.5196-1-phh@phh.me>
 <20171013225337.5196-2-phh@phh.me>
 <CAOMZO5CtP=A0jF1FimScjSUvv-t6a2ua=ungr0LUHmQvUTKr3Q@mail.gmail.com>
 <CAJ-oXjQG9pbrXpTWyPWnJZ30DBkcQ1vjMG26rQunZq4V_-k8-w@mail.gmail.com>
Message-ID: <CAOMZO5AxNRj5o0cw1-bjtZbHeQZwZJ0dYV+zPBd8TKxpSZxizQ@mail.gmail.com>

Hi Pierre,

On Sat, Oct 14, 2017 at 10:21 AM, Pierre-Hugues Husson <phh at phh.me> wrote:

> As far as I understand, dw_hdmi_cec_enable only gates
> the CEC clock inside the Synopsis IP,
> but the SOC still has to provide a specific CEC clock to it.
> To enable such an external CEC clock, the binding documentation [1]
> mentions a "cec" optional clock, and I'm not seeing any code in dw-hdmi
> to enable it.

Ok, understood.

In the case of i.MX6 we control the CEC clock via
HDMI_MC_CLKDIS_CECCLK_DISABLE bit inside the Synopsis IP.

Looks like Rockchip needs the external CEC clock then.

Regards,

Fabio Estevam


From heiko at sntech.de  Sat Oct 14 07:52:29 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 16:52:29 +0200
Subject: [PATCH 0/3] Enable CEC on rk3399
In-Reply-To: <CAJ-oXjQ3e1UHVGq=uV=yAK9Bu=ZoiNZaEbnHyvNtyc15RQQSKg@mail.gmail.com>
References: <20171013225337.5196-1-phh@phh.me>
 <9833f103-769f-b9b9-05c7-4d75bd7e487c@xs4all.nl>
 <CAJ-oXjQ3e1UHVGq=uV=yAK9Bu=ZoiNZaEbnHyvNtyc15RQQSKg@mail.gmail.com>
Message-ID: <2009704.s5LEIeT6xV@phil>

Am Samstag, 14. Oktober 2017, 15:14:40 CEST schrieb Pierre-Hugues Husson:
> Hi Hans,
> 
> > Nice! I had a similar dw-hdmi.c patch pending but got around to posting it.
> >
> > I'll brush off my old rk3288 patches and see if I can get CEC enabled
> > for my firefly-reload. I was close to getting it work, but I guess
> > missed the "enable cec pin" change.
> Please note that on rk3288, there are two CEC pins, and you must write
> in RK3288_GRF_SOC_CON8 which pin you're using.
> On the firefly-reload, the pin used is GPIO7C0, while the default pin
> configuration is GPIO7C7.

And as an additional note, later socs have even more of these pin-routing
settings and we currently have infrastructure in the pinctrl driver to do
this automatically depending on the pinctrl settings.

So most likely this can also be added there for the rk3288.


Heiko


From heiko at sntech.de  Sat Oct 14 08:39:17 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 17:39:17 +0200
Subject: [PATCH] pinctrl: rockchip: Add iomux-route switching support for
 rk3288
In-Reply-To: <2009704.s5LEIeT6xV@phil>
References: <20171013225337.5196-1-phh@phh.me>
 <CAJ-oXjQ3e1UHVGq=uV=yAK9Bu=ZoiNZaEbnHyvNtyc15RQQSKg@mail.gmail.com>
 <2009704.s5LEIeT6xV@phil>
Message-ID: <13020229.tRmotBUImn@phil>

So far only the hdmi cec supports using one of two different pins
as source, so add the route switching for it.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
If I didn't mess up any numbering, the pinctrl change should look like
the following patch.

Hope that helps
Heiko

 drivers/pinctrl/pinctrl-rockchip.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index b5cb7858ffdc..8dd49e2e144b 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -884,6 +884,24 @@ static struct rockchip_mux_route_data rk3228_mux_route_data[] = {
 	},
 };
 
+static struct rockchip_mux_route_data rk3288_mux_route_data[] = {
+	{
+		/* edphdmi_cecinoutt1 */
+		.bank_num = 7,
+		.pin = 16,
+		.func = 2,
+		.route_offset = 0x264,
+		.route_val = BIT(16 + 12) | BIT(12),
+	}, {
+		/* edphdmi_cecinout */
+		.bank_num = 7,
+		.pin = 23,
+		.func = 4,
+		.route_offset = 0x264,
+		.route_val = BIT(16 + 12),
+	},
+};
+
 static struct rockchip_mux_route_data rk3328_mux_route_data[] = {
 	{
 		/* uart2dbg_rxm0 */
@@ -3391,6 +3409,8 @@ static struct rockchip_pin_ctrl rk3288_pin_ctrl = {
 		.type			= RK3288,
 		.grf_mux_offset		= 0x0,
 		.pmu_mux_offset		= 0x84,
+		.iomux_routes		= rk3288_mux_route_data,
+		.niomux_routes		= ARRAY_SIZE(rk3288_mux_route_data),
 		.pull_calc_reg		= rk3288_calc_pull_reg_and_bit,
 		.drv_calc_reg		= rk3288_calc_drv_reg_and_bit,
 };
-- 
2.14.1




From heiko at sntech.de  Sat Oct 14 12:11:32 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 21:11:32 +0200
Subject: [PATCH] ARM: dts: rockchip: Enable thermal on rk3288-vyasa board
In-Reply-To: <1507916012-3980-1-git-send-email-jagan@amarulasolutions.com>
References: <1507916012-3980-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <2652045.P3tYhJ1IQu@phil>

Am Freitag, 13. Oktober 2017, 23:03:32 CEST schrieb Jagan Teki:
> From: Michael Trimarchi <michael at amarulasolutions.com>
> 
> Enable thermal on rk3288-vyasa board, TSHUT is high active.
> 
> Signed-off-by: Michael Trimarchi <michael at amarulasolutions.com>
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

applied for 4.15


Thanks
Heiko


From heiko at sntech.de  Sat Oct 14 12:14:13 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 21:14:13 +0200
Subject: [PATCH] arm64: dts: rockchip: enable touchpad button for
 rk3399-gru-kevin
In-Reply-To: <20171009184028.11829-1-kernel@esmil.dk>
References: <20171009184028.11829-1-kernel@esmil.dk>
Message-ID: <6303636.5G9IA0odAe@phil>

Am Montag, 9. Oktober 2017, 20:40:28 CEST schrieb Emil Renner Berthing:
> Adding the linux,gpio-keymap entry also has
> the side-effect of making the driver register
> the touchpad as a touchpad rather than another
> touchscreen.
> 
> The index for BTN_LEFT was found by trial and error.
> 
> Signed-off-by: Emil Renner Berthing <kernel at esmil.dk>

applied for 4.15 with Dmitry's Ack


Thanks
Heiko


From heiko at sntech.de  Sat Oct 14 12:20:03 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 21:20:03 +0200
Subject: [PATCH 1/1] arm64: dts: rockchip: default serial for
 Firefly-RK3399
In-Reply-To: <20170930040640.25526-1-xypron.glpk@gmx.de>
References: <20170930040640.25526-1-xypron.glpk@gmx.de>
Message-ID: <2041727.0dCHrNDLFI@phil>

Am Samstag, 30. September 2017, 06:06:40 CEST schrieb Heinrich Schuchardt:
> The Firefly-RK3399 uses serial2 with 1,500,000 baud by default
> for communication in U-Boot and in the vendor provided distros.
> 
> So let us set the same default in the Linux kernel.
> 
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>

applied for 4.15


Thanks
Heiko


From heiko at sntech.de  Sat Oct 14 12:27:25 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 21:27:25 +0200
Subject: [PATCH v2 1/4] clk: rockchip: add clock id for PCLK_EFUSE256 of
 RK3368 SoCs
In-Reply-To: <20170904085119.25981-2-romain.perier@collabora.com>
References: <20170904085119.25981-1-romain.perier@collabora.com>
 <20170904085119.25981-2-romain.perier@collabora.com>
Message-ID: <1912374.Z4ZSI3ogOp@phil>

Am Montag, 4. September 2017, 10:51:16 CEST schrieb Romain Perier:
> Signed-off-by: Romain Perier <romain.perier at collabora.com>

applied for 4.15

Thanks
Heiko


From heiko at sntech.de  Sat Oct 14 12:30:48 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 21:30:48 +0200
Subject: [PATCH 1/9] clk: rockchip: add more rk3188 graphics clock ids
In-Reply-To: <20170915083357.11296-2-heiko@sntech.de>
References: <20170915083357.11296-1-heiko@sntech.de>
 <20170915083357.11296-2-heiko@sntech.de>
Message-ID: <5386849.LLMIu0zLOz@phil>

Am Freitag, 15. September 2017, 10:33:49 CEST schrieb Heiko Stuebner:
> Add ids for cif, v{d/e}pu clocks on rk3188. ACLK_CIF does get a needed
> 1 at it's end but that should be safe because no driver for the camera
> interface has surfaced so far and the old vendor kernels for these socs
> are based on linux-3.0 and still used board files then, so there really
> are no previous users anywhere to be found.
> 
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>

applied for 4.15


From heiko at sntech.de  Sat Oct 14 14:03:59 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 23:03:59 +0200
Subject: [PATCH 2/9] clk: rockchip: use new cif/vdpu clock ids on rk3188
In-Reply-To: <20170915083357.11296-3-heiko@sntech.de>
References: <20170915083357.11296-1-heiko@sntech.de>
 <20170915083357.11296-3-heiko@sntech.de>
Message-ID: <3886973.ei8WaCr8Td@phil>

Am Freitag, 15. September 2017, 10:33:50 CEST schrieb Heiko Stuebner:
> Use the new clock-ids for cif, vdpu, vepu on rk3188
> 
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>

applied for 4.15


From heiko at sntech.de  Sat Oct 14 14:29:07 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 23:29:07 +0200
Subject: [PATCH v2 2/4] clk: rockchip: export clock pclk_efuse_256 for
 RK3368 SoCs
In-Reply-To: <20170904085119.25981-3-romain.perier@collabora.com>
References: <20170904085119.25981-1-romain.perier@collabora.com>
 <20170904085119.25981-3-romain.perier@collabora.com>
Message-ID: <2959871.y9lmPDGV1V@phil>

Am Montag, 4. September 2017, 10:51:17 CEST schrieb Romain Perier:
> This exports the clock for the pclk gate of the eFuse that is part of
> the RK3368 SoCs. So we can use it from the dt-bindings.
> 
> Signed-off-by: Romain Perier <romain.perier at collabora.com>

applied for 4.15


Thanks
Heiko


From heiko at sntech.de  Sat Oct 14 14:31:50 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 Oct 2017 23:31:50 +0200
Subject: [PATCH v2 3/4] nvmem: rockchip: add support for RK3368
In-Reply-To: <20170904085119.25981-4-romain.perier@collabora.com>
References: <20170904085119.25981-1-romain.perier@collabora.com>
 <20170904085119.25981-4-romain.perier@collabora.com>
Message-ID: <1634846.UTLyzHzuUI@phil>

Hi Srinivas,

Am Montag, 4. September 2017, 10:51:18 CEST schrieb Romain Perier:
> This adds the necessary function for handling support on RK3368 SoCs
> 
> Signed-off-by: Romain Perier <romain.perier at collabora.com>
> Acked-by: Rob Herring <robh at kernel.org>

Reviewed-by: Heiko Stuebner <heiko at sntech.de>

Srinivas, could you take a look at this patch and maybe pick it up?


Thanks
Heiko


From hverkuil at xs4all.nl  Sun Oct 15 03:31:29 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Sun, 15 Oct 2017 12:31:29 +0200
Subject: [PATCH 0/3] Enable CEC on rk3399
In-Reply-To: <2009704.s5LEIeT6xV@phil>
References: <20171013225337.5196-1-phh@phh.me>
 <9833f103-769f-b9b9-05c7-4d75bd7e487c@xs4all.nl>
 <CAJ-oXjQ3e1UHVGq=uV=yAK9Bu=ZoiNZaEbnHyvNtyc15RQQSKg@mail.gmail.com>
 <2009704.s5LEIeT6xV@phil>
Message-ID: <4592c26c-3aab-ba86-7e70-de0cac1e2e71@xs4all.nl>

On 10/14/2017 04:52 PM, Heiko Stuebner wrote:
> Am Samstag, 14. Oktober 2017, 15:14:40 CEST schrieb Pierre-Hugues Husson:
>> Hi Hans,
>>
>>> Nice! I had a similar dw-hdmi.c patch pending but got around to posting it.
>>>
>>> I'll brush off my old rk3288 patches and see if I can get CEC enabled
>>> for my firefly-reload. I was close to getting it work, but I guess
>>> missed the "enable cec pin" change.
>> Please note that on rk3288, there are two CEC pins, and you must write
>> in RK3288_GRF_SOC_CON8 which pin you're using.
>> On the firefly-reload, the pin used is GPIO7C0, while the default pin
>> configuration is GPIO7C7.
> 
> And as an additional note, later socs have even more of these pin-routing
> settings and we currently have infrastructure in the pinctrl driver to do
> this automatically depending on the pinctrl settings.
> 
> So most likely this can also be added there for the rk3288.
> 
> 
> Heiko
> 

How does 'GPIO7C0' translate to a 'rockchip,pins' line?

I have this in rk3288-firefly-reload.dts:

       hdmi {
                hdmi_cec: hdmi-cec {
                        rockchip,pins = <7 16 RK_FUNC_2 &pcfg_pull_none>;
                };
        };

I think this is correct. You can find my patches for the firefly reload here:

https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=firefly2

I don't have access to my firefly reload until Friday, so I can't test this
until then.

I'd be very grateful though if you can check the last three patches in that
branch. It's just a test branch, so the subject/changelog of those patches
are incomplete.

The very last patch adds CEC support for the firefly/firefly beta. I don't
have that hardware, so I won't be able to test that.

Regards,

	Hans


From heiko at sntech.de  Sun Oct 15 04:13:57 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 15 Oct 2017 13:13:57 +0200
Subject: [PATCH 0/3] Enable CEC on rk3399
In-Reply-To: <4592c26c-3aab-ba86-7e70-de0cac1e2e71@xs4all.nl>
References: <20171013225337.5196-1-phh@phh.me> <2009704.s5LEIeT6xV@phil>
 <4592c26c-3aab-ba86-7e70-de0cac1e2e71@xs4all.nl>
Message-ID: <3386486.DJGKCdk2Sx@phil>

Hi Hans,

Am Sonntag, 15. Oktober 2017, 12:31:29 CEST schrieb Hans Verkuil:
> On 10/14/2017 04:52 PM, Heiko Stuebner wrote:
> > Am Samstag, 14. Oktober 2017, 15:14:40 CEST schrieb Pierre-Hugues Husson:
> >>> Nice! I had a similar dw-hdmi.c patch pending but got around to posting it.
> >>>
> >>> I'll brush off my old rk3288 patches and see if I can get CEC enabled
> >>> for my firefly-reload. I was close to getting it work, but I guess
> >>> missed the "enable cec pin" change.
> >> Please note that on rk3288, there are two CEC pins, and you must write
> >> in RK3288_GRF_SOC_CON8 which pin you're using.
> >> On the firefly-reload, the pin used is GPIO7C0, while the default pin
> >> configuration is GPIO7C7.
> > 
> > And as an additional note, later socs have even more of these pin-routing
> > settings and we currently have infrastructure in the pinctrl driver to do
> > this automatically depending on the pinctrl settings.
> > 
> > So most likely this can also be added there for the rk3288.
> > 
> > 
> > Heiko
> > 
> 
> How does 'GPIO7C0' translate to a 'rockchip,pins' line?
> 
> I have this in rk3288-firefly-reload.dts:
> 
>        hdmi {
>                 hdmi_cec: hdmi-cec {
>                         rockchip,pins = <7 16 RK_FUNC_2 &pcfg_pull_none>;
>                 };
>         };
> 
> I think this is correct. You can find my patches for the firefly reload here:

Yep, looks correct (i.e. we have 8 pins per A,B,C,D bank, so C0 is pin 16)
but as a helping measure we now also have constants, RK_PC7 in your case.

> https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=firefly2
> 
> I don't have access to my firefly reload until Friday, so I can't test this
> until then.
> 
> I'd be very grateful though if you can check the last three patches in that
> branch. It's just a test branch, so the subject/changelog of those patches
> are incomplete.

While basically ok, I'd suggest having the cec pin definitions in rk3288.dtsi,
like adding entries "hdmi-cec-c0" and "hdmi-cec-c7" or similar and selecting
the correct one per board, so that we don't need to duplicate them into each
and every board dts.

The cec pin function is after all a function of the soc itself.


> The very last patch adds CEC support for the firefly/firefly beta. I don't
> have that hardware, so I won't be able to test that.

at least in the schematics for the old firefly-rk3288 it specifies gpio7c0
as cec pin, similar to the reload but in your patch you selected gpio7c7?

Especially as gpio7c7 is part of the debug uart, this would be quite strange.


Heiko


From heiko at sntech.de  Sun Oct 15 05:13:23 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 15 Oct 2017 14:13:23 +0200
Subject: [PATCH 2/3] arm64: dts: rockchip: add the cec clk for
 dw-mipi-hdmi on rk3399
In-Reply-To: <20171013225337.5196-3-phh@phh.me>
References: <20171013225337.5196-1-phh@phh.me>
 <20171013225337.5196-3-phh@phh.me>
Message-ID: <22869807.lE8YPlrxN5@phil>

Am Samstag, 14. Oktober 2017, 00:53:36 CEST schrieb Pierre-Hugues Husson:
> Signed-off-by: Pierre-Hugues Husson <phh at phh.me>

applied for 4.15 after adding a basic commit message.
It is custom to always provide at least some sort of message there.


Thanks
Heiko


From heiko at sntech.de  Sun Oct 15 05:13:35 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 15 Oct 2017 14:13:35 +0200
Subject: [PATCH 3/3] arm64: dts: rockchip: enable cec pin for rk3399
 firefly
In-Reply-To: <20171013225337.5196-4-phh@phh.me>
References: <20171013225337.5196-1-phh@phh.me>
 <20171013225337.5196-4-phh@phh.me>
Message-ID: <3188481.VU1olLilPF@phil>

Am Samstag, 14. Oktober 2017, 00:53:37 CEST schrieb Pierre-Hugues Husson:
> Signed-off-by: Pierre-Hugues Husson <phh at phh.me>

applied for 4.15 after adding a basic commit message.
It is custom to always provide at least some sort of message there.


Thanks
Heiko


From srinivas.kandagatla at linaro.org  Mon Oct 16 02:09:34 2017
From: srinivas.kandagatla at linaro.org (Srinivas Kandagatla)
Date: Mon, 16 Oct 2017 10:09:34 +0100
Subject: [PATCH v2 3/4] nvmem: rockchip: add support for RK3368
In-Reply-To: <1634846.UTLyzHzuUI@phil>
References: <20170904085119.25981-1-romain.perier@collabora.com>
 <20170904085119.25981-4-romain.perier@collabora.com>
 <1634846.UTLyzHzuUI@phil>
Message-ID: <fb1c4d16-afae-6401-4b4a-75a5aa61c101@linaro.org>



On 14/10/17 22:31, Heiko Stuebner wrote:
> Hi Srinivas,
> 
> Am Montag, 4. September 2017, 10:51:18 CEST schrieb Romain Perier:
>> This adds the necessary function for handling support on RK3368 SoCs
>>
>> Signed-off-by: Romain Perier <romain.perier at collabora.com>
>> Acked-by: Rob Herring <robh at kernel.org>
> 
> Reviewed-by: Heiko Stuebner <heiko at sntech.de>
> 
> Srinivas, could you take a look at this patch and maybe pick it up?
> 
Its already sent to Greg KH for inclusion in 4.15.

--srini
> 
> Thanks
> Heiko
> 


From jeffy.chen at rock-chips.com  Mon Oct 16 02:59:13 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Mon, 16 Oct 2017 17:59:13 +0800
Subject: [PATCH 0/5] rockchip: kevin: Enable edp display
Message-ID: <20171016095918.25588-1-jeffy.chen@rock-chips.com>


Make edp display works on chromebook kevin(at least for boot animation).

Also solve some issues i meet during the bringup.


Jeffy Chen (4):
  arm64: dts: rockchip: Enable edp disaplay on kevin
  backlight: pwm_bl: Add device link for pwm_bl and pwm
  drm/rockchip: Fix error handling path in rockchip_dp_bind()
  drm/rockchip: Add device links for master and components

Tomasz Figa (1):
  drm/bridge/analogix: Do not use device's drvdata

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts  | 29 +++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi       | 16 ++++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 ++++++++-----------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 26 +++++-----
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 57 ++++++++++++++--------
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c        | 24 +++++++--
 drivers/video/backlight/pwm_bl.c                   |  2 +
 include/drm/bridge/analogix_dp.h                   | 19 +++++---
 8 files changed, 151 insertions(+), 72 deletions(-)

-- 
2.11.0




From jeffy.chen at rock-chips.com  Mon Oct 16 02:59:14 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Mon, 16 Oct 2017 17:59:14 +0800
Subject: [PATCH 1/5] arm64: dts: rockchip: Enable edp disaplay on kevin
In-Reply-To: <20171016095918.25588-1-jeffy.chen@rock-chips.com>
References: <20171016095918.25588-1-jeffy.chen@rock-chips.com>
Message-ID: <20171016095918.25588-2-jeffy.chen@rock-chips.com>

Add edp panel and enable related nodes on kevin.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index a3d3cea7dc4f..bc67b19f0af5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -93,6 +93,18 @@
 		pwm-delay-us = <10000>;
 	};
 
+	edp_panel: edp-panel {
+		compatible = "sharp,lq123p1jx31", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&pp3300_disp>;
+
+		ports {
+			panel_in_edp: endpoint {
+				remote-endpoint = <&edp_out_panel>;
+			};
+		};
+	};
+
 	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
 		compatible = "murata,ncp15wb473";
 		pullup-uv = <1800000>;
@@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
 	};
 };
 
+&edp {
+	status = "okay";
+
+	ports {
+		edp_out: port at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_out_panel: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&panel_in_edp>;
+			};
+		};
+	};
+};
+
 &ppvar_bigcpu_pwm {
 	regulator-min-microvolt = <798674>;
 	regulator-max-microvolt = <1302172>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..470105d651c2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
 	dr_mode = "host";
 };
 
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
 #include <arm/cros-ec-keyboard.dtsi>
 #include <arm/cros-ec-sbs.dtsi>
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Mon Oct 16 03:06:35 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Mon, 16 Oct 2017 18:06:35 +0800
Subject: [RESEND PATCH v2 0/5] rockchip: kevin: Enable edp display
Message-ID: <20171016100640.26575-1-jeffy.chen@rock-chips.com>


Make edp display works on chromebook kevin(at least for boot animation).

Also solve some issues i meet during the bringup.

Changes in v2:
Use device link to correct the suspend/resume and shutdown ordering,
instead of converting rockchip spi's suspend/resume PM callbacks to
late suspend/resume PM callbacks.

Jeffy Chen (4):
  arm64: dts: rockchip: Enable edp disaplay on kevin
  backlight: pwm_bl: Add device link for pwm_bl and pwm
  drm/rockchip: Fix error handling path in rockchip_dp_bind()
  drm/rockchip: Add device links for master and components

Tomasz Figa (1):
  drm/bridge/analogix: Do not use device's drvdata

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts  | 29 +++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi       | 16 ++++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 ++++++++-----------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 26 +++++-----
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 57 ++++++++++++++--------
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c        | 24 +++++++--
 drivers/video/backlight/pwm_bl.c                   |  2 +
 include/drm/bridge/analogix_dp.h                   | 19 +++++---
 8 files changed, 151 insertions(+), 72 deletions(-)

-- 
2.11.0




From jeffy.chen at rock-chips.com  Mon Oct 16 03:06:36 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Mon, 16 Oct 2017 18:06:36 +0800
Subject: [RESEND PATCH v2 1/5] arm64: dts: rockchip: Enable edp disaplay on
 kevin
In-Reply-To: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
References: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
Message-ID: <20171016100640.26575-2-jeffy.chen@rock-chips.com>

Add edp panel and enable related nodes on kevin.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v2: None

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index a3d3cea7dc4f..bc67b19f0af5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -93,6 +93,18 @@
 		pwm-delay-us = <10000>;
 	};
 
+	edp_panel: edp-panel {
+		compatible = "sharp,lq123p1jx31", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&pp3300_disp>;
+
+		ports {
+			panel_in_edp: endpoint {
+				remote-endpoint = <&edp_out_panel>;
+			};
+		};
+	};
+
 	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
 		compatible = "murata,ncp15wb473";
 		pullup-uv = <1800000>;
@@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
 	};
 };
 
+&edp {
+	status = "okay";
+
+	ports {
+		edp_out: port at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_out_panel: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&panel_in_edp>;
+			};
+		};
+	};
+};
+
 &ppvar_bigcpu_pwm {
 	regulator-min-microvolt = <798674>;
 	regulator-max-microvolt = <1302172>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..470105d651c2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
 	dr_mode = "host";
 };
 
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
 #include <arm/cros-ec-keyboard.dtsi>
 #include <arm/cros-ec-sbs.dtsi>
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Mon Oct 16 03:06:38 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Mon, 16 Oct 2017 18:06:38 +0800
Subject: [RESEND PATCH v2 3/5] drm/rockchip: Fix error handling path in
 rockchip_dp_bind()
In-Reply-To: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
References: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
Message-ID: <20171016100640.26575-4-jeffy.chen@rock-chips.com>

Add missing error handling in rockchip_dp_bind().

Fixes: 9e32e16e9e98 ("drm: rockchip: dp: add rockchip platform dp driver")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v2: None

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 4d3f6ad0abdd..cb8941e8bcdd 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -371,7 +371,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	ret = rockchip_dp_drm_create_encoder(dp);
 	if (ret) {
 		DRM_ERROR("failed to create drm encoder\n");
-		return ret;
+		goto err_deinit_dp;
 	}
 
 	dp->plat_data.encoder = &dp->encoder;
@@ -387,7 +387,17 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	ret = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (ret < 0)
+		goto err_unreg_psr;
+	return 0;
+
+err_unreg_psr:
+	rockchip_drm_psr_unregister(&dp->encoder);
+	rockchip_dp_drm_encoder_destroy(&dp->encoder);
+err_deinit_dp:
+	clk_disable_unprepare(dp->pclk);
+	return ret;
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
-- 
2.11.0




From jeffy.chen at rock-chips.com  Mon Oct 16 03:06:40 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Mon, 16 Oct 2017 18:06:40 +0800
Subject: [RESEND PATCH v2 5/5] drm/rockchip: Add device links for master and
 components
In-Reply-To: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
References: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
Message-ID: <20171016100640.26575-6-jeffy.chen@rock-chips.com>

Since we are trying to access components' resources in the master's
suspend/resume PM callbacks(e.g. panel), add device links to correct
the suspend/resume and shutdown ordering.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v2:
Use device link to correct the suspend/resume and shutdown ordering,
instead of converting rockchip spi's suspend/resume PM callbacks to
late suspend/resume PM callbacks.

 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 76d63de5921d..af18967f699b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -337,6 +337,8 @@ static struct component_match *rockchip_drm_match_add(struct device *dev)
 
 			if (!d)
 				break;
+
+			device_link_add(dev, d, DL_FLAG_STATELESS);
 			component_match_add(dev, &match, compare_dev, d);
 		} while (true);
 	}
@@ -406,6 +408,7 @@ static int rockchip_drm_platform_of_probe(struct device *dev)
 static int rockchip_drm_platform_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct device_link *link;
 	struct component_match *match = NULL;
 	int ret;
 
@@ -414,16 +417,31 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev)
 		return ret;
 
 	match = rockchip_drm_match_add(dev);
-	if (IS_ERR(match))
-		return PTR_ERR(match);
+	if (IS_ERR(match)) {
+		ret = PTR_ERR(match);
+		goto err_cleanup_dev_links;
+	}
 
-	return component_master_add_with_match(dev, &rockchip_drm_ops, match);
+	ret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
+	if (ret < 0)
+		goto err_cleanup_dev_links;
+
+	return 0;
+err_cleanup_dev_links:
+	list_for_each_entry(link, &dev->links.consumers, s_node)
+		device_link_del(link);
+	return ret;
 }
 
 static int rockchip_drm_platform_remove(struct platform_device *pdev)
 {
+	struct device_link *link;
+
 	component_master_del(&pdev->dev, &rockchip_drm_ops);
 
+	list_for_each_entry(link, &pdev->dev.links.consumers, s_node)
+		device_link_del(link);
+
 	return 0;
 }
 
-- 
2.11.0




From a.hajda at samsung.com  Mon Oct 16 03:44:09 2017
From: a.hajda at samsung.com (Andrzej Hajda)
Date: Mon, 16 Oct 2017 12:44:09 +0200
Subject: [RESEND PATCH v2 4/5] drm/bridge/analogix: Do not use device's
 drvdata
In-Reply-To: <20171016100640.26575-5-jeffy.chen@rock-chips.com>
References: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
 <CGME20171016100746epcas2p436f3573bcb862275aea1869aabe4ad17@epcas2p4.samsung.com>
 <20171016100640.26575-5-jeffy.chen@rock-chips.com>
Message-ID: <be199812-9fc5-11ec-cca4-5b9fcff57070@samsung.com>

On 16.10.2017 12:06, Jeffy Chen wrote:
> From: Tomasz Figa <tfiga at chromium.org>
>
> The driver that instantiates the bridge should own the drvdata, as all
> driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
> owned by its driver struct. Moreover, storing two different pointer
> types in driver data depending on driver initialization status is barely
> a good practice and in fact has led to many bugs in this driver.
>
> Let's clean up this mess and change Analogix entry points to simply
> accept some opaque struct pointer, adjusting their users at the same
> time to avoid breaking the compilation.
>
> Signed-off-by: Tomasz Figa <tfiga at chromium.org>
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>

Thanks for making it a bit saner.

Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>

?--
Regards
Andrzej


From jeffy.chen at rock-chips.com  Mon Oct 16 03:06:39 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Mon, 16 Oct 2017 18:06:39 +0800
Subject: [RESEND PATCH v2 4/5] drm/bridge/analogix: Do not use device's drvdata
In-Reply-To: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
References: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
Message-ID: <20171016100640.26575-5-jeffy.chen@rock-chips.com>

From: Tomasz Figa <tfiga at chromium.org>

The driver that instantiates the bridge should own the drvdata, as all
driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
owned by its driver struct. Moreover, storing two different pointer
types in driver data depending on driver initialization status is barely
a good practice and in fact has led to many bugs in this driver.

Let's clean up this mess and change Analogix entry points to simply
accept some opaque struct pointer, adjusting their users at the same
time to avoid breaking the compilation.

Signed-off-by: Tomasz Figa <tfiga at chromium.org>
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++-------------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 47 +++++++++++---------
 include/drm/bridge/analogix_dp.h                   | 19 ++++----
 4 files changed, 73 insertions(+), 69 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5dd3f1cd074a..74d274b6d31d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -98,17 +98,15 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
 	return 0;
 }
 
-int analogix_dp_psr_supported(struct device *dev)
+int analogix_dp_psr_supported(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 
 	return dp->psr_support;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
 
-int analogix_dp_enable_psr(struct device *dev)
+int analogix_dp_enable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 
 	if (!dp->psr_support)
@@ -129,9 +127,8 @@ int analogix_dp_enable_psr(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
-int analogix_dp_disable_psr(struct device *dev)
+int analogix_dp_disable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 	int ret;
 
@@ -1281,8 +1278,9 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
 	return analogix_dp_transfer(dp, msg);
 }
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data)
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct analogix_dp_device *dp;
@@ -1292,14 +1290,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (!plat_data) {
 		dev_err(dev, "Invalided input plat_data\n");
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
 	if (!dp)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, dp);
+		return ERR_PTR(-ENOMEM);
 
 	dp->dev = &pdev->dev;
 	dp->dpms_mode = DRM_MODE_DPMS_OFF;
@@ -1316,7 +1312,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	ret = analogix_dp_dt_parse_pdata(dp);
 	if (ret)
-		return ret;
+		return ERR_PTR(ret);
 
 	dp->phy = devm_phy_get(dp->dev, "dp");
 	if (IS_ERR(dp->phy)) {
@@ -1330,14 +1326,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 			if (ret == -ENOSYS || ret == -ENODEV)
 				dp->phy = NULL;
 			else
-				return ret;
+				return ERR_PTR(ret);
 		}
 	}
 
 	dp->clock = devm_clk_get(&pdev->dev, "dp");
 	if (IS_ERR(dp->clock)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
-		return PTR_ERR(dp->clock);
+		return ERR_CAST(dp->clock);
 	}
 
 	clk_prepare_enable(dp->clock);
@@ -1346,7 +1342,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(dp->reg_base))
-		return PTR_ERR(dp->reg_base);
+		return ERR_CAST(dp->reg_base);
 
 	dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
 
@@ -1367,7 +1363,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 					    "hpd_gpio");
 		if (ret) {
 			dev_err(&pdev->dev, "failed to get hpd gpio\n");
-			return ret;
+			return ERR_PTR(ret);
 		}
 		dp->irq = gpio_to_irq(dp->hpd_gpio);
 		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@@ -1379,7 +1375,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (dp->irq == -ENXIO) {
 		dev_err(&pdev->dev, "failed to get irq\n");
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 	}
 
 	pm_runtime_enable(dev);
@@ -1420,7 +1416,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	phy_power_off(dp->phy);
 	pm_runtime_put(dev);
 
-	return 0;
+	return dp;
 
 err_disable_pm_runtime:
 
@@ -1428,15 +1424,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	pm_runtime_put(dev);
 	pm_runtime_disable(dev);
 
-	return ret;
+	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_bind);
 
-void analogix_dp_unbind(struct device *dev, struct device *master,
-			void *data)
+void analogix_dp_unbind(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	analogix_dp_bridge_disable(dp->bridge);
 	dp->connector.funcs->destroy(&dp->connector);
 	dp->encoder->funcs->destroy(dp->encoder);
@@ -1449,16 +1442,14 @@ void analogix_dp_unbind(struct device *dev, struct device *master,
 	}
 
 	drm_dp_aux_unregister(&dp->aux);
-	pm_runtime_disable(dev);
+	pm_runtime_disable(dp->dev);
 	clk_disable_unprepare(dp->clock);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_unbind);
 
 #ifdef CONFIG_PM
-int analogix_dp_suspend(struct device *dev)
+int analogix_dp_suspend(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	clk_disable_unprepare(dp->clock);
 
 	if (dp->plat_data->panel) {
@@ -1470,9 +1461,8 @@ int analogix_dp_suspend(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_suspend);
 
-int analogix_dp_resume(struct device *dev)
+int analogix_dp_resume(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	int ret;
 
 	ret = clk_prepare_enable(dp->clock);
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 39629e7a80b9..f7e5b2c405ed 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -41,6 +41,7 @@ struct exynos_dp_device {
 	struct device              *dev;
 
 	struct videomode           vm;
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -157,13 +158,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp->dev = dev;
 	dp->drm_dev = drm_dev;
 
@@ -190,13 +184,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
 	dp->plat_data.encoder = encoder;
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp))
+		return PTR_ERR(dp->adp);
+
+	return 0;
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
 			     void *data)
 {
-	return analogix_dp_unbind(dev, master, data);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_unbind(dp->adp);
 }
 
 static const struct component_ops exynos_dp_ops = {
@@ -257,12 +257,16 @@ static int exynos_dp_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int exynos_dp_suspend(struct device *dev)
 {
-	return analogix_dp_suspend(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
 }
 
 static int exynos_dp_resume(struct device *dev)
 {
-	return analogix_dp_resume(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
 }
 #endif
 
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index cb8941e8bcdd..e8be6cbc5f3f 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -77,6 +77,7 @@ struct rockchip_dp_device {
 
 	const struct rockchip_dp_chip_data *data;
 
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -85,7 +86,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
 	struct rockchip_dp_device *dp = to_dp(encoder);
 	unsigned long flags;
 
-	if (!analogix_dp_psr_supported(dp->dev))
+	if (!analogix_dp_psr_supported(dp->adp))
 		return;
 
 	DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
@@ -116,9 +117,9 @@ static void analogix_dp_psr_work(struct work_struct *work)
 
 	spin_lock_irqsave(&dp->psr_lock, flags);
 	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
-		analogix_dp_enable_psr(dp->dev);
+		analogix_dp_enable_psr(dp->adp);
 	else
-		analogix_dp_disable_psr(dp->dev);
+		analogix_dp_disable_psr(dp->adp);
 	spin_unlock_irqrestore(&dp->psr_lock, flags);
 }
 
@@ -350,13 +351,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp_data = of_device_get_match_data(dev);
 	if (!dp_data)
 		return -ENODEV;
@@ -387,9 +381,11 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 
-	ret = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-	if (ret < 0)
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp)) {
+		ret = PTR_ERR(dp->adp);
 		goto err_unreg_psr;
+	}
 	return 0;
 
 err_unreg_psr:
@@ -407,7 +403,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_unregister(&dp->encoder);
 
-	analogix_dp_unbind(dev, master, data);
+	analogix_dp_unbind(dp->adp);
 	clk_disable_unprepare(dp->pclk);
 }
 
@@ -435,11 +431,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 
 	dp->plat_data.panel = panel;
 
-	/*
-	 * We just use the drvdata until driver run into component
-	 * add function, and then we would set drvdata to null, so
-	 * that analogix dp driver could take charge of the drvdata.
-	 */
 	platform_set_drvdata(pdev, dp);
 
 	return component_add(dev, &rockchip_dp_component_ops);
@@ -452,10 +443,26 @@ static int rockchip_dp_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_dp_suspend(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
+}
+
+static int rockchip_dp_resume(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
+}
+#endif
+
 static const struct dev_pm_ops rockchip_dp_pm_ops = {
 #ifdef CONFIG_PM_SLEEP
-	.suspend = analogix_dp_suspend,
-	.resume_early = analogix_dp_resume,
+	.suspend = rockchip_dp_suspend,
+	.resume_early = rockchip_dp_resume,
 #endif
 };
 
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index c99d6eaef1ac..5518fc75dd6e 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -13,6 +13,8 @@
 
 #include <drm/drm_crtc.h>
 
+struct analogix_dp_device;
+
 enum analogix_dp_devtype {
 	EXYNOS_DP,
 	RK3288_DP,
@@ -38,16 +40,17 @@ struct analogix_dp_plat_data {
 			 struct drm_connector *);
 };
 
-int analogix_dp_psr_supported(struct device *dev);
-int analogix_dp_enable_psr(struct device *dev);
-int analogix_dp_disable_psr(struct device *dev);
+int analogix_dp_psr_supported(struct analogix_dp_device *dp);
+int analogix_dp_enable_psr(struct analogix_dp_device *dp);
+int analogix_dp_disable_psr(struct analogix_dp_device *dp);
 
-int analogix_dp_resume(struct device *dev);
-int analogix_dp_suspend(struct device *dev);
+int analogix_dp_resume(struct analogix_dp_device *dp);
+int analogix_dp_suspend(struct analogix_dp_device *dp);
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data);
-void analogix_dp_unbind(struct device *dev, struct device *master, void *data);
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data);
+void analogix_dp_unbind(struct analogix_dp_device *dp);
 
 int analogix_dp_start_crc(struct drm_connector *connector);
 int analogix_dp_stop_crc(struct drm_connector *connector);
-- 
2.11.0




From jagannadh.teki at gmail.com  Mon Oct 16 05:16:18 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:18 +0530
Subject: [PATCH 0/9] rockchip: rk3288-vyasa: dts fixes/additions
Message-ID: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>

Series add new dts nodes like gmac, usb, io_domains and fixed existing
regulator, pmic stuff as per schematic. 

Jagan Teki (9):
  ARM: dts: rockchip: rk3288-vyasa: Remove vdd_log from rk808, DCDC_REG1
  ARM: dts: rockchip: rk3288-vyasa: Use fixed voltage range for vccio_sd
  ARM: dts: rockchip: rk3288-vyasa: Use vmmc-supply from PMIC
  ARM: dts: rockchip: Add regulators for rk3288-vyasa
  ARM: dts: rockchip: Add gmac support for rk3288-vyasa board
  ARM: dts: rockchip: Add usb host for rk3288-vyasa
  ARM: dts: rockchip: Add usb otg for rk3288-vyasa
  ARM: dts: rockchip: Add io domains for rk3288-vyasa
  ARM: multi_v7_defconfig: Statically build RTC_DRV_RK808

 arch/arm/boot/dts/rk3288-vyasa.dts     | 181 ++++++++++++++++++++++++++++++---
 arch/arm/configs/multi_v7_defconfig    |   2 +-
 include/dt-bindings/pinctrl/rockchip.h |   1 +
 3 files changed, 168 insertions(+), 16 deletions(-)

-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 05:16:19 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:19 +0530
Subject: [PATCH 1/9] ARM: dts: rockchip: rk3288-vyasa: Remove vdd_log from
 rk808, DCDC_REG1
In-Reply-To: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1508156187-27519-2-git-send-email-jagan@amarulasolutions.com>

vdd_log, never used on DCDC_REG1 of rk808 from latest schematic so
remove the same and update the regulator-name as 'vdd_arm' to sync
with existing rk3288 board dts files.

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/boot/dts/rk3288-vyasa.dts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index 3546eb8..7a0f945 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -121,8 +121,8 @@
 		vcc12-supply = <&vcc_io>;
 
 		regulators {
-			vdd_cpu: vdd_log: DCDC_REG1 {
-				regulator-name = "vdd_log";
+			vdd_cpu: DCDC_REG1 {
+				regulator-name = "vdd_arm";
 				regulator-min-microvolt = <750000>;
 				regulator-max-microvolt = <1350000>;
 				regulator-always-on;
-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 05:16:20 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:20 +0530
Subject: [PATCH 2/9] ARM: dts: rockchip: rk3288-vyasa: Use fixed voltage range
 for vccio_sd
In-Reply-To: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1508156187-27519-3-git-send-email-jagan@amarulasolutions.com>

vccio_sd has supplied to vqmmc-supply for sdmmc, use fixed voltage
range of 3.3v for better IO lines supply voltage.

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/boot/dts/rk3288-vyasa.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index 7a0f945..915b4a3 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -214,7 +214,7 @@
 
 			vccio_sd: LDO_REG5 {
 				regulator-name = "vccio_sd";
-				regulator-min-microvolt = <1800000>;
+				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-always-on;
 				regulator-boot-on;
-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 05:16:21 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:21 +0530
Subject: [PATCH 3/9] ARM: dts: rockchip: rk3288-vyasa: Use vmmc-supply from
 PMIC
In-Reply-To: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1508156187-27519-4-git-send-email-jagan@amarulasolutions.com>

rk808, SWITCH_REG1 has configured for sdmmc regulator as vcc_sd,
so use the same by renaming vcc33_sd to vcc_sd(as per schematic)
and drop explicit regulator definition from root.

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/boot/dts/rk3288-vyasa.dts | 22 ++--------------------
 1 file changed, 2 insertions(+), 20 deletions(-)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index 915b4a3..c14ebf9 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -56,18 +56,6 @@
 		device_type = "memory";
 	};
 
-	vcc_sd: sdmmc-regulator {
-		compatible = "regulator-fixed";
-		gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_LOW>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&sdmmc_pwr>;
-		regulator-name = "vcc_sd";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		startup-delay-us = <100000>;
-		vin-supply = <&vcc_io>;
-	};
-
 	vcc_sys: vsys-regulator {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_sys";
@@ -260,8 +248,8 @@
 				};
 			};
 
-			vcc33_sd: SWITCH_REG1 {
-				regulator-name = "vcc33_sd";
+			vcc_sd: SWITCH_REG1 {
+				regulator-name = "vcc_sd";
 				regulator-min-microvolt = <3300000>;
 				regulator-max-microvolt = <3300000>;
 				regulator-always-on;
@@ -338,10 +326,4 @@
 			rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
 		};
 	};
-
-	sdmmc {
-		sdmmc_pwr: sdmmc-pwr {
-			rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
 };
-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 05:16:23 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:23 +0530
Subject: [PATCH 5/9] ARM: dts: rockchip: Add gmac support for rk3288-vyasa
 board
In-Reply-To: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1508156187-27519-6-git-send-email-jagan@amarulasolutions.com>

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/boot/dts/rk3288-vyasa.dts | 41 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index 0fa447f..c79a4c7 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -104,12 +104,35 @@
 		regulator-boot-on;
 		vin-supply = <&dc12_vbat>;
 	};
+
+	ext_gmac: external-gmac-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <125000000>;
+		clock-output-names = "ext_gmac";
+	};
 };
 
 &cpu0 {
 	cpu0-supply = <&vdd_cpu>;
 };
 
+&gmac {
+	assigned-clocks = <&cru SCLK_MAC>;
+	assigned-clock-parents = <&ext_gmac>;
+	clock_in_out = "input";
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>, <&phy_rst>, <&phy_pmeb>, <&phy_int>;
+	phy-supply = <&vcc_lan>;
+	phy-mode = "rgmii";
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 10000 1000000>;
+	snps,reset-gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
+	tx_delay = <0x30>;
+	rx_delay = <0x10>;
+	status = "ok";
+};
+
 &gpu {
 	mali-supply = <&vdd_gpu>;
 	status = "okay";
@@ -361,6 +384,24 @@
 };
 
 &pinctrl {
+	pcfg_output_high: pcfg-output-high {
+		output-high;
+	};
+
+	gmac {
+		phy_int: phy-int {
+			rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		phy_pmeb: phy-pmeb {
+			rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		phy_rst: phy-rst {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+	};
+
 	pmic {
 		pmic_int: pmic-int {
 			rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 05:16:25 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:25 +0530
Subject: [PATCH 7/9] ARM: dts: rockchip: Add usb otg for rk3288-vyasa
In-Reply-To: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1508156187-27519-8-git-send-email-jagan@amarulasolutions.com>

Add usb otg support for rk3288-vyasa, board support usb1 otg
power through otg_vbus_drv and naming conversion followed
as per schematic.

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
Note: g_ether/g_serial fired an issue with mainline tree 
https://paste.ubuntu.com/25752571/

 arch/arm/boot/dts/rk3288-vyasa.dts | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index c22d674..2f1389a 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -115,6 +115,20 @@
 		vin-supply = <&vcc_io>;
 	};
 
+	vusb1_5v: vusb1-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "vusb1_5v";
+		enable-active-high;
+		gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; /* OTG_VBUS_DRV */
+		pinctrl-names = "default";
+		pinctrl-0 = <&otg_vbus_drv>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&vsus_5v>;
+	};
+
 	vusb2_5v: vusb2-5v {
 		compatible = "regulator-fixed";
 		regulator-name = "vusb2_5v";
@@ -401,6 +415,10 @@
 	status = "okay";
 };
 
+&usb_otg {
+	status = "okay";
+};
+
 &vopb {
 	status = "okay";
 };
@@ -455,4 +473,11 @@
 			rockchip,pins = <RK_GPIO8 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
 	};
+
+	usb_otg {
+		otg_vbus_drv: otg-vbus-drv {
+			rockchip,pins = <RK_GPIO0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+
+		};
+	};
 };
-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 05:16:26 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:26 +0530
Subject: [PATCH 8/9] ARM: dts: rockchip: Add io domains for rk3288-vyasa
In-Reply-To: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1508156187-27519-9-git-send-email-jagan@amarulasolutions.com>

Add io domains supported by rk3288-vyasa board.

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/boot/dts/rk3288-vyasa.dts | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index 2f1389a..0e0995f 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -374,6 +374,21 @@
 	};
 };
 
+&io_domains {
+	status = "okay";
+
+	audio-supply = <&vcc_18>;
+	bb-supply = <&vcc_io>;
+	dvp-supply = <&vcc_io>;
+	flash0-suuply = <&vcc_18>;
+	flash1-supply = <&vcc_lan>;
+	gpio30-supply = <&vcc_io>;
+	gpio1830 = <&vcc_io>;
+	lcdc-supply = <&vcc_io>;
+	sdcard-supply = <&vccio_sd>;
+	wifi-supply = <&vcc_18>;
+};
+
 &i2c2 {
 	status = "okay";
 };
-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 05:16:24 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:24 +0530
Subject: [PATCH 6/9] ARM: dts: rockchip: Add usb host for rk3288-vyasa
In-Reply-To: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1508156187-27519-7-git-send-email-jagan@amarulasolutions.com>

Add usb host support for rk3288-vyasa, board support hub power
through phy_pwr_en and usb2 host power through usb2_pwr_en and
naming conversion followed as per schematic.

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/boot/dts/rk3288-vyasa.dts     | 48 ++++++++++++++++++++++++++++++++++
 include/dt-bindings/pinctrl/rockchip.h |  1 +
 2 files changed, 49 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index c79a4c7..c22d674 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -105,6 +105,30 @@
 		vin-supply = <&dc12_vbat>;
 	};
 
+	vsus_5v: vsus-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "vsus_5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&vcc_io>;
+	};
+
+	vusb2_5v: vusb2-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "vusb2_5v";
+		enable-active-high;
+		gpio = <&gpio8 RK_PB1 GPIO_ACTIVE_HIGH>; /* USB2_PWR_EN */
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_pwr_en>;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&vsus_5v>;
+	};
+
 	ext_gmac: external-gmac-clock {
 		compatible = "fixed-clock";
 		#clock-cells = <0>;
@@ -363,6 +387,20 @@
 	status = "okay";
 };
 
+&usbphy {
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&phy_pwr_en>;
+	status = "okay";
+};
+
 &vopb {
 	status = "okay";
 };
@@ -407,4 +445,14 @@
 			rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
 		};
 	};
+
+	usb_host {
+		phy_pwr_en: phy-pwr-en {
+			rockchip,pins = <RK_GPIO2 RK_PB1 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+
+		usb2_pwr_en: usb2-pwr-en {
+			rockchip,pins = <RK_GPIO8 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
 };
diff --git a/include/dt-bindings/pinctrl/rockchip.h b/include/dt-bindings/pinctrl/rockchip.h
index aaec8ba..dc3d661 100644
--- a/include/dt-bindings/pinctrl/rockchip.h
+++ b/include/dt-bindings/pinctrl/rockchip.h
@@ -24,6 +24,7 @@
 #define RK_GPIO3	3
 #define RK_GPIO4	4
 #define RK_GPIO6	6
+#define RK_GPIO8	8
 
 #define RK_PA0		0
 #define RK_PA1		1
-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 05:16:22 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:22 +0530
Subject: [PATCH 4/9] ARM: dts: rockchip: Add regulators for rk3288-vyasa
In-Reply-To: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1508156187-27519-5-git-send-email-jagan@amarulasolutions.com>

Add supporting regulators for rk3288-vyasa board, dc12_vbat is
parent regulatorand followed regulators as are child regulators.
regulator naming conversion followed as per schematic for better
readability and easy for identification.

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/boot/dts/rk3288-vyasa.dts | 40 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index c14ebf9..0fa447f 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -56,13 +56,53 @@
 		device_type = "memory";
 	};
 
+	dc12_vbat: dc12-vbat {
+		compatible = "regulator-fixed";
+		regulator-name = "dc12_vbat";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	vboot_3v3: vboot-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vboot_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&dc12_vbat>;
+	};
+
 	vcc_sys: vsys-regulator {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_sys";
+		regulator-min-microvolt = <3700000>;
+		regulator-max-microvolt = <3700000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&dc12_vbat>;
+	};
+
+	vboot_5v: vboot-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "vboot_sv";
 		regulator-min-microvolt = <5000000>;
 		regulator-max-microvolt = <5000000>;
 		regulator-always-on;
 		regulator-boot-on;
+		vin-supply = <&dc12_vbat>;
+	};
+
+	v3g_3v3: v3g-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "v3g_3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&dc12_vbat>;
 	};
 };
 
-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 05:16:27 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 17:46:27 +0530
Subject: [PATCH 9/9] ARM: multi_v7_defconfig: Statically build RTC_DRV_RK808
In-Reply-To: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1508156187-27519-10-git-send-email-jagan@amarulasolutions.com>

RTC_DRV_RK808 need to have build statically for the platforms
do use MFB_RK808 so replace module with statical link.

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
 arch/arm/configs/multi_v7_defconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 2adef49..6ddc35c 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -768,7 +768,7 @@ CONFIG_RTC_DRV_MAX8907=y
 CONFIG_RTC_DRV_MAX8998=m
 CONFIG_RTC_DRV_MAX8997=m
 CONFIG_RTC_DRV_MAX77686=y
-CONFIG_RTC_DRV_RK808=m
+CONFIG_RTC_DRV_RK808=y
 CONFIG_RTC_DRV_RS5C372=m
 CONFIG_RTC_DRV_BQ32K=m
 CONFIG_RTC_DRV_PALMAS=y
-- 
2.7.4



From jagannadh.teki at gmail.com  Mon Oct 16 10:13:07 2017
From: jagannadh.teki at gmail.com (Jagan Teki)
Date: Mon, 16 Oct 2017 22:43:07 +0530
Subject: [PATCH v2 5/9] ARM: dts: rockchip: Add gmac support for rk3288-vyasa
 board
Message-ID: <1508173987-26688-1-git-send-email-jagan@amarulasolutions.com>

Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
---
Changes for v2:
- status s/ok/okay

 arch/arm/boot/dts/rk3288-vyasa.dts | 41 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
index 0fa447f..c79a4c7 100644
--- a/arch/arm/boot/dts/rk3288-vyasa.dts
+++ b/arch/arm/boot/dts/rk3288-vyasa.dts
@@ -104,12 +104,35 @@
 		regulator-boot-on;
 		vin-supply = <&dc12_vbat>;
 	};
+
+	ext_gmac: external-gmac-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <125000000>;
+		clock-output-names = "ext_gmac";
+	};
 };
 
 &cpu0 {
 	cpu0-supply = <&vdd_cpu>;
 };
 
+&gmac {
+	assigned-clocks = <&cru SCLK_MAC>;
+	assigned-clock-parents = <&ext_gmac>;
+	clock_in_out = "input";
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>, <&phy_rst>, <&phy_pmeb>, <&phy_int>;
+	phy-supply = <&vcc_lan>;
+	phy-mode = "rgmii";
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 10000 1000000>;
+	snps,reset-gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
+	tx_delay = <0x30>;
+	rx_delay = <0x10>;
+	status = "okay";
+};
+
 &gpu {
 	mali-supply = <&vdd_gpu>;
 	status = "okay";
@@ -361,6 +384,24 @@
 };
 
 &pinctrl {
+	pcfg_output_high: pcfg-output-high {
+		output-high;
+	};
+
+	gmac {
+		phy_int: phy-int {
+			rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		phy_pmeb: phy-pmeb {
+			rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		phy_rst: phy-rst {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+	};
+
 	pmic {
 		pmic_int: pmic-int {
 			rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
-- 
2.7.4



From heiko at sntech.de  Mon Oct 16 11:02:29 2017
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Mon, 16 Oct 2017 20:02:29 +0200
Subject: [PATCH 9/9] ARM: multi_v7_defconfig: Statically build
 RTC_DRV_RK808
In-Reply-To: <1508156187-27519-10-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-10-git-send-email-jagan@amarulasolutions.com>
Message-ID: <3238534.Bk1TS2fSCp@diego>

Hi,

Am Montag, 16. Oktober 2017, 17:46:27 CEST schrieb Jagan Teki:
> RTC_DRV_RK808 need to have build statically for the platforms
> do use MFB_RK808 so replace module with statical link.

why would you need this to be compiled on? MFD_RK808 will happily
just create the platform-devices which are then bound to the RTC
driver later once the module is ready.

Heiko

> 
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>
> ---
>  arch/arm/configs/multi_v7_defconfig | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/configs/multi_v7_defconfig
> b/arch/arm/configs/multi_v7_defconfig index 2adef49..6ddc35c 100644
> --- a/arch/arm/configs/multi_v7_defconfig
> +++ b/arch/arm/configs/multi_v7_defconfig
> @@ -768,7 +768,7 @@ CONFIG_RTC_DRV_MAX8907=y
>  CONFIG_RTC_DRV_MAX8998=m
>  CONFIG_RTC_DRV_MAX8997=m
>  CONFIG_RTC_DRV_MAX77686=y
> -CONFIG_RTC_DRV_RK808=m
> +CONFIG_RTC_DRV_RK808=y
>  CONFIG_RTC_DRV_RS5C372=m
>  CONFIG_RTC_DRV_BQ32K=m
>  CONFIG_RTC_DRV_PALMAS=y




From jagan at amarulasolutions.com  Mon Oct 16 11:13:29 2017
From: jagan at amarulasolutions.com (Jagan Teki)
Date: Mon, 16 Oct 2017 23:43:29 +0530
Subject: [PATCH 9/9] ARM: multi_v7_defconfig: Statically build
 RTC_DRV_RK808
In-Reply-To: <3238534.Bk1TS2fSCp@diego>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-10-git-send-email-jagan@amarulasolutions.com>
 <3238534.Bk1TS2fSCp@diego>
Message-ID: <CAMty3ZBcBAHTk5eQU99rRqYm7tQAjtuEaTT_q6J5FYmY=ybvOA@mail.gmail.com>

On Mon, Oct 16, 2017 at 11:32 PM, Heiko St?bner <heiko at sntech.de> wrote:
> Hi,
>
> Am Montag, 16. Oktober 2017, 17:46:27 CEST schrieb Jagan Teki:
>> RTC_DRV_RK808 need to have build statically for the platforms
>> do use MFB_RK808 so replace module with statical link.
>
> why would you need this to be compiled on? MFD_RK808 will happily
> just create the platform-devices which are then bound to the RTC
> driver later once the module is ready.

Yeah, that can be true but seems like rk808 need rtc at the
beginning(like boot time) because we observed the boot hang even with
gmac (like one with HDMI [1]) eventually booting continue only when it
linked statically.

[1] https://lkml.org/lkml/2017/9/4/224

thanks!
-- 
Jagan Teki
Senior Linux Kernel Engineer | Amarula Solutions
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.


From helgaas at kernel.org  Mon Oct 16 13:03:50 2017
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Mon, 16 Oct 2017 15:03:50 -0500
Subject: [PATCH v6 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171013195059.23865-2-jeffy.chen@rock-chips.com>
References: <20171013195059.23865-1-jeffy.chen@rock-chips.com>
 <20171013195059.23865-2-jeffy.chen@rock-chips.com>
Message-ID: <20171016200350.GH25517@bhelgaas-glaptop.roam.corp.google.com>

On Sat, Oct 14, 2017 at 03:50:56AM +0800, Jeffy Chen wrote:
> Add support for PCIE_WAKE pin in rockchip pcie driver.
> 
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v6:
> Fix device_init_wake error handling, and add some comments.
> 
> Changes in v5:
> Rebase
> 
> Changes in v3:
> Fix error handling
> 
> Changes in v2:
> Use dev_pm_set_dedicated_wake_irq
>         -- Suggested by Brian Norris <briannorris at chromium.com>
> 
>  drivers/pci/host/pcie-rockchip.c | 27 +++++++++++++++++++++------
>  1 file changed, 21 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> index 9051c6c8fea4..268513b6c9c4 100644
> --- a/drivers/pci/host/pcie-rockchip.c
> +++ b/drivers/pci/host/pcie-rockchip.c
> @@ -37,6 +37,7 @@
>  #include <linux/pci_ids.h>
>  #include <linux/phy/phy.h>
>  #include <linux/platform_device.h>
> +#include <linux/pm_wakeirq.h>
>  #include <linux/reset.h>
>  #include <linux/regmap.h>
>  
> @@ -995,6 +996,17 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
>  		return err;
>  	}
>  
> +	irq = platform_get_irq_byname(pdev, "wakeup");
> +	if (irq >= 0) {
> +		/* Must init wakeup before setting dedicated wakeup irq. */
> +		device_init_wakeup(dev, true);
> +		err = dev_pm_set_dedicated_wake_irq(dev, irq);
> +		if (err) {
> +			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
> +			device_init_wakeup(dev, false);
> +		}
> +	}

There's nothing Rockchip-specific here, so I'm hoping you can explore
putting this support in the PCI core, so any system that describes the
WAKE# connection in the DT can benefit.

>  	return 0;
>  }
>  
> @@ -1123,10 +1135,6 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
>  		return PTR_ERR(rockchip->clk_pcie_pm);
>  	}
>  
> -	err = rockchip_pcie_setup_irq(rockchip);
> -	if (err)
> -		return err;
> -
>  	rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v");
>  	if (IS_ERR(rockchip->vpcie12v)) {
>  		if (PTR_ERR(rockchip->vpcie12v) == -EPROBE_DEFER)
> @@ -1155,7 +1163,7 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
>  		dev_info(dev, "no vpcie0v9 regulator found\n");
>  	}
>  
> -	return 0;
> +	return rockchip_pcie_setup_irq(rockchip);
>  }
>  
>  static int rockchip_pcie_set_vpcie(struct rockchip_pcie *rockchip)
> @@ -1546,7 +1554,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
>  
>  	err = rockchip_pcie_enable_clocks(rockchip);
>  	if (err)
> -		return err;
> +		/* Cleanup rockchip_pcie_parse_dt() */
> +		goto err_disable_wake;
>  
>  	err = rockchip_pcie_set_vpcie(rockchip);
>  	if (err) {
> @@ -1656,6 +1665,10 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
>  		regulator_disable(rockchip->vpcie0v9);
>  err_set_vpcie:
>  	rockchip_pcie_disable_clocks(rockchip);
> +err_disable_wake:
> +	/* It's harmless to disable wake even not enabled */
> +	dev_pm_clear_wake_irq(dev);
> +	device_init_wakeup(dev, false);
>  	return err;
>  }
>  
> @@ -1682,6 +1695,8 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
>  	if (!IS_ERR(rockchip->vpcie0v9))
>  		regulator_disable(rockchip->vpcie0v9);
>  
> +	dev_pm_clear_wake_irq(dev);
> +	device_init_wakeup(dev, false);
>  	return 0;
>  }
>  
> -- 
> 2.11.0
> 
> 


From mchehab at osg.samsung.com  Mon Oct 16 16:28:10 2017
From: mchehab at osg.samsung.com (Mauro Carvalho Chehab)
Date: Mon, 16 Oct 2017 16:28:10 -0700
Subject: [PATCH] media: rga: make some functions static
Message-ID: <ec8df85f312e299e6d92f7cc3446e67e510ccafb.1508196474.git.mchehab@osg.samsung.com>

drivers/media/platform/rockchip/rga/rga-hw.c:383:6: warning: no previous prototype for 'rga_cmd_set' [-Wmissing-prototypes]
 void rga_cmd_set(struct rga_ctx *ctx)
      ^~~~~~~~~~~
drivers/media/platform/rockchip/rga/rga.c:359:17: warning: no previous prototype for 'rga_fmt_find' [-Wmissing-prototypes]
 struct rga_fmt *rga_fmt_find(struct v4l2_format *f)
                 ^~~~~~~~~~~~

Signed-off-by: Mauro Carvalho Chehab <mchehab at osg.samsung.com>
---
 drivers/media/platform/rockchip/rga/rga-hw.c | 2 +-
 drivers/media/platform/rockchip/rga/rga.c    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 0645481c9a5e..96d1b1b3fe8e 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -380,7 +380,7 @@ static void rga_cmd_set_mode(struct rga_ctx *ctx)
 	dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;
 }
 
-void rga_cmd_set(struct rga_ctx *ctx)
+static void rga_cmd_set(struct rga_ctx *ctx)
 {
 	struct rockchip_rga *rga = ctx->rga;
 
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 2cf3bb29a2b3..e7d1b34baf1c 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -356,7 +356,7 @@ struct rga_fmt formats[] = {
 
 #define NUM_FORMATS ARRAY_SIZE(formats)
 
-struct rga_fmt *rga_fmt_find(struct v4l2_format *f)
+static struct rga_fmt *rga_fmt_find(struct v4l2_format *f)
 {
 	unsigned int i;
 
-- 
2.13.6



From edubezval at gmail.com  Mon Oct 16 17:15:37 2017
From: edubezval at gmail.com (Eduardo Valentin)
Date: Mon, 16 Oct 2017 17:15:37 -0700
Subject: [PATCH 0/5] thermal: rockchip: add tsadc support in thermal
 driver and IPA thermal control for RV1108 in dts
In-Reply-To: <1503570475-7850-1-git-send-email-rocky.hao@rock-chips.com>
References: <1503570475-7850-1-git-send-email-rocky.hao@rock-chips.com>
Message-ID: <20171017001535.GA16006@localhost.localdomain>

Hello,

On Thu, Aug 24, 2017 at 06:27:50PM +0800, Rocky Hao wrote:
> This series patches add the tsadc support in thermal driver and in devicetree for RV1108.
> Also add thermal control with Intelligent Power Allocation (IPA) policy by default.  Please
> refer to https://developer.arm.com/open-source/intelligent-power-allocation for more information
> about IPA.
> 
> Rocky Hao (5):
>   dt-bindings: rockchip-thermal: Support the RV1108 SoC compatible
>   thermal: rockchip: Support the RV1108 SoC in thermal driver

Applied patches 1  and 2.

>   arm: dts: rockchip: add tsadc node for RV1108 SoC
>   arm: dts: rockchip: add thermal nodes for RV1108 SoC
>   arm: dts: rockchip: enable tsadc module on RV1108 evaluation board
> 

Acked-by: Eduardo Valentin <edubezval at gmail.com>

for the DT changes.

>  .../bindings/thermal/rockchip-thermal.txt          |  1 +
>  arch/arm/boot/dts/rv1108-evb.dts                   |  4 ++
>  arch/arm/boot/dts/rv1108.dtsi                      | 69 ++++++++++++++++++++++
>  drivers/thermal/rockchip_thermal.c                 | 67 +++++++++++++++++++++
>  4 files changed, 141 insertions(+)
> 
> -- 
> 1.9.1
> 
> 


From shawn.lin at rock-chips.com  Mon Oct 16 17:54:05 2017
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 17 Oct 2017 08:54:05 +0800
Subject: [PATCH v2 3/5] mmc: dw_mmc: Add locking to the CTO timer
In-Reply-To: <CAD=FV=UMuJBKV2-pNo4yiyfxXxYJo_tX6RkxCCzm_UFg9XyjyQ@mail.gmail.com>
References: <20171012201118.23570-1-dianders@chromium.org>
 <20171012201118.23570-4-dianders@chromium.org>
 <41ae1571-4723-2700-1f03-7215e874c42e@rock-chips.com>
 <CAD=FV=UMuJBKV2-pNo4yiyfxXxYJo_tX6RkxCCzm_UFg9XyjyQ@mail.gmail.com>
Message-ID: <d6acce96-b292-ee4e-8f9b-1d524c14e0fc@rock-chips.com>

Hi Doug

On 2017/10/13 12:20, Doug Anderson wrote:
> Shawn,
> 
> On Thu, Oct 12, 2017 at 6:32 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>
>> On 2017/10/13 4:11, Douglas Anderson wrote:
>>>
>>> This attempts to instill a bit of paranoia to the code dealing with
>>> the CTO timer.  It's believed that this will make the CTO timer more
>>> robust in the case that we're having very long interrupt latencies.
>>>
>>
>> Ack. It could help fix some problems observed.
>>
>>
>>> Note that I originally thought that perhaps this patch was being
>>> overly paranoid and wasn't really needed, but then while I was running
>>> mmc_test on an rk3399 board I saw one instance of the message:
>>>     dwmmc_rockchip fe320000.dwmmc: Unexpected interrupt latency
>>>
>>> I had debug prints in the CTO timer code and I found that it was
>>> running CMD 13 at the time.
>>>
>>> ...so even though this patch seems like it might be overly paranoid,
>>> maybe it really isn't?
>>>
>>> Presumably the bad interrupt latency experienced was due to the fact
>>> that I had serial console enabled as serial console is typically where
>>> I place blame when I see absurdly large interrupt latencies.  In this
>>> particular case there was an (unrelated) printout to the serial
>>> console just before I saw the "Unexpected interrupt latency" printout.
>>>
>>> ...and actually, I managed to even reproduce the problems by running
>>> "iw mlan0 scan > /dev/null" while mmc_test was running.  That not only
>>> does a bunch of PCIe traffic but it also (on my system) outputs some
>>> SELinux log spam.
>>>> Fixes: 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command
>>
>> transfer over scheme")
>>>
>>> Tested-by: Emil Renner Berthing <kernel at esmil.dk>
>>> Signed-off-by: Douglas Anderson <dianders at chromium.org>
>>> ---
>>>
>>> Changes in v2:
>>> - Removed extra "int i"
>>>
>>>    drivers/mmc/host/dw_mmc.c | 91
>>> +++++++++++++++++++++++++++++++++++++++++------
>>>    1 file changed, 81 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>>> index 16516c528a88..50148991f30e 100644
>>> --- a/drivers/mmc/host/dw_mmc.c
>>> +++ b/drivers/mmc/host/dw_mmc.c
>>> @@ -403,6 +403,7 @@ static inline void dw_mci_set_cto(struct dw_mci *host)
>>>          unsigned int cto_clks;
>>>          unsigned int cto_div;
>>>          unsigned int cto_ms;
>>> +       unsigned long irqflags;
>>>          cto_clks = mci_readl(host, TMOUT) & 0xff;
>>>          cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
>>> @@ -413,8 +414,24 @@ static inline void dw_mci_set_cto(struct dw_mci
>>> *host)
>>>          /* add a bit spare time */
>>>          cto_ms += 10;
>>>    -     mod_timer(&host->cto_timer,
>>> -                 jiffies + msecs_to_jiffies(cto_ms) + 1);
>>> +       /*
>>> +        * The durations we're working with are fairly short so we have to
>>> be
>>> +        * extra careful about synchronization here.  Specifically in
>>> hardware a
>>> +        * command timeout is _at most_ 5.1 ms, so that means we expect an
>>> +        * interrupt (either command done or timeout) to come rather
>>> quickly
>>> +        * after the mci_writel.  ...but just in case we have a long
>>> interrupt
>>> +        * latency let's add a bit of paranoia.
>>> +        *
>>> +        * In general we'll assume that at least an interrupt will be
>>> asserted
>>> +        * in hardware by the time the cto_timer runs.  ...and if it
>>> hasn't
>>> +        * been asserted in hardware by that time then we'll assume it'll
>>> never
>>> +        * come.
>>> +        */
>>> +       spin_lock_irqsave(&host->irq_lock, irqflags);
>>> +       if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events))
>>> +               mod_timer(&host->cto_timer,
>>> +                       jiffies + msecs_to_jiffies(cto_ms) + 1);
>>> +       spin_unlock_irqrestore(&host->irq_lock, irqflags);
>>
>>
>> IIUC, this change is beacuse you move
>> mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START) before
>> setting up the timer, so there is a timing gap that the cmd_done
>> already comes and handled by dw_mci_interrupt->dw_mci_cmd_interrupt.
>> At this point, we don't need the cto timer at all.
> 
> As per below, if I don't move the mci_writel() before setting up the
> timer then there's still a race.  ...and actually that race was harder
> for me to write code for, but I invite you to try to see if it's
> somehow cleaner.
> 
> 
>>>    }
>>>      static void dw_mci_start_command(struct dw_mci *host,
>>> @@ -429,11 +446,11 @@ static void dw_mci_start_command(struct dw_mci
>>> *host,
>>>          wmb(); /* drain writebuffer */
>>>          dw_mci_wait_while_busy(host, cmd_flags);
>>>    +     mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
>>> +
>>>          /* response expected command only */
>>>          if (cmd_flags & SDMMC_CMD_RESP_EXP)
>>>                  dw_mci_set_cto(host);
>>> -
>>> -       mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
>>
>>
>>
>> But why? If we still keep the original logic, it's always correct
>> that cmd_done comes after setting up the cto timer. So could you
>> eleborate a bit more to help me understand the real intention here?
> 
> No matter which order you put things, there's a race one way or the
> other.  You need a lock.
> 
> Let's think about the old code you wrote.  You did this:
> 1. Start the CTO timer.
> 2. Start the command.
> 
> Now if you (somehow) take 20 ms to handle the interrupt, then this happens:
> 
> 1. Start the CTO timer.
> 2. Start the command.
> 3. Interrupt is pending, but interrupt handler doesn't run yet.
> 4. CTO timer fires and enqueues CTO timeout.
> 5. Interrupt finally fires.

OK, got it.

> 
> 
> Now normally things are pretty bad if you've got an interrupt latency
> of 20 ms.  ...and, in fact, I originally wrote up a commit that simply
> explained why the race didn't matter and was thinking of posting that
> instead of this one.  I wrote up:
> 
>       * Start a timer to detect missing cmd timeout if we expect a response.
>       *
>       * Note that we need to be a little careful about race conditions here
>       * since our timer will be racing with the actual hardware interrupt
>       * and things would get confused if both of them happened.
>       *
>       * We end up avoiding races here mostly because of our 10 ms "spare
>       * time" buffer above.  That's probably reliable enough because:
>       * - There's "guaranteed" "very little" time between setting the timer
>       *   and starting the command.  We're holding a spinlock (host->lock)
>       *   in all calls to this function so we won't get preempted.  Possibly
>       *   we could get interrupts still, but that shouldn't add up to
>       *   anything like the 10 ms spare time.
>       * - We expect that when the actual interrupt fires that our interrupt
>       *   routine should get called "relatively quickly" (compared to the
>       *   10 ms buffer) and will be able to cancel this timer.
> 
> ...but then I ran a whole bunch of tests and I found that, as far as I
> could tell, we actually _were_ getting a super long interrupt latency.
> Specifically I saw the printout "Unexpected interrupt latency" in my
> patch.  In order to see that printout in my patch (which even starts
> the command _before_ the CTO timer), the only explanation is bad
> interrupt latency, right?  Also: based on my past experience I believe
> it is possible to get upwards of 100 ms interrupt latency if you've
> got serial console enabled.  printk, especially printk from an
> interrupt context, can do some funny things.
> 

Right! It makes sense to me now.

> 
> ...but this stuff is always hard to get right, so if I messed up the
> above please let me know!  I tried to think of all of the cases so it
> would work no matter if delays happened in any random place but
> concurrency is hard.

Yes, it looks hard to get concurrency right. I have a comment for your
DRTO case(patch 5). Let's do some brainstorm there.

> 
> 
> -Doug
> 
> 
> 



From shawn.lin at rock-chips.com  Mon Oct 16 18:17:30 2017
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 17 Oct 2017 09:17:30 +0800
Subject: [PATCH v2 5/5] mmc: dw_mmc: Cleanup the DTO timer like the CTO one
In-Reply-To: <20171012201118.23570-6-dianders@chromium.org>
References: <20171012201118.23570-1-dianders@chromium.org>
 <20171012201118.23570-6-dianders@chromium.org>
Message-ID: <48ad69fd-b85a-d9c6-308f-dea72caa70b5@rock-chips.com>

Hi Doug

On 2017/10/13 4:11, Douglas Anderson wrote:
> The recent CTO timer introduced in commit 03de19212ea3 ("mmc: dw_mmc:
> introduce timer for broken command transfer over scheme") was causing
> observable problems due to race conditions.  Previous patches have
> fixed those race conditions.
> 
> It can be observed that these same race conditions ought to be
> theoretically possible with the DTO timer too though they are
> massively less likely to happen because the data timeout is always set
> to 0xffffff right now.  That means even at a 200 MHz card clock we
> were arming the DTO timer for 94 ms:
>    >>> (0xffffff * 1000. / 200000000) + 10
>    93.886075
> 
> We always also were setting the DTO timer _after_ starting the
> transfer, unlike how the old code was seting the CTO timer.
> 
> In any case, even though the DTO timer is much less likely to have
> races, it still makes sense to add code to handle it _just in case_.
> 
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
> 
> Changes in v2:
> - Cleanup the DTO timer new for v2
> 
>   drivers/mmc/host/dw_mmc.c | 54 ++++++++++++++++++++++++++++++++++++++++++++---
>   1 file changed, 51 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 6bc87b1385a9..bc0808615431 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1950,7 +1950,11 @@ static void dw_mci_set_drto(struct dw_mci *host)
>   	/* add a bit spare time */
>   	drto_ms += 10;
>   
> -	mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));
> +	spin_lock_irqsave(&host->irq_lock, irqflags);
> +	if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
> +		mod_timer(&host->dto_timer,
> +			  jiffies + msecs_to_jiffies(drto_ms));
> +	spin_unlock_irqrestore(&host->irq_lock, irqflags);
>   }
>   
>   static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
> @@ -1971,6 +1975,18 @@ static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
>   	return true;
>   }
>   
> +static bool dw_mci_clear_pending_data_complete(struct dw_mci *host)
> +{
> +	if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
> +		return false;
> +
> +	/* Extra paranoia just like dw_mci_clear_pending_cmd_complete() */
> +	WARN_ON(del_timer_sync(&host->dto_timer));
> +	clear_bit(EVENT_DATA_COMPLETE, &host->pending_events);
> +
> +	return true;
> +}
> +
>   static void dw_mci_tasklet_func(unsigned long priv)
>   {
>   	struct dw_mci *host = (struct dw_mci *)priv;
> @@ -2112,8 +2128,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
>   			/* fall through */
>   
>   		case STATE_DATA_BUSY:
> -			if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
> -						&host->pending_events)) {
> +			if (!dw_mci_clear_pending_data_complete(host)) {
>   				/*
>   				 * If data error interrupt comes but data over
>   				 * interrupt doesn't come within the given time.
> @@ -2683,6 +2698,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
>   		}
>   
>   		if (pending & SDMMC_INT_DATA_OVER) {
> +			spin_lock_irqsave(&host->irq_lock, irqflags);
> +
>   			del_timer(&host->dto_timer);
>   
>   			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
> @@ -2695,6 +2712,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
>   			}
>   			set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
>   			tasklet_schedule(&host->tasklet);
> +
> +			spin_unlock_irqrestore(&host->irq_lock, irqflags);
>   		}
>   
>   		if (pending & SDMMC_INT_RXDR) {
> @@ -3044,7 +3063,31 @@ static void dw_mci_cto_timer(unsigned long arg)
>   static void dw_mci_dto_timer(unsigned long arg)
>   {
>   	struct dw_mci *host = (struct dw_mci *)arg;
> +	unsigned long irqflags;
> +	u32 pending;
> +
> +	spin_lock_irqsave(&host->irq_lock, irqflags);
>   
> +	/*
> +	 * The DTO timer is much longer than the CTO timer, so it's even less
> +	 * likely that we'll these cases, but it pays to be paranoid.
> +	 */
> +	pending = mci_readl(host, MINTSTS); /* read-only mask reg */
> +	if (pending & SDMMC_INT_DATA_OVER) {
> +		/* The interrupt should fire; no need to act but we can warn */
> +		dev_warn(host->dev, "Unexpected data interrupt latency\n");
> +		goto exit;

I was checking a problem like this:

(1) Start a CTO timer
(2) Start a command
(3) Got CMD_DONE interrupt and cancel the CTO timer
(4) Start a DRTO timer
(5) Start external dma to get the data from fifo
(6) The system bus/DRAM port is idle for a very long time for no
matter what happen.
(7) DRTO timer fires but DTO was set as the card have already
sent all data to the fifo.
(8) Now you patch bails out earlier  and notify the mmc core that this
data transfer was finished successfully.
(9) mmc core propgate the successful state to block layer and maybe
a critical reader in file system will use the data right now but it
falls into trouble due to the incomplete data.


The problem comes from step 6 and setep 7. Quote some bit from dwmmc
databook, V270a, section 7.1,

"While using the external DMA interface for reading from a card, the DTO
interrupt occurs only after all the data is flushed to memory by the DMA
Interface unit. A Busy Clear Interrupt is asserted after the DTO."

So the DTO isn't reliable or perfectly good in practice for that case
that the delay is in external DMA side. That is hard to reproduced but
it was the reason for me to come up with the immature idea of adding
a longer enough and catch-all timer. Or we only set a longer enough
timeout value for CTO and DRTO timer and we could blindly believe the
hardware falls into troube for HW reason and seems that makes the change
simpler. Looking forward to your opinion. :)





> +	}
> +	if (test_bit(EVENT_DATA_COMPLETE, &host->pending_events)) {
> +		/* Presumably interrupt handler couldn't delete the timer */
> +		dev_warn(host->dev, "DTO timeout when already completed\n");
> +		goto exit;
> +	}
> +
> +	/*
> +	 * Continued paranoia to make sure we're in the state we expect.
> +	 * This paranoia isn't really justified but it seems good to be safe.
> +	 */
>   	switch (host->state) {
>   	case STATE_SENDING_DATA:
>   	case STATE_DATA_BUSY:
> @@ -3059,8 +3102,13 @@ static void dw_mci_dto_timer(unsigned long arg)
>   		tasklet_schedule(&host->tasklet);
>   		break;
>   	default:
> +		dev_warn(host->dev, "Unexpected data timeout, state %d\n",
> +			 host->state);
>   		break;
>   	}
> +
> +exit:
> +	spin_unlock_irqrestore(&host->irq_lock, irqflags);
>   }
>   
>   #ifdef CONFIG_OF
> 



From mark.yao at rock-chips.com  Mon Oct 16 18:47:24 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Tue, 17 Oct 2017 09:47:24 +0800
Subject: [PATCH v3 3/4] drm/rockchip: Add support for Rockchip Soc RGB
 output interface
In-Reply-To: <1507536416-110807-1-git-send-email-hjc@rock-chips.com>
References: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>
 <1507536416-110807-1-git-send-email-hjc@rock-chips.com>
Message-ID: <02a599df-c866-92dc-3aa0-f63c6bc67257@rock-chips.com>

On 2017?10?09? 16:06, Sandy Huang wrote:
> Some Rockchip CRTCs, like rv1108, can directly output parallel and
> serial RGB data to panel or conversion chip, so we add this driver to
> probe encoder and connector.
>
> Signed-off-by: Sandy Huang <hjc at rock-chips.com>
> ---
> Changes in v3:
>    update for rgb-mode move to panel node.
> Changes in v2:
>    1. add error log when probe failed;
>    2. update name_to_output_mode() according to sean's suggest;
>    3. Fix uninitialized use of ret.
>
>   drivers/gpu/drm/rockchip/Kconfig            |   9 +
>   drivers/gpu/drm/rockchip/Makefile           |   1 +
>   drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   2 +
>   drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   1 +
>   drivers/gpu/drm/rockchip/rockchip_rgb.c     | 343 ++++++++++++++++++++++++++++
>   5 files changed, 356 insertions(+)
>   create mode 100644 drivers/gpu/drm/rockchip/rockchip_rgb.c
>
> diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
> index 0c31f0a..85c7cc5 100644
> --- a/drivers/gpu/drm/rockchip/Kconfig
> +++ b/drivers/gpu/drm/rockchip/Kconfig
> @@ -8,6 +8,7 @@ config DRM_ROCKCHIP
>   	select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
>   	select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
>   	select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
> +	select DRM_RGB if ROCKCHIP_RGB
>   	select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
>   	help
>   	  Choose this option if you have a Rockchip soc chipset.
> @@ -65,4 +66,12 @@ config ROCKCHIP_LVDS
>   	  Rockchip rk3288 SoC has LVDS TX Controller can be used, and it
>   	  support LVDS, rgb, dual LVDS output mode. say Y to enable its
>   	  driver.
> +
> +config ROCKCHIP_RGB
> +	bool "Rockchip RGB support"

See the fix[0] for lvds,  RGB driver using pinctl also need "depends on PINCTRL".

[0]https://patchwork.kernel.org/patch/9987017/



From mark.yao at rock-chips.com  Mon Oct 16 18:50:38 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Tue, 17 Oct 2017 09:50:38 +0800
Subject: [RESEND PATCH v2 1/5] arm64: dts: rockchip: Enable edp disaplay
 on kevin
In-Reply-To: <20171016100640.26575-2-jeffy.chen@rock-chips.com>
References: <20171016100640.26575-1-jeffy.chen@rock-chips.com>
 <20171016100640.26575-2-jeffy.chen@rock-chips.com>
Message-ID: <5295f622-647a-c6d3-9ead-de8182d008e6@rock-chips.com>

On 2017?10?16? 18:06, Jeffy Chen wrote:
> Add edp panel and enable related nodes on kevin.
>
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---

Looks good.

Reviewed-by: Mark Yao <mark.yao at rock-chips.com>

> Changes in v2: None
>
>   arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
>   arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
>   2 files changed, 45 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
> index a3d3cea7dc4f..bc67b19f0af5 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
> @@ -93,6 +93,18 @@
>   		pwm-delay-us = <10000>;
>   	};
>   
> +	edp_panel: edp-panel {
> +		compatible = "sharp,lq123p1jx31", "simple-panel";
> +		backlight = <&backlight>;
> +		power-supply = <&pp3300_disp>;
> +
> +		ports {
> +			panel_in_edp: endpoint {
> +				remote-endpoint = <&edp_out_panel>;
> +			};
> +		};
> +	};
> +
>   	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
>   		compatible = "murata,ncp15wb473";
>   		pullup-uv = <1800000>;
> @@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
>   	};
>   };
>   
> +&edp {
> +	status = "okay";
> +
> +	ports {
> +		edp_out: port at 1 {
> +			reg = <1>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			edp_out_panel: endpoint at 0 {
> +				reg = <0>;
> +				remote-endpoint = <&panel_in_edp>;
> +			};
> +		};
> +	};
> +};
> +
>   &ppvar_bigcpu_pwm {
>   	regulator-min-microvolt = <798674>;
>   	regulator-max-microvolt = <1302172>;
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
> index 5772c52fbfd3..470105d651c2 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
> @@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
>   	dr_mode = "host";
>   };
>   
> +&vopb {
> +	status = "okay";
> +};
> +
> +&vopb_mmu {
> +	status = "okay";
> +};
> +
> +&vopl {
> +	status = "okay";
> +};
> +
> +&vopl_mmu {
> +	status = "okay";
> +};
> +
>   #include <arm/cros-ec-keyboard.dtsi>
>   #include <arm/cros-ec-sbs.dtsi>
>   



From shawn.lin at rock-chips.com  Mon Oct 16 20:38:04 2017
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 17 Oct 2017 11:38:04 +0800
Subject: [PATCH] arm64: dts: rockchip: correct vqmmc voltage for rk3399
 platforms
Message-ID: <1508211484-210856-1-git-send-email-shawn.lin@rock-chips.com>

The vcc_sd or vcc_sdio used for IO voltage for sdmmc and sdio
interface on rk3399 platform have a limitation that it can't be
larger than 3.0v, otherwise it has a potential risk for the chip.
Correct all of them.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

 arch/arm64/boot/dts/rockchip/rk3399-firefly.dts   | 4 ++--
 arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi     | 4 ++--
 arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
index da373dd..4f28628 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
@@ -382,10 +382,10 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <3300000>;
+				regulator-max-microvolt = <3000000>;
 				regulator-state-mem {
 					regulator-on-in-suspend;
-					regulator-suspend-microvolt = <3300000>;
+					regulator-suspend-microvolt = <3000000>;
 				};
 			};
 
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
index 53ff3d1..910628d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
@@ -325,12 +325,12 @@
 			vcc_sd: LDO_REG4 {
 				regulator-name = "vcc_sd";
 				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <3300000>;
+				regulator-max-microvolt = <3000000>;
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-state-mem {
 					regulator-on-in-suspend;
-					regulator-suspend-microvolt = <3300000>;
+					regulator-suspend-microvolt = <3000000>;
 				};
 			};
 
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
index 6c30bb0..0f873c8 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
@@ -315,10 +315,10 @@
 				regulator-always-on;
 				regulator-boot-on;
 				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <3300000>;
+				regulator-max-microvolt = <3000000>;
 				regulator-state-mem {
 					regulator-on-in-suspend;
-					regulator-suspend-microvolt = <3300000>;
+					regulator-suspend-microvolt = <3000000>;
 				};
 			};
 
-- 
1.9.1




From dianders at chromium.org  Mon Oct 16 22:05:30 2017
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 16 Oct 2017 22:05:30 -0700
Subject: [PATCH v2 5/5] mmc: dw_mmc: Cleanup the DTO timer like the CTO one
In-Reply-To: <48ad69fd-b85a-d9c6-308f-dea72caa70b5@rock-chips.com>
References: <20171012201118.23570-1-dianders@chromium.org>
 <20171012201118.23570-6-dianders@chromium.org>
 <48ad69fd-b85a-d9c6-308f-dea72caa70b5@rock-chips.com>
Message-ID: <CAD=FV=WiYn7GhW=U74pQuyFHbNKa8NFN14ADoZ+ovFFW4+h4AQ@mail.gmail.com>

Hi,

On Mon, Oct 16, 2017 at 6:17 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Hi Doug
>
>
> On 2017/10/13 4:11, Douglas Anderson wrote:
>>
>> The recent CTO timer introduced in commit 03de19212ea3 ("mmc: dw_mmc:
>> introduce timer for broken command transfer over scheme") was causing
>> observable problems due to race conditions.  Previous patches have
>> fixed those race conditions.
>>
>> It can be observed that these same race conditions ought to be
>> theoretically possible with the DTO timer too though they are
>> massively less likely to happen because the data timeout is always set
>> to 0xffffff right now.  That means even at a 200 MHz card clock we
>> were arming the DTO timer for 94 ms:
>>    >>> (0xffffff * 1000. / 200000000) + 10
>>    93.886075
>>
>> We always also were setting the DTO timer _after_ starting the
>> transfer, unlike how the old code was seting the CTO timer.
>>
>> In any case, even though the DTO timer is much less likely to have
>> races, it still makes sense to add code to handle it _just in case_.
>>
>> Signed-off-by: Douglas Anderson <dianders at chromium.org>
>> ---
>>
>> Changes in v2:
>> - Cleanup the DTO timer new for v2
>>
>>   drivers/mmc/host/dw_mmc.c | 54
>> ++++++++++++++++++++++++++++++++++++++++++++---
>>   1 file changed, 51 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 6bc87b1385a9..bc0808615431 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -1950,7 +1950,11 @@ static void dw_mci_set_drto(struct dw_mci *host)
>>         /* add a bit spare time */
>>         drto_ms += 10;
>>   -     mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));
>> +       spin_lock_irqsave(&host->irq_lock, irqflags);
>> +       if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
>> +               mod_timer(&host->dto_timer,
>> +                         jiffies + msecs_to_jiffies(drto_ms));
>> +       spin_unlock_irqrestore(&host->irq_lock, irqflags);
>>   }
>>     static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
>> @@ -1971,6 +1975,18 @@ static bool
>> dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
>>         return true;
>>   }
>>   +static bool dw_mci_clear_pending_data_complete(struct dw_mci *host)
>> +{
>> +       if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
>> +               return false;
>> +
>> +       /* Extra paranoia just like dw_mci_clear_pending_cmd_complete() */
>> +       WARN_ON(del_timer_sync(&host->dto_timer));
>> +       clear_bit(EVENT_DATA_COMPLETE, &host->pending_events);
>> +
>> +       return true;
>> +}
>> +
>>   static void dw_mci_tasklet_func(unsigned long priv)
>>   {
>>         struct dw_mci *host = (struct dw_mci *)priv;
>> @@ -2112,8 +2128,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
>>                         /* fall through */
>>                 case STATE_DATA_BUSY:
>> -                       if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
>> -                                               &host->pending_events)) {
>> +                       if (!dw_mci_clear_pending_data_complete(host)) {
>>                                 /*
>>                                  * If data error interrupt comes but data
>> over
>>                                  * interrupt doesn't come within the given
>> time.
>> @@ -2683,6 +2698,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void
>> *dev_id)
>>                 }
>>                 if (pending & SDMMC_INT_DATA_OVER) {
>> +                       spin_lock_irqsave(&host->irq_lock, irqflags);
>> +
>>                         del_timer(&host->dto_timer);
>>                         mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
>> @@ -2695,6 +2712,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void
>> *dev_id)
>>                         }
>>                         set_bit(EVENT_DATA_COMPLETE,
>> &host->pending_events);
>>                         tasklet_schedule(&host->tasklet);
>> +
>> +                       spin_unlock_irqrestore(&host->irq_lock, irqflags);
>>                 }
>>                 if (pending & SDMMC_INT_RXDR) {
>> @@ -3044,7 +3063,31 @@ static void dw_mci_cto_timer(unsigned long arg)
>>   static void dw_mci_dto_timer(unsigned long arg)
>>   {
>>         struct dw_mci *host = (struct dw_mci *)arg;
>> +       unsigned long irqflags;
>> +       u32 pending;
>> +
>> +       spin_lock_irqsave(&host->irq_lock, irqflags);
>>   +     /*
>> +        * The DTO timer is much longer than the CTO timer, so it's even
>> less
>> +        * likely that we'll these cases, but it pays to be paranoid.
>> +        */
>> +       pending = mci_readl(host, MINTSTS); /* read-only mask reg */
>> +       if (pending & SDMMC_INT_DATA_OVER) {
>> +               /* The interrupt should fire; no need to act but we can
>> warn */
>> +               dev_warn(host->dev, "Unexpected data interrupt
>> latency\n");
>> +               goto exit;
>
>
> I was checking a problem like this:
>
> (1) Start a CTO timer
> (2) Start a command
> (3) Got CMD_DONE interrupt and cancel the CTO timer
> (4) Start a DRTO timer
> (5) Start external dma to get the data from fifo
> (6) The system bus/DRAM port is idle for a very long time for no
> matter what happen.
> (7) DRTO timer fires but DTO was set as the card have already
> sent all data to the fifo.
> (8) Now you patch bails out earlier  and notify the mmc core that this
> data transfer was finished successfully.

I don't understand how you're saying that my patch will notify the mmc
core that the data transfer was finished successfully.  Two things:

A) My patch should only be fixing race conditions here and not
introducing anything new.  In other words if we are somehow
accidentally telling the MMC core that we have a successful transfer
then I don't believe that's something new that my patch introduced.


B) If the dw_mci_dto_timer function gets called then we always
indicate an error.

Specifically the _only_ action that the dw_mci_dto_timer() function
can take is this:

                host->data_status = SDMMC_INT_DRTO;
                set_bit(EVENT_DATA_ERROR, &host->pending_events);
                set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
                tasklet_schedule(&host->tasklet);

Which sets the "EVENT_DATA_ERROR" and thus can't tell the mmc core
that this data transfer was finished "successfully"

> (9) mmc core propgate the successful state to block layer and maybe
> a critical reader in file system will use the data right now but it
> falls into trouble due to the incomplete data.
>
>
> The problem comes from step 6 and setep 7. Quote some bit from dwmmc
> databook, V270a, section 7.1,
>
> "While using the external DMA interface for reading from a card, the DTO
> interrupt occurs only after all the data is flushed to memory by the DMA
> Interface unit. A Busy Clear Interrupt is asserted after the DTO."

Ugh.  Not your fault, but terrible terms.  I keep getting "DTO" and
"DRTO" confused, especially since in the code the "drto" timer is
called the "dto" timer.

DTO = Data Transfer Over
DRTO = Data Read Time Out

NOTE: it seems the bit you're quoting from the databook say that the
DTO is expected to be delayed with external DMA.  This doesn't seem to
match what you said above that  "(7) DRTO timer fires but DTO was set
as the card have already sent all data to the fifo.".  If the databook
is saying that "DTO" will be delayed then how could DTO already be set
when the timer fires??



> So the DTO isn't reliable or perfectly good in practice for that case
> that the delay is in external DMA side.

So just to restate to make sure I'm understanding you properly:

If you're using external DMA then it's possible that you'll get a Data
Transfer Over (DTO) interrupt at some point in time _later_ than the
more than 94 ms that we're waiting because the DTO timer can't be
asserted until all the DMA is flushed.  Actually, on Rockchip you
can't run faster than 150 MHz, so it's actually 121 ms.  It seems a
little bit hard to believe that DMA for a transfer is taking more than
121 ms to flush, but I guess it could happen?

It seems even harder to believe that it's taking > 121 ms to flush and
the system is running well enough that it was able to get to the dto
timer function all without the DTO interrupt bit even being set.

In any case, if the DMA transfer really is taking more than 121 ms to
flush then we'll assert a DRTO interrupt and report an error to the
MMC core.  I suppose (by chance) we could somehow get confused when
the DTO interrupt finally fires and then we could think that a 2nd
transfer finished, but I'm not even sure that would happen...


> That is hard to reproduced but
> it was the reason for me to come up with the immature idea of adding
> a longer enough and catch-all timer. Or we only set a longer enough
> timeout value for CTO and DRTO timer and we could blindly believe the
> hardware falls into troube for HW reason and seems that makes the change
> simpler. Looking forward to your opinion. :)

If you're running into the problem you describe, it kinda sounds like
it's more reason _not_ to use the same code for the CTO and DRTO
timers.  As I understand it, the CTO timer _doesn't_ suffer from the
problems above., so we shouldn't make it suffer any workarounds we
need for the DRTO.  Also the CTO timer is _very_ fast.  We expect a
normal CTO within 1 ms whereas the DRTO timer is much, much longer.
If it's been 10 ms and we haven't seen a command finish and haven't
seen a real CTO then there's no reason to delay further.


As for blindly setting a longer timeout for CTO / DRTO I'm not sure
that's a great idea.  We routinely get these timeouts in tuning and we
really don't want to make tuning even slower than it already is by
lengthening any of these timeouts too much.


Overall: if you're having weird trouble with external DMA as you
describe, I suppose you could just have an even longer DRTO delay only
for external DMA?


NOTE also: the DesignWare Manual that I have (2.80a) actually even
suggests that for long data timeouts (like 100ms) that a software
timeout is appropriate.  They even suggest that in that case you could
rely only on the software timeout.  They say:

> Note: The software timer should be used if the timeout value is in the order
> of 100 ms. In this case, read data timeout interrupt needs to be disabled.

Presumably they are saying that because you can't really express much
more than 100 ms in the TMOUT register?

---

Just to summarize:

* I don't think my patch introduces any new problems like the one you
describe.  I think if there are problems like that, they are
pre-existing.

* I don't see a reason to use a catchall timer where we use the same
timeout for CTO and DRTO.  We could try to save a few bytes of storage
space and have a single "struct timer" at the expense of a little
extra logic to try to disambiguate, but I'm not terribly interested in
writing or reviewing that patch.

---

As always, please let me know if I got mixed up somewhere.

-Doug


From shawn.lin at rock-chips.com  Mon Oct 16 23:33:54 2017
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 17 Oct 2017 14:33:54 +0800
Subject: [PATCH v2 5/5] mmc: dw_mmc: Cleanup the DTO timer like the CTO one
In-Reply-To: <CAD=FV=WiYn7GhW=U74pQuyFHbNKa8NFN14ADoZ+ovFFW4+h4AQ@mail.gmail.com>
References: <20171012201118.23570-1-dianders@chromium.org>
 <20171012201118.23570-6-dianders@chromium.org>
 <48ad69fd-b85a-d9c6-308f-dea72caa70b5@rock-chips.com>
 <CAD=FV=WiYn7GhW=U74pQuyFHbNKa8NFN14ADoZ+ovFFW4+h4AQ@mail.gmail.com>
Message-ID: <815efb17-801e-9c79-4168-b5bc911d725a@rock-chips.com>



On 2017/10/17 13:05, Doug Anderson wrote:
> Hi,
> 
> On Mon, Oct 16, 2017 at 6:17 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> Hi Doug
>>
>>
>> On 2017/10/13 4:11, Douglas Anderson wrote:
>>>
>>> The recent CTO timer introduced in commit 03de19212ea3 ("mmc: dw_mmc:
>>> introduce timer for broken command transfer over scheme") was causing
>>> observable problems due to race conditions.  Previous patches have
>>> fixed those race conditions.
>>>
>>> It can be observed that these same race conditions ought to be
>>> theoretically possible with the DTO timer too though they are
>>> massively less likely to happen because the data timeout is always set
>>> to 0xffffff right now.  That means even at a 200 MHz card clock we
>>> were arming the DTO timer for 94 ms:
>>>     >>> (0xffffff * 1000. / 200000000) + 10
>>>     93.886075
>>>
>>> We always also were setting the DTO timer _after_ starting the
>>> transfer, unlike how the old code was seting the CTO timer.
>>>
>>> In any case, even though the DTO timer is much less likely to have
>>> races, it still makes sense to add code to handle it _just in case_.
>>>
>>> Signed-off-by: Douglas Anderson <dianders at chromium.org>
>>> ---
>>>
>>> Changes in v2:
>>> - Cleanup the DTO timer new for v2
>>>
>>>    drivers/mmc/host/dw_mmc.c | 54
>>> ++++++++++++++++++++++++++++++++++++++++++++---
>>>    1 file changed, 51 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>>> index 6bc87b1385a9..bc0808615431 100644
>>> --- a/drivers/mmc/host/dw_mmc.c
>>> +++ b/drivers/mmc/host/dw_mmc.c
>>> @@ -1950,7 +1950,11 @@ static void dw_mci_set_drto(struct dw_mci *host)
>>>          /* add a bit spare time */
>>>          drto_ms += 10;
>>>    -     mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));
>>> +       spin_lock_irqsave(&host->irq_lock, irqflags);
>>> +       if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
>>> +               mod_timer(&host->dto_timer,
>>> +                         jiffies + msecs_to_jiffies(drto_ms));
>>> +       spin_unlock_irqrestore(&host->irq_lock, irqflags);
>>>    }
>>>      static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
>>> @@ -1971,6 +1975,18 @@ static bool
>>> dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
>>>          return true;
>>>    }
>>>    +static bool dw_mci_clear_pending_data_complete(struct dw_mci *host)
>>> +{
>>> +       if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
>>> +               return false;
>>> +
>>> +       /* Extra paranoia just like dw_mci_clear_pending_cmd_complete() */
>>> +       WARN_ON(del_timer_sync(&host->dto_timer));
>>> +       clear_bit(EVENT_DATA_COMPLETE, &host->pending_events);
>>> +
>>> +       return true;
>>> +}
>>> +
>>>    static void dw_mci_tasklet_func(unsigned long priv)
>>>    {
>>>          struct dw_mci *host = (struct dw_mci *)priv;
>>> @@ -2112,8 +2128,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
>>>                          /* fall through */
>>>                  case STATE_DATA_BUSY:
>>> -                       if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
>>> -                                               &host->pending_events)) {
>>> +                       if (!dw_mci_clear_pending_data_complete(host)) {
>>>                                  /*
>>>                                   * If data error interrupt comes but data
>>> over
>>>                                   * interrupt doesn't come within the given
>>> time.
>>> @@ -2683,6 +2698,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void
>>> *dev_id)
>>>                  }
>>>                  if (pending & SDMMC_INT_DATA_OVER) {
>>> +                       spin_lock_irqsave(&host->irq_lock, irqflags);
>>> +
>>>                          del_timer(&host->dto_timer);
>>>                          mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
>>> @@ -2695,6 +2712,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void
>>> *dev_id)
>>>                          }
>>>                          set_bit(EVENT_DATA_COMPLETE,
>>> &host->pending_events);
>>>                          tasklet_schedule(&host->tasklet);
>>> +
>>> +                       spin_unlock_irqrestore(&host->irq_lock, irqflags);
>>>                  }
>>>                  if (pending & SDMMC_INT_RXDR) {
>>> @@ -3044,7 +3063,31 @@ static void dw_mci_cto_timer(unsigned long arg)
>>>    static void dw_mci_dto_timer(unsigned long arg)
>>>    {
>>>          struct dw_mci *host = (struct dw_mci *)arg;
>>> +       unsigned long irqflags;
>>> +       u32 pending;
>>> +
>>> +       spin_lock_irqsave(&host->irq_lock, irqflags);
>>>    +     /*
>>> +        * The DTO timer is much longer than the CTO timer, so it's even
>>> less
>>> +        * likely that we'll these cases, but it pays to be paranoid.
>>> +        */
>>> +       pending = mci_readl(host, MINTSTS); /* read-only mask reg */
>>> +       if (pending & SDMMC_INT_DATA_OVER) {
>>> +               /* The interrupt should fire; no need to act but we can
>>> warn */
>>> +               dev_warn(host->dev, "Unexpected data interrupt
>>> latency\n");
>>> +               goto exit;
>>
>>
>> I was checking a problem like this:
>>
>> (1) Start a CTO timer
>> (2) Start a command
>> (3) Got CMD_DONE interrupt and cancel the CTO timer
>> (4) Start a DRTO timer
>> (5) Start external dma to get the data from fifo
>> (6) The system bus/DRAM port is idle for a very long time for no
>> matter what happen.
>> (7) DRTO timer fires but DTO was set as the card have already
>> sent all data to the fifo.
>> (8) Now you patch bails out earlier  and notify the mmc core that this
>> data transfer was finished successfully.
> 
> I don't understand how you're saying that my patch will notify the mmc
> core that the data transfer was finished successfully.  Two things:
> 
> A) My patch should only be fixing race conditions here and not
> introducing anything new.  In other words if we are somehow
> accidentally telling the MMC core that we have a successful transfer
> then I don't believe that's something new that my patch introduced.
> 
> 
> B) If the dw_mci_dto_timer function gets called then we always
> indicate an error.

Oh?yes it is. I overlooked the "goto exit;".

> 
> Specifically the _only_ action that the dw_mci_dto_timer() function
> can take is this:
> 
>                  host->data_status = SDMMC_INT_DRTO;
>                  set_bit(EVENT_DATA_ERROR, &host->pending_events);
>                  set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
>                  tasklet_schedule(&host->tasklet);
> 
> Which sets the "EVENT_DATA_ERROR" and thus can't tell the mmc core
> that this data transfer was finished "successfully"
> 
>> (9) mmc core propgate the successful state to block layer and maybe
>> a critical reader in file system will use the data right now but it
>> falls into trouble due to the incomplete data.
>>
>>
>> The problem comes from step 6 and setep 7. Quote some bit from dwmmc
>> databook, V270a, section 7.1,
>>
>> "While using the external DMA interface for reading from a card, the DTO
>> interrupt occurs only after all the data is flushed to memory by the DMA
>> Interface unit. A Busy Clear Interrupt is asserted after the DTO."
> 
> Ugh.  Not your fault, but terrible terms.  I keep getting "DTO" and
> "DRTO" confused, especially since in the code the "drto" timer is
> called the "dto" timer.
> 
> DTO = Data Transfer Over
> DRTO = Data Read Time Out
> 
> NOTE: it seems the bit you're quoting from the databook say that the
> DTO is expected to be delayed with external DMA.  This doesn't seem to
> match what you said above that  "(7) DRTO timer fires but DTO was set
> as the card have already sent all data to the fifo.".  If the databook
> is saying that "DTO" will be delayed then how could DTO already be set
> when the timer fires??
> >
> 
>> So the DTO isn't reliable or perfectly good in practice for that case
>> that the delay is in external DMA side.
> 
> So just to restate to make sure I'm understanding you properly:
> 
> If you're using external DMA then it's possible that you'll get a Data
> Transfer Over (DTO) interrupt at some point in time _later_ than the
> more than 94 ms that we're waiting because the DTO timer can't be
> asserted until all the DMA is flushed.  Actually, on Rockchip you
> can't run faster than 150 MHz, so it's actually 121 ms.  It seems a
> little bit hard to believe that DMA for a transfer is taking more than
> 121 ms to flush, but I guess it could happen?
> 

In theory it could, but I didn't see it.

> It seems even harder to believe that it's taking > 121 ms to flush and
> the system is running well enough that it was able to get to the dto
> timer function all without the DTO interrupt bit even being set.
> 
> In any case, if the DMA transfer really is taking more than 121 ms to
> flush then we'll assert a DRTO interrupt and report an error to the
> MMC core.  I suppose (by chance) we could somehow get confused when
> the DTO interrupt finally fires and then we could think that a 2nd
> transfer finished, but I'm not even sure that would happen...

So there is no problem now for me as I missed some code above.

> 
> 
>> That is hard to reproduced but
>> it was the reason for me to come up with the immature idea of adding
>> a longer enough and catch-all timer. Or we only set a longer enough
>> timeout value for CTO and DRTO timer and we could blindly believe the
>> hardware falls into troube for HW reason and seems that makes the change
>> simpler. Looking forward to your opinion. :)
> 
> If you're running into the problem you describe, it kinda sounds like
> it's more reason _not_ to use the same code for the CTO and DRTO
> timers.  As I understand it, the CTO timer _doesn't_ suffer from the
> problems above., so we shouldn't make it suffer any workarounds we
> need for the DRTO.  Also the CTO timer is _very_ fast.  We expect a
> normal CTO within 1 ms whereas the DRTO timer is much, much longer.
> If it's been 10 ms and we haven't seen a command finish and haven't
> seen a real CTO then there's no reason to delay further.

Ok, now I aggree with you.

> 
> 
> As for blindly setting a longer timeout for CTO / DRTO I'm not sure
> that's a great idea.  We routinely get these timeouts in tuning and we
> really don't want to make tuning even slower than it already is by
> lengthening any of these timeouts too much.
> 
> 
> Overall: if you're having weird trouble with external DMA as you
> describe, I suppose you could just have an even longer DRTO delay only
> for external DMA?
> 
> 
> NOTE also: the DesignWare Manual that I have (2.80a) actually even
> suggests that for long data timeouts (like 100ms) that a software
> timeout is appropriate.  They even suggest that in that case you could
> rely only on the software timeout.  They say:
> 
>> Note: The software timer should be used if the timeout value is in the order
>> of 100 ms. In this case, read data timeout interrupt needs to be disabled.
> 
> Presumably they are saying that because you can't really express much
> more than 100 ms in the TMOUT register?

I'm not sure, as it says the timeout value is in the *order* of 100ms.

> 
> ---
> 
> Just to summarize:
> 
> * I don't think my patch introduces any new problems like the one you
> describe.  I think if there are problems like that, they are
> pre-existing.
> 
> * I don't see a reason to use a catchall timer where we use the same
> timeout for CTO and DRTO.  We could try to save a few bytes of storage
> space and have a single "struct timer" at the expense of a little
> extra logic to try to disambiguate, but I'm not terribly interested in
> writing or reviewing that patch.

Not need to do that.

> 
> ---
> 
> As always, please let me know if I got mixed up somewhere.

Thanks for helping me understand the solution correctly.

FWIW:

Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>

> 
> -Doug
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
> 



From jeffy.chen at rock-chips.com  Tue Oct 17 01:09:22 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 16:09:22 +0800
Subject: [RFC PATCH v3 2/5] drm/rockchip: Fix error handling path in
 rockchip_dp_bind()
In-Reply-To: <20171017080925.23763-1-jeffy.chen@rock-chips.com>
References: <20171017080925.23763-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017080925.23763-3-jeffy.chen@rock-chips.com>

Add missing error handling in rockchip_dp_bind().

Fixes: 9e32e16e9e98 ("drm: rockchip: dp: add rockchip platform dp driver")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 4d3f6ad0abdd..cb8941e8bcdd 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -371,7 +371,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	ret = rockchip_dp_drm_create_encoder(dp);
 	if (ret) {
 		DRM_ERROR("failed to create drm encoder\n");
-		return ret;
+		goto err_deinit_dp;
 	}
 
 	dp->plat_data.encoder = &dp->encoder;
@@ -387,7 +387,17 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	ret = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (ret < 0)
+		goto err_unreg_psr;
+	return 0;
+
+err_unreg_psr:
+	rockchip_drm_psr_unregister(&dp->encoder);
+	rockchip_dp_drm_encoder_destroy(&dp->encoder);
+err_deinit_dp:
+	clk_disable_unprepare(dp->pclk);
+	return ret;
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 01:09:23 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 16:09:23 +0800
Subject: [RFC PATCH v3 3/5] drm/bridge/analogix: Do not use device's drvdata
In-Reply-To: <20171017080925.23763-1-jeffy.chen@rock-chips.com>
References: <20171017080925.23763-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017080925.23763-4-jeffy.chen@rock-chips.com>

From: Tomasz Figa <tfiga at chromium.org>

The driver that instantiates the bridge should own the drvdata, as all
driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
owned by its driver struct. Moreover, storing two different pointer
types in driver data depending on driver initialization status is barely
a good practice and in fact has led to many bugs in this driver.

Let's clean up this mess and change Analogix entry points to simply
accept some opaque struct pointer, adjusting their users at the same
time to avoid breaking the compilation.

Signed-off-by: Tomasz Figa <tfiga at chromium.org>
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>
---

Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++-------------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 47 +++++++++++---------
 include/drm/bridge/analogix_dp.h                   | 19 ++++----
 4 files changed, 73 insertions(+), 69 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5dd3f1cd074a..74d274b6d31d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -98,17 +98,15 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
 	return 0;
 }
 
-int analogix_dp_psr_supported(struct device *dev)
+int analogix_dp_psr_supported(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 
 	return dp->psr_support;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
 
-int analogix_dp_enable_psr(struct device *dev)
+int analogix_dp_enable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 
 	if (!dp->psr_support)
@@ -129,9 +127,8 @@ int analogix_dp_enable_psr(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
-int analogix_dp_disable_psr(struct device *dev)
+int analogix_dp_disable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 	int ret;
 
@@ -1281,8 +1278,9 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
 	return analogix_dp_transfer(dp, msg);
 }
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data)
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct analogix_dp_device *dp;
@@ -1292,14 +1290,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (!plat_data) {
 		dev_err(dev, "Invalided input plat_data\n");
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
 	if (!dp)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, dp);
+		return ERR_PTR(-ENOMEM);
 
 	dp->dev = &pdev->dev;
 	dp->dpms_mode = DRM_MODE_DPMS_OFF;
@@ -1316,7 +1312,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	ret = analogix_dp_dt_parse_pdata(dp);
 	if (ret)
-		return ret;
+		return ERR_PTR(ret);
 
 	dp->phy = devm_phy_get(dp->dev, "dp");
 	if (IS_ERR(dp->phy)) {
@@ -1330,14 +1326,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 			if (ret == -ENOSYS || ret == -ENODEV)
 				dp->phy = NULL;
 			else
-				return ret;
+				return ERR_PTR(ret);
 		}
 	}
 
 	dp->clock = devm_clk_get(&pdev->dev, "dp");
 	if (IS_ERR(dp->clock)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
-		return PTR_ERR(dp->clock);
+		return ERR_CAST(dp->clock);
 	}
 
 	clk_prepare_enable(dp->clock);
@@ -1346,7 +1342,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(dp->reg_base))
-		return PTR_ERR(dp->reg_base);
+		return ERR_CAST(dp->reg_base);
 
 	dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
 
@@ -1367,7 +1363,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 					    "hpd_gpio");
 		if (ret) {
 			dev_err(&pdev->dev, "failed to get hpd gpio\n");
-			return ret;
+			return ERR_PTR(ret);
 		}
 		dp->irq = gpio_to_irq(dp->hpd_gpio);
 		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@@ -1379,7 +1375,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (dp->irq == -ENXIO) {
 		dev_err(&pdev->dev, "failed to get irq\n");
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 	}
 
 	pm_runtime_enable(dev);
@@ -1420,7 +1416,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	phy_power_off(dp->phy);
 	pm_runtime_put(dev);
 
-	return 0;
+	return dp;
 
 err_disable_pm_runtime:
 
@@ -1428,15 +1424,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	pm_runtime_put(dev);
 	pm_runtime_disable(dev);
 
-	return ret;
+	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_bind);
 
-void analogix_dp_unbind(struct device *dev, struct device *master,
-			void *data)
+void analogix_dp_unbind(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	analogix_dp_bridge_disable(dp->bridge);
 	dp->connector.funcs->destroy(&dp->connector);
 	dp->encoder->funcs->destroy(dp->encoder);
@@ -1449,16 +1442,14 @@ void analogix_dp_unbind(struct device *dev, struct device *master,
 	}
 
 	drm_dp_aux_unregister(&dp->aux);
-	pm_runtime_disable(dev);
+	pm_runtime_disable(dp->dev);
 	clk_disable_unprepare(dp->clock);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_unbind);
 
 #ifdef CONFIG_PM
-int analogix_dp_suspend(struct device *dev)
+int analogix_dp_suspend(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	clk_disable_unprepare(dp->clock);
 
 	if (dp->plat_data->panel) {
@@ -1470,9 +1461,8 @@ int analogix_dp_suspend(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_suspend);
 
-int analogix_dp_resume(struct device *dev)
+int analogix_dp_resume(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	int ret;
 
 	ret = clk_prepare_enable(dp->clock);
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 39629e7a80b9..f7e5b2c405ed 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -41,6 +41,7 @@ struct exynos_dp_device {
 	struct device              *dev;
 
 	struct videomode           vm;
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -157,13 +158,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp->dev = dev;
 	dp->drm_dev = drm_dev;
 
@@ -190,13 +184,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
 	dp->plat_data.encoder = encoder;
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp))
+		return PTR_ERR(dp->adp);
+
+	return 0;
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
 			     void *data)
 {
-	return analogix_dp_unbind(dev, master, data);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_unbind(dp->adp);
 }
 
 static const struct component_ops exynos_dp_ops = {
@@ -257,12 +257,16 @@ static int exynos_dp_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int exynos_dp_suspend(struct device *dev)
 {
-	return analogix_dp_suspend(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
 }
 
 static int exynos_dp_resume(struct device *dev)
 {
-	return analogix_dp_resume(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
 }
 #endif
 
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index cb8941e8bcdd..e8be6cbc5f3f 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -77,6 +77,7 @@ struct rockchip_dp_device {
 
 	const struct rockchip_dp_chip_data *data;
 
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -85,7 +86,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
 	struct rockchip_dp_device *dp = to_dp(encoder);
 	unsigned long flags;
 
-	if (!analogix_dp_psr_supported(dp->dev))
+	if (!analogix_dp_psr_supported(dp->adp))
 		return;
 
 	DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
@@ -116,9 +117,9 @@ static void analogix_dp_psr_work(struct work_struct *work)
 
 	spin_lock_irqsave(&dp->psr_lock, flags);
 	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
-		analogix_dp_enable_psr(dp->dev);
+		analogix_dp_enable_psr(dp->adp);
 	else
-		analogix_dp_disable_psr(dp->dev);
+		analogix_dp_disable_psr(dp->adp);
 	spin_unlock_irqrestore(&dp->psr_lock, flags);
 }
 
@@ -350,13 +351,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp_data = of_device_get_match_data(dev);
 	if (!dp_data)
 		return -ENODEV;
@@ -387,9 +381,11 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 
-	ret = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-	if (ret < 0)
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp)) {
+		ret = PTR_ERR(dp->adp);
 		goto err_unreg_psr;
+	}
 	return 0;
 
 err_unreg_psr:
@@ -407,7 +403,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_unregister(&dp->encoder);
 
-	analogix_dp_unbind(dev, master, data);
+	analogix_dp_unbind(dp->adp);
 	clk_disable_unprepare(dp->pclk);
 }
 
@@ -435,11 +431,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 
 	dp->plat_data.panel = panel;
 
-	/*
-	 * We just use the drvdata until driver run into component
-	 * add function, and then we would set drvdata to null, so
-	 * that analogix dp driver could take charge of the drvdata.
-	 */
 	platform_set_drvdata(pdev, dp);
 
 	return component_add(dev, &rockchip_dp_component_ops);
@@ -452,10 +443,26 @@ static int rockchip_dp_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_dp_suspend(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
+}
+
+static int rockchip_dp_resume(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
+}
+#endif
+
 static const struct dev_pm_ops rockchip_dp_pm_ops = {
 #ifdef CONFIG_PM_SLEEP
-	.suspend = analogix_dp_suspend,
-	.resume_early = analogix_dp_resume,
+	.suspend = rockchip_dp_suspend,
+	.resume_early = rockchip_dp_resume,
 #endif
 };
 
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index c99d6eaef1ac..5518fc75dd6e 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -13,6 +13,8 @@
 
 #include <drm/drm_crtc.h>
 
+struct analogix_dp_device;
+
 enum analogix_dp_devtype {
 	EXYNOS_DP,
 	RK3288_DP,
@@ -38,16 +40,17 @@ struct analogix_dp_plat_data {
 			 struct drm_connector *);
 };
 
-int analogix_dp_psr_supported(struct device *dev);
-int analogix_dp_enable_psr(struct device *dev);
-int analogix_dp_disable_psr(struct device *dev);
+int analogix_dp_psr_supported(struct analogix_dp_device *dp);
+int analogix_dp_enable_psr(struct analogix_dp_device *dp);
+int analogix_dp_disable_psr(struct analogix_dp_device *dp);
 
-int analogix_dp_resume(struct device *dev);
-int analogix_dp_suspend(struct device *dev);
+int analogix_dp_resume(struct analogix_dp_device *dp);
+int analogix_dp_suspend(struct analogix_dp_device *dp);
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data);
-void analogix_dp_unbind(struct device *dev, struct device *master, void *data);
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data);
+void analogix_dp_unbind(struct analogix_dp_device *dp);
 
 int analogix_dp_start_crc(struct drm_connector *connector);
 int analogix_dp_stop_crc(struct drm_connector *connector);
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 01:09:25 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 16:09:25 +0800
Subject: [RFC PATCH v3 5/5] drm/rockchip: Add device links for master and
 components
In-Reply-To: <20171017080925.23763-1-jeffy.chen@rock-chips.com>
References: <20171017080925.23763-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017080925.23763-6-jeffy.chen@rock-chips.com>

Since we are trying to access components' resources in the master's
suspend/resume PM callbacks(e.g. panel), add device links to correct
the suspend/resume and shutdown ordering.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v3: None
Changes in v2:
Use device link to correct the suspend/resume and shutdown ordering,
instead of converting rockchip spi's suspend/resume PM callbacks to
late suspend/resume PM callbacks.

 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 76d63de5921d..af18967f699b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -337,6 +337,8 @@ static struct component_match *rockchip_drm_match_add(struct device *dev)
 
 			if (!d)
 				break;
+
+			device_link_add(dev, d, DL_FLAG_STATELESS);
 			component_match_add(dev, &match, compare_dev, d);
 		} while (true);
 	}
@@ -406,6 +408,7 @@ static int rockchip_drm_platform_of_probe(struct device *dev)
 static int rockchip_drm_platform_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct device_link *link;
 	struct component_match *match = NULL;
 	int ret;
 
@@ -414,16 +417,31 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev)
 		return ret;
 
 	match = rockchip_drm_match_add(dev);
-	if (IS_ERR(match))
-		return PTR_ERR(match);
+	if (IS_ERR(match)) {
+		ret = PTR_ERR(match);
+		goto err_cleanup_dev_links;
+	}
 
-	return component_master_add_with_match(dev, &rockchip_drm_ops, match);
+	ret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
+	if (ret < 0)
+		goto err_cleanup_dev_links;
+
+	return 0;
+err_cleanup_dev_links:
+	list_for_each_entry(link, &dev->links.consumers, s_node)
+		device_link_del(link);
+	return ret;
 }
 
 static int rockchip_drm_platform_remove(struct platform_device *pdev)
 {
+	struct device_link *link;
+
 	component_master_del(&pdev->dev, &rockchip_drm_ops);
 
+	list_for_each_entry(link, &pdev->dev.links.consumers, s_node)
+		device_link_del(link);
+
 	return 0;
 }
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 01:09:21 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 16:09:21 +0800
Subject: [RFC PATCH v3 1/5] arm64: dts: rockchip: Enable edp disaplay on kevin
In-Reply-To: <20171017080925.23763-1-jeffy.chen@rock-chips.com>
References: <20171017080925.23763-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017080925.23763-2-jeffy.chen@rock-chips.com>

Add edp panel and enable related nodes on kevin.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Mark Yao <mark.yao at rock-chips.com>

---

Changes in v3: None
Changes in v2: None

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index a3d3cea7dc4f..bc67b19f0af5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -93,6 +93,18 @@
 		pwm-delay-us = <10000>;
 	};
 
+	edp_panel: edp-panel {
+		compatible = "sharp,lq123p1jx31", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&pp3300_disp>;
+
+		ports {
+			panel_in_edp: endpoint {
+				remote-endpoint = <&edp_out_panel>;
+			};
+		};
+	};
+
 	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
 		compatible = "murata,ncp15wb473";
 		pullup-uv = <1800000>;
@@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
 	};
 };
 
+&edp {
+	status = "okay";
+
+	ports {
+		edp_out: port at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_out_panel: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&panel_in_edp>;
+			};
+		};
+	};
+};
+
 &ppvar_bigcpu_pwm {
 	regulator-min-microvolt = <798674>;
 	regulator-max-microvolt = <1302172>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..470105d651c2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
 	dr_mode = "host";
 };
 
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
 #include <arm/cros-ec-keyboard.dtsi>
 #include <arm/cros-ec-sbs.dtsi>
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 01:09:20 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 16:09:20 +0800
Subject: [RFC PATCH v3 0/5] rockchip: kevin: Enable edp display
Message-ID: <20171017080925.23763-1-jeffy.chen@rock-chips.com>


Make edp display works on chromebook kevin(at least for boot animation).

Also solve some issues i meet during the bringup.

Changes in v3:
Assign orphan pwms to dummy pwmchip instead of adding device link in the
customer driver.

Changes in v2:
Use device link to correct the suspend/resume and shutdown ordering,
instead of converting rockchip spi's suspend/resume PM callbacks to
late suspend/resume PM callbacks.

Jeffy Chen (4):
  arm64: dts: rockchip: Enable edp disaplay on kevin
  drm/rockchip: Fix error handling path in rockchip_dp_bind()
  pwm: Add dummy pwmchip for orphan pwms
  drm/rockchip: Add device links for master and components

Tomasz Figa (1):
  drm/bridge/analogix: Do not use device's drvdata

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts  | 29 ++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi       | 16 +++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 ++++++-------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++---
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 57 +++++++++------
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c        | 24 ++++++-
 drivers/pwm/core.c                                 | 84 ++++++++++++++++++++--
 include/drm/bridge/analogix_dp.h                   | 19 ++---
 8 files changed, 226 insertions(+), 79 deletions(-)

-- 
2.11.0




From klaus.goger at theobroma-systems.com  Tue Oct 17 02:16:57 2017
From: klaus.goger at theobroma-systems.com (klaus.goger at theobroma-systems.com)
Date: Tue, 17 Oct 2017 11:16:57 +0200
Subject: arm64: dts: rockchip: correct vqmmc voltage for rk3399 platforms
In-Reply-To: <1508211484-210856-1-git-send-email-shawn.lin@rock-chips.com>
References: <1508211484-210856-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <50FF2B8E-A24F-444C-80C2-D301D02C9F03@theobroma-systems.com>

Hi Shawn,

> On 17.10.2017, at 05:38, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> 
> The vcc_sd or vcc_sdio used for IO voltage for sdmmc and sdio
> interface on rk3399 platform have a limitation that it can't be
> larger than 3.0v, otherwise it has a potential risk for the chip.
> Correct all of them.

For rk3399-puma.dtsi
Tested-by: Klaus Goger <klaus.goger at theobroma-systems.com>

? 
Klaus

From jeffy.chen at rock-chips.com  Tue Oct 17 03:16:16 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 18:16:16 +0800
Subject: [RFC PATCH v4 0/8] rockchip: kevin: Enable edp display
Message-ID: <20171017101624.12506-1-jeffy.chen@rock-chips.com>


Make edp display works on chromebook kevin(at least for boot animation).

Also solve some issues i meet during the bringup.

Changes in v4:
Fix compile warning.

Changes in v3:
Assign orphan pwms to dummy pwmchip instead of adding device link in the
customer driver.

Changes in v2:
Use device link to correct the suspend/resume and shutdown ordering,
instead of converting rockchip spi's suspend/resume PM callbacks to
late suspend/resume PM callbacks.

Jeffy Chen (7):
  arm64: dts: rockchip: Enable edp disaplay on kevin
  drm/rockchip: analogix_dp: Fix error handling path
  drm/rockchip: dw-mipi-dsi: Fix error handling path
  drm/rockchip: dw_hdmi: Fix error handling path
  drm/rockchip: inno_hdmi: Fix error handling path
  pwm: Add dummy pwmchip for orphan pwms
  drm/rockchip: Add device links for master and components

Tomasz Figa (1):
  drm/bridge/analogix: Do not use device's drvdata

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts  | 29 ++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi       | 16 +++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 ++++++-------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++---
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 57 +++++++++------
 drivers/gpu/drm/rockchip/dw-mipi-dsi.c             | 17 +++--
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c        |  4 +-
 drivers/gpu/drm/rockchip/inno_hdmi.c               | 20 ++++--
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c        | 24 ++++++-
 drivers/pwm/core.c                                 | 81 ++++++++++++++++++++--
 include/drm/bridge/analogix_dp.h                   | 19 ++---
 11 files changed, 254 insertions(+), 89 deletions(-)

-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 03:16:18 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 18:16:18 +0800
Subject: [RFC PATCH v4 2/8] drm/rockchip: analogix_dp: Fix error handling path
In-Reply-To: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017101624.12506-3-jeffy.chen@rock-chips.com>

Add missing error handling in rockchip_dp_bind().

Fixes: 9e32e16e9e98 ("drm: rockchip: dp: add rockchip platform dp driver")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 4d3f6ad0abdd..4b689c0f3fc1 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -371,7 +371,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	ret = rockchip_dp_drm_create_encoder(dp);
 	if (ret) {
 		DRM_ERROR("failed to create drm encoder\n");
-		return ret;
+		goto err_disable_pclk;
 	}
 
 	dp->plat_data.encoder = &dp->encoder;
@@ -387,7 +387,17 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	ret = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (ret < 0)
+		goto err_unreg_psr;
+	return 0;
+
+err_unreg_psr:
+	rockchip_drm_psr_unregister(&dp->encoder);
+	rockchip_dp_drm_encoder_destroy(&dp->encoder);
+err_disable_pclk:
+	clk_disable_unprepare(dp->pclk);
+	return ret;
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 03:16:17 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 18:16:17 +0800
Subject: [RFC PATCH v4 1/8] arm64: dts: rockchip: Enable edp disaplay on kevin
In-Reply-To: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017101624.12506-2-jeffy.chen@rock-chips.com>

Add edp panel and enable related nodes on kevin.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Mark Yao <mark.yao at rock-chips.com>

---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index a3d3cea7dc4f..bc67b19f0af5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -93,6 +93,18 @@
 		pwm-delay-us = <10000>;
 	};
 
+	edp_panel: edp-panel {
+		compatible = "sharp,lq123p1jx31", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&pp3300_disp>;
+
+		ports {
+			panel_in_edp: endpoint {
+				remote-endpoint = <&edp_out_panel>;
+			};
+		};
+	};
+
 	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
 		compatible = "murata,ncp15wb473";
 		pullup-uv = <1800000>;
@@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
 	};
 };
 
+&edp {
+	status = "okay";
+
+	ports {
+		edp_out: port at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_out_panel: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&panel_in_edp>;
+			};
+		};
+	};
+};
+
 &ppvar_bigcpu_pwm {
 	regulator-min-microvolt = <798674>;
 	regulator-max-microvolt = <1302172>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..470105d651c2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
 	dr_mode = "host";
 };
 
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
 #include <arm/cros-ec-keyboard.dtsi>
 #include <arm/cros-ec-sbs.dtsi>
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 03:16:19 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 18:16:19 +0800
Subject: [RFC PATCH v4 3/8] drm/rockchip: dw-mipi-dsi: Fix error handling path
In-Reply-To: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017101624.12506-4-jeffy.chen@rock-chips.com>

Add missing pm_runtime_disable() in bind()'s error handling path.

Also cleanup encoder & connector in unbind().

Fixes: 80a9a059d4e4 ("drm/rockchip/dsi: add dw-mipi power domain support")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index b15755b6129c..a17ff0f6f489 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -1282,7 +1282,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	ret = dw_mipi_dsi_register(drm, dsi);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
-		goto err_pllref;
+		goto err_disable_pllref;
 	}
 
 	pm_runtime_enable(dev);
@@ -1292,23 +1292,24 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	ret = mipi_dsi_host_register(&dsi->dsi_host);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
-		goto err_cleanup;
+		goto err_disable_pm_runtime;
 	}
 
 	if (!dsi->panel) {
 		ret = -EPROBE_DEFER;
-		goto err_mipi_dsi_host;
+		goto err_unreg_mipi_dsi_host;
 	}
 
 	dev_set_drvdata(dev, dsi);
 	return 0;
 
-err_mipi_dsi_host:
+err_unreg_mipi_dsi_host:
 	mipi_dsi_host_unregister(&dsi->dsi_host);
-err_cleanup:
+err_disable_pm_runtime:
+	pm_runtime_disable(dev);
 	drm_encoder_cleanup(&dsi->encoder);
 	drm_connector_cleanup(&dsi->connector);
-err_pllref:
+err_disable_pllref:
 	clk_disable_unprepare(dsi->pllref_clk);
 	return ret;
 }
@@ -1320,6 +1321,10 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
 
 	mipi_dsi_host_unregister(&dsi->dsi_host);
 	pm_runtime_disable(dev);
+
+	dsi->connector.funcs->destroy(&dsi->connector);
+	dsi->encoder.funcs->destroy(&dsi->encoder);
+
 	clk_disable_unprepare(dsi->pllref_clk);
 }
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 03:16:22 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 18:16:22 +0800
Subject: [RFC PATCH v4 6/8] drm/bridge/analogix: Do not use device's drvdata
In-Reply-To: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017101624.12506-7-jeffy.chen@rock-chips.com>

From: Tomasz Figa <tfiga at chromium.org>

The driver that instantiates the bridge should own the drvdata, as all
driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
owned by its driver struct. Moreover, storing two different pointer
types in driver data depending on driver initialization status is barely
a good practice and in fact has led to many bugs in this driver.

Let's clean up this mess and change Analogix entry points to simply
accept some opaque struct pointer, adjusting their users at the same
time to avoid breaking the compilation.

Signed-off-by: Tomasz Figa <tfiga at chromium.org>
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++-------------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 47 +++++++++++---------
 include/drm/bridge/analogix_dp.h                   | 19 ++++----
 4 files changed, 73 insertions(+), 69 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5dd3f1cd074a..74d274b6d31d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -98,17 +98,15 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
 	return 0;
 }
 
-int analogix_dp_psr_supported(struct device *dev)
+int analogix_dp_psr_supported(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 
 	return dp->psr_support;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
 
-int analogix_dp_enable_psr(struct device *dev)
+int analogix_dp_enable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 
 	if (!dp->psr_support)
@@ -129,9 +127,8 @@ int analogix_dp_enable_psr(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
-int analogix_dp_disable_psr(struct device *dev)
+int analogix_dp_disable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 	int ret;
 
@@ -1281,8 +1278,9 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
 	return analogix_dp_transfer(dp, msg);
 }
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data)
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct analogix_dp_device *dp;
@@ -1292,14 +1290,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (!plat_data) {
 		dev_err(dev, "Invalided input plat_data\n");
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
 	if (!dp)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, dp);
+		return ERR_PTR(-ENOMEM);
 
 	dp->dev = &pdev->dev;
 	dp->dpms_mode = DRM_MODE_DPMS_OFF;
@@ -1316,7 +1312,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	ret = analogix_dp_dt_parse_pdata(dp);
 	if (ret)
-		return ret;
+		return ERR_PTR(ret);
 
 	dp->phy = devm_phy_get(dp->dev, "dp");
 	if (IS_ERR(dp->phy)) {
@@ -1330,14 +1326,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 			if (ret == -ENOSYS || ret == -ENODEV)
 				dp->phy = NULL;
 			else
-				return ret;
+				return ERR_PTR(ret);
 		}
 	}
 
 	dp->clock = devm_clk_get(&pdev->dev, "dp");
 	if (IS_ERR(dp->clock)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
-		return PTR_ERR(dp->clock);
+		return ERR_CAST(dp->clock);
 	}
 
 	clk_prepare_enable(dp->clock);
@@ -1346,7 +1342,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(dp->reg_base))
-		return PTR_ERR(dp->reg_base);
+		return ERR_CAST(dp->reg_base);
 
 	dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
 
@@ -1367,7 +1363,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 					    "hpd_gpio");
 		if (ret) {
 			dev_err(&pdev->dev, "failed to get hpd gpio\n");
-			return ret;
+			return ERR_PTR(ret);
 		}
 		dp->irq = gpio_to_irq(dp->hpd_gpio);
 		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@@ -1379,7 +1375,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (dp->irq == -ENXIO) {
 		dev_err(&pdev->dev, "failed to get irq\n");
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 	}
 
 	pm_runtime_enable(dev);
@@ -1420,7 +1416,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	phy_power_off(dp->phy);
 	pm_runtime_put(dev);
 
-	return 0;
+	return dp;
 
 err_disable_pm_runtime:
 
@@ -1428,15 +1424,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	pm_runtime_put(dev);
 	pm_runtime_disable(dev);
 
-	return ret;
+	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_bind);
 
-void analogix_dp_unbind(struct device *dev, struct device *master,
-			void *data)
+void analogix_dp_unbind(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	analogix_dp_bridge_disable(dp->bridge);
 	dp->connector.funcs->destroy(&dp->connector);
 	dp->encoder->funcs->destroy(dp->encoder);
@@ -1449,16 +1442,14 @@ void analogix_dp_unbind(struct device *dev, struct device *master,
 	}
 
 	drm_dp_aux_unregister(&dp->aux);
-	pm_runtime_disable(dev);
+	pm_runtime_disable(dp->dev);
 	clk_disable_unprepare(dp->clock);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_unbind);
 
 #ifdef CONFIG_PM
-int analogix_dp_suspend(struct device *dev)
+int analogix_dp_suspend(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	clk_disable_unprepare(dp->clock);
 
 	if (dp->plat_data->panel) {
@@ -1470,9 +1461,8 @@ int analogix_dp_suspend(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_suspend);
 
-int analogix_dp_resume(struct device *dev)
+int analogix_dp_resume(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	int ret;
 
 	ret = clk_prepare_enable(dp->clock);
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 39629e7a80b9..f7e5b2c405ed 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -41,6 +41,7 @@ struct exynos_dp_device {
 	struct device              *dev;
 
 	struct videomode           vm;
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -157,13 +158,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp->dev = dev;
 	dp->drm_dev = drm_dev;
 
@@ -190,13 +184,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
 	dp->plat_data.encoder = encoder;
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp))
+		return PTR_ERR(dp->adp);
+
+	return 0;
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
 			     void *data)
 {
-	return analogix_dp_unbind(dev, master, data);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_unbind(dp->adp);
 }
 
 static const struct component_ops exynos_dp_ops = {
@@ -257,12 +257,16 @@ static int exynos_dp_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int exynos_dp_suspend(struct device *dev)
 {
-	return analogix_dp_suspend(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
 }
 
 static int exynos_dp_resume(struct device *dev)
 {
-	return analogix_dp_resume(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
 }
 #endif
 
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 4b689c0f3fc1..b5f39bf59234 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -77,6 +77,7 @@ struct rockchip_dp_device {
 
 	const struct rockchip_dp_chip_data *data;
 
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -85,7 +86,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
 	struct rockchip_dp_device *dp = to_dp(encoder);
 	unsigned long flags;
 
-	if (!analogix_dp_psr_supported(dp->dev))
+	if (!analogix_dp_psr_supported(dp->adp))
 		return;
 
 	DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
@@ -116,9 +117,9 @@ static void analogix_dp_psr_work(struct work_struct *work)
 
 	spin_lock_irqsave(&dp->psr_lock, flags);
 	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
-		analogix_dp_enable_psr(dp->dev);
+		analogix_dp_enable_psr(dp->adp);
 	else
-		analogix_dp_disable_psr(dp->dev);
+		analogix_dp_disable_psr(dp->adp);
 	spin_unlock_irqrestore(&dp->psr_lock, flags);
 }
 
@@ -350,13 +351,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp_data = of_device_get_match_data(dev);
 	if (!dp_data)
 		return -ENODEV;
@@ -387,9 +381,11 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 
-	ret = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-	if (ret < 0)
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp)) {
+		ret = PTR_ERR(dp->adp);
 		goto err_unreg_psr;
+	}
 	return 0;
 
 err_unreg_psr:
@@ -407,7 +403,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_unregister(&dp->encoder);
 
-	analogix_dp_unbind(dev, master, data);
+	analogix_dp_unbind(dp->adp);
 	clk_disable_unprepare(dp->pclk);
 }
 
@@ -435,11 +431,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 
 	dp->plat_data.panel = panel;
 
-	/*
-	 * We just use the drvdata until driver run into component
-	 * add function, and then we would set drvdata to null, so
-	 * that analogix dp driver could take charge of the drvdata.
-	 */
 	platform_set_drvdata(pdev, dp);
 
 	return component_add(dev, &rockchip_dp_component_ops);
@@ -452,10 +443,26 @@ static int rockchip_dp_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_dp_suspend(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
+}
+
+static int rockchip_dp_resume(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
+}
+#endif
+
 static const struct dev_pm_ops rockchip_dp_pm_ops = {
 #ifdef CONFIG_PM_SLEEP
-	.suspend = analogix_dp_suspend,
-	.resume_early = analogix_dp_resume,
+	.suspend = rockchip_dp_suspend,
+	.resume_early = rockchip_dp_resume,
 #endif
 };
 
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index c99d6eaef1ac..5518fc75dd6e 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -13,6 +13,8 @@
 
 #include <drm/drm_crtc.h>
 
+struct analogix_dp_device;
+
 enum analogix_dp_devtype {
 	EXYNOS_DP,
 	RK3288_DP,
@@ -38,16 +40,17 @@ struct analogix_dp_plat_data {
 			 struct drm_connector *);
 };
 
-int analogix_dp_psr_supported(struct device *dev);
-int analogix_dp_enable_psr(struct device *dev);
-int analogix_dp_disable_psr(struct device *dev);
+int analogix_dp_psr_supported(struct analogix_dp_device *dp);
+int analogix_dp_enable_psr(struct analogix_dp_device *dp);
+int analogix_dp_disable_psr(struct analogix_dp_device *dp);
 
-int analogix_dp_resume(struct device *dev);
-int analogix_dp_suspend(struct device *dev);
+int analogix_dp_resume(struct analogix_dp_device *dp);
+int analogix_dp_suspend(struct analogix_dp_device *dp);
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data);
-void analogix_dp_unbind(struct device *dev, struct device *master, void *data);
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data);
+void analogix_dp_unbind(struct analogix_dp_device *dp);
 
 int analogix_dp_start_crc(struct drm_connector *connector);
 int analogix_dp_stop_crc(struct drm_connector *connector);
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 03:16:21 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 18:16:21 +0800
Subject: [RFC PATCH v4 5/8] drm/rockchip: inno_hdmi: Fix error handling path
In-Reply-To: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017101624.12506-6-jeffy.chen@rock-chips.com>

Add missing error handling in bind().

Fixes: 412d4ae6b7a5 ("drm/rockchip: hdmi: add Innosilicon HDMI support")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/rockchip/inno_hdmi.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
index ee584d87111f..9c258b05dfa5 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -851,8 +851,10 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
+	if (irq < 0) {
+		ret = irq;
+		goto err_disable_clk;
+	}
 
 	inno_hdmi_reset(hdmi);
 
@@ -860,7 +862,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 	if (IS_ERR(hdmi->ddc)) {
 		ret = PTR_ERR(hdmi->ddc);
 		hdmi->ddc = NULL;
-		return ret;
+		goto err_disable_clk;
 	}
 
 	/*
@@ -874,7 +876,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 
 	ret = inno_hdmi_register(drm, hdmi);
 	if (ret)
-		return ret;
+		goto err_put_adapter;
 
 	dev_set_drvdata(dev, hdmi);
 
@@ -884,7 +886,17 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 	ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq,
 					inno_hdmi_irq, IRQF_SHARED,
 					dev_name(dev), hdmi);
+	if (ret < 0)
+		goto err_cleanup_hdmi;
 
+	return 0;
+err_cleanup_hdmi:
+	drm_connector_cleanup(&hdmi->connector);
+	drm_encoder_cleanup(&hdmi->encoder);
+err_put_adapter:
+	i2c_put_adapter(hdmi->ddc);
+err_disable_clk:
+	clk_disable_unprepare(hdmi->pclk);
 	return ret;
 }
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 03:16:24 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 18:16:24 +0800
Subject: [RFC PATCH v4 8/8] drm/rockchip: Add device links for master and
 components
In-Reply-To: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017101624.12506-9-jeffy.chen@rock-chips.com>

Since we are trying to access components' resources in the master's
suspend/resume PM callbacks(e.g. panel), add device links to correct
the suspend/resume and shutdown ordering.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2:
Use device link to correct the suspend/resume and shutdown ordering,
instead of converting rockchip spi's suspend/resume PM callbacks to
late suspend/resume PM callbacks.

 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 76d63de5921d..af18967f699b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -337,6 +337,8 @@ static struct component_match *rockchip_drm_match_add(struct device *dev)
 
 			if (!d)
 				break;
+
+			device_link_add(dev, d, DL_FLAG_STATELESS);
 			component_match_add(dev, &match, compare_dev, d);
 		} while (true);
 	}
@@ -406,6 +408,7 @@ static int rockchip_drm_platform_of_probe(struct device *dev)
 static int rockchip_drm_platform_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct device_link *link;
 	struct component_match *match = NULL;
 	int ret;
 
@@ -414,16 +417,31 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev)
 		return ret;
 
 	match = rockchip_drm_match_add(dev);
-	if (IS_ERR(match))
-		return PTR_ERR(match);
+	if (IS_ERR(match)) {
+		ret = PTR_ERR(match);
+		goto err_cleanup_dev_links;
+	}
 
-	return component_master_add_with_match(dev, &rockchip_drm_ops, match);
+	ret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
+	if (ret < 0)
+		goto err_cleanup_dev_links;
+
+	return 0;
+err_cleanup_dev_links:
+	list_for_each_entry(link, &dev->links.consumers, s_node)
+		device_link_del(link);
+	return ret;
 }
 
 static int rockchip_drm_platform_remove(struct platform_device *pdev)
 {
+	struct device_link *link;
+
 	component_master_del(&pdev->dev, &rockchip_drm_ops);
 
+	list_for_each_entry(link, &pdev->dev.links.consumers, s_node)
+		device_link_del(link);
+
 	return 0;
 }
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Tue Oct 17 03:16:20 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Tue, 17 Oct 2017 18:16:20 +0800
Subject: [RFC PATCH v4 4/8] drm/rockchip: dw_hdmi: Fix error handling path
In-Reply-To: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
Message-ID: <20171017101624.12506-5-jeffy.chen@rock-chips.com>

Add missing clk_disable_unprepare() in bind()'s error handling path.

Fixes: 12b9f204e804 ("drm: bridge/dw_hdmi: add rockchip rk3288 support")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 1eb02a82fd91..582283da7861 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -383,8 +383,10 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
 	 * which would have called the encoder cleanup.  Do it manually.
 	 */
-	if (ret)
+	if (ret) {
 		drm_encoder_cleanup(encoder);
+		clk_disable_unprepare(hdmi->vpll_clk);
+	}
 
 	return ret;
 }
-- 
2.11.0




From seanpaul at chromium.org  Tue Oct 17 08:43:17 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Tue, 17 Oct 2017 11:43:17 -0400
Subject: [PATCH v3 3/4] drm/rockchip: Add support for Rockchip Soc RGB
 output interface
In-Reply-To: <1507536416-110807-1-git-send-email-hjc@rock-chips.com>
References: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>
 <1507536416-110807-1-git-send-email-hjc@rock-chips.com>
Message-ID: <20171017154317.zphpwbzlv2pu7elm@art_vandelay>

On Mon, Oct 09, 2017 at 04:06:53PM +0800, Sandy Huang wrote:
> Some Rockchip CRTCs, like rv1108, can directly output parallel and
> serial RGB data to panel or conversion chip, so we add this driver to
> probe encoder and connector.
> 
> Signed-off-by: Sandy Huang <hjc at rock-chips.com>
> ---
> Changes in v3:
>   update for rgb-mode move to panel node.
> Changes in v2:
>   1. add error log when probe failed;
>   2. update name_to_output_mode() according to sean's suggest;
>   3. Fix uninitialized use of ret.
> 
>  drivers/gpu/drm/rockchip/Kconfig            |   9 +
>  drivers/gpu/drm/rockchip/Makefile           |   1 +
>  drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   2 +
>  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   1 +
>  drivers/gpu/drm/rockchip/rockchip_rgb.c     | 343 ++++++++++++++++++++++++++++
>  5 files changed, 356 insertions(+)
>  create mode 100644 drivers/gpu/drm/rockchip/rockchip_rgb.c
> 
> diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
> index 0c31f0a..85c7cc5 100644
> --- a/drivers/gpu/drm/rockchip/Kconfig
> +++ b/drivers/gpu/drm/rockchip/Kconfig
> @@ -8,6 +8,7 @@ config DRM_ROCKCHIP
>  	select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
>  	select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
>  	select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
> +	select DRM_RGB if ROCKCHIP_RGB
>  	select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
>  	help
>  	  Choose this option if you have a Rockchip soc chipset.
> @@ -65,4 +66,12 @@ config ROCKCHIP_LVDS
>  	  Rockchip rk3288 SoC has LVDS TX Controller can be used, and it
>  	  support LVDS, rgb, dual LVDS output mode. say Y to enable its
>  	  driver.
> +
> +config ROCKCHIP_RGB
> +	bool "Rockchip RGB support"
> +	help
> +	  Choose this option to enable support for Rockchip RGB output.
> +	  Some Rockchip CRTCs, like rv1108, can directly output parallel
> +	  and serial RGB format to panel or connect to a conversion chip.
> +	  say Y to enable its driver.
>  endif
> diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
> index a881d2c..f32a17f 100644
> --- a/drivers/gpu/drm/rockchip/Makefile
> +++ b/drivers/gpu/drm/rockchip/Makefile
> @@ -13,5 +13,6 @@ rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
>  rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
>  rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
>  rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
> +rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
>  
>  obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> index 76d63de..265597c 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> @@ -459,6 +459,8 @@ static int __init rockchip_drm_init(void)
>  				CONFIG_ROCKCHIP_LVDS);
>  	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
>  				CONFIG_ROCKCHIP_ANALOGIX_DP);
> +	ADD_ROCKCHIP_SUB_DRIVER(rockchip_rgb_driver,
> +				CONFIG_ROCKCHIP_RGB);
>  	ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
>  	ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
>  				CONFIG_ROCKCHIP_DW_HDMI);
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> index 498dfbc..6b0ec7e 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> @@ -70,5 +70,6 @@ extern struct platform_driver dw_mipi_dsi_driver;
>  extern struct platform_driver inno_hdmi_driver;
>  extern struct platform_driver rockchip_dp_driver;
>  extern struct platform_driver rockchip_lvds_driver;
> +extern struct platform_driver rockchip_rgb_driver;
>  extern struct platform_driver vop_platform_driver;
>  #endif /* _ROCKCHIP_DRM_DRV_H_ */
> diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
> new file mode 100644
> index 0000000..6227ed7
> --- /dev/null
> +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
> @@ -0,0 +1,343 @@
> +/*
> + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
> + * Author:
> + *      Sandy Huang <hjc at rock-chips.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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 <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_dp_helper.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_of.h>
> +
> +#include <linux/component.h>
> +#include <linux/of_graph.h>
> +
> +#include "rockchip_drm_drv.h"
> +#include "rockchip_drm_vop.h"
> +
> +#define connector_to_rgb(c) container_of(c, struct rockchip_rgb, connector)
> +#define encoder_to_rgb(c) container_of(c, struct rockchip_rgb, encoder)
> +
> +struct rockchip_rgb {
> +	struct device *dev;
> +	struct drm_device *drm_dev;
> +	struct drm_panel *panel;
> +	struct drm_bridge *bridge;
> +	struct drm_connector connector;
> +	struct drm_encoder encoder;
> +	struct dev_pin_info *pins;
> +	int output_mode;
> +};
> +
> +static inline int name_to_output_mode(const char *s)
> +{
> +	static const struct {
> +		const char *name;
> +		int format;
> +	} formats[] = {
> +		{ "p888", ROCKCHIP_OUT_MODE_P888 },
> +		{ "p666", ROCKCHIP_OUT_MODE_P666 },
> +		{ "p565", ROCKCHIP_OUT_MODE_P565 },
> +		{ "s888", ROCKCHIP_OUT_MODE_S888 },
> +		{ "s888_dummy", ROCKCHIP_OUT_MODE_S888_DUMMY }
> +	};
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(formats); i++)
> +		if (!strncmp(s, formats[i].name, strlen(formats[i].name)))
> +			return formats[i].format;
> +
> +	return -EINVAL;
> +}
> +
> +static const struct drm_connector_funcs rockchip_rgb_connector_funcs = {
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = drm_connector_cleanup,
> +	.reset = drm_atomic_helper_connector_reset,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static int rockchip_rgb_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct rockchip_rgb *rgb = connector_to_rgb(connector);
> +	struct drm_panel *panel = rgb->panel;
> +
> +	return drm_panel_get_modes(panel);
> +}
> +
> +static const
> +struct drm_connector_helper_funcs rockchip_rgb_connector_helper_funcs = {
> +	.get_modes = rockchip_rgb_connector_get_modes,
> +};
> +
> +static void rockchip_rgb_encoder_enable(struct drm_encoder *encoder)
> +{
> +	struct rockchip_rgb *rgb = encoder_to_rgb(encoder);
> +
> +	drm_panel_prepare(rgb->panel);
> +	/* iomux to LCD data/sync mode */
> +	if (rgb->pins && !IS_ERR(rgb->pins->default_state))
> +		pinctrl_select_state(rgb->pins->p, rgb->pins->default_state);
> +
> +	drm_panel_enable(rgb->panel);
> +}
> +
> +static void rockchip_rgb_encoder_disable(struct drm_encoder *encoder)
> +{
> +	struct rockchip_rgb *rgb = encoder_to_rgb(encoder);
> +
> +	drm_panel_disable(rgb->panel);
> +	drm_panel_unprepare(rgb->panel);
> +}
> +
> +static int
> +rockchip_rgb_encoder_atomic_check(struct drm_encoder *encoder,
> +				   struct drm_crtc_state *crtc_state,
> +				   struct drm_connector_state *conn_state)
> +{
> +	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
> +	struct rockchip_rgb *rgb = encoder_to_rgb(encoder);
> +
> +	s->output_mode = rgb->output_mode;
> +	s->output_type = DRM_MODE_CONNECTOR_LVDS;
> +
> +	return 0;
> +}
> +
> +static const
> +struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = {
> +	.enable = rockchip_rgb_encoder_enable,
> +	.disable = rockchip_rgb_encoder_disable,
> +	.atomic_check = rockchip_rgb_encoder_atomic_check,
> +};
> +
> +static const struct drm_encoder_funcs rockchip_rgb_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +static const struct of_device_id rockchip_rgb_dt_ids[] = {
> +	{
> +		.compatible = "rockchip,rv1108-rgb",
> +	},
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(of, rockchip_rgb_dt_ids);
> +
> +static int rockchip_rgb_bind(struct device *dev, struct device *master,
> +			     void *data)
> +{
> +	struct rockchip_rgb *rgb = dev_get_drvdata(dev);
> +	struct drm_device *drm_dev = data;
> +	struct drm_encoder *encoder;
> +	struct drm_connector *connector;
> +	struct device_node *remote = NULL;
> +	struct device_node  *port, *endpoint;
> +	u32 endpoint_id;
> +	const char *name;
> +	int ret = 0, child_count = 0;
> +
> +	rgb->drm_dev = drm_dev;
> +	port = of_graph_get_port_by_id(dev->of_node, 1);
> +	if (!port) {
> +		DRM_DEV_ERROR(dev,
> +			      "can't found port point, please init rgb panel port!\n");
> +		return -EINVAL;
> +	}
> +	for_each_child_of_node(port, endpoint) {
> +		child_count++;
> +		if (of_property_read_u32(endpoint, "reg", &endpoint_id))
> +			endpoint_id = 0;
> +		ret = drm_of_find_panel_or_bridge(dev->of_node, 1, endpoint_id,
> +						  &rgb->panel, &rgb->bridge);
> +		if (!ret)
> +			break;
> +	}
> +	if (!child_count) {
> +		DRM_DEV_ERROR(dev, "rgb port does not have any children\n");
> +		ret = -EINVAL;
> +		goto err_put_port;
> +	} else if (ret) {
> +		DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n");
> +		ret = -EPROBE_DEFER;
> +		goto err_put_port;
> +	}
> +	if (rgb->panel)
> +		remote = rgb->panel->dev->of_node;
> +	else
> +		remote = rgb->bridge->of_node;
> +	if (of_property_read_string(remote, "rgb-mode", &name))
> +		/* default set it as output mode P888 */
> +		rgb->output_mode = ROCKCHIP_OUT_MODE_P888;
> +	else
> +		rgb->output_mode = name_to_output_mode(name);
> +	if (rgb->output_mode < 0) {
> +		DRM_DEV_ERROR(dev, "invalid rockchip,rgb-mode [%s]\n", name);
> +		ret = rgb->output_mode;
> +		goto err_put_remote;
> +	}
> +
> +	encoder = &rgb->encoder;
> +	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
> +							     dev->of_node);
> +
> +	ret = drm_encoder_init(drm_dev, encoder, &rockchip_rgb_encoder_funcs,
> +			       DRM_MODE_ENCODER_NONE, NULL);
> +	if (ret < 0) {
> +		DRM_DEV_ERROR(drm_dev->dev,
> +			      "failed to initialize encoder: %d\n", ret);
> +		goto err_put_remote;
> +	}
> +
> +	drm_encoder_helper_add(encoder, &rockchip_rgb_encoder_helper_funcs);
> +
> +	if (rgb->panel) {
> +		connector = &rgb->connector;
> +		connector->dpms = DRM_MODE_DPMS_OFF;
> +		ret = drm_connector_init(drm_dev, connector,
> +					 &rockchip_rgb_connector_funcs,
> +					 DRM_MODE_CONNECTOR_Unknown);
> +		if (ret < 0) {
> +			DRM_DEV_ERROR(drm_dev->dev,
> +				      "failed to initialize connector: %d\n",
> +				      ret);
> +			goto err_free_encoder;
> +		}
> +
> +		drm_connector_helper_add(connector,
> +					 &rockchip_rgb_connector_helper_funcs);
> +
> +		ret = drm_mode_connector_attach_encoder(connector, encoder);
> +		if (ret < 0) {
> +			DRM_DEV_ERROR(drm_dev->dev,
> +				      "failed to attach encoder: %d\n", ret);
> +			goto err_free_connector;
> +		}
> +
> +		ret = drm_panel_attach(rgb->panel, connector);
> +		if (ret < 0) {
> +			DRM_DEV_ERROR(drm_dev->dev,
> +				      "failed to attach panel: %d\n", ret);
> +			goto err_free_connector;
> +		}
> +	} else {
> +		rgb->bridge->encoder = encoder;
> +		ret = drm_bridge_attach(encoder, rgb->bridge, NULL);
> +		if (ret) {
> +			DRM_DEV_ERROR(drm_dev->dev,
> +				      "failed to attach bridge: %d\n", ret);
> +			goto err_free_encoder;
> +		}
> +		encoder->bridge = rgb->bridge;
> +	}
> +
> +	of_node_put(remote);
> +	of_node_put(port);
> +
> +	return 0;
> +
> +err_free_connector:
> +	drm_connector_cleanup(connector);
> +err_free_encoder:
> +	drm_encoder_cleanup(encoder);
> +err_put_remote:
> +	of_node_put(remote);
> +err_put_port:
> +	of_node_put(port);
> +
> +	return ret;
> +}
> +
> +static void rockchip_rgb_unbind(struct device *dev, struct device *master,
> +				void *data)
> +{
> +	struct rockchip_rgb *rgb = dev_get_drvdata(dev);
> +
> +	rockchip_rgb_encoder_disable(&rgb->encoder);
> +	if (rgb->panel)
> +		drm_panel_detach(rgb->panel);
> +	drm_connector_cleanup(&rgb->connector);

Connector cleanup should also be gated on rgb->panel

Once that's fixed:
Reviewed-by: Sean Paul <seanpaul at chromium.org>

Sean

> +	drm_encoder_cleanup(&rgb->encoder);
> +}
> +
> +static const struct component_ops rockchip_rgb_component_ops = {
> +	.bind = rockchip_rgb_bind,
> +	.unbind = rockchip_rgb_unbind,
> +};
> +
> +static int rockchip_rgb_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct rockchip_rgb *rgb;
> +	const struct of_device_id *match;
> +	int ret;
> +
> +	if (!dev->of_node) {
> +		DRM_DEV_ERROR(dev, "dev->of_node is null\n");
> +		return -ENODEV;
> +	}
> +
> +	rgb = devm_kzalloc(&pdev->dev, sizeof(*rgb), GFP_KERNEL);
> +	if (!rgb)
> +		return -ENOMEM;
> +
> +	rgb->dev = dev;
> +	match = of_match_node(rockchip_rgb_dt_ids, dev->of_node);
> +	if (!match) {
> +		DRM_DEV_ERROR(dev, "match node failed\n");
> +		return -ENODEV;
> +	}
> +
> +	rgb->pins = devm_kzalloc(rgb->dev, sizeof(*rgb->pins), GFP_KERNEL);
> +	if (!rgb->pins)
> +		return -ENOMEM;
> +	rgb->pins->p = devm_pinctrl_get(rgb->dev);
> +	if (IS_ERR(rgb->pins->p)) {
> +		DRM_DEV_ERROR(dev, "no pinctrl handle\n");
> +		devm_kfree(rgb->dev, rgb->pins);
> +		rgb->pins = NULL;
> +	} else {
> +		rgb->pins->default_state =
> +			pinctrl_lookup_state(rgb->pins->p, "lcdc");
> +		if (IS_ERR(rgb->pins->default_state)) {
> +			DRM_DEV_ERROR(dev, "no default pinctrl state\n");
> +			devm_kfree(rgb->dev, rgb->pins);
> +			rgb->pins = NULL;
> +		}
> +	}
> +
> +	dev_set_drvdata(dev, rgb);
> +	ret = component_add(&pdev->dev, &rockchip_rgb_component_ops);
> +	if (ret < 0)
> +		DRM_DEV_ERROR(dev, "failed to add component\n");
> +
> +	return ret;
> +}
> +
> +static int rockchip_rgb_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &rockchip_rgb_component_ops);
> +
> +	return 0;
> +}
> +
> +struct platform_driver rockchip_rgb_driver = {
> +	.probe = rockchip_rgb_probe,
> +	.remove = rockchip_rgb_remove,
> +	.driver = {
> +		   .name = "rockchip-rgb",
> +		   .of_match_table = of_match_ptr(rockchip_rgb_dt_ids),
> +	},
> +};
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Tue Oct 17 08:43:31 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Tue, 17 Oct 2017 11:43:31 -0400
Subject: [PATCH v3 4/4] drm/rockchip: vop: Add more RGB output interface
 type
In-Reply-To: <1507536424-110871-1-git-send-email-hjc@rock-chips.com>
References: <1507536396-106827-1-git-send-email-hjc@rock-chips.com>
 <1507536424-110871-1-git-send-email-hjc@rock-chips.com>
Message-ID: <20171017154331.ti2pnl4gmclbrfmu@art_vandelay>

On Mon, Oct 09, 2017 at 04:07:04PM +0800, Sandy Huang wrote:
> This patch add serial RGB output interface for rockchip vop, the
> more info about serial RGB output interface described at the
> following file:
> 
> Documentation/devicetree/bindings/display/panel/panel-rgb.txt
> 
> Signed-off-by: Sandy Huang <hjc at rock-chips.com>
Reviewed-by: Sean Paul <seanpaul at chromium.org>
> ---
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> index 56bbd2e..59a01c3 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> @@ -209,6 +209,8 @@ struct vop_data {
>  #define ROCKCHIP_OUT_MODE_P888	0
>  #define ROCKCHIP_OUT_MODE_P666	1
>  #define ROCKCHIP_OUT_MODE_P565	2
> +#define ROCKCHIP_OUT_MODE_S888	8
> +#define ROCKCHIP_OUT_MODE_S888_DUMMY	12
>  /* for use special outface */
>  #define ROCKCHIP_OUT_MODE_AAAA	15
>  
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From dianders at chromium.org  Tue Oct 17 09:40:03 2017
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 17 Oct 2017 09:40:03 -0700
Subject: [PATCH v2 3/5] mmc: dw_mmc: Add locking to the CTO timer
In-Reply-To: <d6acce96-b292-ee4e-8f9b-1d524c14e0fc@rock-chips.com>
References: <20171012201118.23570-1-dianders@chromium.org>
 <20171012201118.23570-4-dianders@chromium.org>
 <41ae1571-4723-2700-1f03-7215e874c42e@rock-chips.com>
 <CAD=FV=UMuJBKV2-pNo4yiyfxXxYJo_tX6RkxCCzm_UFg9XyjyQ@mail.gmail.com>
 <d6acce96-b292-ee4e-8f9b-1d524c14e0fc@rock-chips.com>
Message-ID: <CAD=FV=W7u0_kr9HXHpKmw=Hgco2P=u3jeSb8v0OoVvD+2kJorw@mail.gmail.com>

Hi,

On Mon, Oct 16, 2017 at 5:54 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Hi Doug
>
>
> On 2017/10/13 12:20, Doug Anderson wrote:
>>
>> Shawn,
>>
>> On Thu, Oct 12, 2017 at 6:32 PM, Shawn Lin <shawn.lin at rock-chips.com>
>> wrote:
>>>
>>>
>>> On 2017/10/13 4:11, Douglas Anderson wrote:
>>>>
>>>>
>>>> This attempts to instill a bit of paranoia to the code dealing with
>>>> the CTO timer.  It's believed that this will make the CTO timer more
>>>> robust in the case that we're having very long interrupt latencies.
>>>>
>>>
>>> Ack. It could help fix some problems observed.
>>>
>>>
>>>> Note that I originally thought that perhaps this patch was being
>>>> overly paranoid and wasn't really needed, but then while I was running
>>>> mmc_test on an rk3399 board I saw one instance of the message:
>>>>     dwmmc_rockchip fe320000.dwmmc: Unexpected interrupt latency
>>>>
>>>> I had debug prints in the CTO timer code and I found that it was
>>>> running CMD 13 at the time.
>>>>
>>>> ...so even though this patch seems like it might be overly paranoid,
>>>> maybe it really isn't?
>>>>
>>>> Presumably the bad interrupt latency experienced was due to the fact
>>>> that I had serial console enabled as serial console is typically where
>>>> I place blame when I see absurdly large interrupt latencies.  In this
>>>> particular case there was an (unrelated) printout to the serial
>>>> console just before I saw the "Unexpected interrupt latency" printout.
>>>>
>>>> ...and actually, I managed to even reproduce the problems by running
>>>> "iw mlan0 scan > /dev/null" while mmc_test was running.  That not only
>>>> does a bunch of PCIe traffic but it also (on my system) outputs some
>>>> SELinux log spam.
>>>>>
>>>>> Fixes: 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command
>>>
>>>
>>> transfer over scheme")
>>>>
>>>>
>>>> Tested-by: Emil Renner Berthing <kernel at esmil.dk>
>>>> Signed-off-by: Douglas Anderson <dianders at chromium.org>
>>>> ---
>>>>
>>>> Changes in v2:
>>>> - Removed extra "int i"
>>>>
>>>>    drivers/mmc/host/dw_mmc.c | 91
>>>> +++++++++++++++++++++++++++++++++++++++++------
>>>>    1 file changed, 81 insertions(+), 10 deletions(-)
>>>>
>>>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>>>> index 16516c528a88..50148991f30e 100644
>>>> --- a/drivers/mmc/host/dw_mmc.c
>>>> +++ b/drivers/mmc/host/dw_mmc.c
>>>> @@ -403,6 +403,7 @@ static inline void dw_mci_set_cto(struct dw_mci
>>>> *host)
>>>>          unsigned int cto_clks;
>>>>          unsigned int cto_div;
>>>>          unsigned int cto_ms;
>>>> +       unsigned long irqflags;
>>>>          cto_clks = mci_readl(host, TMOUT) & 0xff;
>>>>          cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
>>>> @@ -413,8 +414,24 @@ static inline void dw_mci_set_cto(struct dw_mci
>>>> *host)
>>>>          /* add a bit spare time */
>>>>          cto_ms += 10;
>>>>    -     mod_timer(&host->cto_timer,
>>>> -                 jiffies + msecs_to_jiffies(cto_ms) + 1);
>>>> +       /*
>>>> +        * The durations we're working with are fairly short so we have
>>>> to
>>>> be
>>>> +        * extra careful about synchronization here.  Specifically in
>>>> hardware a
>>>> +        * command timeout is _at most_ 5.1 ms, so that means we expect
>>>> an
>>>> +        * interrupt (either command done or timeout) to come rather
>>>> quickly
>>>> +        * after the mci_writel.  ...but just in case we have a long
>>>> interrupt
>>>> +        * latency let's add a bit of paranoia.
>>>> +        *
>>>> +        * In general we'll assume that at least an interrupt will be
>>>> asserted
>>>> +        * in hardware by the time the cto_timer runs.  ...and if it
>>>> hasn't
>>>> +        * been asserted in hardware by that time then we'll assume
>>>> it'll
>>>> never
>>>> +        * come.
>>>> +        */
>>>> +       spin_lock_irqsave(&host->irq_lock, irqflags);
>>>> +       if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events))
>>>> +               mod_timer(&host->cto_timer,
>>>> +                       jiffies + msecs_to_jiffies(cto_ms) + 1);
>>>> +       spin_unlock_irqrestore(&host->irq_lock, irqflags);
>>>
>>>
>>>
>>> IIUC, this change is beacuse you move
>>> mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START) before
>>> setting up the timer, so there is a timing gap that the cmd_done
>>> already comes and handled by dw_mci_interrupt->dw_mci_cmd_interrupt.
>>> At this point, we don't need the cto timer at all.
>>
>>
>> As per below, if I don't move the mci_writel() before setting up the
>> timer then there's still a race.  ...and actually that race was harder
>> for me to write code for, but I invite you to try to see if it's
>> somehow cleaner.
>>
>>
>>>>    }
>>>>      static void dw_mci_start_command(struct dw_mci *host,
>>>> @@ -429,11 +446,11 @@ static void dw_mci_start_command(struct dw_mci
>>>> *host,
>>>>          wmb(); /* drain writebuffer */
>>>>          dw_mci_wait_while_busy(host, cmd_flags);
>>>>    +     mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
>>>> +
>>>>          /* response expected command only */
>>>>          if (cmd_flags & SDMMC_CMD_RESP_EXP)
>>>>                  dw_mci_set_cto(host);
>>>> -
>>>> -       mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
>>>
>>>
>>>
>>>
>>> But why? If we still keep the original logic, it's always correct
>>> that cmd_done comes after setting up the cto timer. So could you
>>> eleborate a bit more to help me understand the real intention here?
>>
>>
>> No matter which order you put things, there's a race one way or the
>> other.  You need a lock.
>>
>> Let's think about the old code you wrote.  You did this:
>> 1. Start the CTO timer.
>> 2. Start the command.
>>
>> Now if you (somehow) take 20 ms to handle the interrupt, then this
>> happens:
>>
>> 1. Start the CTO timer.
>> 2. Start the command.
>> 3. Interrupt is pending, but interrupt handler doesn't run yet.
>> 4. CTO timer fires and enqueues CTO timeout.
>> 5. Interrupt finally fires.
>
>
> OK, got it.
>
>
>>
>>
>> Now normally things are pretty bad if you've got an interrupt latency
>> of 20 ms.  ...and, in fact, I originally wrote up a commit that simply
>> explained why the race didn't matter and was thinking of posting that
>> instead of this one.  I wrote up:
>>
>>       * Start a timer to detect missing cmd timeout if we expect a
>> response.
>>       *
>>       * Note that we need to be a little careful about race conditions
>> here
>>       * since our timer will be racing with the actual hardware interrupt
>>       * and things would get confused if both of them happened.
>>       *
>>       * We end up avoiding races here mostly because of our 10 ms "spare
>>       * time" buffer above.  That's probably reliable enough because:
>>       * - There's "guaranteed" "very little" time between setting the
>> timer
>>       *   and starting the command.  We're holding a spinlock (host->lock)
>>       *   in all calls to this function so we won't get preempted.
>> Possibly
>>       *   we could get interrupts still, but that shouldn't add up to
>>       *   anything like the 10 ms spare time.
>>       * - We expect that when the actual interrupt fires that our
>> interrupt
>>       *   routine should get called "relatively quickly" (compared to the
>>       *   10 ms buffer) and will be able to cancel this timer.
>>
>> ...but then I ran a whole bunch of tests and I found that, as far as I
>> could tell, we actually _were_ getting a super long interrupt latency.
>> Specifically I saw the printout "Unexpected interrupt latency" in my
>> patch.  In order to see that printout in my patch (which even starts
>> the command _before_ the CTO timer), the only explanation is bad
>> interrupt latency, right?  Also: based on my past experience I believe
>> it is possible to get upwards of 100 ms interrupt latency if you've
>> got serial console enabled.  printk, especially printk from an
>> interrupt context, can do some funny things.
>>
>
> Right! It makes sense to me now.
>
>>
>> ...but this stuff is always hard to get right, so if I messed up the
>> above please let me know!  I tried to think of all of the cases so it
>> would work no matter if delays happened in any random place but
>> concurrency is hard.
>
>
> Yes, it looks hard to get concurrency right. I have a comment for your
> DRTO case(patch 5). Let's do some brainstorm there.

Since your comments in this patch are positive and you've now added
your Reviewed-by to patch #5, I'm going to assume that you'd also like
your Reviewed-by on this patch?


Jaehoon: I think I have Shawn's review on all this series.  It would
be great if you could review them yourself and/or pick them up in your
tree.  Since they fix a regression on 4.14 we really don't want to
delay too long.  If you're busy, please yell and we can figure out a
way to get these in (either through Ulf directly or we should find
someone else to make a git tree and send a pull request).

Thanks!

-Doug


From heiko at sntech.de  Tue Oct 17 10:40:05 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 19:40:05 +0200
Subject: [GIT PULL 1/2] Rockchip dts32 updates for 4.15 part1
Message-ID: <5843673.lOC77YXMZV@phil>

Hi Arnd, Kevin, Olof,

please find below the first round of Rockchip dts32 updates targetted
for 4.15.

Thanks
Heiko

The following changes since commit 2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e:

  Linux 4.14-rc1 (2017-09-16 15:47:51 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.15-rockchip-dts32-1

for you to fetch changes up to 345b40f1e50759d09144c4aa044d07823d77c283:

  ARM: dts: rockchip: Enable thermal on rk3288-vyasa board (2017-10-14 21:10:31 +0200)

----------------------------------------------------------------
One new board the Vyasa from Amarula Solutions using a rk3288
and core lvds node for the newly added driver+binding.
Also bindings + nodes for the Mali-Utgard GPUs found on some
Rockchip socs like rk3036 and rk3188. With the recently revived
Lima project they can even render a red triangle to a png file.

----------------------------------------------------------------
Heiko Stuebner (9):
      dt-bindings: gpu: mali-utgard: Add Rockchip Utgard Malis
      dt-bindings: gpu: mali-utgard: add optional supply regulator
      dt-bindings: gpu: mali-utgard: add optional power-domain reference
      ARM: dts: rockchip: add rk3036 gpu node
      ARM: dts: rockchip: enable the gpu on rk3036-kylin boards
      ARM: dts: rockchip: add rk322x gpu node
      ARM: dts: rockchip: add gpu nodes on rk3066/rk3188
      ARM: dts: rockchip: enable gpu on rk3188-radxarock
      ARM: dts: rockchip: fix mali400 ppmmu interrupt names

Jagan Teki (4):
      dt-bindings: Add vendor prefix for Amarula Solutions
      ARM: dts: rockchip: Add rk3288 vyasa board
      ARM: dts: rockchip: enable vops and hdmi output on rk3288-vyasa
      ARM: dts: rockchip: Enable mali GPU node on rk3288-vyasa

Michael Trimarchi (1):
      ARM: dts: rockchip: Enable thermal on rk3288-vyasa board

Sandy Huang (1):
      ARM: dts: rockchip: add LVDS node for rk3288

 Documentation/devicetree/bindings/arm/rockchip.txt |   4 +
 .../devicetree/bindings/gpu/arm,mali-utgard.txt    |  16 +
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 arch/arm/boot/dts/Makefile                         |   3 +-
 arch/arm/boot/dts/rk3036-kylin.dts                 |   5 +
 arch/arm/boot/dts/rk3036.dtsi                      |  19 ++
 arch/arm/boot/dts/rk3066a.dtsi                     |  24 ++
 arch/arm/boot/dts/rk3188-radxarock.dts             |   4 +
 arch/arm/boot/dts/rk3188.dtsi                      |  24 ++
 arch/arm/boot/dts/rk322x.dtsi                      |  21 ++
 arch/arm/boot/dts/rk3288-vyasa.dts                 | 347 +++++++++++++++++++++
 arch/arm/boot/dts/rk3288.dtsi                      |  52 +++
 arch/arm/boot/dts/rk3xxx.dtsi                      |  11 +
 13 files changed, 530 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/rk3288-vyasa.dts



From heiko at sntech.de  Tue Oct 17 10:40:45 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 19:40:45 +0200
Subject: [GIT PULL 2/2] Rockchip dts64 updates for 4.15 part1
In-Reply-To: <5843673.lOC77YXMZV@phil>
References: <5843673.lOC77YXMZV@phil>
Message-ID: <5888991.PG7Gbs0CIl@phil>

The following changes since commit 2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e:

  Linux 4.14-rc1 (2017-09-16 15:47:51 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.15-rockchip-dts64-1

for you to fetch changes up to d85438991874205467f9739d5f3ee771245b4754:

  arm64: dts: rockchip: enable cec pin for rk3399 firefly (2017-10-15 14:11:32 +0200)

----------------------------------------------------------------
The biggest step forward is probably the enablement of display support
on the rk3399-firefly, which got its default serial set as well and
got cec support as well.
Gru boards got their touchpad support refined to actually mark the button
correctly and also git their rt5514 dsp added.
And finally the rk3328 eval board got its cpu regulator and mmc nodes.

----------------------------------------------------------------
Emil Renner Berthing (1):
      arm64: dts: rockchip: enable touchpad button for rk3399-gru-kevin

Heiko Stuebner (1):
      arm64: dts: rockchip: enable display subsystem on rk3399-firefly

Heinrich Schuchardt (1):
      arm64: dts: rockchip: default serial for Firefly-RK3399

Jeffy Chen (1):
      arm64: dts: rockchip: Add rt5514 dsp for rk3399 gru

Liang Chen (2):
      arm64: dts: rockchip: add mmc nodes for rk3328 evaluation board
      arm64: dts: rockchip: add cpu regulator for rk3328 evaluation board

Pierre-Hugues Husson (2):
      arm64: dts: rockchip: add the cec clk for dw-mipi-hdmi on rk3399
      arm64: dts: rockchip: enable cec pin for rk3399 firefly

 arch/arm64/boot/dts/rockchip/rk3328-evb.dts       | 72 ++++++++++++++++++++++-
 arch/arm64/boot/dts/rockchip/rk3399-firefly.dts   | 27 +++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts |  4 ++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      |  3 +-
 arch/arm64/boot/dts/rockchip/rk3399.dtsi          |  8 ++-
 5 files changed, 110 insertions(+), 4 deletions(-)



From heiko at sntech.de  Tue Oct 17 10:43:31 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 19:43:31 +0200
Subject: [GIT PULL] Rockchip clock updates for 4.15 round 1
Message-ID: <14384670.j3hM3TuojQ@phil>

Hi Mike, Stephen,

please find below the (tiny) first round of Rockchip clock changes for 4.15.
Right now there isn't any more in the pipeline, but who knows that may
change yet.

Please pull.
Thanks
Heiko

The following changes since commit 2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e:

  Linux 4.14-rc1 (2017-09-16 15:47:51 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.15-rockchip-clk-1

for you to fetch changes up to 47e3ec0e4dae1714cc76596e38d16913f0e574e2:

  clk: rockchip: use new cif/vdpu clock ids on rk3188 (2017-10-14 21:32:11 +0200)

----------------------------------------------------------------
Some new clock ids for rk3188 and rk3368 as well as removal of a
superfluous memory allocation error message.

----------------------------------------------------------------
Heiko Stuebner (3):
      clk: rockchip: add more rk3188 graphics clock ids
      Merge branch 'v4.15-shared/clkids' into v4.15-clk/next
      clk: rockchip: use new cif/vdpu clock ids on rk3188

Markus Elfring (1):
      clk: rockchip: Remove superfluous error message in rockchip_clk_register_cpuclk()

Romain Perier (2):
      clk: rockchip: add clock id for PCLK_EFUSE256 of RK3368 SoCs
      clk: rockchip: export clock pclk_efuse_256 for RK3368 SoCs

 drivers/clk/rockchip/clk-cpu.c                |  2 --
 drivers/clk/rockchip/clk-rk3188.c             | 12 ++++++------
 drivers/clk/rockchip/clk-rk3368.c             |  2 +-
 include/dt-bindings/clock/rk3188-cru-common.h |  9 +++++++--
 include/dt-bindings/clock/rk3368-cru.h        |  1 +
 5 files changed, 15 insertions(+), 11 deletions(-)



From seanpaul at chromium.org  Tue Oct 17 10:57:37 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Tue, 17 Oct 2017 13:57:37 -0400
Subject: [RFC PATCH v4 2/8] drm/rockchip: analogix_dp: Fix error handling
 path
In-Reply-To: <20171017101624.12506-3-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
 <20171017101624.12506-3-jeffy.chen@rock-chips.com>
Message-ID: <20171017175737.qkqwi2jn6vj2h7ev@art_vandelay>

On Tue, Oct 17, 2017 at 06:16:18PM +0800, Jeffy Chen wrote:
> Add missing error handling in rockchip_dp_bind().
> 
> Fixes: 9e32e16e9e98 ("drm: rockchip: dp: add rockchip platform dp driver")
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index 4d3f6ad0abdd..4b689c0f3fc1 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -371,7 +371,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
>  	ret = rockchip_dp_drm_create_encoder(dp);
>  	if (ret) {
>  		DRM_ERROR("failed to create drm encoder\n");
> -		return ret;
> +		goto err_disable_pclk;
>  	}
>  
>  	dp->plat_data.encoder = &dp->encoder;
> @@ -387,7 +387,17 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
>  
>  	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
>  
> -	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> +	ret = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> +	if (ret < 0)
> +		goto err_unreg_psr;
> +	return 0;
> +
> +err_unreg_psr:
> +	rockchip_drm_psr_unregister(&dp->encoder);
> +	rockchip_dp_drm_encoder_destroy(&dp->encoder);
> +err_disable_pclk:
> +	clk_disable_unprepare(dp->pclk);

Hi Jeffy,
This part of the cleanup is handling things setup by rockchip_dp_init().
However if someone adds something to rockchip_dp_init(), it's not obvious that
it should be cleaned up here and in unbind(). I'd suggest rebasing this on
a new patch which folds everything rockchip_dp_init() does into
rockchip_dp_bind(), then it will be obvious what needs to be cleaned up.

Sean


> +	return ret;
>  }
>  
>  static void rockchip_dp_unbind(struct device *dev, struct device *master,
> -- 
> 2.11.0
> 
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Tue Oct 17 11:02:55 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Tue, 17 Oct 2017 14:02:55 -0400
Subject: [RFC PATCH v4 3/8] drm/rockchip: dw-mipi-dsi: Fix error handling
 path
In-Reply-To: <20171017101624.12506-4-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
 <20171017101624.12506-4-jeffy.chen@rock-chips.com>
Message-ID: <20171017180255.qdoonirsy6xyhhru@art_vandelay>

On Tue, Oct 17, 2017 at 06:16:19PM +0800, Jeffy Chen wrote:
> Add missing pm_runtime_disable() in bind()'s error handling path.
> 
> Also cleanup encoder & connector in unbind().
> 
> Fixes: 80a9a059d4e4 ("drm/rockchip/dsi: add dw-mipi power domain support")
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 17 +++++++++++------
>  1 file changed, 11 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index b15755b6129c..a17ff0f6f489 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -1282,7 +1282,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
>  	ret = dw_mipi_dsi_register(drm, dsi);
>  	if (ret) {
>  		DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
> -		goto err_pllref;
> +		goto err_disable_pllref;
>  	}
>  
>  	pm_runtime_enable(dev);
> @@ -1292,23 +1292,24 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
>  	ret = mipi_dsi_host_register(&dsi->dsi_host);
>  	if (ret) {
>  		DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
> -		goto err_cleanup;
> +		goto err_disable_pm_runtime;
>  	}
>  
>  	if (!dsi->panel) {
>  		ret = -EPROBE_DEFER;
> -		goto err_mipi_dsi_host;
> +		goto err_unreg_mipi_dsi_host;
>  	}
>  
>  	dev_set_drvdata(dev, dsi);
>  	return 0;
>  
> -err_mipi_dsi_host:
> +err_unreg_mipi_dsi_host:
>  	mipi_dsi_host_unregister(&dsi->dsi_host);
> -err_cleanup:
> +err_disable_pm_runtime:
> +	pm_runtime_disable(dev);
>  	drm_encoder_cleanup(&dsi->encoder);
>  	drm_connector_cleanup(&dsi->connector);

Should you update these to call the destroy hook like in unbind()?

Sean

> -err_pllref:
> +err_disable_pllref:
>  	clk_disable_unprepare(dsi->pllref_clk);
>  	return ret;
>  }
> @@ -1320,6 +1321,10 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
>  
>  	mipi_dsi_host_unregister(&dsi->dsi_host);
>  	pm_runtime_disable(dev);
> +
> +	dsi->connector.funcs->destroy(&dsi->connector);
> +	dsi->encoder.funcs->destroy(&dsi->encoder);
> +
>  	clk_disable_unprepare(dsi->pllref_clk);
>  }
>  
> -- 
> 2.11.0
> 
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Tue Oct 17 11:10:34 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Tue, 17 Oct 2017 14:10:34 -0400
Subject: [RFC PATCH v4 4/8] drm/rockchip: dw_hdmi: Fix error handling path
In-Reply-To: <20171017101624.12506-5-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
 <20171017101624.12506-5-jeffy.chen@rock-chips.com>
Message-ID: <20171017181034.tsplfsmq7vi4uhmo@art_vandelay>

On Tue, Oct 17, 2017 at 06:16:20PM +0800, Jeffy Chen wrote:
> Add missing clk_disable_unprepare() in bind()'s error handling path.

This also isn't disabled in unbind(), is that intentional?

> 
> Fixes: 12b9f204e804 ("drm: bridge/dw_hdmi: add rockchip rk3288 support")
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> index 1eb02a82fd91..582283da7861 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> @@ -383,8 +383,10 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
>  	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
>  	 * which would have called the encoder cleanup.  Do it manually.
>  	 */
> -	if (ret)
> +	if (ret) {
>  		drm_encoder_cleanup(encoder);
> +		clk_disable_unprepare(hdmi->vpll_clk);

Same comment with respect to rockchip_hdmi_parse_dt(). This bug would have
probably been avoided if the contents of rockchip_hdmi_parse_dt() were inline
with dw_hdmi_rockchip_bind(), since then it's obvious what needs to be cleaned
up.

Sean

> +	}
>  
>  	return ret;
>  }
> -- 
> 2.11.0
> 
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From heiko at sntech.de  Tue Oct 17 11:17:26 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 20:17:26 +0200
Subject: [GIT PULL] Rockchip dts64 Fixes for 4.14 part 2
Message-ID: <6151423.bSX8Os9Bvg@phil>

Hi Arnd, Kevin, Olof,

looks like I need two rounds of fixes this time around.
But the vqmmc voltage issue warrants that I think, especially
as 4.14 is going to be a LTS release.

Please pull.

Thanks
Heiko

The following changes since commit 0bc15d85d97d44e8979ff91d0c1fbafe6fd4172c:

  arm64: dts: rockchip: add the grf clk for dw-mipi-dsi on rk3399 (2017-09-26 15:59:17 +0200)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.14-rockchip-dts64fixes-2

for you to fetch changes up to b521102d935d0501f5d95242ade2988f3f069c77:

  arm64: dts: rockchip: fix typo in iommu nodes (2017-10-17 20:13:52 +0200)

----------------------------------------------------------------
The vqmmc voltages on rk3399 pose a risk for the chip if they
exceed 3.0V, so they got fixed to not be at 3.3V
And Arnd found a typo in the recently added iommu nodes.

----------------------------------------------------------------
Arnd Bergmann (1):
      arm64: dts: rockchip: fix typo in iommu nodes

Shawn Lin (1):
      arm64: dts: rockchip: correct vqmmc voltage for rk3399 platforms

 arch/arm64/boot/dts/rockchip/rk3328.dtsi          | 2 +-
 arch/arm64/boot/dts/rockchip/rk3368.dtsi          | 2 +-
 arch/arm64/boot/dts/rockchip/rk3399-firefly.dts   | 4 ++--
 arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi     | 4 ++--
 arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi | 4 ++--
 5 files changed, 8 insertions(+), 8 deletions(-)



From seanpaul at chromium.org  Tue Oct 17 11:18:10 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Tue, 17 Oct 2017 14:18:10 -0400
Subject: [RFC PATCH v4 5/8] drm/rockchip: inno_hdmi: Fix error handling
 path
In-Reply-To: <20171017101624.12506-6-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
 <20171017101624.12506-6-jeffy.chen@rock-chips.com>
Message-ID: <20171017181810.smvocm63gr2qygw6@art_vandelay>

On Tue, Oct 17, 2017 at 06:16:21PM +0800, Jeffy Chen wrote:
> Add missing error handling in bind().
> 
> Fixes: 412d4ae6b7a5 ("drm/rockchip: hdmi: add Innosilicon HDMI support")
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/gpu/drm/rockchip/inno_hdmi.c | 20 ++++++++++++++++----
>  1 file changed, 16 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
> index ee584d87111f..9c258b05dfa5 100644
> --- a/drivers/gpu/drm/rockchip/inno_hdmi.c
> +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
> @@ -851,8 +851,10 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
>  	}
>  
>  	irq = platform_get_irq(pdev, 0);
> -	if (irq < 0)
> -		return irq;
> +	if (irq < 0) {
> +		ret = irq;
> +		goto err_disable_clk;
> +	}
>  
>  	inno_hdmi_reset(hdmi);
>  
> @@ -860,7 +862,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
>  	if (IS_ERR(hdmi->ddc)) {
>  		ret = PTR_ERR(hdmi->ddc);
>  		hdmi->ddc = NULL;
> -		return ret;
> +		goto err_disable_clk;
>  	}
>  
>  	/*
> @@ -874,7 +876,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
>  
>  	ret = inno_hdmi_register(drm, hdmi);
>  	if (ret)
> -		return ret;
> +		goto err_put_adapter;
>  
>  	dev_set_drvdata(dev, hdmi);
>  
> @@ -884,7 +886,17 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
>  	ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq,
>  					inno_hdmi_irq, IRQF_SHARED,
>  					dev_name(dev), hdmi);
> +	if (ret < 0)
> +		goto err_cleanup_hdmi;
>  
> +	return 0;
> +err_cleanup_hdmi:
> +	drm_connector_cleanup(&hdmi->connector);
> +	drm_encoder_cleanup(&hdmi->encoder);

Same question regarding cleanup vs destroy.

> +err_put_adapter:
> +	i2c_put_adapter(hdmi->ddc);
> +err_disable_clk:
> +	clk_disable_unprepare(hdmi->pclk);

I also noticed the order of these two functions is reversed in unbind(). Can you
please update the order to match?

Sean

>  	return ret;
>  }
>  
> -- 
> 2.11.0
> 
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Tue Oct 17 11:18:39 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Tue, 17 Oct 2017 14:18:39 -0400
Subject: [RFC PATCH v4 6/8] drm/bridge/analogix: Do not use device's
 drvdata
In-Reply-To: <20171017101624.12506-7-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
 <20171017101624.12506-7-jeffy.chen@rock-chips.com>
Message-ID: <20171017181839.nse6dgfeafkmvzog@art_vandelay>

On Tue, Oct 17, 2017 at 06:16:22PM +0800, Jeffy Chen wrote:
> From: Tomasz Figa <tfiga at chromium.org>
> 
> The driver that instantiates the bridge should own the drvdata, as all
> driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
> owned by its driver struct. Moreover, storing two different pointer
> types in driver data depending on driver initialization status is barely
> a good practice and in fact has led to many bugs in this driver.
> 
> Let's clean up this mess and change Analogix entry points to simply
> accept some opaque struct pointer, adjusting their users at the same
> time to avoid breaking the compilation.
> 
> Signed-off-by: Tomasz Figa <tfiga at chromium.org>
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>

Reviewed-by: Sean Paul <seanpaul at chromium.org>

> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++-------------
>  drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 47 +++++++++++---------
>  include/drm/bridge/analogix_dp.h                   | 19 ++++----
>  4 files changed, 73 insertions(+), 69 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 5dd3f1cd074a..74d274b6d31d 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -98,17 +98,15 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
>  	return 0;
>  }
>  
> -int analogix_dp_psr_supported(struct device *dev)
> +int analogix_dp_psr_supported(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
>  
>  	return dp->psr_support;
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
>  
> -int analogix_dp_enable_psr(struct device *dev)
> +int analogix_dp_enable_psr(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
>  	struct edp_vsc_psr psr_vsc;
>  
>  	if (!dp->psr_support)
> @@ -129,9 +127,8 @@ int analogix_dp_enable_psr(struct device *dev)
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
>  
> -int analogix_dp_disable_psr(struct device *dev)
> +int analogix_dp_disable_psr(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
>  	struct edp_vsc_psr psr_vsc;
>  	int ret;
>  
> @@ -1281,8 +1278,9 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
>  	return analogix_dp_transfer(dp, msg);
>  }
>  
> -int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
> -		     struct analogix_dp_plat_data *plat_data)
> +struct analogix_dp_device *
> +analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
> +		 struct analogix_dp_plat_data *plat_data)
>  {
>  	struct platform_device *pdev = to_platform_device(dev);
>  	struct analogix_dp_device *dp;
> @@ -1292,14 +1290,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  
>  	if (!plat_data) {
>  		dev_err(dev, "Invalided input plat_data\n");
> -		return -EINVAL;
> +		return ERR_PTR(-EINVAL);
>  	}
>  
>  	dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
>  	if (!dp)
> -		return -ENOMEM;
> -
> -	dev_set_drvdata(dev, dp);
> +		return ERR_PTR(-ENOMEM);
>  
>  	dp->dev = &pdev->dev;
>  	dp->dpms_mode = DRM_MODE_DPMS_OFF;
> @@ -1316,7 +1312,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  
>  	ret = analogix_dp_dt_parse_pdata(dp);
>  	if (ret)
> -		return ret;
> +		return ERR_PTR(ret);
>  
>  	dp->phy = devm_phy_get(dp->dev, "dp");
>  	if (IS_ERR(dp->phy)) {
> @@ -1330,14 +1326,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  			if (ret == -ENOSYS || ret == -ENODEV)
>  				dp->phy = NULL;
>  			else
> -				return ret;
> +				return ERR_PTR(ret);
>  		}
>  	}
>  
>  	dp->clock = devm_clk_get(&pdev->dev, "dp");
>  	if (IS_ERR(dp->clock)) {
>  		dev_err(&pdev->dev, "failed to get clock\n");
> -		return PTR_ERR(dp->clock);
> +		return ERR_CAST(dp->clock);
>  	}
>  
>  	clk_prepare_enable(dp->clock);
> @@ -1346,7 +1342,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  
>  	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(dp->reg_base))
> -		return PTR_ERR(dp->reg_base);
> +		return ERR_CAST(dp->reg_base);
>  
>  	dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
>  
> @@ -1367,7 +1363,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  					    "hpd_gpio");
>  		if (ret) {
>  			dev_err(&pdev->dev, "failed to get hpd gpio\n");
> -			return ret;
> +			return ERR_PTR(ret);
>  		}
>  		dp->irq = gpio_to_irq(dp->hpd_gpio);
>  		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
> @@ -1379,7 +1375,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  
>  	if (dp->irq == -ENXIO) {
>  		dev_err(&pdev->dev, "failed to get irq\n");
> -		return -ENODEV;
> +		return ERR_PTR(-ENODEV);
>  	}
>  
>  	pm_runtime_enable(dev);
> @@ -1420,7 +1416,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  	phy_power_off(dp->phy);
>  	pm_runtime_put(dev);
>  
> -	return 0;
> +	return dp;
>  
>  err_disable_pm_runtime:
>  
> @@ -1428,15 +1424,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  	pm_runtime_put(dev);
>  	pm_runtime_disable(dev);
>  
> -	return ret;
> +	return ERR_PTR(ret);
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_bind);
>  
> -void analogix_dp_unbind(struct device *dev, struct device *master,
> -			void *data)
> +void analogix_dp_unbind(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
> -
>  	analogix_dp_bridge_disable(dp->bridge);
>  	dp->connector.funcs->destroy(&dp->connector);
>  	dp->encoder->funcs->destroy(dp->encoder);
> @@ -1449,16 +1442,14 @@ void analogix_dp_unbind(struct device *dev, struct device *master,
>  	}
>  
>  	drm_dp_aux_unregister(&dp->aux);
> -	pm_runtime_disable(dev);
> +	pm_runtime_disable(dp->dev);
>  	clk_disable_unprepare(dp->clock);
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_unbind);
>  
>  #ifdef CONFIG_PM
> -int analogix_dp_suspend(struct device *dev)
> +int analogix_dp_suspend(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
> -
>  	clk_disable_unprepare(dp->clock);
>  
>  	if (dp->plat_data->panel) {
> @@ -1470,9 +1461,8 @@ int analogix_dp_suspend(struct device *dev)
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_suspend);
>  
> -int analogix_dp_resume(struct device *dev)
> +int analogix_dp_resume(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
>  	int ret;
>  
>  	ret = clk_prepare_enable(dp->clock);
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 39629e7a80b9..f7e5b2c405ed 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -41,6 +41,7 @@ struct exynos_dp_device {
>  	struct device              *dev;
>  
>  	struct videomode           vm;
> +	struct analogix_dp_device *adp;
>  	struct analogix_dp_plat_data plat_data;
>  };
>  
> @@ -157,13 +158,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
>  	struct drm_device *drm_dev = data;
>  	int ret;
>  
> -	/*
> -	 * Just like the probe function said, we don't need the
> -	 * device drvrate anymore, we should leave the charge to
> -	 * analogix dp driver, set the device drvdata to NULL.
> -	 */
> -	dev_set_drvdata(dev, NULL);
> -
>  	dp->dev = dev;
>  	dp->drm_dev = drm_dev;
>  
> @@ -190,13 +184,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
>  
>  	dp->plat_data.encoder = encoder;
>  
> -	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> +	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> +	if (IS_ERR(dp->adp))
> +		return PTR_ERR(dp->adp);
> +
> +	return 0;
>  }
>  
>  static void exynos_dp_unbind(struct device *dev, struct device *master,
>  			     void *data)
>  {
> -	return analogix_dp_unbind(dev, master, data);
> +	struct exynos_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_unbind(dp->adp);
>  }
>  
>  static const struct component_ops exynos_dp_ops = {
> @@ -257,12 +257,16 @@ static int exynos_dp_remove(struct platform_device *pdev)
>  #ifdef CONFIG_PM
>  static int exynos_dp_suspend(struct device *dev)
>  {
> -	return analogix_dp_suspend(dev);
> +	struct exynos_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_suspend(dp->adp);
>  }
>  
>  static int exynos_dp_resume(struct device *dev)
>  {
> -	return analogix_dp_resume(dev);
> +	struct exynos_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_resume(dp->adp);
>  }
>  #endif
>  
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index 4b689c0f3fc1..b5f39bf59234 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -77,6 +77,7 @@ struct rockchip_dp_device {
>  
>  	const struct rockchip_dp_chip_data *data;
>  
> +	struct analogix_dp_device *adp;
>  	struct analogix_dp_plat_data plat_data;
>  };
>  
> @@ -85,7 +86,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
>  	struct rockchip_dp_device *dp = to_dp(encoder);
>  	unsigned long flags;
>  
> -	if (!analogix_dp_psr_supported(dp->dev))
> +	if (!analogix_dp_psr_supported(dp->adp))
>  		return;
>  
>  	DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
> @@ -116,9 +117,9 @@ static void analogix_dp_psr_work(struct work_struct *work)
>  
>  	spin_lock_irqsave(&dp->psr_lock, flags);
>  	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
> -		analogix_dp_enable_psr(dp->dev);
> +		analogix_dp_enable_psr(dp->adp);
>  	else
> -		analogix_dp_disable_psr(dp->dev);
> +		analogix_dp_disable_psr(dp->adp);
>  	spin_unlock_irqrestore(&dp->psr_lock, flags);
>  }
>  
> @@ -350,13 +351,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
>  	struct drm_device *drm_dev = data;
>  	int ret;
>  
> -	/*
> -	 * Just like the probe function said, we don't need the
> -	 * device drvrate anymore, we should leave the charge to
> -	 * analogix dp driver, set the device drvdata to NULL.
> -	 */
> -	dev_set_drvdata(dev, NULL);
> -
>  	dp_data = of_device_get_match_data(dev);
>  	if (!dp_data)
>  		return -ENODEV;
> @@ -387,9 +381,11 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
>  
>  	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
>  
> -	ret = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> -	if (ret < 0)
> +	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> +	if (IS_ERR(dp->adp)) {
> +		ret = PTR_ERR(dp->adp);
>  		goto err_unreg_psr;
> +	}
>  	return 0;
>  
>  err_unreg_psr:
> @@ -407,7 +403,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
>  
>  	rockchip_drm_psr_unregister(&dp->encoder);
>  
> -	analogix_dp_unbind(dev, master, data);
> +	analogix_dp_unbind(dp->adp);
>  	clk_disable_unprepare(dp->pclk);
>  }
>  
> @@ -435,11 +431,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
>  
>  	dp->plat_data.panel = panel;
>  
> -	/*
> -	 * We just use the drvdata until driver run into component
> -	 * add function, and then we would set drvdata to null, so
> -	 * that analogix dp driver could take charge of the drvdata.
> -	 */
>  	platform_set_drvdata(pdev, dp);
>  
>  	return component_add(dev, &rockchip_dp_component_ops);
> @@ -452,10 +443,26 @@ static int rockchip_dp_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_PM_SLEEP
> +static int rockchip_dp_suspend(struct device *dev)
> +{
> +	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_suspend(dp->adp);
> +}
> +
> +static int rockchip_dp_resume(struct device *dev)
> +{
> +	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_resume(dp->adp);
> +}
> +#endif
> +
>  static const struct dev_pm_ops rockchip_dp_pm_ops = {
>  #ifdef CONFIG_PM_SLEEP
> -	.suspend = analogix_dp_suspend,
> -	.resume_early = analogix_dp_resume,
> +	.suspend = rockchip_dp_suspend,
> +	.resume_early = rockchip_dp_resume,
>  #endif
>  };
>  
> diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
> index c99d6eaef1ac..5518fc75dd6e 100644
> --- a/include/drm/bridge/analogix_dp.h
> +++ b/include/drm/bridge/analogix_dp.h
> @@ -13,6 +13,8 @@
>  
>  #include <drm/drm_crtc.h>
>  
> +struct analogix_dp_device;
> +
>  enum analogix_dp_devtype {
>  	EXYNOS_DP,
>  	RK3288_DP,
> @@ -38,16 +40,17 @@ struct analogix_dp_plat_data {
>  			 struct drm_connector *);
>  };
>  
> -int analogix_dp_psr_supported(struct device *dev);
> -int analogix_dp_enable_psr(struct device *dev);
> -int analogix_dp_disable_psr(struct device *dev);
> +int analogix_dp_psr_supported(struct analogix_dp_device *dp);
> +int analogix_dp_enable_psr(struct analogix_dp_device *dp);
> +int analogix_dp_disable_psr(struct analogix_dp_device *dp);
>  
> -int analogix_dp_resume(struct device *dev);
> -int analogix_dp_suspend(struct device *dev);
> +int analogix_dp_resume(struct analogix_dp_device *dp);
> +int analogix_dp_suspend(struct analogix_dp_device *dp);
>  
> -int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
> -		     struct analogix_dp_plat_data *plat_data);
> -void analogix_dp_unbind(struct device *dev, struct device *master, void *data);
> +struct analogix_dp_device *
> +analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
> +		 struct analogix_dp_plat_data *plat_data);
> +void analogix_dp_unbind(struct analogix_dp_device *dp);
>  
>  int analogix_dp_start_crc(struct drm_connector *connector);
>  int analogix_dp_stop_crc(struct drm_connector *connector);
> -- 
> 2.11.0
> 
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Tue Oct 17 11:24:42 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Tue, 17 Oct 2017 14:24:42 -0400
Subject: [RFC PATCH v4 8/8] drm/rockchip: Add device links for master and
 components
In-Reply-To: <20171017101624.12506-9-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
 <20171017101624.12506-9-jeffy.chen@rock-chips.com>
Message-ID: <20171017182442.l74ie27lq4gvt2fs@art_vandelay>

On Tue, Oct 17, 2017 at 06:16:24PM +0800, Jeffy Chen wrote:
> Since we are trying to access components' resources in the master's
> suspend/resume PM callbacks(e.g. panel), add device links to correct
> the suspend/resume and shutdown ordering.
> 
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2:
> Use device link to correct the suspend/resume and shutdown ordering,
> instead of converting rockchip spi's suspend/resume PM callbacks to
> late suspend/resume PM callbacks.
> 
>  drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 24 +++++++++++++++++++++---
>  1 file changed, 21 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> index 76d63de5921d..af18967f699b 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> @@ -337,6 +337,8 @@ static struct component_match *rockchip_drm_match_add(struct device *dev)
>  
>  			if (!d)
>  				break;
> +
> +			device_link_add(dev, d, DL_FLAG_STATELESS);
>  			component_match_add(dev, &match, compare_dev, d);
>  		} while (true);
>  	}
> @@ -406,6 +408,7 @@ static int rockchip_drm_platform_of_probe(struct device *dev)
>  static int rockchip_drm_platform_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> +	struct device_link *link;
>  	struct component_match *match = NULL;
>  	int ret;
>  
> @@ -414,16 +417,31 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	match = rockchip_drm_match_add(dev);
> -	if (IS_ERR(match))
> -		return PTR_ERR(match);
> +	if (IS_ERR(match)) {
> +		ret = PTR_ERR(match);
> +		goto err_cleanup_dev_links;

This cleanup should take place in rockchip_drm_match_add(). The review theme for
this entire series is that, when possible, we should cleanup things where they
are initialized.

Since you'll also need to clean up the links elsewhere, consider adding a helper
function to do the cleanup (rockchip_drm_match_remove or similar) and calling it
where needed.

Sean

> +	}
>  
> -	return component_master_add_with_match(dev, &rockchip_drm_ops, match);
> +	ret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
> +	if (ret < 0)
> +		goto err_cleanup_dev_links;
> +
> +	return 0;
> +err_cleanup_dev_links:
> +	list_for_each_entry(link, &dev->links.consumers, s_node)
> +		device_link_del(link);
> +	return ret;
>  }
>  
>  static int rockchip_drm_platform_remove(struct platform_device *pdev)
>  {
> +	struct device_link *link;
> +
>  	component_master_del(&pdev->dev, &rockchip_drm_ops);
>  
> +	list_for_each_entry(link, &pdev->dev.links.consumers, s_node)
> +		device_link_del(link);
> +
>  	return 0;
>  }
>  
> -- 
> 2.11.0
> 
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From heiko at sntech.de  Tue Oct 17 11:31:00 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 20:31:00 +0200
Subject: [PATCH v12 4/5] ARM: dts: rockchip: add RGA device node for RK3288
In-Reply-To: <20171011072938.383-5-jacob-chen@iotwrt.com>
References: <20171011072938.383-1-jacob-chen@iotwrt.com>
 <20171011072938.383-5-jacob-chen@iotwrt.com>
Message-ID: <6753594.RkbY0XHeV6@phil>

Am Mittwoch, 11. Oktober 2017, 15:29:37 CEST schrieb Jacob Chen:
> This patch add the RGA dt config of rk3288 SoC.
> 
> Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
> Signed-off-by: Yakir Yang <ykk at rock-chips.com>

applied for 4.15


Thanks
Heiko


From heiko at sntech.de  Tue Oct 17 11:31:23 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 20:31:23 +0200
Subject: [PATCH v12 5/5] arm64: dts: rockchip: add RGA device node for
 RK3399
In-Reply-To: <20171011072938.383-6-jacob-chen@iotwrt.com>
References: <20171011072938.383-1-jacob-chen@iotwrt.com>
 <20171011072938.383-6-jacob-chen@iotwrt.com>
Message-ID: <2638783.szBAEUNl8E@phil>

Am Mittwoch, 11. Oktober 2017, 15:29:38 CEST schrieb Jacob Chen:
> This patch add the RGA dt config of RK3399 SoC.
> 
> Signed-off-by: Jacob Chen <jacob-chen at iotwrt.com>
> Signed-off-by: Yakir Yang <ykk at rock-chips.com>

applied for 4.15


Thanks
Heiko


From heiko at sntech.de  Tue Oct 17 10:52:55 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 19:52:55 +0200
Subject: [PATCH] arm64: dts: rockchip: fix typo in iommu nodes
In-Reply-To: <4123717.0VmPnCpUOn@diego>
References: <20171010085648.1339605-1-arnd@arndb.de> <4123717.0VmPnCpUOn@diego>
Message-ID: <35096146.J7tq43JfW1@phil>

Am Dienstag, 10. Oktober 2017, 11:48:25 CEST schrieb Heiko St?bner:
> Hi Arnd,
> 
> Am Dienstag, 10. Oktober 2017, 10:56:01 CEST schrieb Arnd Bergmann:
> > The latest dtc warns about an extraneous cell in the interrupt
> > property of two of the iommu device nodes:
> > 
> > Warning (interrupts_property): interrupts size is (16), expected multiple of
> > 12 in /iommu at ff373f00 Warning (interrupts_property): interrupts size is
> > (16), expected multiple of 12 in /iommu at ff900800
> > 
> > This removes the typo.
> > 
> > Fixes: cede4c79de28 ("arm64: dts: rockchip: add rk3368 iommu nodes")
> > Fixes: 49c82f2b7c5d ("arm64: dts: rockchip: add rk3328 iommu nodes")
> > Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> 
> looks like that got copy-pasted from rk3399 where we have 4 elements per irq.
> In any case the change looks good, so if you want to apply it directly to 
> armsoc-fixes here is a
> 
> Acked-by: Heiko Stuebner <heiko at sntech.de>
> 
> Depending on how you want to handle it I can also merge it, but
> Olof already picked up my 2 fixes for 4.14, so you applying it might
> save us the round-trip for a further 1-patch pull request :-)

as another (somewhat urgent) fix for 64bit dts has come up, I've now also
picked this change up for the following pull request.


Heiko


From heiko at sntech.de  Tue Oct 17 10:50:52 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 19:50:52 +0200
Subject: [PATCH] arm64: dts: rockchip: correct vqmmc voltage for rk3399
 platforms
In-Reply-To: <1508211484-210856-1-git-send-email-shawn.lin@rock-chips.com>
References: <1508211484-210856-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1720676.h40eDqr0yM@phil>

Am Dienstag, 17. Oktober 2017, 11:38:04 CEST schrieb Shawn Lin:
> The vcc_sd or vcc_sdio used for IO voltage for sdmmc and sdio
> interface on rk3399 platform have a limitation that it can't be
> larger than 3.0v, otherwise it has a potential risk for the chip.
> Correct all of them.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

applied as fix for 4.14 with Klaus' tested tag.


Thanks
Heiko


From heiko at sntech.de  Tue Oct 17 12:00:54 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:00:54 +0200
Subject: [PATCH 4/5] arm: dts: rockchip: add thermal nodes for RV1108 SoC
In-Reply-To: <1503570475-7850-5-git-send-email-rocky.hao@rock-chips.com>
References: <1503570475-7850-1-git-send-email-rocky.hao@rock-chips.com>
 <1503570475-7850-5-git-send-email-rocky.hao@rock-chips.com>
Message-ID: <2261377.Dl0AzrzCiW@phil>

Am Donnerstag, 24. August 2017, 18:27:54 CEST schrieb Rocky Hao:
> Add thermal zone and dynamic CPU power coefficients for RV1108
> 
> Signed-off-by: Rocky Hao <rocky.hao at rock-chips.com>

applied for 4.15 with Eduardo's Ack.

Please make further adjustments for things like temperatures
in follow-up patches.


Thanks
Heiko


From heiko at sntech.de  Tue Oct 17 12:00:40 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:00:40 +0200
Subject: [PATCH 3/5] arm: dts: rockchip: add tsadc node for RV1108 SoC
In-Reply-To: <1503570475-7850-4-git-send-email-rocky.hao@rock-chips.com>
References: <1503570475-7850-1-git-send-email-rocky.hao@rock-chips.com>
 <1503570475-7850-4-git-send-email-rocky.hao@rock-chips.com>
Message-ID: <1784322.nOOBHvxH5Z@phil>

Am Donnerstag, 24. August 2017, 18:27:53 CEST schrieb Rocky Hao:
> Add tsadc needed main information for RV1108 SoC.
> 750000Hz is the max clock rate supported by tsadc module.
> 
> Signed-off-by: Rocky Hao <rocky.hao at rock-chips.com>

applied for 4.15 with Eduardo's Ack.

Please make further adjustments for things like temperatures
in follow-up patches.


Thanks
Heiko


From heiko at sntech.de  Tue Oct 17 12:01:11 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:01:11 +0200
Subject: [PATCH 5/5] arm: dts: rockchip: enable tsadc module on RV1108
 evaluation board
In-Reply-To: <1503570734-8942-1-git-send-email-rocky.hao@rock-chips.com>
References: <1503570475-7850-1-git-send-email-rocky.hao@rock-chips.com>
 <1503570734-8942-1-git-send-email-rocky.hao@rock-chips.com>
Message-ID: <2302063.Z22fM4bRKP@phil>

Am Donnerstag, 24. August 2017, 18:32:14 CEST schrieb Rocky Hao:
> Enable tsadc module on RV1108 evaluation board
> 
> Signed-off-by: Rocky Hao <rocky.hao at rock-chips.com>

applied for 4.15 with Eduardo's Ack.


Thanks
Heiko


From heiko at sntech.de  Tue Oct 17 12:07:14 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:07:14 +0200
Subject: [PATCH 1/9] ARM: dts: rockchip: rk3288-vyasa: Remove vdd_log from
 rk808, DCDC_REG1
In-Reply-To: <1508156187-27519-2-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-2-git-send-email-jagan@amarulasolutions.com>
Message-ID: <3424934.UivI2BNsfM@phil>

Am Montag, 16. Oktober 2017, 17:46:19 CEST schrieb Jagan Teki:
> vdd_log, never used on DCDC_REG1 of rk808 from latest schematic so
> remove the same and update the regulator-name as 'vdd_arm' to sync
> with existing rk3288 board dts files.
> 
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

applied for 4.15


From heiko at sntech.de  Tue Oct 17 12:09:04 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:09:04 +0200
Subject: [PATCH 2/9] ARM: dts: rockchip: rk3288-vyasa: Use fixed voltage
 range for vccio_sd
In-Reply-To: <1508156187-27519-3-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-3-git-send-email-jagan@amarulasolutions.com>
Message-ID: <3394467.76otEihhKb@phil>

Hi,

Am Montag, 16. Oktober 2017, 17:46:20 CEST schrieb Jagan Teki:
> vccio_sd has supplied to vqmmc-supply for sdmmc, use fixed voltage
> range of 3.3v for better IO lines supply voltage.
> 
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

not sure I understand this one.

I.e. the regulator should be at 3.3V anyway and only when it
reaches UHS speeds should the mmc core reduce the voltage
to 1.8V, so having this variable here, shouldn't pose a problem?

So maybe you could explain a bit more what the problem is?


Thanks
Heiko

> ---
>  arch/arm/boot/dts/rk3288-vyasa.dts | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/rk3288-vyasa.dts b/arch/arm/boot/dts/rk3288-vyasa.dts
> index 7a0f945..915b4a3 100644
> --- a/arch/arm/boot/dts/rk3288-vyasa.dts
> +++ b/arch/arm/boot/dts/rk3288-vyasa.dts
> @@ -214,7 +214,7 @@
>  
>  			vccio_sd: LDO_REG5 {
>  				regulator-name = "vccio_sd";
> -				regulator-min-microvolt = <1800000>;
> +				regulator-min-microvolt = <3300000>;
>  				regulator-max-microvolt = <3300000>;
>  				regulator-always-on;
>  				regulator-boot-on;
> 




From heiko at sntech.de  Tue Oct 17 12:10:23 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:10:23 +0200
Subject: [PATCH 3/9] ARM: dts: rockchip: rk3288-vyasa: Use vmmc-supply
 from PMIC
In-Reply-To: <1508156187-27519-4-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-4-git-send-email-jagan@amarulasolutions.com>
Message-ID: <3048917.UNI3VLpOcx@phil>

Am Montag, 16. Oktober 2017, 17:46:21 CEST schrieb Jagan Teki:
> rk808, SWITCH_REG1 has configured for sdmmc regulator as vcc_sd,
> so use the same by renaming vcc33_sd to vcc_sd(as per schematic)
> and drop explicit regulator definition from root.
> 
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

applied for 4.15


From heiko at sntech.de  Tue Oct 17 12:11:31 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:11:31 +0200
Subject: [PATCH 4/9] ARM: dts: rockchip: Add regulators for rk3288-vyasa
In-Reply-To: <1508156187-27519-5-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-5-git-send-email-jagan@amarulasolutions.com>
Message-ID: <3848358.4O5aWzMl3H@phil>

Am Montag, 16. Oktober 2017, 17:46:22 CEST schrieb Jagan Teki:
> Add supporting regulators for rk3288-vyasa board, dc12_vbat is
> parent regulatorand followed regulators as are child regulators.
> regulator naming conversion followed as per schematic for better
> readability and easy for identification.
> 
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

applied for 4.15


From heiko at sntech.de  Tue Oct 17 12:12:58 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:12:58 +0200
Subject: [PATCH 5/9] ARM: dts: rockchip: Add gmac support for rk3288-vyasa
 board
In-Reply-To: <1508156187-27519-6-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-6-git-send-email-jagan@amarulasolutions.com>
Message-ID: <2126786.mg1eWuGTTL@phil>

Am Montag, 16. Oktober 2017, 17:46:23 CEST schrieb Jagan Teki:
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

I've picked your v2 of the patch.


From heiko at sntech.de  Tue Oct 17 12:14:08 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:14:08 +0200
Subject: [PATCH v2 5/9] ARM: dts: rockchip: Add gmac support for
 rk3288-vyasa board
In-Reply-To: <1508173987-26688-1-git-send-email-jagan@amarulasolutions.com>
References: <1508173987-26688-1-git-send-email-jagan@amarulasolutions.com>
Message-ID: <8892430.bUk4D2SYKf@phil>

Am Montag, 16. Oktober 2017, 22:43:07 CEST schrieb Jagan Teki:
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

applied for 4.15 after adding a basic commit message.


From heiko at sntech.de  Tue Oct 17 12:19:11 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:19:11 +0200
Subject: [PATCH 6/9] ARM: dts: rockchip: Add usb host for rk3288-vyasa
In-Reply-To: <1508156187-27519-7-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-7-git-send-email-jagan@amarulasolutions.com>
Message-ID: <1761916.pIAoj0xHaJ@phil>

Am Montag, 16. Oktober 2017, 17:46:24 CEST schrieb Jagan Teki:
> Add usb host support for rk3288-vyasa, board support hub power
> through phy_pwr_en and usb2 host power through usb2_pwr_en and
> naming conversion followed as per schematic.
> 
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

applied for 4.15, after dropping the RK_GPIO8 addition and making
the pin use "8" directly instead of the outdated constant.

It isn't planned to extend this GPIOx -> x ... instead it is more or
less deprecated.



From heiko at sntech.de  Tue Oct 17 12:19:40 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:19:40 +0200
Subject: [PATCH 7/9] ARM: dts: rockchip: Add usb otg for rk3288-vyasa
In-Reply-To: <1508156187-27519-8-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-8-git-send-email-jagan@amarulasolutions.com>
Message-ID: <3717003.CkzGvurGmR@phil>

Am Montag, 16. Oktober 2017, 17:46:25 CEST schrieb Jagan Teki:
> Add usb otg support for rk3288-vyasa, board support usb1 otg
> power through otg_vbus_drv and naming conversion followed
> as per schematic.
> 
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

applied for 4.15


From heiko at sntech.de  Tue Oct 17 12:22:27 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 Oct 2017 21:22:27 +0200
Subject: [PATCH 8/9] ARM: dts: rockchip: Add io domains for rk3288-vyasa
In-Reply-To: <1508156187-27519-9-git-send-email-jagan@amarulasolutions.com>
References: <1508156187-27519-1-git-send-email-jagan@amarulasolutions.com>
 <1508156187-27519-9-git-send-email-jagan@amarulasolutions.com>
Message-ID: <4522560.db0ptWQylr@phil>

Am Montag, 16. Oktober 2017, 17:46:26 CEST schrieb Jagan Teki:
> Add io domains supported by rk3288-vyasa board.
> 
> Signed-off-by: Jagan Teki <jagan at amarulasolutions.com>

applied for 4.15 after moving it below the i2c node


From briannorris at chromium.org  Tue Oct 17 16:39:05 2017
From: briannorris at chromium.org (Brian Norris)
Date: Tue, 17 Oct 2017 16:39:05 -0700
Subject: [PATCH 1/3] Documentation/devicetree: Add pcie-reset-suspend
 property
In-Reply-To: <20171013165152.GE25517@bhelgaas-glaptop.roam.corp.google.com>
References: <20171012205220.130048-1-briannorris@chromium.org>
 <20171012205220.130048-2-briannorris@chromium.org>
 <20171013165152.GE25517@bhelgaas-glaptop.roam.corp.google.com>
Message-ID: <20171017233904.GA65743@google.com>

Hi Bjorn,

Sorry for a little delay. I haven't been able to get much better answers
out of the problematic vendor here (they insist they are within the
spec), so I guess I'll have to go ahead based on current knowledge.

On Fri, Oct 13, 2017 at 11:51:52AM -0500, Bjorn Helgaas wrote:
> [+cc Doug]
> 
> On Thu, Oct 12, 2017 at 01:52:18PM -0700, Brian Norris wrote:
> > The patch is self-descriptive. I've found that we may need
> > platform-specific behavior for the PERST# signal in system suspend,
> > depending on the type of PCIe endpoints are attached.
> > 
> > Signed-off-by: Brian Norris <briannorris at chromium.org>
> > ---
> >  Documentation/devicetree/bindings/pci/pci.txt | 11 +++++++++++
> >  1 file changed, 11 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt
> > index c77981c5dd18..91339b6d0652 100644
> > --- a/Documentation/devicetree/bindings/pci/pci.txt
> > +++ b/Documentation/devicetree/bindings/pci/pci.txt
> > @@ -24,3 +24,14 @@ driver implementation may support the following properties:
> >     unsupported link speed, for instance, trying to do training for
> >     unsupported link speed, etc.  Must be '4' for gen4, '3' for gen3, '2'
> >     for gen2, and '1' for gen1. Any other values are invalid.
> > +- pcie-reset-suspend:
> > +   If present this property defines whether the PCIe Reset signal (referred to
> > +   as PERST#) should be asserted when the system enters low-power suspend modes
> > +   (e.g., S3). Depending on the form factor, the associated PCIe
> > +   electromechanical specification may specify a particular behavior (e.g.,
> > +   "PERST# is asserted in advance of the power being switched off in a
> > +   power-managed state like S3") or it may be less clear. The net result is
> > +   that some endpoints perform better (e.g., lower power consumption) with
> > +   PERST# asserted, and others prefer PERST# deasserted. The value must be '0'
> > +   or '1', where '0' means do not assert PERST# and '1' means assert PERST#.
> > +   When absent, behavior may be platform-specific.
> 
> I don't understand this at all.  Are you suggesting that we need
> different "pcie-reset-suspend" values based on what sort of endpoint
> the user plugs in?

Partly. I guess I also failed to mention in this particular text (but I
did, in patch 3) that it can be a board-specific problem, related to the
fact that the only endpoint used on said board--soldered on, not
replaceable--never seemed to require PERST# to be asserted in suspend.
On such boards, I believe [1] it is physically impossible to drive this
pin low in S3 suspend. So even if we tried to assert PERST#, it would
pull back up when we suspend the system. I'm not sure if that's better
or worse than not asserting it at all.

So, that's why I settled on a device tree property. It describes the
physical ability of the board too, in some cases. (I could document this
better, I see.)

However, in other cases, we might have boards that are physically
capable, but where the use of this endpoint might still cause
interoperability problems, per your next comment. So... (continued
below)

> If so, I really don't want to get involved in that, because that's an
> issue that needs to be resolved by the vendors and the PCI-SIG.  If we

Judging by conversations with these vendors, I can't really imagine them
proactively dealing with the PCI-SIG on this. Is that really what you
think will work best?

I personally believe deferring (i.e., ignoring) the problem will not
cause any change; badly behaved vendors will just do whatever suits
them, and system designers will have to figure it out somehow -- ACPI
systems will have platform-specific behavior hidden in firmware; device
tree systems will do whatever they want out of tree; and the rare device
tree system that gets upstream support will either have suboptimal power
management, or have to have these sorts of conversations again. None of
that puts pressure on an endpoint vendor to talk to the PCI-SIG.

(I can try to put that pressure on them, but I only have so much power.)

> put in a tweak like this, I think it would be a band-aid that only
> delays getting a real solution figured out.
> 
> If you want a quirk to tune this based on specific devices, that might
> make sense.  It would still sound like an interoperability issue and
> an ongoing maintenance problem, but at least we would have specific
> details about which devices are involved, and we'd have a chance to
> make them work on more controllers than just Rockchip.

(continued) ...I suppose we could do this too. Like, a new entry in enum
pci_dev_flags, and code in drivers/pci/quirks.c? And then some helper so
that a PCIe root port driver like Rockchip's can walk its children and
check for the existence of this quirk? I'll see if I can write that up
reasonably.

Then I guess technically we could get away with not supporting the
aforementioned device tree property, since any board where the HW won't
support asserting PERST# in S3 should also have an endpoint with this
quirk.

Brian

[1] I say "I believe" because the GPIO power rail is not powered in S3
    (so at best we can possibly give a weak pull) and it is pulled up
    externally. I don't think there's any way around this.


From jingoohan1 at gmail.com  Tue Oct 17 16:42:38 2017
From: jingoohan1 at gmail.com (Jingoo Han)
Date: Tue, 17 Oct 2017 19:42:38 -0400
Subject: [RFC PATCH v3 3/5] drm/bridge/analogix: Do not use device's
 drvdata
In-Reply-To: <20171017080925.23763-4-jeffy.chen@rock-chips.com>
References: <20171017080925.23763-1-jeffy.chen@rock-chips.com>
 <20171017080925.23763-4-jeffy.chen@rock-chips.com>
Message-ID: <000001d347a1$9f11ffa0$dd35fee0$@gmail.com>

On Tuesday, October 17, 2017 4:09 AM, Jeffy Chen wrote:
> 
> From: Tomasz Figa <tfiga at chromium.org>
> 
> The driver that instantiates the bridge should own the drvdata, as all
> driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
> owned by its driver struct. Moreover, storing two different pointer
> types in driver data depending on driver initialization status is barely
> a good practice and in fact has led to many bugs in this driver.
> 
> Let's clean up this mess and change Analogix entry points to simply
> accept some opaque struct pointer, adjusting their users at the same
> time to avoid breaking the compilation.
> 
> Signed-off-by: Tomasz Figa <tfiga at chromium.org>
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>

Acked-by: Jingoo Han <jingoohan1 at gmail.com>

Best regards,
Jingoo Han

> ---
> 
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++--------
> -----
>  drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 47
+++++++++++-------
> --
>  include/drm/bridge/analogix_dp.h                   | 19 ++++----
>  4 files changed, 73 insertions(+), 69 deletions(-)
> 



From jingoohan1 at gmail.com  Tue Oct 17 16:43:56 2017
From: jingoohan1 at gmail.com (Jingoo Han)
Date: Tue, 17 Oct 2017 19:43:56 -0400
Subject: [RFC PATCH v4 6/8] drm/bridge/analogix: Do not use device's
 drvdata
In-Reply-To: <20171017101624.12506-7-jeffy.chen@rock-chips.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
 <20171017101624.12506-7-jeffy.chen@rock-chips.com>
Message-ID: <000101d347a1$cd216160$67642420$@gmail.com>

On Tuesday, October 17, 2017 6:16 AM, Jeffy Chen wrote:
> 
> From: Tomasz Figa <tfiga at chromium.org>
> 
> The driver that instantiates the bridge should own the drvdata, as all
> driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
> owned by its driver struct. Moreover, storing two different pointer
> types in driver data depending on driver initialization status is barely
> a good practice and in fact has led to many bugs in this driver.
> 
> Let's clean up this mess and change Analogix entry points to simply
> accept some opaque struct pointer, adjusting their users at the same
> time to avoid breaking the compilation.
> 
> Signed-off-by: Tomasz Figa <tfiga at chromium.org>
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>

Acked-by: Jingoo Han <jingoohan1 at gmail.com>

Best regards,
Jingoo Han

> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++--------
> -----
>  drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 47
+++++++++++-------
> --
>  include/drm/bridge/analogix_dp.h                   | 19 ++++----
>  4 files changed, 73 insertions(+), 69 deletions(-)
> 



From briannorris at chromium.org  Tue Oct 17 17:56:32 2017
From: briannorris at chromium.org (Brian Norris)
Date: Tue, 17 Oct 2017 17:56:32 -0700
Subject: [PATCH 1/3] Documentation/devicetree: Add pcie-reset-suspend
 property
In-Reply-To: <20171017233904.GA65743@google.com>
References: <20171012205220.130048-1-briannorris@chromium.org>
 <20171012205220.130048-2-briannorris@chromium.org>
 <20171013165152.GE25517@bhelgaas-glaptop.roam.corp.google.com>
 <20171017233904.GA65743@google.com>
Message-ID: <CA+ASDXPNcoUE=F+TWsYpxw=e-NcPaqguSRb5fEYC+zoCCdvDvg@mail.gmail.com>

On Tue, Oct 17, 2017 at 4:39 PM, Brian Norris <briannorris at chromium.org> wrote:
> On Fri, Oct 13, 2017 at 11:51:52AM -0500, Bjorn Helgaas wrote:
> > If so, I really don't want to get involved in that, because that's an
> > issue that needs to be resolved by the vendors and the PCI-SIG.  If we
>
> Judging by conversations with these vendors, I can't really imagine them
> proactively dealing with the PCI-SIG on this. Is that really what you
> think will work best?
>
> I personally believe deferring (i.e., ignoring) the problem will not
> cause any change; badly behaved vendors will just do whatever suits
> them, and system designers will have to figure it out somehow -- ACPI
> systems will have platform-specific behavior hidden in firmware; device
> tree systems will do whatever they want out of tree; and the rare device
> tree system that gets upstream support will either have suboptimal power
> management, or have to have these sorts of conversations again. None of
> that puts pressure on an endpoint vendor to talk to the PCI-SIG.

I'll add a little more to my claim about ACPI systems. I chatted a
little more with another engineer on my team who has dealt with ACPI
firmware for a few generations of Intel platforms. Even among the
latest two platforms he dealt with, there have been two different
sorts of chipset bugs (at the host/root complex side, not just the
endpoint) that have yielded different decisions on how to handle
PERST#. This was opaque to Linux though, since that's how system
firmware rolls :)

I expect this will not be the last discrepancy on how to handle
PERST#. And to my knowledge, none of the above initiated any
discussion with the PCI-SIG.

Brian


From briannorris at chromium.org  Tue Oct 17 18:03:14 2017
From: briannorris at chromium.org (Brian Norris)
Date: Tue, 17 Oct 2017 18:03:14 -0700
Subject: [PATCH v6 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171016200350.GH25517@bhelgaas-glaptop.roam.corp.google.com>
References: <20171013195059.23865-1-jeffy.chen@rock-chips.com>
 <20171013195059.23865-2-jeffy.chen@rock-chips.com>
 <20171016200350.GH25517@bhelgaas-glaptop.roam.corp.google.com>
Message-ID: <20171018010312.GB65743@google.com>

On Mon, Oct 16, 2017 at 03:03:50PM -0500, Bjorn Helgaas wrote:
> On Sat, Oct 14, 2017 at 03:50:56AM +0800, Jeffy Chen wrote:
> > Add support for PCIE_WAKE pin in rockchip pcie driver.
> > 
> > Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> > ---
> > 
> > Changes in v6:
> > Fix device_init_wake error handling, and add some comments.
> > 
> > Changes in v5:
> > Rebase
> > 
> > Changes in v3:
> > Fix error handling
> > 
> > Changes in v2:
> > Use dev_pm_set_dedicated_wake_irq
> >         -- Suggested by Brian Norris <briannorris at chromium.com>
> > 
> >  drivers/pci/host/pcie-rockchip.c | 27 +++++++++++++++++++++------
> >  1 file changed, 21 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> > index 9051c6c8fea4..268513b6c9c4 100644
> > --- a/drivers/pci/host/pcie-rockchip.c
> > +++ b/drivers/pci/host/pcie-rockchip.c
...
> > @@ -995,6 +996,17 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
> >  		return err;
> >  	}
> >  
> > +	irq = platform_get_irq_byname(pdev, "wakeup");
> > +	if (irq >= 0) {
> > +		/* Must init wakeup before setting dedicated wakeup irq. */
> > +		device_init_wakeup(dev, true);
> > +		err = dev_pm_set_dedicated_wake_irq(dev, irq);
> > +		if (err) {
> > +			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
> > +			device_init_wakeup(dev, false);
> > +		}
> > +	}
> 
> There's nothing Rockchip-specific here, so I'm hoping you can explore
> putting this support in the PCI core, so any system that describes the
> WAKE# connection in the DT can benefit.

I guess it could work to look into pci_create_root_bus(), and
do something like the following?

	if (IS_ENABLED(CONFIG_OF) && parent && parent->of_node)
		... do OF parsing for generic features like WAKE# ...

Brian


From cw00.choi at samsung.com  Tue Oct 17 19:14:39 2017
From: cw00.choi at samsung.com (Chanwoo Choi)
Date: Wed, 18 Oct 2017 11:14:39 +0900
Subject: [PATCH v2] extcon: Split out extcon header file for consumer
 and provider device
In-Reply-To: <59DEE429.2000608@samsung.com>
References: <CGME20171010101758epcas2p3b3f379076f5be5e81edee2bd00354c28@epcas2p3.samsung.com>
 <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>
 <59DEE429.2000608@samsung.com>
Message-ID: <59E6B90F.8000808@samsung.com>

Gently Ping.

Dear Kishon,

Could you please review this patch for 'drivers/phy/*'?

Regards,
Chanwoo Choi

On 2017? 10? 12? 12:40, Chanwoo Choi wrote:
> Dear Kishon,
> 
> Could you please review this patch?
> After that, I'll make the immutable brand and then send the pull request
> for power_supply, mfd, phy, usb and extcon framework.
> 
> On 2017? 10? 10? 19:17, Chanwoo Choi wrote:
>> The extcon has two type of extcon devices as following.
>> - 'extcon provider deivce' adds new extcon device and detect the
>>    state/properties of external connector. Also, it notifies the
>>    state/properties to the extcon consumer device.
>> - 'extcon consumer device' gets the change state/properties
>>    from extcon provider device.
>> Prior to that, include/linux/extcon.h contains all exported API for
>> both provider and consumer device driver. To clarify the meaning of
>> header file and to remove the wrong use-case on consumer device,
>> this patch separates into extcon.h and extcon-provider.h.
>>
>> [Description for include/linux/{extcon.h|extcon-provider.h}]
>> - extcon.h includes the extcon API and data structure for extcon consumer
>>   device driver. This header file contains the following APIs:
>>   : Register/unregister the notifier to catch the change of extcon device
>>   : Get the extcon device instance
>>   : Get the extcon device name
>>   : Get the state of each external connector
>>   : Get the property value of each external connector
>>   : Get the property capability of each external connector
>>
>> - extcon-provider.h includes the extcon API and data structure for extcon
>>   provider device driver. This header file contains the following APIs:
>>   : Include 'include/linux/extcon.h'
>>   : Allocate the memory for extcon device instance
>>   : Register/unregister extcon device
>>   : Set the state of each external connector
>>   : Set the property value of each external connector
>>   : Set the property capability of each external connector
>>
>> Cc: Felipe Balbi <balbi at kernel.org>
>> Cc: Kishon Vijay Abraham I <kishon at ti.com>
>> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
>> Acked-by: Sebastian Reichel <sebastian.reichel at collabora.co.uk>
>> Acked-by: Chen-Yu Tsai <wens at csie.org>
>> Acked-by: Charles Keepax <ckeepax at opensource.cirrus.com>
>> Acked-by: Lee Jones <lee.jones at linaro.org>
>> Signed-off-by: Chanwoo Choi <cw00.choi at samsung.com>
>> ---
>> Changes from v1:
>> - Don't touch drivers/usb/renesas_usbhs/common.h.
>> - Add acked-by from Sebastian Reichel (for drivers/power/supply/)
>> - Add acked-by from Chen-Yu Tsai (for phy-sun4i-usb.c & extcon-axp288.c)
>> - Add acked-by from Charles Keepax (for drivers/extcon/extcon-arizona.c)
>> - Add acked-by from Lee Jones (fo include/linux/mfd/palmas.h)
>>
>>  drivers/extcon/extcon-adc-jack.c              |   2 +-
>>  drivers/extcon/extcon-arizona.c               |   2 +-
>>  drivers/extcon/extcon-axp288.c                |   2 +-
>>  drivers/extcon/extcon-gpio.c                  |   2 +-
>>  drivers/extcon/extcon-intel-cht-wc.c          |   2 +-
>>  drivers/extcon/extcon-intel-int3496.c         |   2 +-
>>  drivers/extcon/extcon-max14577.c              |   2 +-
>>  drivers/extcon/extcon-max3355.c               |   2 +-
>>  drivers/extcon/extcon-max77693.c              |   2 +-
>>  drivers/extcon/extcon-max77843.c              |   2 +-
>>  drivers/extcon/extcon-max8997.c               |   2 +-
>>  drivers/extcon/extcon-qcom-spmi-misc.c        |   2 +-
>>  drivers/extcon/extcon-rt8973a.c               |   2 +-
>>  drivers/extcon/extcon-sm5502.c                |   2 +-
>>  drivers/extcon/extcon-usb-gpio.c              |   2 +-
>>  drivers/extcon/extcon-usbc-cros-ec.c          |   2 +-
>>  drivers/extcon/extcon.h                       |   2 +-
>>  drivers/phy/allwinner/phy-sun4i-usb.c         |   2 +-
>>  drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c     |   2 +-
>>  drivers/phy/renesas/phy-rcar-gen3-usb2.c      |   2 +-
>>  drivers/phy/rockchip/phy-rockchip-inno-usb2.c |   2 +-
>>  drivers/power/supply/qcom_smbb.c              |   2 +-
>>  drivers/usb/gadget/udc/renesas_usb3.c         |   2 +-
>>  drivers/usb/phy/phy-tahvo.c                   |   2 +-
>>  include/linux/extcon-provider.h               | 142 ++++++++++++++++++++++++++
>>  include/linux/extcon.h                        | 109 +-------------------
>>  include/linux/mfd/palmas.h                    |   2 +-
>>  27 files changed, 172 insertions(+), 129 deletions(-)
>>  create mode 100644 include/linux/extcon-provider.h
>>
>> diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
>> index 6f6537ab0a79..3877d86c746a 100644
>> --- a/drivers/extcon/extcon-adc-jack.c
>> +++ b/drivers/extcon/extcon-adc-jack.c
>> @@ -26,7 +26,7 @@
>>  #include <linux/workqueue.h>
>>  #include <linux/iio/consumer.h>
>>  #include <linux/extcon/extcon-adc-jack.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  
>>  /**
>>   * struct adc_jack_data - internal data for adc_jack device driver
>> diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
>> index f84da4a17724..da0e9bc4262f 100644
>> --- a/drivers/extcon/extcon-arizona.c
>> +++ b/drivers/extcon/extcon-arizona.c
>> @@ -27,7 +27,7 @@
>>  #include <linux/pm_runtime.h>
>>  #include <linux/property.h>
>>  #include <linux/regulator/consumer.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  
>>  #include <sound/soc.h>
>>  
>> diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c
>> index f4fd03e58e37..981fba56bc18 100644
>> --- a/drivers/extcon/extcon-axp288.c
>> +++ b/drivers/extcon/extcon-axp288.c
>> @@ -22,7 +22,7 @@
>>  #include <linux/platform_device.h>
>>  #include <linux/property.h>
>>  #include <linux/notifier.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/regmap.h>
>>  #include <linux/gpio.h>
>>  #include <linux/gpio/consumer.h>
>> diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
>> index ebed22f22d75..ab770adcca7e 100644
>> --- a/drivers/extcon/extcon-gpio.c
>> +++ b/drivers/extcon/extcon-gpio.c
>> @@ -17,7 +17,7 @@
>>   * GNU General Public License for more details.
>>   */
>>  
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/extcon/extcon-gpio.h>
>>  #include <linux/gpio.h>
>>  #include <linux/gpio/consumer.h>
>> diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c
>> index 91a0023074af..7c4bc8c44c3f 100644
>> --- a/drivers/extcon/extcon-intel-cht-wc.c
>> +++ b/drivers/extcon/extcon-intel-cht-wc.c
>> @@ -15,7 +15,7 @@
>>   * more details.
>>   */
>>  
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/kernel.h>
>>  #include <linux/mfd/intel_soc_pmic.h>
>> diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
>> index 1a45e745717d..c8691b5a9cb0 100644
>> --- a/drivers/extcon/extcon-intel-int3496.c
>> +++ b/drivers/extcon/extcon-intel-int3496.c
>> @@ -19,7 +19,7 @@
>>   */
>>  
>>  #include <linux/acpi.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/gpio.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/module.h>
>> diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
>> index f6414b7fa5bc..6c2c9996eb71 100644
>> --- a/drivers/extcon/extcon-max14577.c
>> +++ b/drivers/extcon/extcon-max14577.c
>> @@ -23,7 +23,7 @@
>>  #include <linux/platform_device.h>
>>  #include <linux/mfd/max14577.h>
>>  #include <linux/mfd/max14577-private.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  
>>  #define	DELAY_MS_DEFAULT		17000		/* unit: millisecond */
>>  
>> diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c
>> index 533e16a952b8..0aa410836f4e 100644
>> --- a/drivers/extcon/extcon-max3355.c
>> +++ b/drivers/extcon/extcon-max3355.c
>> @@ -9,7 +9,7 @@
>>   * may be copied, distributed, and modified under those terms.
>>   */
>>  
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/gpio.h>
>>  #include <linux/gpio/consumer.h>
>>  #include <linux/interrupt.h>
>> diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
>> index 7a5856809047..643411066ad9 100644
>> --- a/drivers/extcon/extcon-max77693.c
>> +++ b/drivers/extcon/extcon-max77693.c
>> @@ -26,7 +26,7 @@
>>  #include <linux/mfd/max77693.h>
>>  #include <linux/mfd/max77693-common.h>
>>  #include <linux/mfd/max77693-private.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/regmap.h>
>>  #include <linux/irqdomain.h>
>>  
>> diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
>> index 6e722d552cf1..28f251ff0fa2 100644
>> --- a/drivers/extcon/extcon-max77843.c
>> +++ b/drivers/extcon/extcon-max77843.c
>> @@ -11,7 +11,7 @@
>>   * (at your option) any later version.
>>   */
>>  
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/i2c.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/kernel.h>
>> diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
>> index 4a0612fb9c07..8152790d72e1 100644
>> --- a/drivers/extcon/extcon-max8997.c
>> +++ b/drivers/extcon/extcon-max8997.c
>> @@ -25,7 +25,7 @@
>>  #include <linux/kobject.h>
>>  #include <linux/mfd/max8997.h>
>>  #include <linux/mfd/max8997-private.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/irqdomain.h>
>>  
>>  #define	DEV_NAME			"max8997-muic"
>> diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c
>> index b8cde096a808..660bbf163bf5 100644
>> --- a/drivers/extcon/extcon-qcom-spmi-misc.c
>> +++ b/drivers/extcon/extcon-qcom-spmi-misc.c
>> @@ -15,7 +15,7 @@
>>   * GNU General Public License for more details.
>>   */
>>  
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/init.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/kernel.h>
>> diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
>> index eaa355e7d9e4..e059bd5f2041 100644
>> --- a/drivers/extcon/extcon-rt8973a.c
>> +++ b/drivers/extcon/extcon-rt8973a.c
>> @@ -20,7 +20,7 @@
>>  #include <linux/platform_device.h>
>>  #include <linux/regmap.h>
>>  #include <linux/slab.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  
>>  #include "extcon-rt8973a.h"
>>  
>> diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
>> index 106ef0297b53..0cfb5a3efdf6 100644
>> --- a/drivers/extcon/extcon-sm5502.c
>> +++ b/drivers/extcon/extcon-sm5502.c
>> @@ -19,7 +19,7 @@
>>  #include <linux/platform_device.h>
>>  #include <linux/regmap.h>
>>  #include <linux/slab.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  
>>  #include "extcon-sm5502.h"
>>  
>> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
>> index 9c925b05b7aa..53762864a9f7 100644
>> --- a/drivers/extcon/extcon-usb-gpio.c
>> +++ b/drivers/extcon/extcon-usb-gpio.c
>> @@ -14,7 +14,7 @@
>>   * GNU General Public License for more details.
>>   */
>>  
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/gpio.h>
>>  #include <linux/gpio/consumer.h>
>>  #include <linux/init.h>
>> diff --git a/drivers/extcon/extcon-usbc-cros-ec.c b/drivers/extcon/extcon-usbc-cros-ec.c
>> index 598956f1dcae..6187f731b29d 100644
>> --- a/drivers/extcon/extcon-usbc-cros-ec.c
>> +++ b/drivers/extcon/extcon-usbc-cros-ec.c
>> @@ -14,7 +14,7 @@
>>   * GNU General Public License for more details.
>>   */
>>  
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/kernel.h>
>>  #include <linux/mfd/cros_ec.h>
>>  #include <linux/module.h>
>> diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h
>> index dddddcfa0587..cc1b436eb66a 100644
>> --- a/drivers/extcon/extcon.h
>> +++ b/drivers/extcon/extcon.h
>> @@ -1,7 +1,7 @@
>>  #ifndef __LINUX_EXTCON_INTERNAL_H__
>>  #define __LINUX_EXTCON_INTERNAL_H__
>>  
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  
>>  /**
>>   * struct extcon_dev - An extcon device represents one external connector.
>> diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
>> index 1161e11fb3cf..ef34f97f214b 100644
>> --- a/drivers/phy/allwinner/phy-sun4i-usb.c
>> +++ b/drivers/phy/allwinner/phy-sun4i-usb.c
>> @@ -24,7 +24,7 @@
>>  #include <linux/clk.h>
>>  #include <linux/delay.h>
>>  #include <linux/err.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/io.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/kernel.h>
>> diff --git a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
>> index d099a0c8cee5..7ceea5ae2704 100644
>> --- a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
>> +++ b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
>> @@ -12,7 +12,7 @@
>>   */
>>  
>>  #include <linux/delay.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/gpio.h>
>>  #include <linux/gpio/consumer.h>
>>  #include <linux/init.h>
>> diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
>> index 54c34298a000..b33e2994ccce 100644
>> --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
>> +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
>> @@ -12,7 +12,7 @@
>>   * published by the Free Software Foundation.
>>   */
>>  
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/io.h>
>>  #include <linux/module.h>
>> diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
>> index ee7ce5ee53f9..5049dac79bd0 100644
>> --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
>> +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
>> @@ -17,7 +17,7 @@
>>  #include <linux/clk.h>
>>  #include <linux/clk-provider.h>
>>  #include <linux/delay.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/io.h>
>>  #include <linux/gpio/consumer.h>
>> diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c
>> index f6a0d245731d..11de691b9a71 100644
>> --- a/drivers/power/supply/qcom_smbb.c
>> +++ b/drivers/power/supply/qcom_smbb.c
>> @@ -34,7 +34,7 @@
>>  #include <linux/power_supply.h>
>>  #include <linux/regmap.h>
>>  #include <linux/slab.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/regulator/driver.h>
>>  
>>  #define SMBB_CHG_VMAX		0x040
>> diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
>> index df37c1e6e9d5..8b4d051fdbed 100644
>> --- a/drivers/usb/gadget/udc/renesas_usb3.c
>> +++ b/drivers/usb/gadget/udc/renesas_usb3.c
>> @@ -12,7 +12,7 @@
>>  #include <linux/delay.h>
>>  #include <linux/dma-mapping.h>
>>  #include <linux/err.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/interrupt.h>
>>  #include <linux/io.h>
>>  #include <linux/module.h>
>> diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c
>> index 8babd318c0ed..354e8c98af05 100644
>> --- a/drivers/usb/phy/phy-tahvo.c
>> +++ b/drivers/usb/phy/phy-tahvo.c
>> @@ -23,7 +23,7 @@
>>  #include <linux/io.h>
>>  #include <linux/clk.h>
>>  #include <linux/usb.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/kernel.h>
>>  #include <linux/module.h>
>>  #include <linux/usb/otg.h>
>> diff --git a/include/linux/extcon-provider.h b/include/linux/extcon-provider.h
>> new file mode 100644
>> index 000000000000..2feca5881fa7
>> --- /dev/null
>> +++ b/include/linux/extcon-provider.h
>> @@ -0,0 +1,142 @@
>> +/*
>> + * External Connector (extcon) framework
>> + * - linux/include/linux/extcon-provider.h for extcon provider device driver.
>> + *
>> + * Copyright (C) 2017 Samsung Electronics
>> + * Author: Chanwoo Choi <cw00.choi at samsung.com>
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * 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 __LINUX_EXTCON_PROVIDER_H__
>> +#define __LINUX_EXTCON_PROVIDER_H__
>> +
>> +#include <linux/extcon.h>
>> +
>> +struct extcon_dev;
>> +
>> +#if IS_ENABLED(CONFIG_EXTCON)
>> +
>> +/* Following APIs register/unregister the extcon device. */
>> +extern int extcon_dev_register(struct extcon_dev *edev);
>> +extern void extcon_dev_unregister(struct extcon_dev *edev);
>> +extern int devm_extcon_dev_register(struct device *dev,
>> +				struct extcon_dev *edev);
>> +extern void devm_extcon_dev_unregister(struct device *dev,
>> +				struct extcon_dev *edev);
>> +
>> +/* Following APIs allocate/free the memory of the extcon device. */
>> +extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable);
>> +extern void extcon_dev_free(struct extcon_dev *edev);
>> +extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
>> +				const unsigned int *cable);
>> +extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
>> +
>> +/* Synchronize the state and property value for each external connector. */
>> +extern int extcon_sync(struct extcon_dev *edev, unsigned int id);
>> +
>> +/*
>> + * Following APIs set the connected state of each external connector.
>> + * The 'id' argument indicates the defined external connector.
>> + */
>> +extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>> +				bool state);
>> +extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
>> +				bool state);
>> +
>> +/*
>> + * Following APIs set the property of each external connector.
>> + * The 'id' argument indicates the defined external connector
>> + * and the 'prop' indicates the extcon property.
>> + *
>> + * And extcon_set_property_capability() set the capability of the property
>> + * for each external connector. They are used to set the capability of the
>> + * property of each external connector based on the id and property.
>> + */
>> +extern int extcon_set_property(struct extcon_dev *edev, unsigned int id,
>> +				unsigned int prop,
>> +				union extcon_property_value prop_val);
>> +extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
>> +				unsigned int prop,
>> +				union extcon_property_value prop_val);
>> +extern int extcon_set_property_capability(struct extcon_dev *edev,
>> +				unsigned int id, unsigned int prop);
>> +
>> +#else /* CONFIG_EXTCON */
>> +static inline int extcon_dev_register(struct extcon_dev *edev)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
>> +
>> +static inline int devm_extcon_dev_register(struct device *dev,
>> +				struct extcon_dev *edev)
>> +{
>> +	return -EINVAL;
>> +}
>> +
>> +static inline void devm_extcon_dev_unregister(struct device *dev,
>> +				struct extcon_dev *edev) { }
>> +
>> +static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable)
>> +{
>> +	return ERR_PTR(-ENOSYS);
>> +}
>> +
>> +static inline void extcon_dev_free(struct extcon_dev *edev) { }
>> +
>> +static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
>> +				const unsigned int *cable)
>> +{
>> +	return ERR_PTR(-ENOSYS);
>> +}
>> +
>> +static inline void devm_extcon_dev_free(struct extcon_dev *edev) { }
>> +
>> +
>> +static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>> +				bool state)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
>> +				bool state)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
>> +				unsigned int prop,
>> +				union extcon_property_value prop_val)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline int extcon_set_property_sync(struct extcon_dev *edev,
>> +				unsigned int id, unsigned int prop,
>> +				union extcon_property_value prop_val)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline int extcon_set_property_capability(struct extcon_dev *edev,
>> +				unsigned int id, unsigned int prop)
>> +{
>> +	return 0;
>> +}
>> +#endif /* CONFIG_EXTCON */
>> +#endif /* __LINUX_EXTCON_PROVIDER_H__ */
>> diff --git a/include/linux/extcon.h b/include/linux/extcon.h
>> index 744d60ca80c3..6d94e82c8ad9 100644
>> --- a/include/linux/extcon.h
>> +++ b/include/linux/extcon.h
>> @@ -1,5 +1,6 @@
>>  /*
>>   * External Connector (extcon) framework
>> + * - linux/include/linux/extcon.h for extcon consumer device driver.
>>   *
>>   * Copyright (C) 2015 Samsung Electronics
>>   * Author: Chanwoo Choi <cw00.choi at samsung.com>
>> @@ -170,61 +171,29 @@
>>  	int intval;	/* type : integer (intval) */
>>  };
>>  
>> -struct extcon_cable;
>>  struct extcon_dev;
>>  
>>  #if IS_ENABLED(CONFIG_EXTCON)
>> -
>> -/* Following APIs register/unregister the extcon device. */
>> -extern int extcon_dev_register(struct extcon_dev *edev);
>> -extern void extcon_dev_unregister(struct extcon_dev *edev);
>> -extern int devm_extcon_dev_register(struct device *dev,
>> -				struct extcon_dev *edev);
>> -extern void devm_extcon_dev_unregister(struct device *dev,
>> -				struct extcon_dev *edev);
>> -
>> -/* Following APIs allocate/free the memory of the extcon device. */
>> -extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable);
>> -extern void extcon_dev_free(struct extcon_dev *edev);
>> -extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
>> -				const unsigned int *cable);
>> -extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
>> -
>> -/* Synchronize the state and property value for each external connector. */
>> -extern int extcon_sync(struct extcon_dev *edev, unsigned int id);
>> -
>>  /*
>> - * Following APIs get/set the connected state of each external connector.
>> + * Following APIs get the connected state of each external connector.
>>   * The 'id' argument indicates the defined external connector.
>>   */
>>  extern int extcon_get_state(struct extcon_dev *edev, unsigned int id);
>> -extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>> -				bool state);
>> -extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
>> -				bool state);
>>  
>>  /*
>> - * Following APIs get/set the property of each external connector.
>> + * Following APIs get the property of each external connector.
>>   * The 'id' argument indicates the defined external connector
>>   * and the 'prop' indicates the extcon property.
>>   *
>> - * And extcon_get/set_property_capability() set the capability of the property
>> - * for each external connector. They are used to set the capability of the
>> + * And extcon_get_property_capability() get the capability of the property
>> + * for each external connector. They are used to get the capability of the
>>   * property of each external connector based on the id and property.
>>   */
>>  extern int extcon_get_property(struct extcon_dev *edev, unsigned int id,
>>  				unsigned int prop,
>>  				union extcon_property_value *prop_val);
>> -extern int extcon_set_property(struct extcon_dev *edev, unsigned int id,
>> -				unsigned int prop,
>> -				union extcon_property_value prop_val);
>> -extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
>> -				unsigned int prop,
>> -				union extcon_property_value prop_val);
>>  extern int extcon_get_property_capability(struct extcon_dev *edev,
>>  				unsigned int id, unsigned int prop);
>> -extern int extcon_set_property_capability(struct extcon_dev *edev,
>> -				unsigned int id, unsigned int prop);
>>  
>>  /*
>>   * Following APIs register the notifier block in order to detect
>> @@ -268,79 +237,17 @@ extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
>>  extern const char *extcon_get_edev_name(struct extcon_dev *edev);
>>  
>>  #else /* CONFIG_EXTCON */
>> -static inline int extcon_dev_register(struct extcon_dev *edev)
>> -{
>> -	return 0;
>> -}
>> -
>> -static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
>> -
>> -static inline int devm_extcon_dev_register(struct device *dev,
>> -				struct extcon_dev *edev)
>> -{
>> -	return -EINVAL;
>> -}
>> -
>> -static inline void devm_extcon_dev_unregister(struct device *dev,
>> -				struct extcon_dev *edev) { }
>> -
>> -static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable)
>> -{
>> -	return ERR_PTR(-ENOSYS);
>> -}
>> -
>> -static inline void extcon_dev_free(struct extcon_dev *edev) { }
>> -
>> -static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
>> -				const unsigned int *cable)
>> -{
>> -	return ERR_PTR(-ENOSYS);
>> -}
>> -
>> -static inline void devm_extcon_dev_free(struct extcon_dev *edev) { }
>> -
>> -
>>  static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id)
>>  {
>>  	return 0;
>>  }
>>  
>> -static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>> -				bool state)
>> -{
>> -	return 0;
>> -}
>> -
>> -static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
>> -				bool state)
>> -{
>> -	return 0;
>> -}
>> -
>> -static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
>> -{
>> -	return 0;
>> -}
>> -
>>  static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id,
>>  				unsigned int prop,
>>  				union extcon_property_value *prop_val)
>>  {
>>  	return 0;
>>  }
>> -static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
>> -				unsigned int prop,
>> -				union extcon_property_value prop_val)
>> -{
>> -	return 0;
>> -}
>> -
>> -static inline int extcon_set_property_sync(struct extcon_dev *edev,
>> -				unsigned int id, unsigned int prop,
>> -				union extcon_property_value prop_val)
>> -{
>> -	return 0;
>> -}
>>  
>>  static inline int extcon_get_property_capability(struct extcon_dev *edev,
>>  				unsigned int id, unsigned int prop)
>> @@ -348,12 +255,6 @@ static inline int extcon_get_property_capability(struct extcon_dev *edev,
>>  	return 0;
>>  }
>>  
>> -static inline int extcon_set_property_capability(struct extcon_dev *edev,
>> -				unsigned int id, unsigned int prop)
>> -{
>> -	return 0;
>> -}
>> -
>>  static inline int extcon_register_notifier(struct extcon_dev *edev,
>>  				unsigned int id, struct notifier_block *nb)
>>  {
>> diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
>> index 6dec43826303..3c8568aa82a5 100644
>> --- a/include/linux/mfd/palmas.h
>> +++ b/include/linux/mfd/palmas.h
>> @@ -20,7 +20,7 @@
>>  #include <linux/leds.h>
>>  #include <linux/regmap.h>
>>  #include <linux/regulator/driver.h>
>> -#include <linux/extcon.h>
>> +#include <linux/extcon-provider.h>
>>  #include <linux/of_gpio.h>
>>  #include <linux/usb/phy_companion.h>
>>  
>>
> 
> 


From architt at codeaurora.org  Tue Oct 17 21:46:08 2017
From: architt at codeaurora.org (Archit Taneja)
Date: Wed, 18 Oct 2017 10:16:08 +0530
Subject: [RFC PATCH v4 6/8] drm/bridge/analogix: Do not use device's
 drvdata
In-Reply-To: <000101d347a1$cd216160$67642420$@gmail.com>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
 <20171017101624.12506-7-jeffy.chen@rock-chips.com>
 <000101d347a1$cd216160$67642420$@gmail.com>
Message-ID: <c11c1115-58fb-f6d4-56f8-05277a9ccea9@codeaurora.org>

Hi,

On 10/18/2017 05:13 AM, Jingoo Han wrote:
> On Tuesday, October 17, 2017 6:16 AM, Jeffy Chen wrote:
>>
>> From: Tomasz Figa <tfiga at chromium.org>
>>
>> The driver that instantiates the bridge should own the drvdata, as all
>> driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
>> owned by its driver struct. Moreover, storing two different pointer
>> types in driver data depending on driver initialization status is barely
>> a good practice and in fact has led to many bugs in this driver.
>>
>> Let's clean up this mess and change Analogix entry points to simply
>> accept some opaque struct pointer, adjusting their users at the same
>> time to avoid breaking the compilation.
>>
>> Signed-off-by: Tomasz Figa <tfiga at chromium.org>
>> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
>> Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>
> 

This depends on previous patches of the series. I guess it would be easier
to queue this to drm-misc as a part of the eDP support series. For that:

Acked-by: Archit Taneja <architt at codeaurora.org>

> Acked-by: Jingoo Han <jingoohan1 at gmail.com>
> 
> Best regards,
> Jingoo Han
> 
>> ---
>>
>> Changes in v4: None
>> Changes in v3: None
>> Changes in v2: None
>>
>>   drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++--------
>> -----
>>   drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
>>   drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 47
> +++++++++++-------
>> --
>>   include/drm/bridge/analogix_dp.h                   | 19 ++++----
>>   4 files changed, 73 insertions(+), 69 deletions(-)
>>
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From kishon at ti.com  Wed Oct 18 04:19:27 2017
From: kishon at ti.com (Kishon Vijay Abraham I)
Date: Wed, 18 Oct 2017 16:49:27 +0530
Subject: [PATCH v3 4/4] phy: rockchip-typec: Do the calibration more
 correctly
In-Reply-To: <20170922164406.27606-5-dianders@chromium.org>
References: <20170922164406.27606-1-dianders@chromium.org>
 <20170922164406.27606-5-dianders@chromium.org>
Message-ID: <e357cfd7-b5a3-29d8-02d7-2bf75a05aa19@ti.com>



On Friday 22 September 2017 10:14 PM, Douglas Anderson wrote:
> Calculate the calibration code as per the docs.  The docs talk about
> reading and averaging the pullup and pulldown calibration codes.  They
> also talk about adding in some adjustment codes.  Let's do what the
> docs say.
> 
> In practice this doesn't seem to matter a whole lot.  On a device I
> tested the pullup and pulldown codes were nearly the same (0x23 and
> 0x24) and the adjustment codes were 0.
> 
> Reviewed-by: Chris Zhong <zyw at rock-chips.com>
> Signed-off-by: Douglas Anderson <dianders at chromium.org>

merged the 3rd and 4th patch to next. Thanks!

-Kishon
> ---
> 
> Changes in v3: None
> Changes in v2:
> - Removed extra blank line.
> 
>  drivers/phy/rockchip/phy-rockchip-typec.c | 27 ++++++++++++++++++---------
>  1 file changed, 18 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
> index 95f8f23676b4..a96635447d48 100644
> --- a/drivers/phy/rockchip/phy-rockchip-typec.c
> +++ b/drivers/phy/rockchip/phy-rockchip-typec.c
> @@ -560,24 +560,33 @@ static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
>  	u16 val;
>  	u16 tx_ana_ctrl_reg_1;
>  	u16 tx_ana_ctrl_reg_2;
> -	s32 pu_calib_code;
> -
> -	/* disable txda_cal_latch_en for rewrite the calibration values */
> -	tx_ana_ctrl_reg_1 = readl(tcphy->base + TX_ANA_CTRL_REG_1);
> -	tx_ana_ctrl_reg_1 &= ~TXDA_CAL_LATCH_EN;
> -	writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
> +	s32 pu_calib_code, pd_calib_code;
> +	s32 pu_adj, pd_adj;
> +	u16 calib;
>  
>  	/*
> -	 * read a resistor calibration code from CMN_TXPUCAL_CTRL[5:0] and
> -	 * write it to TX_DIG_CTRL_REG_2[5:0].
> +	 * Calculate calibration code as per docs: use an average of the
> +	 * pull down and pull up.  Then add in adjustments.
>  	 */
>  	val = readl(tcphy->base + CMN_TXPUCAL_CTRL);
>  	pu_calib_code = CMN_CALIB_CODE_POS(val);
> +	val = readl(tcphy->base + CMN_TXPDCAL_CTRL);
> +	pd_calib_code = CMN_CALIB_CODE_POS(val);
> +	val = readl(tcphy->base + CMN_TXPU_ADJ_CTRL);
> +	pu_adj = CMN_CALIB_CODE(val);
> +	val = readl(tcphy->base + CMN_TXPD_ADJ_CTRL);
> +	pd_adj = CMN_CALIB_CODE(val);
> +	calib = (pu_calib_code + pd_calib_code) / 2 + pu_adj + pd_adj;
> +
> +	/* disable txda_cal_latch_en for rewrite the calibration values */
> +	tx_ana_ctrl_reg_1 = readl(tcphy->base + TX_ANA_CTRL_REG_1);
> +	tx_ana_ctrl_reg_1 &= ~TXDA_CAL_LATCH_EN;
> +	writel(tx_ana_ctrl_reg_1, tcphy->base + TX_ANA_CTRL_REG_1);
>  
>  	/* write the calibration, then delay 10 ms as sample in docs */
>  	val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
>  	val &= ~(TX_RESCAL_CODE_MASK << TX_RESCAL_CODE_OFFSET);
> -	val |= pu_calib_code << TX_RESCAL_CODE_OFFSET;
> +	val |= calib << TX_RESCAL_CODE_OFFSET;
>  	writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
>  	usleep_range(10000, 10050);
>  
> 


From jeffy.chen at rock-chips.com  Wed Oct 18 05:09:35 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Wed, 18 Oct 2017 20:09:35 +0800
Subject: [PATCH v5 0/9] rockchip: kevin: Enable edp display
Message-ID: <20171018120944.7819-1-jeffy.chen@rock-chips.com>


Make edp display works on chromebook kevin(at least for boot animation).

Also solve some issues i meet during the bringup.

Changes in v5:
Call the destroy hook in the error handling path like in unbind().
Call the destroy hook in the error handling path like in unbind().
Update cleanup order in unbind().
Add disable to unbind(), and inline clk_prepare_enable() with bind().

Jeffy Chen (9):
  arm64: dts: rockchip: Enable edp disaplay on kevin
  drm/rockchip: analogix_dp: Remove unnecessary init code
  drm/bridge: analogix: Do not use device's drvdata
  drm/bridge: analogix_dp: Fix connector & encoder cleanup
  drm/rockchip: dw-mipi-dsi: Fix error handling path
  drm/rockchip: inno_hdmi: Fix error handling path
  drm/bridge/synopsys: dw-hdmi: Add missing bridge detach
  drm/bridge/synopsys: dw-hdmi: Do not use device's drvdata
  drm/rockchip: dw_hdmi: Fix error handling path

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts  | 29 ++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi       | 16 ++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 52 +++++--------
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          | 53 ++++++-------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 29 +++++---
 drivers/gpu/drm/imx/dw_hdmi-imx.c                  | 22 +++---
 drivers/gpu/drm/meson/meson_dw_hdmi.c              | 20 +++--
 drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c             | 14 +++-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 87 ++++++++++------------
 drivers/gpu/drm/rockchip/dw-mipi-dsi.c             | 21 ++++--
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c        | 39 +++++-----
 drivers/gpu/drm/rockchip/inno_hdmi.c               | 22 ++++--
 include/drm/bridge/analogix_dp.h                   | 19 +++--
 include/drm/bridge/dw_hdmi.h                       | 17 +++--
 14 files changed, 257 insertions(+), 183 deletions(-)

-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 05:09:36 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Wed, 18 Oct 2017 20:09:36 +0800
Subject: [PATCH v5 1/9] arm64: dts: rockchip: Enable edp disaplay on kevin
In-Reply-To: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
Message-ID: <20171018120944.7819-2-jeffy.chen@rock-chips.com>

Add edp panel and enable related nodes on kevin.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Mark Yao <mark.yao at rock-chips.com>

---

Changes in v5: None

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index a3d3cea7dc4f..bc67b19f0af5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -93,6 +93,18 @@
 		pwm-delay-us = <10000>;
 	};
 
+	edp_panel: edp-panel {
+		compatible = "sharp,lq123p1jx31", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&pp3300_disp>;
+
+		ports {
+			panel_in_edp: endpoint {
+				remote-endpoint = <&edp_out_panel>;
+			};
+		};
+	};
+
 	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
 		compatible = "murata,ncp15wb473";
 		pullup-uv = <1800000>;
@@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
 	};
 };
 
+&edp {
+	status = "okay";
+
+	ports {
+		edp_out: port at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_out_panel: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&panel_in_edp>;
+			};
+		};
+	};
+};
+
 &ppvar_bigcpu_pwm {
 	regulator-min-microvolt = <798674>;
 	regulator-max-microvolt = <1302172>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..470105d651c2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
 	dr_mode = "host";
 };
 
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
 #include <arm/cros-ec-keyboard.dtsi>
 #include <arm/cros-ec-sbs.dtsi>
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 05:09:37 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Wed, 18 Oct 2017 20:09:37 +0800
Subject: [PATCH v5 2/9] drm/rockchip: analogix_dp: Remove unnecessary init code
In-Reply-To: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
Message-ID: <20171018120944.7819-3-jeffy.chen@rock-chips.com>

Remove unnecessary init code, since we would do it in the power_on()
callback.

Also move of parse code to probe().

Fixes: 9e32e16e9e98 ("drm: rockchip: dp: add rockchip platform dp driver")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v5: None

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 27 ++++++-------------------
 1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 4d3f6ad0abdd..8cae5ad926cd 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -269,7 +269,7 @@ static struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
 	.destroy = rockchip_dp_drm_encoder_destroy,
 };
 
-static int rockchip_dp_init(struct rockchip_dp_device *dp)
+static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
 {
 	struct device *dev = dp->dev;
 	struct device_node *np = dev->of_node;
@@ -303,19 +303,6 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp)
 		return PTR_ERR(dp->rst);
 	}
 
-	ret = clk_prepare_enable(dp->pclk);
-	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret);
-		return ret;
-	}
-
-	ret = rockchip_dp_pre_init(dp);
-	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "failed to pre init %d\n", ret);
-		clk_disable_unprepare(dp->pclk);
-		return ret;
-	}
-
 	return 0;
 }
 
@@ -361,10 +348,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	if (!dp_data)
 		return -ENODEV;
 
-	ret = rockchip_dp_init(dp);
-	if (ret < 0)
-		return ret;
-
 	dp->data = dp_data;
 	dp->drm_dev = drm_dev;
 
@@ -398,7 +381,6 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 	rockchip_drm_psr_unregister(&dp->encoder);
 
 	analogix_dp_unbind(dev, master, data);
-	clk_disable_unprepare(dp->pclk);
 }
 
 static const struct component_ops rockchip_dp_component_ops = {
@@ -414,7 +396,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 	int ret;
 
 	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
-	if (ret)
+	if (ret < 0)
 		return ret;
 
 	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
@@ -422,9 +404,12 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	dp->dev = dev;
-
 	dp->plat_data.panel = panel;
 
+	ret = rockchip_dp_of_probe(dp);
+	if (ret < 0)
+		return ret;
+
 	/*
 	 * We just use the drvdata until driver run into component
 	 * add function, and then we would set drvdata to null, so
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 05:09:39 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Wed, 18 Oct 2017 20:09:39 +0800
Subject: [PATCH v5 4/9] drm/bridge: analogix_dp: Fix connector & encoder
 cleanup
In-Reply-To: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
Message-ID: <20171018120944.7819-5-jeffy.chen@rock-chips.com>

Since we are initing connector in the core driver and encoder in the
plat driver, let's clean them up in the right places.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v5: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  2 --
 drivers/gpu/drm/exynos/exynos_dp.c                 |  7 +++++--
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 15 ++++++---------
 3 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 74d274b6d31d..3f910ab36ff6 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1409,7 +1409,6 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	ret = analogix_dp_create_bridge(drm_dev, dp);
 	if (ret) {
 		DRM_ERROR("failed to create bridge (%d)\n", ret);
-		drm_encoder_cleanup(dp->encoder);
 		goto err_disable_pm_runtime;
 	}
 
@@ -1432,7 +1431,6 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
 {
 	analogix_dp_bridge_disable(dp->bridge);
 	dp->connector.funcs->destroy(&dp->connector);
-	dp->encoder->funcs->destroy(dp->encoder);
 
 	if (dp->plat_data->panel) {
 		if (drm_panel_unprepare(dp->plat_data->panel))
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index f7e5b2c405ed..33319a858f3a 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -185,8 +185,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 	dp->plat_data.encoder = encoder;
 
 	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-	if (IS_ERR(dp->adp))
+	if (IS_ERR(dp->adp)) {
+		dp->encoder.funcs->destroy(&dp->encoder);
 		return PTR_ERR(dp->adp);
+	}
 
 	return 0;
 }
@@ -196,7 +198,8 @@ static void exynos_dp_unbind(struct device *dev, struct device *master,
 {
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-	return analogix_dp_unbind(dp->adp);
+	analogix_dp_unbind(dp->adp);
+	dp->encoder.funcs->destroy(&dp->encoder);
 }
 
 static const struct component_ops exynos_dp_ops = {
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index fa0365de31d2..c0fb3f3748f4 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -261,13 +261,8 @@ static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = {
 	.atomic_check = rockchip_dp_drm_encoder_atomic_check,
 };
 
-static void rockchip_dp_drm_encoder_destroy(struct drm_encoder *encoder)
-{
-	drm_encoder_cleanup(encoder);
-}
-
 static struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
-	.destroy = rockchip_dp_drm_encoder_destroy,
+	.destroy = drm_encoder_cleanup,
 };
 
 static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
@@ -361,12 +356,13 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
 	INIT_WORK(&dp->psr_work, analogix_dp_psr_work);
 
-	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
-
 	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-	if (IS_ERR(dp->adp))
+	if (IS_ERR(dp->adp)) {
+		dp->encoder.funcs->destroy(&dp->encoder);
 		return PTR_ERR(dp->adp);
+	}
 
+	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 	return 0;
 }
 
@@ -377,6 +373,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_unregister(&dp->encoder);
 	analogix_dp_unbind(dp->adp);
+	dp->encoder.funcs->destroy(&dp->encoder);
 }
 
 static const struct component_ops rockchip_dp_component_ops = {
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 05:09:38 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Wed, 18 Oct 2017 20:09:38 +0800
Subject: [PATCH v5 3/9] drm/bridge: analogix: Do not use device's drvdata
In-Reply-To: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
Message-ID: <20171018120944.7819-4-jeffy.chen@rock-chips.com>

The driver that instantiates the bridge should own the drvdata, as all
driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
owned by its driver struct. Moreover, storing two different pointer
types in driver data depending on driver initialization status is barely
a good practice and in fact has led to many bugs in this driver.

Let's clean up this mess and change Analogix entry points to simply
accept some opaque struct pointer, adjusting their users at the same
time to avoid breaking the compilation.

Signed-off-by: Tomasz Figa <tfiga at chromium.org>
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>
Reviewed-by: Sean Paul <seanpaul at chromium.org>
Acked-by: Jingoo Han <jingoohan1 at gmail.com>
Acked-by: Archit Taneja <architt at codeaurora.org>
---

Changes in v5: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++-------------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 49 ++++++++++++---------
 include/drm/bridge/analogix_dp.h                   | 19 ++++----
 4 files changed, 74 insertions(+), 70 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5dd3f1cd074a..74d274b6d31d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -98,17 +98,15 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
 	return 0;
 }
 
-int analogix_dp_psr_supported(struct device *dev)
+int analogix_dp_psr_supported(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 
 	return dp->psr_support;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
 
-int analogix_dp_enable_psr(struct device *dev)
+int analogix_dp_enable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 
 	if (!dp->psr_support)
@@ -129,9 +127,8 @@ int analogix_dp_enable_psr(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
-int analogix_dp_disable_psr(struct device *dev)
+int analogix_dp_disable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 	int ret;
 
@@ -1281,8 +1278,9 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
 	return analogix_dp_transfer(dp, msg);
 }
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data)
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct analogix_dp_device *dp;
@@ -1292,14 +1290,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (!plat_data) {
 		dev_err(dev, "Invalided input plat_data\n");
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
 	if (!dp)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, dp);
+		return ERR_PTR(-ENOMEM);
 
 	dp->dev = &pdev->dev;
 	dp->dpms_mode = DRM_MODE_DPMS_OFF;
@@ -1316,7 +1312,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	ret = analogix_dp_dt_parse_pdata(dp);
 	if (ret)
-		return ret;
+		return ERR_PTR(ret);
 
 	dp->phy = devm_phy_get(dp->dev, "dp");
 	if (IS_ERR(dp->phy)) {
@@ -1330,14 +1326,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 			if (ret == -ENOSYS || ret == -ENODEV)
 				dp->phy = NULL;
 			else
-				return ret;
+				return ERR_PTR(ret);
 		}
 	}
 
 	dp->clock = devm_clk_get(&pdev->dev, "dp");
 	if (IS_ERR(dp->clock)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
-		return PTR_ERR(dp->clock);
+		return ERR_CAST(dp->clock);
 	}
 
 	clk_prepare_enable(dp->clock);
@@ -1346,7 +1342,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(dp->reg_base))
-		return PTR_ERR(dp->reg_base);
+		return ERR_CAST(dp->reg_base);
 
 	dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
 
@@ -1367,7 +1363,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 					    "hpd_gpio");
 		if (ret) {
 			dev_err(&pdev->dev, "failed to get hpd gpio\n");
-			return ret;
+			return ERR_PTR(ret);
 		}
 		dp->irq = gpio_to_irq(dp->hpd_gpio);
 		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@@ -1379,7 +1375,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (dp->irq == -ENXIO) {
 		dev_err(&pdev->dev, "failed to get irq\n");
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 	}
 
 	pm_runtime_enable(dev);
@@ -1420,7 +1416,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	phy_power_off(dp->phy);
 	pm_runtime_put(dev);
 
-	return 0;
+	return dp;
 
 err_disable_pm_runtime:
 
@@ -1428,15 +1424,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	pm_runtime_put(dev);
 	pm_runtime_disable(dev);
 
-	return ret;
+	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_bind);
 
-void analogix_dp_unbind(struct device *dev, struct device *master,
-			void *data)
+void analogix_dp_unbind(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	analogix_dp_bridge_disable(dp->bridge);
 	dp->connector.funcs->destroy(&dp->connector);
 	dp->encoder->funcs->destroy(dp->encoder);
@@ -1449,16 +1442,14 @@ void analogix_dp_unbind(struct device *dev, struct device *master,
 	}
 
 	drm_dp_aux_unregister(&dp->aux);
-	pm_runtime_disable(dev);
+	pm_runtime_disable(dp->dev);
 	clk_disable_unprepare(dp->clock);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_unbind);
 
 #ifdef CONFIG_PM
-int analogix_dp_suspend(struct device *dev)
+int analogix_dp_suspend(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	clk_disable_unprepare(dp->clock);
 
 	if (dp->plat_data->panel) {
@@ -1470,9 +1461,8 @@ int analogix_dp_suspend(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_suspend);
 
-int analogix_dp_resume(struct device *dev)
+int analogix_dp_resume(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	int ret;
 
 	ret = clk_prepare_enable(dp->clock);
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 39629e7a80b9..f7e5b2c405ed 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -41,6 +41,7 @@ struct exynos_dp_device {
 	struct device              *dev;
 
 	struct videomode           vm;
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -157,13 +158,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp->dev = dev;
 	dp->drm_dev = drm_dev;
 
@@ -190,13 +184,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
 	dp->plat_data.encoder = encoder;
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp))
+		return PTR_ERR(dp->adp);
+
+	return 0;
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
 			     void *data)
 {
-	return analogix_dp_unbind(dev, master, data);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_unbind(dp->adp);
 }
 
 static const struct component_ops exynos_dp_ops = {
@@ -257,12 +257,16 @@ static int exynos_dp_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int exynos_dp_suspend(struct device *dev)
 {
-	return analogix_dp_suspend(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
 }
 
 static int exynos_dp_resume(struct device *dev)
 {
-	return analogix_dp_resume(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
 }
 #endif
 
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 8cae5ad926cd..fa0365de31d2 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -77,6 +77,7 @@ struct rockchip_dp_device {
 
 	const struct rockchip_dp_chip_data *data;
 
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -85,7 +86,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
 	struct rockchip_dp_device *dp = to_dp(encoder);
 	unsigned long flags;
 
-	if (!analogix_dp_psr_supported(dp->dev))
+	if (!analogix_dp_psr_supported(dp->adp))
 		return;
 
 	DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
@@ -116,9 +117,9 @@ static void analogix_dp_psr_work(struct work_struct *work)
 
 	spin_lock_irqsave(&dp->psr_lock, flags);
 	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
-		analogix_dp_enable_psr(dp->dev);
+		analogix_dp_enable_psr(dp->adp);
 	else
-		analogix_dp_disable_psr(dp->dev);
+		analogix_dp_disable_psr(dp->adp);
 	spin_unlock_irqrestore(&dp->psr_lock, flags);
 }
 
@@ -273,7 +274,6 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
 {
 	struct device *dev = dp->dev;
 	struct device_node *np = dev->of_node;
-	int ret;
 
 	dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
 	if (IS_ERR(dp->grf)) {
@@ -337,13 +337,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp_data = of_device_get_match_data(dev);
 	if (!dp_data)
 		return -ENODEV;
@@ -370,7 +363,11 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp))
+		return PTR_ERR(dp->adp);
+
+	return 0;
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
@@ -379,8 +376,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
 
 	rockchip_drm_psr_unregister(&dp->encoder);
-
-	analogix_dp_unbind(dev, master, data);
+	analogix_dp_unbind(dp->adp);
 }
 
 static const struct component_ops rockchip_dp_component_ops = {
@@ -410,11 +406,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * We just use the drvdata until driver run into component
-	 * add function, and then we would set drvdata to null, so
-	 * that analogix dp driver could take charge of the drvdata.
-	 */
 	platform_set_drvdata(pdev, dp);
 
 	return component_add(dev, &rockchip_dp_component_ops);
@@ -427,10 +418,26 @@ static int rockchip_dp_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_dp_suspend(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
+}
+
+static int rockchip_dp_resume(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
+}
+#endif
+
 static const struct dev_pm_ops rockchip_dp_pm_ops = {
 #ifdef CONFIG_PM_SLEEP
-	.suspend = analogix_dp_suspend,
-	.resume_early = analogix_dp_resume,
+	.suspend = rockchip_dp_suspend,
+	.resume_early = rockchip_dp_resume,
 #endif
 };
 
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index c99d6eaef1ac..5518fc75dd6e 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -13,6 +13,8 @@
 
 #include <drm/drm_crtc.h>
 
+struct analogix_dp_device;
+
 enum analogix_dp_devtype {
 	EXYNOS_DP,
 	RK3288_DP,
@@ -38,16 +40,17 @@ struct analogix_dp_plat_data {
 			 struct drm_connector *);
 };
 
-int analogix_dp_psr_supported(struct device *dev);
-int analogix_dp_enable_psr(struct device *dev);
-int analogix_dp_disable_psr(struct device *dev);
+int analogix_dp_psr_supported(struct analogix_dp_device *dp);
+int analogix_dp_enable_psr(struct analogix_dp_device *dp);
+int analogix_dp_disable_psr(struct analogix_dp_device *dp);
 
-int analogix_dp_resume(struct device *dev);
-int analogix_dp_suspend(struct device *dev);
+int analogix_dp_resume(struct analogix_dp_device *dp);
+int analogix_dp_suspend(struct analogix_dp_device *dp);
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data);
-void analogix_dp_unbind(struct device *dev, struct device *master, void *data);
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data);
+void analogix_dp_unbind(struct analogix_dp_device *dp);
 
 int analogix_dp_start_crc(struct drm_connector *connector);
 int analogix_dp_stop_crc(struct drm_connector *connector);
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 05:09:40 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Wed, 18 Oct 2017 20:09:40 +0800
Subject: [PATCH v5 5/9] drm/rockchip: dw-mipi-dsi: Fix error handling path
In-Reply-To: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
Message-ID: <20171018120944.7819-6-jeffy.chen@rock-chips.com>

Add missing pm_runtime_disable() in bind()'s error handling path.

Also cleanup encoder & connector in unbind().

Fixes: 80a9a059d4e4 ("drm/rockchip/dsi: add dw-mipi power domain support")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v5:
Call the destroy hook in the error handling path like in unbind().

 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index b15755b6129c..e72d4e2b61aa 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -1282,7 +1282,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	ret = dw_mipi_dsi_register(drm, dsi);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
-		goto err_pllref;
+		goto err_disable_pllref;
 	}
 
 	pm_runtime_enable(dev);
@@ -1292,23 +1292,24 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	ret = mipi_dsi_host_register(&dsi->dsi_host);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
-		goto err_cleanup;
+		goto err_disable_pm_runtime;
 	}
 
 	if (!dsi->panel) {
 		ret = -EPROBE_DEFER;
-		goto err_mipi_dsi_host;
+		goto err_unreg_mipi_dsi_host;
 	}
 
 	dev_set_drvdata(dev, dsi);
 	return 0;
 
-err_mipi_dsi_host:
+err_unreg_mipi_dsi_host:
 	mipi_dsi_host_unregister(&dsi->dsi_host);
-err_cleanup:
-	drm_encoder_cleanup(&dsi->encoder);
-	drm_connector_cleanup(&dsi->connector);
-err_pllref:
+err_disable_pm_runtime:
+	pm_runtime_disable(dev);
+	dsi->connector.funcs->destroy(&dsi->connector);
+	dsi->encoder.funcs->destroy(&dsi->encoder);
+err_disable_pllref:
 	clk_disable_unprepare(dsi->pllref_clk);
 	return ret;
 }
@@ -1320,6 +1321,10 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
 
 	mipi_dsi_host_unregister(&dsi->dsi_host);
 	pm_runtime_disable(dev);
+
+	dsi->connector.funcs->destroy(&dsi->connector);
+	dsi->encoder.funcs->destroy(&dsi->encoder);
+
 	clk_disable_unprepare(dsi->pllref_clk);
 }
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 05:09:41 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Wed, 18 Oct 2017 20:09:41 +0800
Subject: [PATCH v5 6/9] drm/rockchip: inno_hdmi: Fix error handling path
In-Reply-To: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
Message-ID: <20171018120944.7819-7-jeffy.chen@rock-chips.com>

Add missing error handling in bind().

Fixes: 412d4ae6b7a5 ("drm/rockchip: hdmi: add Innosilicon HDMI support")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v5:
Call the destroy hook in the error handling path like in unbind().
Update cleanup order in unbind().

 drivers/gpu/drm/rockchip/inno_hdmi.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
index ee584d87111f..9a96ff6b022b 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -851,8 +851,10 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
+	if (irq < 0) {
+		ret = irq;
+		goto err_disable_clk;
+	}
 
 	inno_hdmi_reset(hdmi);
 
@@ -860,7 +862,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 	if (IS_ERR(hdmi->ddc)) {
 		ret = PTR_ERR(hdmi->ddc);
 		hdmi->ddc = NULL;
-		return ret;
+		goto err_disable_clk;
 	}
 
 	/*
@@ -874,7 +876,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 
 	ret = inno_hdmi_register(drm, hdmi);
 	if (ret)
-		return ret;
+		goto err_put_adapter;
 
 	dev_set_drvdata(dev, hdmi);
 
@@ -884,7 +886,17 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 	ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq,
 					inno_hdmi_irq, IRQF_SHARED,
 					dev_name(dev), hdmi);
+	if (ret < 0)
+		goto err_cleanup_hdmi;
 
+	return 0;
+err_cleanup_hdmi:
+	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
+err_put_adapter:
+	i2c_put_adapter(hdmi->ddc);
+err_disable_clk:
+	clk_disable_unprepare(hdmi->pclk);
 	return ret;
 }
 
@@ -896,8 +908,8 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master,
 	hdmi->connector.funcs->destroy(&hdmi->connector);
 	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 
-	clk_disable_unprepare(hdmi->pclk);
 	i2c_put_adapter(hdmi->ddc);
+	clk_disable_unprepare(hdmi->pclk);
 }
 
 static const struct component_ops inno_hdmi_ops = {
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 05:09:43 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Wed, 18 Oct 2017 20:09:43 +0800
Subject: [PATCH v5 8/9] drm/bridge/synopsys: dw-hdmi: Do not use device's
 drvdata
In-Reply-To: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
Message-ID: <20171018120944.7819-9-jeffy.chen@rock-chips.com>

Let plat drivers own the drvdata, so that they could cleanup resources
in their unbind().

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v5: None

 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c   | 43 ++++++++++-------------------
 drivers/gpu/drm/imx/dw_hdmi-imx.c           | 22 +++++++++------
 drivers/gpu/drm/meson/meson_dw_hdmi.c       | 20 ++++++++++----
 drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c      | 14 ++++++++--
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 23 ++++++++-------
 include/drm/bridge/dw_hdmi.h                | 17 ++++++------
 6 files changed, 77 insertions(+), 62 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index ff1b3d2b5d06..6fbfafc5832b 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2072,7 +2072,7 @@ static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
 	return ret;
 }
 
-void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
+void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
 {
 	mutex_lock(&hdmi->mutex);
 
@@ -2098,13 +2098,6 @@ void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
 	}
 	mutex_unlock(&hdmi->mutex);
 }
-
-void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense)
-{
-	struct dw_hdmi *hdmi = dev_get_drvdata(dev);
-
-	__dw_hdmi_setup_rx_sense(hdmi, hpd, rx_sense);
-}
 EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense);
 
 static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
@@ -2140,9 +2133,8 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
 	 */
 	if (intr_stat &
 	    (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) {
-		__dw_hdmi_setup_rx_sense(hdmi,
-					 phy_stat & HDMI_PHY_HPD,
-					 phy_stat & HDMI_PHY_RX_SENSE);
+		dw_hdmi_setup_rx_sense(hdmi, phy_stat & HDMI_PHY_HPD,
+				       phy_stat & HDMI_PHY_RX_SENSE);
 
 		if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0)
 			cec_notifier_set_phys_addr(hdmi->cec_notifier,
@@ -2512,8 +2504,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
 	if (hdmi->i2c)
 		dw_hdmi_i2c_init(hdmi);
 
-	platform_set_drvdata(pdev, hdmi);
-
 	return hdmi;
 
 err_iahb:
@@ -2559,25 +2549,23 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
 /* -----------------------------------------------------------------------------
  * Probe/remove API, used from platforms based on the DRM bridge API.
  */
-int dw_hdmi_probe(struct platform_device *pdev,
-		  const struct dw_hdmi_plat_data *plat_data)
+struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
+			      const struct dw_hdmi_plat_data *plat_data)
 {
 	struct dw_hdmi *hdmi;
 
 	hdmi = __dw_hdmi_probe(pdev, plat_data);
 	if (IS_ERR(hdmi))
-		return PTR_ERR(hdmi);
+		return hdmi;
 
 	drm_bridge_add(&hdmi->bridge);
 
-	return 0;
+	return hdmi;
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_probe);
 
-void dw_hdmi_remove(struct platform_device *pdev)
+void dw_hdmi_remove(struct dw_hdmi *hdmi)
 {
-	struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
-
 	drm_bridge_remove(&hdmi->bridge);
 
 	__dw_hdmi_remove(hdmi);
@@ -2587,31 +2575,30 @@ EXPORT_SYMBOL_GPL(dw_hdmi_remove);
 /* -----------------------------------------------------------------------------
  * Bind/unbind API, used from platforms based on the component framework.
  */
-int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-		 const struct dw_hdmi_plat_data *plat_data)
+struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
+			    struct drm_encoder *encoder,
+			    const struct dw_hdmi_plat_data *plat_data)
 {
 	struct dw_hdmi *hdmi;
 	int ret;
 
 	hdmi = __dw_hdmi_probe(pdev, plat_data);
 	if (IS_ERR(hdmi))
-		return PTR_ERR(hdmi);
+		return hdmi;
 
 	ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
 	if (ret) {
 		__dw_hdmi_remove(hdmi);
 		DRM_ERROR("Failed to initialize bridge with drm\n");
-		return ret;
+		return ERR_PTR(ret);
 	}
 
-	return 0;
+	return hdmi;
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_bind);
 
-void dw_hdmi_unbind(struct device *dev)
+void dw_hdmi_unbind(struct dw_hdmi *hdmi)
 {
-	struct dw_hdmi *hdmi = dev_get_drvdata(dev);
-
 	__dw_hdmi_remove(hdmi);
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index b62763aa8706..b01d03e02ce0 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -26,6 +26,8 @@ struct imx_hdmi {
 	struct device *dev;
 	struct drm_encoder encoder;
 	struct regmap *regmap;
+
+	struct dw_hdmi *hdmi;
 };
 
 static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e)
@@ -239,22 +241,24 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
 	drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS, NULL);
 
-	ret = dw_hdmi_bind(pdev, encoder, plat_data);
+	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
+	if (IS_ERR(hdmi->hdmi)) {
+		encoder->funcs->destroy(encoder);
+		return PTR_ERR(hdmi->hdmi);
+	}
 
-	/*
-	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
-	 * which would have called the encoder cleanup.  Do it manually.
-	 */
-	if (ret)
-		drm_encoder_cleanup(encoder);
+	dev_set_drvdata(dev, hdmi);
 
-	return ret;
+	return 0;
 }
 
 static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
 			       void *data)
 {
-	return dw_hdmi_unbind(dev);
+	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+
+	dw_hdmi_unbind(hdmi->hdmi);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 }
 
 static const struct component_ops dw_hdmi_imx_ops = {
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index cef414466f9f..fc29f69f7108 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -138,6 +138,8 @@ struct meson_dw_hdmi {
 	struct clk *hdmi_pclk;
 	struct clk *venci_clk;
 	u32 irq_stat;
+
+	struct dw_hdmi *hdmi;
 };
 #define encoder_to_meson_dw_hdmi(x) \
 	container_of(x, struct meson_dw_hdmi, encoder)
@@ -526,7 +528,7 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
 		if (stat & HDMITX_TOP_INTR_HPD_RISE)
 			hpd_connected = true;
 
-		dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected,
+		dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected,
 				       hpd_connected);
 
 		drm_helper_hpd_irq_event(dw_hdmi->encoder.dev);
@@ -865,9 +867,14 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 	dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
 	dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
 
-	ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data);
-	if (ret)
-		return ret;
+	meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
+					   &meson_dw_hdmi->dw_plat_data);
+	if (IS_ERR(meson_dw_hdmi->hdmi)) {
+		encoder->funcs->destroy(encoder);
+		return PTR_ERR(meson_dw_hdmi->hdmi);
+	}
+
+	dev_set_drvdata(dev, meson_dw_hdmi);
 
 	DRM_DEBUG_DRIVER("HDMI controller initialized\n");
 
@@ -877,7 +884,10 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
 				   void *data)
 {
-	dw_hdmi_unbind(dev);
+	struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
+
+	dw_hdmi_unbind(meson_dw_hdmi->hdmi);
+	meson_dw_hdmi->encoder.funcs->destroy(&meson_dw_hdmi->encoder);
 }
 
 static const struct component_ops meson_dw_hdmi_ops = {
diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
index dc85b53d58ef..76210ae25094 100644
--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
+++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
@@ -68,12 +68,22 @@ static const struct dw_hdmi_plat_data rcar_dw_hdmi_plat_data = {
 
 static int rcar_dw_hdmi_probe(struct platform_device *pdev)
 {
-	return dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data);
+	struct dw_hdmi *hdmi;
+
+	hdmi = dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data);
+	if (IS_ERR(hdmi))
+		return PTR_ERR(hdmi);
+
+	platform_set_drvdata(pdev, hdmi);
+
+	return 0;
 }
 
 static int rcar_dw_hdmi_remove(struct platform_device *pdev)
 {
-	dw_hdmi_remove(pdev);
+	struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
+
+	dw_hdmi_remove(hdmi);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 1eb02a82fd91..791ab938f998 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -48,6 +48,8 @@ struct rockchip_hdmi {
 	const struct rockchip_hdmi_chip_data *chip_data;
 	struct clk *vpll_clk;
 	struct clk *grf_clk;
+
+	struct dw_hdmi *hdmi;
 };
 
 #define to_rockchip_hdmi(x)	container_of(x, struct rockchip_hdmi, x)
@@ -164,7 +166,6 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
 static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 {
 	struct device_node *np = hdmi->dev->of_node;
-	int ret;
 
 	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
 	if (IS_ERR(hdmi->regmap)) {
@@ -377,22 +378,24 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS, NULL);
 
-	ret = dw_hdmi_bind(pdev, encoder, plat_data);
+	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
+	if (IS_ERR(hdmi->hdmi)) {
+		encoder->funcs->destroy(encoder);
+		return PTR_ERR(hdmi->hdmi);
+	}
 
-	/*
-	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
-	 * which would have called the encoder cleanup.  Do it manually.
-	 */
-	if (ret)
-		drm_encoder_cleanup(encoder);
+	dev_set_drvdata(dev, hdmi);
 
-	return ret;
+	return 0;
 }
 
 static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 				    void *data)
 {
-	return dw_hdmi_unbind(dev);
+	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
+
+	dw_hdmi_unbind(hdmi->hdmi);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 182f83283e24..29b8900caaf7 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -143,14 +143,15 @@ struct dw_hdmi_plat_data {
 			     unsigned long mpixelclock);
 };
 
-int dw_hdmi_probe(struct platform_device *pdev,
-		  const struct dw_hdmi_plat_data *plat_data);
-void dw_hdmi_remove(struct platform_device *pdev);
-void dw_hdmi_unbind(struct device *dev);
-int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-		 const struct dw_hdmi_plat_data *plat_data);
-
-void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense);
+struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
+			      const struct dw_hdmi_plat_data *plat_data);
+void dw_hdmi_remove(struct dw_hdmi *hdmi);
+void dw_hdmi_unbind(struct dw_hdmi *hdmi);
+struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
+			     struct drm_encoder *encoder,
+			     const struct dw_hdmi_plat_data *plat_data);
+
+void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
 
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 05:09:44 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Wed, 18 Oct 2017 20:09:44 +0800
Subject: [PATCH v5 9/9] drm/rockchip: dw_hdmi: Fix error handling path
In-Reply-To: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
Message-ID: <20171018120944.7819-10-jeffy.chen@rock-chips.com>

Add missing clk_disable_unprepare() in bind()'s error handling path and
unbind().

Also inline clk_prepare_enable() with bind().

Fixes: 12b9f204e804 ("drm: bridge/dw_hdmi: add rockchip rk3288 support")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v5:
Add disable to unbind(), and inline clk_prepare_enable() with bind().

 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 791ab938f998..e936dfe6c03d 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -193,13 +193,6 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->grf_clk);
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
-	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev,
-			      "Failed to enable HDMI vpll: %d\n", ret);
-		return ret;
-	}
-
 	return 0;
 }
 
@@ -374,6 +367,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = clk_prepare_enable(hdmi->vpll_clk);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev,
+			      "Failed to enable HDMI vpll: %d\n", ret);
+		return ret;
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS, NULL);
@@ -381,6 +381,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
 	if (IS_ERR(hdmi->hdmi)) {
 		encoder->funcs->destroy(encoder);
+		clk_disable_unprepare(hdmi->vpll_clk);
 		return PTR_ERR(hdmi->hdmi);
 	}
 
@@ -396,6 +397,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 
 	dw_hdmi_unbind(hdmi->hdmi);
 	hdmi->encoder.funcs->destroy(&hdmi->encoder);
+	clk_disable_unprepare(hdmi->vpll_clk);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.11.0




From a.hajda at samsung.com  Wed Oct 18 06:22:13 2017
From: a.hajda at samsung.com (Andrzej Hajda)
Date: Wed, 18 Oct 2017 15:22:13 +0200
Subject: [PATCH v5 4/9] drm/bridge: analogix_dp: Fix connector & encoder
 cleanup
In-Reply-To: <20171018120944.7819-5-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
 <CGME20171018121029epcas3p16c50a5eb912c8553dac9bf1dc0e91bb2@epcas3p1.samsung.com>
 <20171018120944.7819-5-jeffy.chen@rock-chips.com>
Message-ID: <22343b9b-f9fb-200c-45e4-fd3380470864@samsung.com>

On 18.10.2017 14:09, Jeffy Chen wrote:
> Since we are initing connector in the core driver and encoder in the
> plat driver, let's clean them up in the right places.
>
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
>
> Changes in v5: None
>
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  2 --
>  drivers/gpu/drm/exynos/exynos_dp.c                 |  7 +++++--
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 15 ++++++---------
>  3 files changed, 11 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 74d274b6d31d..3f910ab36ff6 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1409,7 +1409,6 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  	ret = analogix_dp_create_bridge(drm_dev, dp);
>  	if (ret) {
>  		DRM_ERROR("failed to create bridge (%d)\n", ret);
> -		drm_encoder_cleanup(dp->encoder);
>  		goto err_disable_pm_runtime;
>  	}
>  
> @@ -1432,7 +1431,6 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
>  {
>  	analogix_dp_bridge_disable(dp->bridge);
>  	dp->connector.funcs->destroy(&dp->connector);
> -	dp->encoder->funcs->destroy(dp->encoder);
>  
>  	if (dp->plat_data->panel) {
>  		if (drm_panel_unprepare(dp->plat_data->panel))
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index f7e5b2c405ed..33319a858f3a 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -185,8 +185,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
>  	dp->plat_data.encoder = encoder;
>  
>  	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> -	if (IS_ERR(dp->adp))
> +	if (IS_ERR(dp->adp)) {
> +		dp->encoder.funcs->destroy(&dp->encoder);
>  		return PTR_ERR(dp->adp);
> +	}
>  
>  	return 0;
>  }
> @@ -196,7 +198,8 @@ static void exynos_dp_unbind(struct device *dev, struct device *master,
>  {
>  	struct exynos_dp_device *dp = dev_get_drvdata(dev);
>  
> -	return analogix_dp_unbind(dp->adp);
> +	analogix_dp_unbind(dp->adp);
> +	dp->encoder.funcs->destroy(&dp->encoder);
>  }
>  
>  static const struct component_ops exynos_dp_ops = {
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index fa0365de31d2..c0fb3f3748f4 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -261,13 +261,8 @@ static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = {
>  	.atomic_check = rockchip_dp_drm_encoder_atomic_check,
>  };
>  
> -static void rockchip_dp_drm_encoder_destroy(struct drm_encoder *encoder)
> -{
> -	drm_encoder_cleanup(encoder);
> -}
> -
>  static struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
> -	.destroy = rockchip_dp_drm_encoder_destroy,
> +	.destroy = drm_encoder_cleanup,
>  };
>  
>  static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
> @@ -361,12 +356,13 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
>  	dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
>  	INIT_WORK(&dp->psr_work, analogix_dp_psr_work);
>  
> -	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
> -
>  	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> -	if (IS_ERR(dp->adp))
> +	if (IS_ERR(dp->adp)) {
> +		dp->encoder.funcs->destroy(&dp->encoder);
>  		return PTR_ERR(dp->adp);
> +	}
>  
> +	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);

You are changing here order of calls: psr_reg after bind, it does not
seem to be related to patch subject.
Anyway psr_register can fail and its result is not checked, but it can
be addressed in separate patch.
So maybe it would be better to leave the order as is, unless there is
reason for change it in one patch, in such case please explain it in
commit message.
Beside this:
Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>

?--
Regards
Andrzej

>  	return 0;
>  }
>  
> @@ -377,6 +373,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
>  
>  	rockchip_drm_psr_unregister(&dp->encoder);
>  	analogix_dp_unbind(dp->adp);
> +	dp->encoder.funcs->destroy(&dp->encoder);
>  }
>  
>  static const struct component_ops rockchip_dp_component_ops = {




From helgaas at kernel.org  Wed Oct 18 06:29:36 2017
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Wed, 18 Oct 2017 08:29:36 -0500
Subject: [PATCH v6 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171018010312.GB65743@google.com>
References: <20171013195059.23865-1-jeffy.chen@rock-chips.com>
 <20171013195059.23865-2-jeffy.chen@rock-chips.com>
 <20171016200350.GH25517@bhelgaas-glaptop.roam.corp.google.com>
 <20171018010312.GB65743@google.com>
Message-ID: <20171018132936.GP5641@bhelgaas-glaptop.roam.corp.google.com>

On Tue, Oct 17, 2017 at 06:03:14PM -0700, Brian Norris wrote:
> On Mon, Oct 16, 2017 at 03:03:50PM -0500, Bjorn Helgaas wrote:
> > On Sat, Oct 14, 2017 at 03:50:56AM +0800, Jeffy Chen wrote:
> > > Add support for PCIE_WAKE pin in rockchip pcie driver.
> > > 
> > > Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> > > ---
> > > 
> > > Changes in v6:
> > > Fix device_init_wake error handling, and add some comments.
> > > 
> > > Changes in v5:
> > > Rebase
> > > 
> > > Changes in v3:
> > > Fix error handling
> > > 
> > > Changes in v2:
> > > Use dev_pm_set_dedicated_wake_irq
> > >         -- Suggested by Brian Norris <briannorris at chromium.com>
> > > 
> > >  drivers/pci/host/pcie-rockchip.c | 27 +++++++++++++++++++++------
> > >  1 file changed, 21 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> > > index 9051c6c8fea4..268513b6c9c4 100644
> > > --- a/drivers/pci/host/pcie-rockchip.c
> > > +++ b/drivers/pci/host/pcie-rockchip.c
> ...
> > > @@ -995,6 +996,17 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
> > >  		return err;
> > >  	}
> > >  
> > > +	irq = platform_get_irq_byname(pdev, "wakeup");
> > > +	if (irq >= 0) {
> > > +		/* Must init wakeup before setting dedicated wakeup irq. */
> > > +		device_init_wakeup(dev, true);
> > > +		err = dev_pm_set_dedicated_wake_irq(dev, irq);
> > > +		if (err) {
> > > +			dev_err(dev, "failed to setup PCIe wakeup IRQ\n");
> > > +			device_init_wakeup(dev, false);
> > > +		}
> > > +	}
> > 
> > There's nothing Rockchip-specific here, so I'm hoping you can explore
> > putting this support in the PCI core, so any system that describes the
> > WAKE# connection in the DT can benefit.
> 
> I guess it could work to look into pci_create_root_bus(), and
> do something like the following?
> 
> 	if (IS_ENABLED(CONFIG_OF) && parent && parent->of_node)
> 		... do OF parsing for generic features like WAKE# ...

That's exactly the sort of thing I was thinking.


From narmstrong at baylibre.com  Wed Oct 18 09:03:03 2017
From: narmstrong at baylibre.com (Neil Armstrong)
Date: Wed, 18 Oct 2017 18:03:03 +0200
Subject: [PATCH v5 8/9] drm/bridge/synopsys: dw-hdmi: Do not use device's
 drvdata
In-Reply-To: <20171018120944.7819-9-jeffy.chen@rock-chips.com>
References: <20171018120944.7819-1-jeffy.chen@rock-chips.com>
 <20171018120944.7819-9-jeffy.chen@rock-chips.com>
Message-ID: <40e49fc2-fd7d-12ab-fe49-b4d0586b65a1@baylibre.com>

On 18/10/2017 14:09, Jeffy Chen wrote:
> Let plat drivers own the drvdata, so that they could cleanup resources
> in their unbind().
> 
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v5: None
> 
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c   | 43 ++++++++++-------------------
>  drivers/gpu/drm/imx/dw_hdmi-imx.c           | 22 +++++++++------
>  drivers/gpu/drm/meson/meson_dw_hdmi.c       | 20 ++++++++++----
>  drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c      | 14 ++++++++--
>  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 23 ++++++++-------
>  include/drm/bridge/dw_hdmi.h                | 17 ++++++------
>  6 files changed, 77 insertions(+), 62 deletions(-)
> 

[...]

> diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> index cef414466f9f..fc29f69f7108 100644
> --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
> +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> @@ -138,6 +138,8 @@ struct meson_dw_hdmi {
>  	struct clk *hdmi_pclk;
>  	struct clk *venci_clk;
>  	u32 irq_stat;
> +
> +	struct dw_hdmi *hdmi;
>  };
>  #define encoder_to_meson_dw_hdmi(x) \
>  	container_of(x, struct meson_dw_hdmi, encoder)
> @@ -526,7 +528,7 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
>  		if (stat & HDMITX_TOP_INTR_HPD_RISE)
>  			hpd_connected = true;
>  
> -		dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected,
> +		dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected,
>  				       hpd_connected);
>  
>  		drm_helper_hpd_irq_event(dw_hdmi->encoder.dev);
> @@ -865,9 +867,14 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>  	dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
>  	dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
>  
> -	ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data);
> -	if (ret)
> -		return ret;
> +	meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
> +					   &meson_dw_hdmi->dw_plat_data);
> +	if (IS_ERR(meson_dw_hdmi->hdmi)) {
> +		encoder->funcs->destroy(encoder);
> +		return PTR_ERR(meson_dw_hdmi->hdmi);
> +	}
> +
> +	dev_set_drvdata(dev, meson_dw_hdmi);
>  
>  	DRM_DEBUG_DRIVER("HDMI controller initialized\n");
>  
> @@ -877,7 +884,10 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
>  static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
>  				   void *data)
>  {
> -	dw_hdmi_unbind(dev);
> +	struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
> +
> +	dw_hdmi_unbind(meson_dw_hdmi->hdmi);
> +	meson_dw_hdmi->encoder.funcs->destroy(&meson_dw_hdmi->encoder);
>  }
>  
>  static const struct component_ops meson_dw_hdmi_ops = {

[...]

For meson/meson_dw_hdmi.c :

Reviewed-by: Neil Armstrong <narmstrong at baylibre.com>


From helgaas at kernel.org  Wed Oct 18 09:17:52 2017
From: helgaas at kernel.org (Bjorn Helgaas)
Date: Wed, 18 Oct 2017 11:17:52 -0500
Subject: [PATCH 1/3] Documentation/devicetree: Add pcie-reset-suspend
 property
In-Reply-To: <20171017233904.GA65743@google.com>
References: <20171012205220.130048-1-briannorris@chromium.org>
 <20171012205220.130048-2-briannorris@chromium.org>
 <20171013165152.GE25517@bhelgaas-glaptop.roam.corp.google.com>
 <20171017233904.GA65743@google.com>
Message-ID: <20171018161752.GQ5641@bhelgaas-glaptop.roam.corp.google.com>

On Tue, Oct 17, 2017 at 04:39:05PM -0700, Brian Norris wrote:
> On Fri, Oct 13, 2017 at 11:51:52AM -0500, Bjorn Helgaas wrote:
> > On Thu, Oct 12, 2017 at 01:52:18PM -0700, Brian Norris wrote:
> > > The patch is self-descriptive. I've found that we may need
> > > platform-specific behavior for the PERST# signal in system suspend,
> > > depending on the type of PCIe endpoints are attached.
> > > 
> > > Signed-off-by: Brian Norris <briannorris at chromium.org>
> > > ---
> > >  Documentation/devicetree/bindings/pci/pci.txt | 11 +++++++++++
> > >  1 file changed, 11 insertions(+)
> > > 
> > > diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt
> > > index c77981c5dd18..91339b6d0652 100644
> > > --- a/Documentation/devicetree/bindings/pci/pci.txt
> > > +++ b/Documentation/devicetree/bindings/pci/pci.txt
> > > @@ -24,3 +24,14 @@ driver implementation may support the following properties:
> > >     unsupported link speed, for instance, trying to do training for
> > >     unsupported link speed, etc.  Must be '4' for gen4, '3' for gen3, '2'
> > >     for gen2, and '1' for gen1. Any other values are invalid.
> > > +- pcie-reset-suspend:
> > > +   If present this property defines whether the PCIe Reset signal (referred to
> > > +   as PERST#) should be asserted when the system enters low-power suspend modes
> > > +   (e.g., S3). Depending on the form factor, the associated PCIe
> > > +   electromechanical specification may specify a particular behavior (e.g.,
> > > +   "PERST# is asserted in advance of the power being switched off in a
> > > +   power-managed state like S3") or it may be less clear. The net result is
> > > +   that some endpoints perform better (e.g., lower power consumption) with
> > > +   PERST# asserted, and others prefer PERST# deasserted. The value must be '0'
> > > +   or '1', where '0' means do not assert PERST# and '1' means assert PERST#.
> > > +   When absent, behavior may be platform-specific.
> > 
> > I don't understand this at all.  Are you suggesting that we need
> > different "pcie-reset-suspend" values based on what sort of endpoint
> > the user plugs in?
> 
> Partly. I guess I also failed to mention in this particular text (but I
> did, in patch 3) that it can be a board-specific problem, related to the
> fact that the only endpoint used on said board--soldered on, not
> replaceable--never seemed to require PERST# to be asserted in suspend.
> On such boards, I believe [1] it is physically impossible to drive this
> pin low in S3 suspend. So even if we tried to assert PERST#, it would
> pull back up when we suspend the system. I'm not sure if that's better
> or worse than not asserting it at all.
> 
> So, that's why I settled on a device tree property. It describes the
> physical ability of the board too, in some cases. (I could document this
> better, I see.)

It would make sense to me to have a DT property in the PCIe host
controller object that describes how that controller works, including
its capabilities with respect to PERST#, assuming there's a reasonable
way to use that information.

If there's a DT way to describe a hard-wired PCIe endpoint, it might
make sense to have a second property in the endpoint object that
describes its preferences.  Obviously this couldn't apply to slots
where we don't know what might be plugged in.

> > If you want a quirk to tune this based on specific devices, that might
> > make sense.  It would still sound like an interoperability issue and
> > an ongoing maintenance problem, but at least we would have specific
> > details about which devices are involved, and we'd have a chance to
> > make them work on more controllers than just Rockchip.
> 
> (continued) ...I suppose we could do this too. Like, a new entry in enum
> pci_dev_flags, and code in drivers/pci/quirks.c? And then some helper so
> that a PCIe root port driver like Rockchip's can walk its children and
> check for the existence of this quirk? I'll see if I can write that up
> reasonably.

I'm not sure how this would work out.  I can see the quirk side (e.g.,
the quirk could set a bit in the root port), but who would consume it?
Would every host bridge driver have to look at the bit?  This doesn't
feel like a generic model that works well across vendors.

If devices rely on things not specified by the spec, they will work
better on some systems than on others.  That feels like an issue for
the vendors, not for us.

Obviously you want to tweak something for your particular
configuration, and you can do that either via out-of-tree code or via
some more generic way that I haven't seen yet.

Bjorn


From briannorris at chromium.org  Wed Oct 18 10:52:11 2017
From: briannorris at chromium.org (Brian Norris)
Date: Wed, 18 Oct 2017 10:52:11 -0700
Subject: [PATCH v2] drm/rockchip: Use an enum to identify Rockchip VOPs
In-Reply-To: <1478202408-11635-1-git-send-email-hoegsberg@chromium.org>
References: <1478202408-11635-1-git-send-email-hoegsberg@chromium.org>
Message-ID: <20171018175208.GA73666@google.com>

Hi Kristian,

On Thu, Nov 03, 2016 at 12:46:48PM -0700, Kristian H?gsberg wrote:
> We used to call drm_of_encoder_active_endpoint_id() from
> rockchip_dp_drm_encoder_atomic_check() to determine the endpoint for the
> active encoder. However, the encoder isn't necessarily active at this
> point or it may be connected to different crtc than what we're switching
> to. Instead, look at the crtc from the drm_crtc_state.  This fixes wrong
> colors when driving the eDP with the big VOP.  Further, we can identify
> the type of VOP we're dealing with by just putting a VOP id enum in the
> vop_data.
> 
> On way to test this is to use the modetest tool from libdrm:
> 
>   $ modetest -M rockchip -s 32 at 28:2400x1600
> 
> which displays dark or black colors because we fail to look up the
> endpoint and use default 0 (which is ROCKCHIP_OUT_MODE_P888) for big
> VOP instead of RGB10 as required.
> 
> For reference,
> 
>   $ modetest -M rockchip -s 32 at 25:2400x1600
> 
> drives the eDP from little VOP and displays correctly.
> 
> Signed-off-by: Kristian H. Kristensen <hoegsberg at chromium.org>
> ---
> v2: Stripped chromeos annotations, fix compile errors for drivers I didn't
> compile when I first wrote the patch.

Do you plan to fix the errors Guenter pointed out and resend? This is
still causing conflicts between our ChromeOS kernel trees and upstream.

Also, please CC linux-rockchip on Rockchip-related patches. It's much
easier for me to find your work that way :)

Brian

> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 45 ++++++++++---------------
>  drivers/gpu/drm/rockchip/cdn-dp-core.c          | 19 +++++------
>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c          | 12 ++++---
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.c     |  7 ++++
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.h     | 10 ++++++
>  drivers/gpu/drm/rockchip/rockchip_vop_reg.c     |  4 +++
>  6 files changed, 56 insertions(+), 41 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index 558a3bc..9ae4a9c 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -196,14 +196,16 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder)
>  	int ret;
>  	u32 val;
>  
> -	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
> -	if (ret < 0)
> -		return;
> -
> -	if (ret)
> +	switch (vop_get_crtc_vop_id(encoder->crtc)) {
> +	case RK3399_VOP_LIT:
>  		val = dp->data->lcdsel_lit;
> -	else
> +		break;
> +	case RK3399_VOP_BIG:
>  		val = dp->data->lcdsel_big;
> +		break;
> +	default:
> +		return;
> +	}
>  
>  	dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
>  
> @@ -231,34 +233,23 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
>  				      struct drm_connector_state *conn_state)
>  {
>  	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
> -	struct rockchip_dp_device *dp = to_dp(encoder);
> -	int ret;
>  
> -	/*
> -	 * The hardware IC designed that VOP must output the RGB10 video
> -	 * format to eDP contoller, and if eDP panel only support RGB8,
> -	 * then eDP contoller should cut down the video data, not via VOP
> -	 * contoller, that's why we need to hardcode the VOP output mode
> -	 * to RGA10 here.
> -	 */
> -
> -	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
> -	if (ret < 0)
> -		return 0;
> -
> -	switch (dp->data->chip_type) {
> -	case RK3399_EDP:
> +	switch (vop_get_crtc_vop_id(crtc_state->crtc)) {
> +	case RK3399_VOP_LIT:
>  		/*
>  		 * For RK3399, VOP Lit must code the out mode to RGB888,
>  		 * VOP Big must code the out mode to RGB10.
>  		 */
> -		if (ret)
> -			s->output_mode = ROCKCHIP_OUT_MODE_P888;
> -		else
> -			s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
> +		s->output_mode = ROCKCHIP_OUT_MODE_P888;
>  		break;
> -
>  	default:
> +		/*
> +		 * The hardware IC designed that VOP must output the RGB10 video
> +		 * format to eDP contoller, and if eDP panel only support RGB8,
> +		 * then eDP contoller should cut down the video data, not via VOP
> +		 * contoller, that's why we need to hardcode the VOP output mode
> +		 * to RGA10 here.
> +		 */
>  		s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>  		break;
>  	}
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> index f020e2e..b9e6184 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> @@ -570,21 +570,20 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
>  	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
>  	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
>  
> -	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
> -	if (ret < 0) {
> -		DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
> -		return;
> -	}
> -
> -	DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n",
> -			  (ret) ? "LIT" : "BIG");
>  	state = to_rockchip_crtc_state(encoder->crtc->state);
> -	if (ret) {
> +	switch (vop_get_crtc_vop_id(encoder->crtc)) {
> +	case RK3399_VOP_LIT:
> +		DRM_DEV_DEBUG_KMS(dp->dev, "vop LIT output to cdn-dp\n");
>  		val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16);
>  		state->output_mode = ROCKCHIP_OUT_MODE_P888;
> -	} else {
> +		break;
> +	case RK3399_VOP_BIG:
> +		DRM_DEV_DEBUG_KMS(dp->dev, "vop BIG output to cdn-dp\n");
>  		val = DP_SEL_VOP_LIT << 16;
>  		state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
> +		break;
> +	default:
> +		break;
>  	}
>  
>  	ret = cdn_dp_grf_write(dp, GRF_SOC_CON9, val);
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index dedc65b..b01a82a 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -878,7 +878,6 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
>  static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
>  {
>  	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
> -	int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
>  	u32 val;
>  
>  	if (clk_prepare_enable(dsi->pclk)) {
> @@ -894,13 +893,18 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
>  
>  	clk_disable_unprepare(dsi->pclk);
>  
> -	if (mux)
> +	switch (vop_get_crtc_vop_id(encoder->crtc)) {
> +	case RK3399_VOP_LIT:
> +		dev_dbg(dsi->dev, "vop LIT output to dsi0\n");
>  		val = DSI0_SEL_VOP_LIT | (DSI0_SEL_VOP_LIT << 16);
> -	else
> +		break;
> +	default:
> +		dev_dbg(dsi->dev, "vop BIG output to dsi0\n");
>  		val = DSI0_SEL_VOP_LIT << 16;
> +		break;
> +	}
>  
>  	regmap_write(dsi->grf_regmap, GRF_SOC_CON6, val);
> -	dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
>  }
>  
>  static int
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> index d5ea4ab..e849f26 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> @@ -141,6 +141,13 @@ struct vop {
>  	struct vop_win win[];
>  };
>  
> +enum vop_id vop_get_crtc_vop_id(struct drm_crtc *crtc)
> +{
> +	struct vop *vop = to_vop(crtc);
> +
> +	return vop->data->id;
> +}
> +
>  static inline void vop_writel(struct vop *vop, uint32_t offset, uint32_t v)
>  {
>  	writel(v, vop->regs + offset);
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> index 5a4faa85..2c54bcc 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> @@ -135,8 +135,16 @@ struct vop_win_data {
>  	enum drm_plane_type type;
>  };
>  
> +enum vop_id {
> +	RK3036_VOP,
> +	RK3288_VOP,
> +	RK3399_VOP_BIG,
> +	RK3399_VOP_LIT,
> +};
> +
>  struct vop_data {
>  	const struct vop_reg_data *init_table;
> +	uint32_t id;
>  	unsigned int table_size;
>  	const struct vop_ctrl *ctrl;
>  	const struct vop_intr *intr;
> @@ -321,5 +329,7 @@ static inline int scl_vop_cal_lb_mode(int width, bool is_yuv)
>  	return lb_mode;
>  }
>  
> +enum vop_id vop_get_crtc_vop_id(struct drm_crtc *crtc);
> +
>  extern const struct component_ops vop_component_ops;
>  #endif /* _ROCKCHIP_DRM_VOP_H */
> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
> index aaede6b..a46e2c8 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
> @@ -131,6 +131,7 @@ static const struct vop_reg_data rk3036_vop_init_reg_table[] = {
>  };
>  
>  static const struct vop_data rk3036_vop = {
> +	.id = RK3036_VOP,
>  	.init_table = rk3036_vop_init_reg_table,
>  	.table_size = ARRAY_SIZE(rk3036_vop_init_reg_table),
>  	.ctrl = &rk3036_ctrl_data,
> @@ -272,6 +273,7 @@ static const struct vop_intr rk3288_vop_intr = {
>  };
>  
>  static const struct vop_data rk3288_vop = {
> +	.id = RK3288_VOP,
>  	.init_table = rk3288_init_reg_table,
>  	.table_size = ARRAY_SIZE(rk3288_init_reg_table),
>  	.intr = &rk3288_vop_intr,
> @@ -340,6 +342,7 @@ static const struct vop_reg_data rk3399_init_reg_table[] = {
>  };
>  
>  static const struct vop_data rk3399_vop_big = {
> +	.id = RK3399_VOP_BIG,
>  	.init_table = rk3399_init_reg_table,
>  	.table_size = ARRAY_SIZE(rk3399_init_reg_table),
>  	.intr = &rk3399_vop_intr,
> @@ -359,6 +362,7 @@ static const struct vop_win_data rk3399_vop_lit_win_data[] = {
>  };
>  
>  static const struct vop_data rk3399_vop_lit = {
> +	.id = RK3399_VOP_LIT,
>  	.init_table = rk3399_init_reg_table,
>  	.table_size = ARRAY_SIZE(rk3399_init_reg_table),
>  	.intr = &rk3399_vop_intr,


From robh+dt at kernel.org  Wed Oct 18 13:38:48 2017
From: robh+dt at kernel.org (Rob Herring)
Date: Wed, 18 Oct 2017 15:38:48 -0500
Subject: [PATCH 1/3] Documentation/devicetree: Add pcie-reset-suspend
 property
In-Reply-To: <20171018161752.GQ5641@bhelgaas-glaptop.roam.corp.google.com>
References: <20171012205220.130048-1-briannorris@chromium.org>
 <20171012205220.130048-2-briannorris@chromium.org>
 <20171013165152.GE25517@bhelgaas-glaptop.roam.corp.google.com>
 <20171017233904.GA65743@google.com>
 <20171018161752.GQ5641@bhelgaas-glaptop.roam.corp.google.com>
Message-ID: <CAL_JsqLYAOGHNRomE2a4Z+MLp807exqsYf7hPJhTd0cAbE85uA@mail.gmail.com>

On Wed, Oct 18, 2017 at 11:17 AM, Bjorn Helgaas <helgaas at kernel.org> wrote:
> On Tue, Oct 17, 2017 at 04:39:05PM -0700, Brian Norris wrote:
>> On Fri, Oct 13, 2017 at 11:51:52AM -0500, Bjorn Helgaas wrote:
>> > On Thu, Oct 12, 2017 at 01:52:18PM -0700, Brian Norris wrote:
>> > > The patch is self-descriptive. I've found that we may need
>> > > platform-specific behavior for the PERST# signal in system suspend,
>> > > depending on the type of PCIe endpoints are attached.
>> > >
>> > > Signed-off-by: Brian Norris <briannorris at chromium.org>
>> > > ---
>> > >  Documentation/devicetree/bindings/pci/pci.txt | 11 +++++++++++
>> > >  1 file changed, 11 insertions(+)
>> > >
>> > > diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt
>> > > index c77981c5dd18..91339b6d0652 100644
>> > > --- a/Documentation/devicetree/bindings/pci/pci.txt
>> > > +++ b/Documentation/devicetree/bindings/pci/pci.txt
>> > > @@ -24,3 +24,14 @@ driver implementation may support the following properties:
>> > >     unsupported link speed, for instance, trying to do training for
>> > >     unsupported link speed, etc.  Must be '4' for gen4, '3' for gen3, '2'
>> > >     for gen2, and '1' for gen1. Any other values are invalid.
>> > > +- pcie-reset-suspend:
>> > > +   If present this property defines whether the PCIe Reset signal (referred to
>> > > +   as PERST#) should be asserted when the system enters low-power suspend modes
>> > > +   (e.g., S3). Depending on the form factor, the associated PCIe
>> > > +   electromechanical specification may specify a particular behavior (e.g.,
>> > > +   "PERST# is asserted in advance of the power being switched off in a
>> > > +   power-managed state like S3") or it may be less clear. The net result is
>> > > +   that some endpoints perform better (e.g., lower power consumption) with
>> > > +   PERST# asserted, and others prefer PERST# deasserted. The value must be '0'
>> > > +   or '1', where '0' means do not assert PERST# and '1' means assert PERST#.
>> > > +   When absent, behavior may be platform-specific.
>> >
>> > I don't understand this at all.  Are you suggesting that we need
>> > different "pcie-reset-suspend" values based on what sort of endpoint
>> > the user plugs in?
>>
>> Partly. I guess I also failed to mention in this particular text (but I
>> did, in patch 3) that it can be a board-specific problem, related to the
>> fact that the only endpoint used on said board--soldered on, not
>> replaceable--never seemed to require PERST# to be asserted in suspend.
>> On such boards, I believe [1] it is physically impossible to drive this
>> pin low in S3 suspend. So even if we tried to assert PERST#, it would
>> pull back up when we suspend the system. I'm not sure if that's better
>> or worse than not asserting it at all.
>>
>> So, that's why I settled on a device tree property. It describes the
>> physical ability of the board too, in some cases. (I could document this
>> better, I see.)
>
> It would make sense to me to have a DT property in the PCIe host
> controller object that describes how that controller works, including
> its capabilities with respect to PERST#, assuming there's a reasonable
> way to use that information.
>
> If there's a DT way to describe a hard-wired PCIe endpoint, it might
> make sense to have a second property in the endpoint object that
> describes its preferences.  Obviously this couldn't apply to slots
> where we don't know what might be plugged in.

That's implicit with having an endpoint described in DT though true OF
would have every device present.

Rob


From mark.yao at rock-chips.com  Wed Oct 18 17:49:46 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Thu, 19 Oct 2017 08:49:46 +0800
Subject: [PATCH v2] drm/rockchip: Use an enum to identify Rockchip VOPs
In-Reply-To: <20171018175208.GA73666@google.com>
References: <1478202408-11635-1-git-send-email-hoegsberg@chromium.org>
 <20171018175208.GA73666@google.com>
Message-ID: <fad6657f-2bfa-c722-27a6-e29bb9fadb52@rock-chips.com>

On 2017?10?19? 01:52, Brian Norris wrote:
> Hi Kristian,
>
> On Thu, Nov 03, 2016 at 12:46:48PM -0700, Kristian H?gsberg wrote:
>> We used to call drm_of_encoder_active_endpoint_id() from
>> rockchip_dp_drm_encoder_atomic_check() to determine the endpoint for the
>> active encoder. However, the encoder isn't necessarily active at this
>> point or it may be connected to different crtc than what we're switching
>> to. Instead, look at the crtc from the drm_crtc_state.  This fixes wrong
>> colors when driving the eDP with the big VOP.  Further, we can identify
>> the type of VOP we're dealing with by just putting a VOP id enum in the
>> vop_data.

Unfortunately, vop iomux and vop data are not one-to-one correspondence.

Such as rk3288, vop big and vop little both use rk3288_vop data, if you use vop data id will not be able
to distinguish between them.

Mark
>>
>> On way to test this is to use the modetest tool from libdrm:
>>
>>    $ modetest -M rockchip -s 32 at 28:2400x1600
>>
>> which displays dark or black colors because we fail to look up the
>> endpoint and use default 0 (which is ROCKCHIP_OUT_MODE_P888) for big
>> VOP instead of RGB10 as required.
>>
>> For reference,
>>
>>    $ modetest -M rockchip -s 32 at 25:2400x1600
>>
>> drives the eDP from little VOP and displays correctly.
>>
>> Signed-off-by: Kristian H. Kristensen <hoegsberg at chromium.org>
>> ---
>> v2: Stripped chromeos annotations, fix compile errors for drivers I didn't
>> compile when I first wrote the patch.
> Do you plan to fix the errors Guenter pointed out and resend? This is
> still causing conflicts between our ChromeOS kernel trees and upstream.
>
> Also, please CC linux-rockchip on Rockchip-related patches. It's much
> easier for me to find your work that way :)
>
> Brian
>
>> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 45 ++++++++++---------------
>>   drivers/gpu/drm/rockchip/cdn-dp-core.c          | 19 +++++------
>>   drivers/gpu/drm/rockchip/dw-mipi-dsi.c          | 12 ++++---
>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.c     |  7 ++++
>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.h     | 10 ++++++
>>   drivers/gpu/drm/rockchip/rockchip_vop_reg.c     |  4 +++
>>   6 files changed, 56 insertions(+), 41 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> index 558a3bc..9ae4a9c 100644
>> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> @@ -196,14 +196,16 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder)
>>   	int ret;
>>   	u32 val;
>>   
>> -	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
>> -	if (ret < 0)
>> -		return;
>> -
>> -	if (ret)
>> +	switch (vop_get_crtc_vop_id(encoder->crtc)) {
>> +	case RK3399_VOP_LIT:
>>   		val = dp->data->lcdsel_lit;
>> -	else
>> +		break;
>> +	case RK3399_VOP_BIG:
>>   		val = dp->data->lcdsel_big;
>> +		break;
>> +	default:
>> +		return;
>> +	}
>>   
>>   	dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
>>   
>> @@ -231,34 +233,23 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
>>   				      struct drm_connector_state *conn_state)
>>   {
>>   	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
>> -	struct rockchip_dp_device *dp = to_dp(encoder);
>> -	int ret;
>>   
>> -	/*
>> -	 * The hardware IC designed that VOP must output the RGB10 video
>> -	 * format to eDP contoller, and if eDP panel only support RGB8,
>> -	 * then eDP contoller should cut down the video data, not via VOP
>> -	 * contoller, that's why we need to hardcode the VOP output mode
>> -	 * to RGA10 here.
>> -	 */
>> -
>> -	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
>> -	if (ret < 0)
>> -		return 0;
>> -
>> -	switch (dp->data->chip_type) {
>> -	case RK3399_EDP:
>> +	switch (vop_get_crtc_vop_id(crtc_state->crtc)) {
>> +	case RK3399_VOP_LIT:
>>   		/*
>>   		 * For RK3399, VOP Lit must code the out mode to RGB888,
>>   		 * VOP Big must code the out mode to RGB10.
>>   		 */
>> -		if (ret)
>> -			s->output_mode = ROCKCHIP_OUT_MODE_P888;
>> -		else
>> -			s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>> +		s->output_mode = ROCKCHIP_OUT_MODE_P888;
>>   		break;
>> -
>>   	default:
>> +		/*
>> +		 * The hardware IC designed that VOP must output the RGB10 video
>> +		 * format to eDP contoller, and if eDP panel only support RGB8,
>> +		 * then eDP contoller should cut down the video data, not via VOP
>> +		 * contoller, that's why we need to hardcode the VOP output mode
>> +		 * to RGA10 here.
>> +		 */
>>   		s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>>   		break;
>>   	}
>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>> index f020e2e..b9e6184 100644
>> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>> @@ -570,21 +570,20 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
>>   	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
>>   	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
>>   
>> -	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
>> -	if (ret < 0) {
>> -		DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
>> -		return;
>> -	}
>> -
>> -	DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n",
>> -			  (ret) ? "LIT" : "BIG");
>>   	state = to_rockchip_crtc_state(encoder->crtc->state);
>> -	if (ret) {
>> +	switch (vop_get_crtc_vop_id(encoder->crtc)) {
>> +	case RK3399_VOP_LIT:
>> +		DRM_DEV_DEBUG_KMS(dp->dev, "vop LIT output to cdn-dp\n");
>>   		val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16);
>>   		state->output_mode = ROCKCHIP_OUT_MODE_P888;
>> -	} else {
>> +		break;
>> +	case RK3399_VOP_BIG:
>> +		DRM_DEV_DEBUG_KMS(dp->dev, "vop BIG output to cdn-dp\n");
>>   		val = DP_SEL_VOP_LIT << 16;
>>   		state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>> +		break;
>> +	default:
>> +		break;
>>   	}
>>   
>>   	ret = cdn_dp_grf_write(dp, GRF_SOC_CON9, val);
>> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>> index dedc65b..b01a82a 100644
>> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>> @@ -878,7 +878,6 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
>>   static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
>>   {
>>   	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
>> -	int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
>>   	u32 val;
>>   
>>   	if (clk_prepare_enable(dsi->pclk)) {
>> @@ -894,13 +893,18 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
>>   
>>   	clk_disable_unprepare(dsi->pclk);
>>   
>> -	if (mux)
>> +	switch (vop_get_crtc_vop_id(encoder->crtc)) {
>> +	case RK3399_VOP_LIT:
>> +		dev_dbg(dsi->dev, "vop LIT output to dsi0\n");
>>   		val = DSI0_SEL_VOP_LIT | (DSI0_SEL_VOP_LIT << 16);
>> -	else
>> +		break;
>> +	default:
>> +		dev_dbg(dsi->dev, "vop BIG output to dsi0\n");
>>   		val = DSI0_SEL_VOP_LIT << 16;
>> +		break;
>> +	}
>>   
>>   	regmap_write(dsi->grf_regmap, GRF_SOC_CON6, val);
>> -	dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
>>   }
>>   
>>   static int
>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>> index d5ea4ab..e849f26 100644
>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>> @@ -141,6 +141,13 @@ struct vop {
>>   	struct vop_win win[];
>>   };
>>   
>> +enum vop_id vop_get_crtc_vop_id(struct drm_crtc *crtc)
>> +{
>> +	struct vop *vop = to_vop(crtc);
>> +
>> +	return vop->data->id;
>> +}
>> +
>>   static inline void vop_writel(struct vop *vop, uint32_t offset, uint32_t v)
>>   {
>>   	writel(v, vop->regs + offset);
>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>> index 5a4faa85..2c54bcc 100644
>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>> @@ -135,8 +135,16 @@ struct vop_win_data {
>>   	enum drm_plane_type type;
>>   };
>>   
>> +enum vop_id {
>> +	RK3036_VOP,
>> +	RK3288_VOP,
>> +	RK3399_VOP_BIG,
>> +	RK3399_VOP_LIT,
>> +};
>> +
>>   struct vop_data {
>>   	const struct vop_reg_data *init_table;
>> +	uint32_t id;
>>   	unsigned int table_size;
>>   	const struct vop_ctrl *ctrl;
>>   	const struct vop_intr *intr;
>> @@ -321,5 +329,7 @@ static inline int scl_vop_cal_lb_mode(int width, bool is_yuv)
>>   	return lb_mode;
>>   }
>>   
>> +enum vop_id vop_get_crtc_vop_id(struct drm_crtc *crtc);
>> +
>>   extern const struct component_ops vop_component_ops;
>>   #endif /* _ROCKCHIP_DRM_VOP_H */
>> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>> index aaede6b..a46e2c8 100644
>> --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>> +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>> @@ -131,6 +131,7 @@ static const struct vop_reg_data rk3036_vop_init_reg_table[] = {
>>   };
>>   
>>   static const struct vop_data rk3036_vop = {
>> +	.id = RK3036_VOP,
>>   	.init_table = rk3036_vop_init_reg_table,
>>   	.table_size = ARRAY_SIZE(rk3036_vop_init_reg_table),
>>   	.ctrl = &rk3036_ctrl_data,
>> @@ -272,6 +273,7 @@ static const struct vop_intr rk3288_vop_intr = {
>>   };
>>   
>>   static const struct vop_data rk3288_vop = {
>> +	.id = RK3288_VOP,
>>   	.init_table = rk3288_init_reg_table,
>>   	.table_size = ARRAY_SIZE(rk3288_init_reg_table),
>>   	.intr = &rk3288_vop_intr,
>> @@ -340,6 +342,7 @@ static const struct vop_reg_data rk3399_init_reg_table[] = {
>>   };
>>   
>>   static const struct vop_data rk3399_vop_big = {
>> +	.id = RK3399_VOP_BIG,
>>   	.init_table = rk3399_init_reg_table,
>>   	.table_size = ARRAY_SIZE(rk3399_init_reg_table),
>>   	.intr = &rk3399_vop_intr,
>> @@ -359,6 +362,7 @@ static const struct vop_win_data rk3399_vop_lit_win_data[] = {
>>   };
>>   
>>   static const struct vop_data rk3399_vop_lit = {
>> +	.id = RK3399_VOP_LIT,
>>   	.init_table = rk3399_init_reg_table,
>>   	.table_size = ARRAY_SIZE(rk3399_init_reg_table),
>>   	.intr = &rk3399_vop_intr,
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
>
>



From jeffy.chen at rock-chips.com  Wed Oct 18 18:54:40 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Thu, 19 Oct 2017 09:54:40 +0800
Subject: [RFC PATCH v4 4/8] drm/rockchip: dw_hdmi: Fix error handling path
In-Reply-To: <20171017181034.tsplfsmq7vi4uhmo@art_vandelay>
References: <20171017101624.12506-1-jeffy.chen@rock-chips.com>
 <20171017101624.12506-5-jeffy.chen@rock-chips.com>
 <20171017181034.tsplfsmq7vi4uhmo@art_vandelay>
Message-ID: <59E805E0.50006@rock-chips.com>

Hi Sean,

Thanks for your review.

On 10/18/2017 02:10 AM, Sean Paul wrote:
> On Tue, Oct 17, 2017 at 06:16:20PM +0800, Jeffy Chen wrote:
>> >Add missing clk_disable_unprepare() in bind()'s error handling path.
> This also isn't disabled in unbind(), is that intentional?
>
i wasn't able to do that because of dw_hdmi drvdata.

i've modified it as tomasz did for dp bridge, and fixed the unbind() in 
the next version :)



From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:02 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:02 +0800
Subject: [PATCH v6 00/10] rockchip: kevin: Enable edp display
Message-ID: <20171019034812.13768-1-jeffy.chen@rock-chips.com>


Make edp display works on chromebook kevin(at least for boot animation).

Also solve some issues i meet during the bringup.

Changes in v6:
Don't change order of rockchip_drm_psr_register().

Changes in v5:
Call the destroy hook in the error handling path like in unbind().
Call the destroy hook in the error handling path like in unbind().
Update cleanup order in unbind().
Add disable to unbind(), and inline clk_prepare_enable() with bind().

Jeffy Chen (10):
  arm64: dts: rockchip: Enable edp disaplay on kevin
  drm/rockchip: analogix_dp: Remove unnecessary init code
  drm/bridge: analogix: Do not use device's drvdata
  drm/bridge: analogix_dp: Fix connector and encoder cleanup
  drm/rockchip: analogix_dp: Add a sanity check for
    rockchip_drm_psr_register()
  drm/rockchip: dw-mipi-dsi: Fix error handling path
  drm/rockchip: inno_hdmi: Fix error handling path
  drm/bridge/synopsys: dw-hdmi: Add missing bridge detach
  drm/bridge/synopsys: dw-hdmi: Do not use device's drvdata
  drm/rockchip: dw_hdmi: Fix error handling path

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts  | 29 +++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi       | 16 ++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 52 +++++-------
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          | 53 ++++++------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 29 ++++---
 drivers/gpu/drm/imx/dw_hdmi-imx.c                  | 22 +++--
 drivers/gpu/drm/meson/meson_dw_hdmi.c              | 20 +++--
 drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c             | 14 +++-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 95 +++++++++++-----------
 drivers/gpu/drm/rockchip/dw-mipi-dsi.c             | 21 +++--
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c        | 39 +++++----
 drivers/gpu/drm/rockchip/inno_hdmi.c               | 22 +++--
 include/drm/bridge/analogix_dp.h                   | 19 +++--
 include/drm/bridge/dw_hdmi.h                       | 17 ++--
 14 files changed, 265 insertions(+), 183 deletions(-)

-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:03 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:03 +0800
Subject: [PATCH v6 01/10] arm64: dts: rockchip: Enable edp disaplay on kevin
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019034812.13768-2-jeffy.chen@rock-chips.com>

Add edp panel and enable related nodes on kevin.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Mark Yao <mark.yao at rock-chips.com>

---

Changes in v6: None
Changes in v5: None

 arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts | 29 +++++++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi      | 16 +++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
index a3d3cea7dc4f..bc67b19f0af5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts
@@ -93,6 +93,18 @@
 		pwm-delay-us = <10000>;
 	};
 
+	edp_panel: edp-panel {
+		compatible = "sharp,lq123p1jx31", "simple-panel";
+		backlight = <&backlight>;
+		power-supply = <&pp3300_disp>;
+
+		ports {
+			panel_in_edp: endpoint {
+				remote-endpoint = <&edp_out_panel>;
+			};
+		};
+	};
+
 	thermistor_ppvar_bigcpu: thermistor-ppvar-bigcpu {
 		compatible = "murata,ncp15wb473";
 		pullup-uv = <1800000>;
@@ -264,6 +276,23 @@ ap_i2c_dig: &i2c2 {
 	};
 };
 
+&edp {
+	status = "okay";
+
+	ports {
+		edp_out: port at 1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_out_panel: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&panel_in_edp>;
+			};
+		};
+	};
+};
+
 &ppvar_bigcpu_pwm {
 	regulator-min-microvolt = <798674>;
 	regulator-max-microvolt = <1302172>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..470105d651c2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -927,6 +927,22 @@ ap_i2c_audio: &i2c8 {
 	dr_mode = "host";
 };
 
+&vopb {
+	status = "okay";
+};
+
+&vopb_mmu {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
 #include <arm/cros-ec-keyboard.dtsi>
 #include <arm/cros-ec-sbs.dtsi>
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:04 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:04 +0800
Subject: [PATCH v6 02/10] drm/rockchip: analogix_dp: Remove unnecessary init
 code
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019034812.13768-3-jeffy.chen@rock-chips.com>

Remove unnecessary init code, since we would do it in the power_on()
callback.

Also move of parse code to probe().

Fixes: 9e32e16e9e98 ("drm: rockchip: dp: add rockchip platform dp driver")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v6: None
Changes in v5: None

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 27 ++++++-------------------
 1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 4d3f6ad0abdd..8cae5ad926cd 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -269,7 +269,7 @@ static struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
 	.destroy = rockchip_dp_drm_encoder_destroy,
 };
 
-static int rockchip_dp_init(struct rockchip_dp_device *dp)
+static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
 {
 	struct device *dev = dp->dev;
 	struct device_node *np = dev->of_node;
@@ -303,19 +303,6 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp)
 		return PTR_ERR(dp->rst);
 	}
 
-	ret = clk_prepare_enable(dp->pclk);
-	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret);
-		return ret;
-	}
-
-	ret = rockchip_dp_pre_init(dp);
-	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "failed to pre init %d\n", ret);
-		clk_disable_unprepare(dp->pclk);
-		return ret;
-	}
-
 	return 0;
 }
 
@@ -361,10 +348,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	if (!dp_data)
 		return -ENODEV;
 
-	ret = rockchip_dp_init(dp);
-	if (ret < 0)
-		return ret;
-
 	dp->data = dp_data;
 	dp->drm_dev = drm_dev;
 
@@ -398,7 +381,6 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 	rockchip_drm_psr_unregister(&dp->encoder);
 
 	analogix_dp_unbind(dev, master, data);
-	clk_disable_unprepare(dp->pclk);
 }
 
 static const struct component_ops rockchip_dp_component_ops = {
@@ -414,7 +396,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 	int ret;
 
 	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
-	if (ret)
+	if (ret < 0)
 		return ret;
 
 	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
@@ -422,9 +404,12 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	dp->dev = dev;
-
 	dp->plat_data.panel = panel;
 
+	ret = rockchip_dp_of_probe(dp);
+	if (ret < 0)
+		return ret;
+
 	/*
 	 * We just use the drvdata until driver run into component
 	 * add function, and then we would set drvdata to null, so
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:05 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:05 +0800
Subject: [PATCH v6 03/10] drm/bridge: analogix: Do not use device's drvdata
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019034812.13768-4-jeffy.chen@rock-chips.com>

The driver that instantiates the bridge should own the drvdata, as all
driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
owned by its driver struct. Moreover, storing two different pointer
types in driver data depending on driver initialization status is barely
a good practice and in fact has led to many bugs in this driver.

Let's clean up this mess and change Analogix entry points to simply
accept some opaque struct pointer, adjusting their users at the same
time to avoid breaking the compilation.

Signed-off-by: Tomasz Figa <tfiga at chromium.org>
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>
Reviewed-by: Sean Paul <seanpaul at chromium.org>
Acked-by: Jingoo Han <jingoohan1 at gmail.com>
Acked-by: Archit Taneja <architt at codeaurora.org>
---

Changes in v6: None
Changes in v5: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++-------------
 drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 49 ++++++++++++---------
 include/drm/bridge/analogix_dp.h                   | 19 ++++----
 4 files changed, 74 insertions(+), 70 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5dd3f1cd074a..74d274b6d31d 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -98,17 +98,15 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
 	return 0;
 }
 
-int analogix_dp_psr_supported(struct device *dev)
+int analogix_dp_psr_supported(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 
 	return dp->psr_support;
 }
 EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
 
-int analogix_dp_enable_psr(struct device *dev)
+int analogix_dp_enable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 
 	if (!dp->psr_support)
@@ -129,9 +127,8 @@ int analogix_dp_enable_psr(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
 
-int analogix_dp_disable_psr(struct device *dev)
+int analogix_dp_disable_psr(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	struct edp_vsc_psr psr_vsc;
 	int ret;
 
@@ -1281,8 +1278,9 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
 	return analogix_dp_transfer(dp, msg);
 }
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data)
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct analogix_dp_device *dp;
@@ -1292,14 +1290,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (!plat_data) {
 		dev_err(dev, "Invalided input plat_data\n");
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
 	if (!dp)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, dp);
+		return ERR_PTR(-ENOMEM);
 
 	dp->dev = &pdev->dev;
 	dp->dpms_mode = DRM_MODE_DPMS_OFF;
@@ -1316,7 +1312,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	ret = analogix_dp_dt_parse_pdata(dp);
 	if (ret)
-		return ret;
+		return ERR_PTR(ret);
 
 	dp->phy = devm_phy_get(dp->dev, "dp");
 	if (IS_ERR(dp->phy)) {
@@ -1330,14 +1326,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 			if (ret == -ENOSYS || ret == -ENODEV)
 				dp->phy = NULL;
 			else
-				return ret;
+				return ERR_PTR(ret);
 		}
 	}
 
 	dp->clock = devm_clk_get(&pdev->dev, "dp");
 	if (IS_ERR(dp->clock)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
-		return PTR_ERR(dp->clock);
+		return ERR_CAST(dp->clock);
 	}
 
 	clk_prepare_enable(dp->clock);
@@ -1346,7 +1342,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(dp->reg_base))
-		return PTR_ERR(dp->reg_base);
+		return ERR_CAST(dp->reg_base);
 
 	dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
 
@@ -1367,7 +1363,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 					    "hpd_gpio");
 		if (ret) {
 			dev_err(&pdev->dev, "failed to get hpd gpio\n");
-			return ret;
+			return ERR_PTR(ret);
 		}
 		dp->irq = gpio_to_irq(dp->hpd_gpio);
 		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@@ -1379,7 +1375,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	if (dp->irq == -ENXIO) {
 		dev_err(&pdev->dev, "failed to get irq\n");
-		return -ENODEV;
+		return ERR_PTR(-ENODEV);
 	}
 
 	pm_runtime_enable(dev);
@@ -1420,7 +1416,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	phy_power_off(dp->phy);
 	pm_runtime_put(dev);
 
-	return 0;
+	return dp;
 
 err_disable_pm_runtime:
 
@@ -1428,15 +1424,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	pm_runtime_put(dev);
 	pm_runtime_disable(dev);
 
-	return ret;
+	return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_bind);
 
-void analogix_dp_unbind(struct device *dev, struct device *master,
-			void *data)
+void analogix_dp_unbind(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	analogix_dp_bridge_disable(dp->bridge);
 	dp->connector.funcs->destroy(&dp->connector);
 	dp->encoder->funcs->destroy(dp->encoder);
@@ -1449,16 +1442,14 @@ void analogix_dp_unbind(struct device *dev, struct device *master,
 	}
 
 	drm_dp_aux_unregister(&dp->aux);
-	pm_runtime_disable(dev);
+	pm_runtime_disable(dp->dev);
 	clk_disable_unprepare(dp->clock);
 }
 EXPORT_SYMBOL_GPL(analogix_dp_unbind);
 
 #ifdef CONFIG_PM
-int analogix_dp_suspend(struct device *dev)
+int analogix_dp_suspend(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
-
 	clk_disable_unprepare(dp->clock);
 
 	if (dp->plat_data->panel) {
@@ -1470,9 +1461,8 @@ int analogix_dp_suspend(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(analogix_dp_suspend);
 
-int analogix_dp_resume(struct device *dev)
+int analogix_dp_resume(struct analogix_dp_device *dp)
 {
-	struct analogix_dp_device *dp = dev_get_drvdata(dev);
 	int ret;
 
 	ret = clk_prepare_enable(dp->clock);
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 39629e7a80b9..f7e5b2c405ed 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -41,6 +41,7 @@ struct exynos_dp_device {
 	struct device              *dev;
 
 	struct videomode           vm;
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -157,13 +158,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp->dev = dev;
 	dp->drm_dev = drm_dev;
 
@@ -190,13 +184,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 
 	dp->plat_data.encoder = encoder;
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp))
+		return PTR_ERR(dp->adp);
+
+	return 0;
 }
 
 static void exynos_dp_unbind(struct device *dev, struct device *master,
 			     void *data)
 {
-	return analogix_dp_unbind(dev, master, data);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_unbind(dp->adp);
 }
 
 static const struct component_ops exynos_dp_ops = {
@@ -257,12 +257,16 @@ static int exynos_dp_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int exynos_dp_suspend(struct device *dev)
 {
-	return analogix_dp_suspend(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
 }
 
 static int exynos_dp_resume(struct device *dev)
 {
-	return analogix_dp_resume(dev);
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
 }
 #endif
 
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 8cae5ad926cd..fa0365de31d2 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -77,6 +77,7 @@ struct rockchip_dp_device {
 
 	const struct rockchip_dp_chip_data *data;
 
+	struct analogix_dp_device *adp;
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -85,7 +86,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
 	struct rockchip_dp_device *dp = to_dp(encoder);
 	unsigned long flags;
 
-	if (!analogix_dp_psr_supported(dp->dev))
+	if (!analogix_dp_psr_supported(dp->adp))
 		return;
 
 	DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
@@ -116,9 +117,9 @@ static void analogix_dp_psr_work(struct work_struct *work)
 
 	spin_lock_irqsave(&dp->psr_lock, flags);
 	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
-		analogix_dp_enable_psr(dp->dev);
+		analogix_dp_enable_psr(dp->adp);
 	else
-		analogix_dp_disable_psr(dp->dev);
+		analogix_dp_disable_psr(dp->adp);
 	spin_unlock_irqrestore(&dp->psr_lock, flags);
 }
 
@@ -273,7 +274,6 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
 {
 	struct device *dev = dp->dev;
 	struct device_node *np = dev->of_node;
-	int ret;
 
 	dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
 	if (IS_ERR(dp->grf)) {
@@ -337,13 +337,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	struct drm_device *drm_dev = data;
 	int ret;
 
-	/*
-	 * Just like the probe function said, we don't need the
-	 * device drvrate anymore, we should leave the charge to
-	 * analogix dp driver, set the device drvdata to NULL.
-	 */
-	dev_set_drvdata(dev, NULL);
-
 	dp_data = of_device_get_match_data(dev);
 	if (!dp_data)
 		return -ENODEV;
@@ -370,7 +363,11 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 
-	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
+	if (IS_ERR(dp->adp))
+		return PTR_ERR(dp->adp);
+
+	return 0;
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
@@ -379,8 +376,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
 
 	rockchip_drm_psr_unregister(&dp->encoder);
-
-	analogix_dp_unbind(dev, master, data);
+	analogix_dp_unbind(dp->adp);
 }
 
 static const struct component_ops rockchip_dp_component_ops = {
@@ -410,11 +406,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 	if (ret < 0)
 		return ret;
 
-	/*
-	 * We just use the drvdata until driver run into component
-	 * add function, and then we would set drvdata to null, so
-	 * that analogix dp driver could take charge of the drvdata.
-	 */
 	platform_set_drvdata(pdev, dp);
 
 	return component_add(dev, &rockchip_dp_component_ops);
@@ -427,10 +418,26 @@ static int rockchip_dp_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_dp_suspend(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_suspend(dp->adp);
+}
+
+static int rockchip_dp_resume(struct device *dev)
+{
+	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+
+	return analogix_dp_resume(dp->adp);
+}
+#endif
+
 static const struct dev_pm_ops rockchip_dp_pm_ops = {
 #ifdef CONFIG_PM_SLEEP
-	.suspend = analogix_dp_suspend,
-	.resume_early = analogix_dp_resume,
+	.suspend = rockchip_dp_suspend,
+	.resume_early = rockchip_dp_resume,
 #endif
 };
 
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index c99d6eaef1ac..5518fc75dd6e 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -13,6 +13,8 @@
 
 #include <drm/drm_crtc.h>
 
+struct analogix_dp_device;
+
 enum analogix_dp_devtype {
 	EXYNOS_DP,
 	RK3288_DP,
@@ -38,16 +40,17 @@ struct analogix_dp_plat_data {
 			 struct drm_connector *);
 };
 
-int analogix_dp_psr_supported(struct device *dev);
-int analogix_dp_enable_psr(struct device *dev);
-int analogix_dp_disable_psr(struct device *dev);
+int analogix_dp_psr_supported(struct analogix_dp_device *dp);
+int analogix_dp_enable_psr(struct analogix_dp_device *dp);
+int analogix_dp_disable_psr(struct analogix_dp_device *dp);
 
-int analogix_dp_resume(struct device *dev);
-int analogix_dp_suspend(struct device *dev);
+int analogix_dp_resume(struct analogix_dp_device *dp);
+int analogix_dp_suspend(struct analogix_dp_device *dp);
 
-int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
-		     struct analogix_dp_plat_data *plat_data);
-void analogix_dp_unbind(struct device *dev, struct device *master, void *data);
+struct analogix_dp_device *
+analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
+		 struct analogix_dp_plat_data *plat_data);
+void analogix_dp_unbind(struct analogix_dp_device *dp);
 
 int analogix_dp_start_crc(struct drm_connector *connector);
 int analogix_dp_stop_crc(struct drm_connector *connector);
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:06 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:06 +0800
Subject: [PATCH v6 04/10] drm/bridge: analogix_dp: Fix connector and encoder
 cleanup
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019034812.13768-5-jeffy.chen@rock-chips.com>

Since we are initing connector in the core driver and encoder in the
plat driver, let's clean them up in the right places.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>
---

Changes in v6:
Don't change order of rockchip_drm_psr_register().

Changes in v5: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  2 --
 drivers/gpu/drm/exynos/exynos_dp.c                 |  7 +++++--
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 12 +++++-------
 3 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 74d274b6d31d..3f910ab36ff6 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1409,7 +1409,6 @@ analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 	ret = analogix_dp_create_bridge(drm_dev, dp);
 	if (ret) {
 		DRM_ERROR("failed to create bridge (%d)\n", ret);
-		drm_encoder_cleanup(dp->encoder);
 		goto err_disable_pm_runtime;
 	}
 
@@ -1432,7 +1431,6 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
 {
 	analogix_dp_bridge_disable(dp->bridge);
 	dp->connector.funcs->destroy(&dp->connector);
-	dp->encoder->funcs->destroy(dp->encoder);
 
 	if (dp->plat_data->panel) {
 		if (drm_panel_unprepare(dp->plat_data->panel))
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index f7e5b2c405ed..33319a858f3a 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -185,8 +185,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 	dp->plat_data.encoder = encoder;
 
 	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-	if (IS_ERR(dp->adp))
+	if (IS_ERR(dp->adp)) {
+		dp->encoder.funcs->destroy(&dp->encoder);
 		return PTR_ERR(dp->adp);
+	}
 
 	return 0;
 }
@@ -196,7 +198,8 @@ static void exynos_dp_unbind(struct device *dev, struct device *master,
 {
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-	return analogix_dp_unbind(dp->adp);
+	analogix_dp_unbind(dp->adp);
+	dp->encoder.funcs->destroy(&dp->encoder);
 }
 
 static const struct component_ops exynos_dp_ops = {
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index fa0365de31d2..117585df73e1 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -261,13 +261,8 @@ static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = {
 	.atomic_check = rockchip_dp_drm_encoder_atomic_check,
 };
 
-static void rockchip_dp_drm_encoder_destroy(struct drm_encoder *encoder)
-{
-	drm_encoder_cleanup(encoder);
-}
-
 static struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
-	.destroy = rockchip_dp_drm_encoder_destroy,
+	.destroy = drm_encoder_cleanup,
 };
 
 static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
@@ -364,8 +359,10 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
 
 	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
-	if (IS_ERR(dp->adp))
+	if (IS_ERR(dp->adp)) {
+		dp->encoder.funcs->destroy(&dp->encoder);
 		return PTR_ERR(dp->adp);
+	}
 
 	return 0;
 }
@@ -377,6 +374,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 
 	rockchip_drm_psr_unregister(&dp->encoder);
 	analogix_dp_unbind(dp->adp);
+	dp->encoder.funcs->destroy(&dp->encoder);
 }
 
 static const struct component_ops rockchip_dp_component_ops = {
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:07 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:07 +0800
Subject: [PATCH v6 05/10] drm/rockchip: analogix_dp: Add a sanity check for
 rockchip_drm_psr_register()
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019034812.13768-6-jeffy.chen@rock-chips.com>

The rockchip_drm_psr_register() can fail, so add a sanity check for that.

Also reorder the calls in unbind() to match bind().

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v6: None
Changes in v5: None

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 117585df73e1..bd3567ad8b53 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -356,15 +356,22 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
 	INIT_WORK(&dp->psr_work, analogix_dp_psr_work);
 
-	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
+	ret = rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
+	if (ret < 0)
+		goto err_cleanup_encoder;
 
 	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
 	if (IS_ERR(dp->adp)) {
-		dp->encoder.funcs->destroy(&dp->encoder);
-		return PTR_ERR(dp->adp);
+		ret = PTR_ERR(dp->adp);
+		goto err_unreg_psr;
 	}
 
 	return 0;
+err_unreg_psr:
+	rockchip_drm_psr_unregister(&dp->encoder);
+err_cleanup_encoder:
+	dp->encoder.funcs->destroy(&dp->encoder);
+	return ret;
 }
 
 static void rockchip_dp_unbind(struct device *dev, struct device *master,
@@ -372,8 +379,8 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 {
 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
 
-	rockchip_drm_psr_unregister(&dp->encoder);
 	analogix_dp_unbind(dp->adp);
+	rockchip_drm_psr_unregister(&dp->encoder);
 	dp->encoder.funcs->destroy(&dp->encoder);
 }
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:08 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:08 +0800
Subject: [PATCH v6 06/10] drm/rockchip: dw-mipi-dsi: Fix error handling path
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019034812.13768-7-jeffy.chen@rock-chips.com>

Add missing pm_runtime_disable() in bind()'s error handling path.

Also cleanup encoder & connector in unbind().

Fixes: 80a9a059d4e4 ("drm/rockchip/dsi: add dw-mipi power domain support")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v6: None
Changes in v5:
Call the destroy hook in the error handling path like in unbind().

 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index b15755b6129c..e72d4e2b61aa 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -1282,7 +1282,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	ret = dw_mipi_dsi_register(drm, dsi);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
-		goto err_pllref;
+		goto err_disable_pllref;
 	}
 
 	pm_runtime_enable(dev);
@@ -1292,23 +1292,24 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	ret = mipi_dsi_host_register(&dsi->dsi_host);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
-		goto err_cleanup;
+		goto err_disable_pm_runtime;
 	}
 
 	if (!dsi->panel) {
 		ret = -EPROBE_DEFER;
-		goto err_mipi_dsi_host;
+		goto err_unreg_mipi_dsi_host;
 	}
 
 	dev_set_drvdata(dev, dsi);
 	return 0;
 
-err_mipi_dsi_host:
+err_unreg_mipi_dsi_host:
 	mipi_dsi_host_unregister(&dsi->dsi_host);
-err_cleanup:
-	drm_encoder_cleanup(&dsi->encoder);
-	drm_connector_cleanup(&dsi->connector);
-err_pllref:
+err_disable_pm_runtime:
+	pm_runtime_disable(dev);
+	dsi->connector.funcs->destroy(&dsi->connector);
+	dsi->encoder.funcs->destroy(&dsi->encoder);
+err_disable_pllref:
 	clk_disable_unprepare(dsi->pllref_clk);
 	return ret;
 }
@@ -1320,6 +1321,10 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
 
 	mipi_dsi_host_unregister(&dsi->dsi_host);
 	pm_runtime_disable(dev);
+
+	dsi->connector.funcs->destroy(&dsi->connector);
+	dsi->encoder.funcs->destroy(&dsi->encoder);
+
 	clk_disable_unprepare(dsi->pllref_clk);
 }
 
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:09 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:09 +0800
Subject: [PATCH v6 07/10] drm/rockchip: inno_hdmi: Fix error handling path
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019034812.13768-8-jeffy.chen@rock-chips.com>

Add missing error handling in bind().

Fixes: 412d4ae6b7a5 ("drm/rockchip: hdmi: add Innosilicon HDMI support")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v6: None
Changes in v5:
Call the destroy hook in the error handling path like in unbind().
Update cleanup order in unbind().

 drivers/gpu/drm/rockchip/inno_hdmi.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c
index ee584d87111f..9a96ff6b022b 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -851,8 +851,10 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 	}
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
+	if (irq < 0) {
+		ret = irq;
+		goto err_disable_clk;
+	}
 
 	inno_hdmi_reset(hdmi);
 
@@ -860,7 +862,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 	if (IS_ERR(hdmi->ddc)) {
 		ret = PTR_ERR(hdmi->ddc);
 		hdmi->ddc = NULL;
-		return ret;
+		goto err_disable_clk;
 	}
 
 	/*
@@ -874,7 +876,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 
 	ret = inno_hdmi_register(drm, hdmi);
 	if (ret)
-		return ret;
+		goto err_put_adapter;
 
 	dev_set_drvdata(dev, hdmi);
 
@@ -884,7 +886,17 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
 	ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq,
 					inno_hdmi_irq, IRQF_SHARED,
 					dev_name(dev), hdmi);
+	if (ret < 0)
+		goto err_cleanup_hdmi;
 
+	return 0;
+err_cleanup_hdmi:
+	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
+err_put_adapter:
+	i2c_put_adapter(hdmi->ddc);
+err_disable_clk:
+	clk_disable_unprepare(hdmi->pclk);
 	return ret;
 }
 
@@ -896,8 +908,8 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master,
 	hdmi->connector.funcs->destroy(&hdmi->connector);
 	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 
-	clk_disable_unprepare(hdmi->pclk);
 	i2c_put_adapter(hdmi->ddc);
+	clk_disable_unprepare(hdmi->pclk);
 }
 
 static const struct component_ops inno_hdmi_ops = {
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:11 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:11 +0800
Subject: [PATCH v6 09/10] drm/bridge/synopsys: dw-hdmi: Do not use device's
 drvdata
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019034812.13768-10-jeffy.chen@rock-chips.com>

Let plat drivers own the drvdata, so that they could cleanup resources
in their unbind().

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
Reviewed-by: Neil Armstrong <narmstrong at baylibre.com>
---

Changes in v6: None
Changes in v5: None

 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c   | 43 ++++++++++-------------------
 drivers/gpu/drm/imx/dw_hdmi-imx.c           | 22 +++++++++------
 drivers/gpu/drm/meson/meson_dw_hdmi.c       | 20 ++++++++++----
 drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c      | 14 ++++++++--
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 23 ++++++++-------
 include/drm/bridge/dw_hdmi.h                | 17 ++++++------
 6 files changed, 77 insertions(+), 62 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index ff1b3d2b5d06..6fbfafc5832b 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2072,7 +2072,7 @@ static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
 	return ret;
 }
 
-void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
+void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
 {
 	mutex_lock(&hdmi->mutex);
 
@@ -2098,13 +2098,6 @@ void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
 	}
 	mutex_unlock(&hdmi->mutex);
 }
-
-void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense)
-{
-	struct dw_hdmi *hdmi = dev_get_drvdata(dev);
-
-	__dw_hdmi_setup_rx_sense(hdmi, hpd, rx_sense);
-}
 EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense);
 
 static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
@@ -2140,9 +2133,8 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
 	 */
 	if (intr_stat &
 	    (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) {
-		__dw_hdmi_setup_rx_sense(hdmi,
-					 phy_stat & HDMI_PHY_HPD,
-					 phy_stat & HDMI_PHY_RX_SENSE);
+		dw_hdmi_setup_rx_sense(hdmi, phy_stat & HDMI_PHY_HPD,
+				       phy_stat & HDMI_PHY_RX_SENSE);
 
 		if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0)
 			cec_notifier_set_phys_addr(hdmi->cec_notifier,
@@ -2512,8 +2504,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
 	if (hdmi->i2c)
 		dw_hdmi_i2c_init(hdmi);
 
-	platform_set_drvdata(pdev, hdmi);
-
 	return hdmi;
 
 err_iahb:
@@ -2559,25 +2549,23 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
 /* -----------------------------------------------------------------------------
  * Probe/remove API, used from platforms based on the DRM bridge API.
  */
-int dw_hdmi_probe(struct platform_device *pdev,
-		  const struct dw_hdmi_plat_data *plat_data)
+struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
+			      const struct dw_hdmi_plat_data *plat_data)
 {
 	struct dw_hdmi *hdmi;
 
 	hdmi = __dw_hdmi_probe(pdev, plat_data);
 	if (IS_ERR(hdmi))
-		return PTR_ERR(hdmi);
+		return hdmi;
 
 	drm_bridge_add(&hdmi->bridge);
 
-	return 0;
+	return hdmi;
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_probe);
 
-void dw_hdmi_remove(struct platform_device *pdev)
+void dw_hdmi_remove(struct dw_hdmi *hdmi)
 {
-	struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
-
 	drm_bridge_remove(&hdmi->bridge);
 
 	__dw_hdmi_remove(hdmi);
@@ -2587,31 +2575,30 @@ EXPORT_SYMBOL_GPL(dw_hdmi_remove);
 /* -----------------------------------------------------------------------------
  * Bind/unbind API, used from platforms based on the component framework.
  */
-int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-		 const struct dw_hdmi_plat_data *plat_data)
+struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
+			    struct drm_encoder *encoder,
+			    const struct dw_hdmi_plat_data *plat_data)
 {
 	struct dw_hdmi *hdmi;
 	int ret;
 
 	hdmi = __dw_hdmi_probe(pdev, plat_data);
 	if (IS_ERR(hdmi))
-		return PTR_ERR(hdmi);
+		return hdmi;
 
 	ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
 	if (ret) {
 		__dw_hdmi_remove(hdmi);
 		DRM_ERROR("Failed to initialize bridge with drm\n");
-		return ret;
+		return ERR_PTR(ret);
 	}
 
-	return 0;
+	return hdmi;
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_bind);
 
-void dw_hdmi_unbind(struct device *dev)
+void dw_hdmi_unbind(struct dw_hdmi *hdmi)
 {
-	struct dw_hdmi *hdmi = dev_get_drvdata(dev);
-
 	__dw_hdmi_remove(hdmi);
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index b62763aa8706..b01d03e02ce0 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -26,6 +26,8 @@ struct imx_hdmi {
 	struct device *dev;
 	struct drm_encoder encoder;
 	struct regmap *regmap;
+
+	struct dw_hdmi *hdmi;
 };
 
 static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e)
@@ -239,22 +241,24 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
 	drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS, NULL);
 
-	ret = dw_hdmi_bind(pdev, encoder, plat_data);
+	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
+	if (IS_ERR(hdmi->hdmi)) {
+		encoder->funcs->destroy(encoder);
+		return PTR_ERR(hdmi->hdmi);
+	}
 
-	/*
-	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
-	 * which would have called the encoder cleanup.  Do it manually.
-	 */
-	if (ret)
-		drm_encoder_cleanup(encoder);
+	dev_set_drvdata(dev, hdmi);
 
-	return ret;
+	return 0;
 }
 
 static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
 			       void *data)
 {
-	return dw_hdmi_unbind(dev);
+	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+
+	dw_hdmi_unbind(hdmi->hdmi);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 }
 
 static const struct component_ops dw_hdmi_imx_ops = {
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index cef414466f9f..fc29f69f7108 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -138,6 +138,8 @@ struct meson_dw_hdmi {
 	struct clk *hdmi_pclk;
 	struct clk *venci_clk;
 	u32 irq_stat;
+
+	struct dw_hdmi *hdmi;
 };
 #define encoder_to_meson_dw_hdmi(x) \
 	container_of(x, struct meson_dw_hdmi, encoder)
@@ -526,7 +528,7 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
 		if (stat & HDMITX_TOP_INTR_HPD_RISE)
 			hpd_connected = true;
 
-		dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected,
+		dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected,
 				       hpd_connected);
 
 		drm_helper_hpd_irq_event(dw_hdmi->encoder.dev);
@@ -865,9 +867,14 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 	dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
 	dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
 
-	ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data);
-	if (ret)
-		return ret;
+	meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
+					   &meson_dw_hdmi->dw_plat_data);
+	if (IS_ERR(meson_dw_hdmi->hdmi)) {
+		encoder->funcs->destroy(encoder);
+		return PTR_ERR(meson_dw_hdmi->hdmi);
+	}
+
+	dev_set_drvdata(dev, meson_dw_hdmi);
 
 	DRM_DEBUG_DRIVER("HDMI controller initialized\n");
 
@@ -877,7 +884,10 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
 				   void *data)
 {
-	dw_hdmi_unbind(dev);
+	struct meson_dw_hdmi *meson_dw_hdmi = dev_get_drvdata(dev);
+
+	dw_hdmi_unbind(meson_dw_hdmi->hdmi);
+	meson_dw_hdmi->encoder.funcs->destroy(&meson_dw_hdmi->encoder);
 }
 
 static const struct component_ops meson_dw_hdmi_ops = {
diff --git a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
index dc85b53d58ef..76210ae25094 100644
--- a/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
+++ b/drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c
@@ -68,12 +68,22 @@ static const struct dw_hdmi_plat_data rcar_dw_hdmi_plat_data = {
 
 static int rcar_dw_hdmi_probe(struct platform_device *pdev)
 {
-	return dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data);
+	struct dw_hdmi *hdmi;
+
+	hdmi = dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data);
+	if (IS_ERR(hdmi))
+		return PTR_ERR(hdmi);
+
+	platform_set_drvdata(pdev, hdmi);
+
+	return 0;
 }
 
 static int rcar_dw_hdmi_remove(struct platform_device *pdev)
 {
-	dw_hdmi_remove(pdev);
+	struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
+
+	dw_hdmi_remove(hdmi);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 1eb02a82fd91..791ab938f998 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -48,6 +48,8 @@ struct rockchip_hdmi {
 	const struct rockchip_hdmi_chip_data *chip_data;
 	struct clk *vpll_clk;
 	struct clk *grf_clk;
+
+	struct dw_hdmi *hdmi;
 };
 
 #define to_rockchip_hdmi(x)	container_of(x, struct rockchip_hdmi, x)
@@ -164,7 +166,6 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
 static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 {
 	struct device_node *np = hdmi->dev->of_node;
-	int ret;
 
 	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
 	if (IS_ERR(hdmi->regmap)) {
@@ -377,22 +378,24 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS, NULL);
 
-	ret = dw_hdmi_bind(pdev, encoder, plat_data);
+	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
+	if (IS_ERR(hdmi->hdmi)) {
+		encoder->funcs->destroy(encoder);
+		return PTR_ERR(hdmi->hdmi);
+	}
 
-	/*
-	 * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
-	 * which would have called the encoder cleanup.  Do it manually.
-	 */
-	if (ret)
-		drm_encoder_cleanup(encoder);
+	dev_set_drvdata(dev, hdmi);
 
-	return ret;
+	return 0;
 }
 
 static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 				    void *data)
 {
-	return dw_hdmi_unbind(dev);
+	struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
+
+	dw_hdmi_unbind(hdmi->hdmi);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 182f83283e24..29b8900caaf7 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -143,14 +143,15 @@ struct dw_hdmi_plat_data {
 			     unsigned long mpixelclock);
 };
 
-int dw_hdmi_probe(struct platform_device *pdev,
-		  const struct dw_hdmi_plat_data *plat_data);
-void dw_hdmi_remove(struct platform_device *pdev);
-void dw_hdmi_unbind(struct device *dev);
-int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
-		 const struct dw_hdmi_plat_data *plat_data);
-
-void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense);
+struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
+			      const struct dw_hdmi_plat_data *plat_data);
+void dw_hdmi_remove(struct dw_hdmi *hdmi);
+void dw_hdmi_unbind(struct dw_hdmi *hdmi);
+struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
+			     struct drm_encoder *encoder,
+			     const struct dw_hdmi_plat_data *plat_data);
+
+void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
 
 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
 void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
-- 
2.11.0




From jeffy.chen at rock-chips.com  Wed Oct 18 20:48:12 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 11:48:12 +0800
Subject: [PATCH v6 10/10] drm/rockchip: dw_hdmi: Fix error handling path
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019034812.13768-11-jeffy.chen@rock-chips.com>

Add missing clk_disable_unprepare() in bind()'s error handling path and
unbind().

Also inline clk_prepare_enable() with bind().

Fixes: 12b9f204e804 ("drm: bridge/dw_hdmi: add rockchip rk3288 support")
Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v6: None
Changes in v5:
Add disable to unbind(), and inline clk_prepare_enable() with bind().

 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 791ab938f998..e936dfe6c03d 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -193,13 +193,6 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
 		return PTR_ERR(hdmi->grf_clk);
 	}
 
-	ret = clk_prepare_enable(hdmi->vpll_clk);
-	if (ret) {
-		DRM_DEV_ERROR(hdmi->dev,
-			      "Failed to enable HDMI vpll: %d\n", ret);
-		return ret;
-	}
-
 	return 0;
 }
 
@@ -374,6 +367,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	ret = clk_prepare_enable(hdmi->vpll_clk);
+	if (ret) {
+		DRM_DEV_ERROR(hdmi->dev,
+			      "Failed to enable HDMI vpll: %d\n", ret);
+		return ret;
+	}
+
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
 	drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS, NULL);
@@ -381,6 +381,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
 	if (IS_ERR(hdmi->hdmi)) {
 		encoder->funcs->destroy(encoder);
+		clk_disable_unprepare(hdmi->vpll_clk);
 		return PTR_ERR(hdmi->hdmi);
 	}
 
@@ -396,6 +397,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
 
 	dw_hdmi_unbind(hdmi->hdmi);
 	hdmi->encoder.funcs->destroy(&hdmi->encoder);
+	clk_disable_unprepare(hdmi->vpll_clk);
 }
 
 static const struct component_ops dw_hdmi_rockchip_ops = {
-- 
2.11.0




From arnd at arndb.de  Thu Oct 19 02:30:34 2017
From: arnd at arndb.de (Arnd Bergmann)
Date: Thu, 19 Oct 2017 11:30:34 +0200
Subject: [PATCH] [media] rockchip/rga: annotate PM functions as __maybe_unused
Message-ID: <20171019093044.531871-1-arnd@arndb.de>

The newly added driver has incorrect #ifdef annotations on its
PM functions, leading to a harmless compile-time warning when
CONFIG_PM is disabled:

drivers/media/platform/rockchip/rga/rga.c:760:13: error: 'rga_disable_clocks' defined but not used [-Werror=unused-function]
 static void rga_disable_clocks(struct rockchip_rga *rga)
             ^~~~~~~~~~~~~~~~~~
drivers/media/platform/rockchip/rga/rga.c:728:12: error: 'rga_enable_clocks' defined but not used [-Werror=unused-function]

This removes the #ifdef and marks the functions as __maybe_unused,
so gcc can silently drop all the unused code.

Fixes: f7e7b48e6d79 ("[media] rockchip/rga: v4l2 m2m support")
Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index e7d1b34baf1c..89296de9cf4a 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -960,8 +960,7 @@ static int rga_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int rga_runtime_suspend(struct device *dev)
+static int __maybe_unused rga_runtime_suspend(struct device *dev)
 {
 	struct rockchip_rga *rga = dev_get_drvdata(dev);
 
@@ -970,13 +969,12 @@ static int rga_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static int rga_runtime_resume(struct device *dev)
+static int __maybe_unused rga_runtime_resume(struct device *dev)
 {
 	struct rockchip_rga *rga = dev_get_drvdata(dev);
 
 	return rga_enable_clocks(rga);
 }
-#endif
 
 static const struct dev_pm_ops rga_pm = {
 	SET_RUNTIME_PM_OPS(rga_runtime_suspend,
-- 
2.9.0



From jeffy.chen at rock-chips.com  Thu Oct 19 04:10:04 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 19:10:04 +0800
Subject: [PATCH v7 0/3] PCI: rockchip: Move PCIE_WAKE handling into pci core
Message-ID: <20171019111007.25234-1-jeffy.chen@rock-chips.com>


Currently we are handling wake irq in mrvl wifi driver. Move it into
pci core.

Tested on my chromebook bob(with cros 4.4 kernel and mrvl wifi).


Changes in v7:
Move PCIE_WAKE handling into pci core.

Changes in v6:
Fix device_init_wake error handling, and add some comments.

Changes in v5:
Rebase
Move to pci.txt
Use "wakeup" instead of "wake"

Changes in v3:
Fix error handling

Changes in v2:
Use dev_pm_set_dedicated_wake_irq
        -- Suggested by Brian Norris <briannorris at chromium.com>

Jeffy Chen (3):
  PCI: Add support for wake irq
  dt-bindings: PCI: Add definition of pcie wake irq
  arm64: dts: rockchip: Handle pcie wake in pcie driver for Gru

 Documentation/devicetree/bindings/pci/pci.txt |  2 ++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi  | 15 +++++++-----
 drivers/pci/pci.c                             | 34 +++++++++++++++++++++++++--
 drivers/pci/probe.c                           | 32 +++++++++++++++++++++----
 drivers/pci/remove.c                          |  9 +++++++
 5 files changed, 80 insertions(+), 12 deletions(-)

-- 
2.11.0




From jeffy.chen at rock-chips.com  Thu Oct 19 04:10:07 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 19 Oct 2017 19:10:07 +0800
Subject: [PATCH v7 3/3] arm64: dts: rockchip: Handle pcie wake in pcie driver
 for Gru
In-Reply-To: <20171019111007.25234-1-jeffy.chen@rock-chips.com>
References: <20171019111007.25234-1-jeffy.chen@rock-chips.com>
Message-ID: <20171019111007.25234-4-jeffy.chen@rock-chips.com>

Currently we are handling pcie wake irq in mrvl wifi driver.
Move it to rockchip pcie driver for Gru boards.

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v7: None
Changes in v6: None
Changes in v5:
Use "wakeup" instead of "wake"

Changes in v3: None
Changes in v2: None

 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 470105d651c2..04499714f541 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -708,7 +708,15 @@ ap_i2c_audio: &i2c8 {
 
 	ep-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wifi_perst_l>;
+	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wlan_host_wake_l>, <&wifi_perst_l>;
+
+	interrupts-extended = <&gic GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gpio0 8 IRQ_TYPE_LEVEL_LOW>;
+	interrupt-names = "sys", "legacy", "client", "wakeup";
+	/delete-property/ interrupts;
+
 	vpcie3v3-supply = <&pp3300_wifi_bt>;
 	vpcie1v8-supply = <&wlan_pd_n>; /* HACK: see &wlan_pd_n */
 	vpcie0v9-supply = <&pp900_pcie>;
@@ -723,11 +731,6 @@ ap_i2c_audio: &i2c8 {
 			compatible = "pci1b4b,2b42";
 			reg = <0x83010000 0x0 0x00000000 0x0 0x00100000
 			       0x83010000 0x0 0x00100000 0x0 0x00100000>;
-			interrupt-parent = <&gpio0>;
-			interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
-			pinctrl-names = "default";
-			pinctrl-0 = <&wlan_host_wake_l>;
-			wakeup-source;
 		};
 	};
 };
-- 
2.11.0




From jeffy.chen at rock-chips.com  Thu Oct 19 04:19:57 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Thu, 19 Oct 2017 19:19:57 +0800
Subject: [PATCH v6 1/3] PCI: rockchip: Add support for pcie wake irq
In-Reply-To: <20171018132936.GP5641@bhelgaas-glaptop.roam.corp.google.com>
References: <20171013195059.23865-1-jeffy.chen@rock-chips.com>
 <20171013195059.23865-2-jeffy.chen@rock-chips.com>
 <20171016200350.GH25517@bhelgaas-glaptop.roam.corp.google.com>
 <20171018010312.GB65743@google.com>
 <20171018132936.GP5641@bhelgaas-glaptop.roam.corp.google.com>
Message-ID: <59E88A5D.8060309@rock-chips.com>

Hi guys,

On 10/18/2017 09:29 PM, Bjorn Helgaas wrote:
>> >
>> >I guess it could work to look into pci_create_root_bus(), and
>> >do something like the following?
>> >
>> >	if (IS_ENABLED(CONFIG_OF) && parent && parent->of_node)
>> >		... do OF parsing for generic features like WAKE# ...
> That's exactly the sort of thing I was thinking.
>
i was looking at that too, but i'm not very clear about how to handle 
the platform_ops's set_wakeup...





From arnd at arndb.de  Thu Oct 19 08:43:15 2017
From: arnd at arndb.de (Arnd Bergmann)
Date: Thu, 19 Oct 2017 17:43:15 +0200
Subject: [GIT PULL] Rockchip dts64 Fixes for 4.14 part 2
In-Reply-To: <6151423.bSX8Os9Bvg@phil>
References: <6151423.bSX8Os9Bvg@phil>
Message-ID: <CAK8P3a0=Rgt7ZgEgOmo5fzkgOW7skn2Pa2B1fkP1HavatLygGQ@mail.gmail.com>

On Tue, Oct 17, 2017 at 8:17 PM, Heiko Stuebner <heiko at sntech.de> wrote:
> Hi Arnd, Kevin, Olof,
>
> looks like I need two rounds of fixes this time around.
> But the vqmmc voltage issue warrants that I think, especially
> as 4.14 is going to be a LTS release.

Pulled into fixes, thanks!

       Arnd


From hoegsberg at gmail.com  Thu Oct 19 10:46:43 2017
From: hoegsberg at gmail.com (=?UTF-8?Q?Kristian_H=C3=B8gsberg?=)
Date: Thu, 19 Oct 2017 10:46:43 -0700
Subject: [PATCH v2] drm/rockchip: Use an enum to identify Rockchip VOPs
In-Reply-To: <fad6657f-2bfa-c722-27a6-e29bb9fadb52@rock-chips.com>
References: <1478202408-11635-1-git-send-email-hoegsberg@chromium.org>
 <20171018175208.GA73666@google.com>
 <fad6657f-2bfa-c722-27a6-e29bb9fadb52@rock-chips.com>
Message-ID: <CAOeoa-ebpsGbUoHBc_Ei5VZHHrvti3MCgReqrEw=SFTYna0cLg@mail.gmail.com>

On Wed, Oct 18, 2017 at 5:49 PM, Mark yao <mark.yao at rock-chips.com> wrote:
> On 2017?10?19? 01:52, Brian Norris wrote:
>>
>> Hi Kristian,
>>
>> On Thu, Nov 03, 2016 at 12:46:48PM -0700, Kristian H?gsberg wrote:
>>>
>>> We used to call drm_of_encoder_active_endpoint_id() from
>>> rockchip_dp_drm_encoder_atomic_check() to determine the endpoint for the
>>> active encoder. However, the encoder isn't necessarily active at this
>>> point or it may be connected to different crtc than what we're switching
>>> to. Instead, look at the crtc from the drm_crtc_state.  This fixes wrong
>>> colors when driving the eDP with the big VOP.  Further, we can identify
>>> the type of VOP we're dealing with by just putting a VOP id enum in the
>>> vop_data.
>
>
> Unfortunately, vop iomux and vop data are not one-to-one correspondence.
>
> Such as rk3288, vop big and vop little both use rk3288_vop data, if you use
> vop data id will not be able
> to distinguish between them.

What would you suggest then? We need this to be able to drive eDP from
the big VOP. We've been carrying this patch for quite a while and it
hasn't regressed neither rk3288 nor rk3399 boards.

Kristian

> Mark
>>>
>>>
>>> On way to test this is to use the modetest tool from libdrm:
>>>
>>>    $ modetest -M rockchip -s 32 at 28:2400x1600
>>>
>>> which displays dark or black colors because we fail to look up the
>>> endpoint and use default 0 (which is ROCKCHIP_OUT_MODE_P888) for big
>>> VOP instead of RGB10 as required.
>>>
>>> For reference,
>>>
>>>    $ modetest -M rockchip -s 32 at 25:2400x1600
>>>
>>> drives the eDP from little VOP and displays correctly.
>>>
>>> Signed-off-by: Kristian H. Kristensen <hoegsberg at chromium.org>
>>> ---
>>> v2: Stripped chromeos annotations, fix compile errors for drivers I
>>> didn't
>>> compile when I first wrote the patch.
>>
>> Do you plan to fix the errors Guenter pointed out and resend? This is
>> still causing conflicts between our ChromeOS kernel trees and upstream.
>>
>> Also, please CC linux-rockchip on Rockchip-related patches. It's much
>> easier for me to find your work that way :)
>>
>> Brian
>>
>>> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 45
>>> ++++++++++---------------
>>>   drivers/gpu/drm/rockchip/cdn-dp-core.c          | 19 +++++------
>>>   drivers/gpu/drm/rockchip/dw-mipi-dsi.c          | 12 ++++---
>>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.c     |  7 ++++
>>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.h     | 10 ++++++
>>>   drivers/gpu/drm/rockchip/rockchip_vop_reg.c     |  4 +++
>>>   6 files changed, 56 insertions(+), 41 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>>> b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>>> index 558a3bc..9ae4a9c 100644
>>> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>>> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>>> @@ -196,14 +196,16 @@ static void rockchip_dp_drm_encoder_enable(struct
>>> drm_encoder *encoder)
>>>         int ret;
>>>         u32 val;
>>>   -     ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node,
>>> encoder);
>>> -       if (ret < 0)
>>> -               return;
>>> -
>>> -       if (ret)
>>> +       switch (vop_get_crtc_vop_id(encoder->crtc)) {
>>> +       case RK3399_VOP_LIT:
>>>                 val = dp->data->lcdsel_lit;
>>> -       else
>>> +               break;
>>> +       case RK3399_VOP_BIG:
>>>                 val = dp->data->lcdsel_big;
>>> +               break;
>>> +       default:
>>> +               return;
>>> +       }
>>>         dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
>>>   @@ -231,34 +233,23 @@ rockchip_dp_drm_encoder_atomic_check(struct
>>> drm_encoder *encoder,
>>>                                       struct drm_connector_state
>>> *conn_state)
>>>   {
>>>         struct rockchip_crtc_state *s =
>>> to_rockchip_crtc_state(crtc_state);
>>> -       struct rockchip_dp_device *dp = to_dp(encoder);
>>> -       int ret;
>>>   -     /*
>>> -        * The hardware IC designed that VOP must output the RGB10 video
>>> -        * format to eDP contoller, and if eDP panel only support RGB8,
>>> -        * then eDP contoller should cut down the video data, not via VOP
>>> -        * contoller, that's why we need to hardcode the VOP output mode
>>> -        * to RGA10 here.
>>> -        */
>>> -
>>> -       ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node,
>>> encoder);
>>> -       if (ret < 0)
>>> -               return 0;
>>> -
>>> -       switch (dp->data->chip_type) {
>>> -       case RK3399_EDP:
>>> +       switch (vop_get_crtc_vop_id(crtc_state->crtc)) {
>>> +       case RK3399_VOP_LIT:
>>>                 /*
>>>                  * For RK3399, VOP Lit must code the out mode to RGB888,
>>>                  * VOP Big must code the out mode to RGB10.
>>>                  */
>>> -               if (ret)
>>> -                       s->output_mode = ROCKCHIP_OUT_MODE_P888;
>>> -               else
>>> -                       s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>>> +               s->output_mode = ROCKCHIP_OUT_MODE_P888;
>>>                 break;
>>> -
>>>         default:
>>> +               /*
>>> +                * The hardware IC designed that VOP must output the
>>> RGB10 video
>>> +                * format to eDP contoller, and if eDP panel only support
>>> RGB8,
>>> +                * then eDP contoller should cut down the video data, not
>>> via VOP
>>> +                * contoller, that's why we need to hardcode the VOP
>>> output mode
>>> +                * to RGA10 here.
>>> +                */
>>>                 s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>>>                 break;
>>>         }
>>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c
>>> b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>>> index f020e2e..b9e6184 100644
>>> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
>>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>>> @@ -570,21 +570,20 @@ static void cdn_dp_encoder_mode_set(struct
>>> drm_encoder *encoder,
>>>         video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
>>>         video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
>>>   -     ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node,
>>> encoder);
>>> -       if (ret < 0) {
>>> -               DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
>>> -               return;
>>> -       }
>>> -
>>> -       DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n",
>>> -                         (ret) ? "LIT" : "BIG");
>>>         state = to_rockchip_crtc_state(encoder->crtc->state);
>>> -       if (ret) {
>>> +       switch (vop_get_crtc_vop_id(encoder->crtc)) {
>>> +       case RK3399_VOP_LIT:
>>> +               DRM_DEV_DEBUG_KMS(dp->dev, "vop LIT output to cdn-dp\n");
>>>                 val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16);
>>>                 state->output_mode = ROCKCHIP_OUT_MODE_P888;
>>> -       } else {
>>> +               break;
>>> +       case RK3399_VOP_BIG:
>>> +               DRM_DEV_DEBUG_KMS(dp->dev, "vop BIG output to cdn-dp\n");
>>>                 val = DP_SEL_VOP_LIT << 16;
>>>                 state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>>> +               break;
>>> +       default:
>>> +               break;
>>>         }
>>>         ret = cdn_dp_grf_write(dp, GRF_SOC_CON9, val);
>>> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>>> b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>>> index dedc65b..b01a82a 100644
>>> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>>> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>>> @@ -878,7 +878,6 @@ static void dw_mipi_dsi_encoder_disable(struct
>>> drm_encoder *encoder)
>>>   static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
>>>   {
>>>         struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
>>> -       int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node,
>>> encoder);
>>>         u32 val;
>>>         if (clk_prepare_enable(dsi->pclk)) {
>>> @@ -894,13 +893,18 @@ static void dw_mipi_dsi_encoder_commit(struct
>>> drm_encoder *encoder)
>>>         clk_disable_unprepare(dsi->pclk);
>>>   -     if (mux)
>>> +       switch (vop_get_crtc_vop_id(encoder->crtc)) {
>>> +       case RK3399_VOP_LIT:
>>> +               dev_dbg(dsi->dev, "vop LIT output to dsi0\n");
>>>                 val = DSI0_SEL_VOP_LIT | (DSI0_SEL_VOP_LIT << 16);
>>> -       else
>>> +               break;
>>> +       default:
>>> +               dev_dbg(dsi->dev, "vop BIG output to dsi0\n");
>>>                 val = DSI0_SEL_VOP_LIT << 16;
>>> +               break;
>>> +       }
>>>         regmap_write(dsi->grf_regmap, GRF_SOC_CON6, val);
>>> -       dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" :
>>> "BIG");
>>>   }
>>>     static int
>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>> b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>> index d5ea4ab..e849f26 100644
>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>> @@ -141,6 +141,13 @@ struct vop {
>>>         struct vop_win win[];
>>>   };
>>>   +enum vop_id vop_get_crtc_vop_id(struct drm_crtc *crtc)
>>> +{
>>> +       struct vop *vop = to_vop(crtc);
>>> +
>>> +       return vop->data->id;
>>> +}
>>> +
>>>   static inline void vop_writel(struct vop *vop, uint32_t offset,
>>> uint32_t v)
>>>   {
>>>         writel(v, vop->regs + offset);
>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>>> b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>>> index 5a4faa85..2c54bcc 100644
>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>>> @@ -135,8 +135,16 @@ struct vop_win_data {
>>>         enum drm_plane_type type;
>>>   };
>>>   +enum vop_id {
>>> +       RK3036_VOP,
>>> +       RK3288_VOP,
>>> +       RK3399_VOP_BIG,
>>> +       RK3399_VOP_LIT,
>>> +};
>>> +
>>>   struct vop_data {
>>>         const struct vop_reg_data *init_table;
>>> +       uint32_t id;
>>>         unsigned int table_size;
>>>         const struct vop_ctrl *ctrl;
>>>         const struct vop_intr *intr;
>>> @@ -321,5 +329,7 @@ static inline int scl_vop_cal_lb_mode(int width, bool
>>> is_yuv)
>>>         return lb_mode;
>>>   }
>>>   +enum vop_id vop_get_crtc_vop_id(struct drm_crtc *crtc);
>>> +
>>>   extern const struct component_ops vop_component_ops;
>>>   #endif /* _ROCKCHIP_DRM_VOP_H */
>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>>> b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>>> index aaede6b..a46e2c8 100644
>>> --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>>> +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>>> @@ -131,6 +131,7 @@ static const struct vop_reg_data
>>> rk3036_vop_init_reg_table[] = {
>>>   };
>>>     static const struct vop_data rk3036_vop = {
>>> +       .id = RK3036_VOP,
>>>         .init_table = rk3036_vop_init_reg_table,
>>>         .table_size = ARRAY_SIZE(rk3036_vop_init_reg_table),
>>>         .ctrl = &rk3036_ctrl_data,
>>> @@ -272,6 +273,7 @@ static const struct vop_intr rk3288_vop_intr = {
>>>   };
>>>     static const struct vop_data rk3288_vop = {
>>> +       .id = RK3288_VOP,
>>>         .init_table = rk3288_init_reg_table,
>>>         .table_size = ARRAY_SIZE(rk3288_init_reg_table),
>>>         .intr = &rk3288_vop_intr,
>>> @@ -340,6 +342,7 @@ static const struct vop_reg_data
>>> rk3399_init_reg_table[] = {
>>>   };
>>>     static const struct vop_data rk3399_vop_big = {
>>> +       .id = RK3399_VOP_BIG,
>>>         .init_table = rk3399_init_reg_table,
>>>         .table_size = ARRAY_SIZE(rk3399_init_reg_table),
>>>         .intr = &rk3399_vop_intr,
>>> @@ -359,6 +362,7 @@ static const struct vop_win_data
>>> rk3399_vop_lit_win_data[] = {
>>>   };
>>>     static const struct vop_data rk3399_vop_lit = {
>>> +       .id = RK3399_VOP_LIT,
>>>         .init_table = rk3399_init_reg_table,
>>>         .table_size = ARRAY_SIZE(rk3399_init_reg_table),
>>>         .intr = &rk3399_vop_intr,
>>
>> _______________________________________________
>> Linux-rockchip mailing list
>> Linux-rockchip at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>>
>>
>>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


From arnd at arndb.de  Thu Oct 19 15:33:46 2017
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 20 Oct 2017 00:33:46 +0200
Subject: [GIT PULL 1/2] Rockchip dts32 updates for 4.15 part1
In-Reply-To: <5843673.lOC77YXMZV@phil>
References: <5843673.lOC77YXMZV@phil>
Message-ID: <CAK8P3a2hemCTVPDkoFMPVT5bM7Qy=9+sU+CUM0fLUKLBbyCtMQ@mail.gmail.com>

On Tue, Oct 17, 2017 at 7:40 PM, Heiko Stuebner <heiko at sntech.de> wrote:
>
> ----------------------------------------------------------------
> One new board the Vyasa from Amarula Solutions using a rk3288
> and core lvds node for the newly added driver+binding.
> Also bindings + nodes for the Mali-Utgard GPUs found on some
> Rockchip socs like rk3036 and rk3188. With the recently revived
> Lima project they can even render a red triangle to a png file.

Pulled into next/dt, thanks!

      Arnd


From arnd at arndb.de  Thu Oct 19 15:34:25 2017
From: arnd at arndb.de (Arnd Bergmann)
Date: Fri, 20 Oct 2017 00:34:25 +0200
Subject: [GIT PULL 2/2] Rockchip dts64 updates for 4.15 part1
In-Reply-To: <5888991.PG7Gbs0CIl@phil>
References: <5843673.lOC77YXMZV@phil> <5888991.PG7Gbs0CIl@phil>
Message-ID: <CAK8P3a3PiJQV-P8+w78tzSKa-awZyrb07sXaD26WLvPg+f5Gnw@mail.gmail.com>

On Tue, Oct 17, 2017 at 7:40 PM, Heiko Stuebner <heiko at sntech.de> wrote:
> The following changes since commit 2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e:
>
>   Linux 4.14-rc1 (2017-09-16 15:47:51 -0700)
>
> are available in the git repository at:
>
>   git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.15-rockchip-dts64-1
>
> for you to fetch changes up to d85438991874205467f9739d5f3ee771245b4754:
>
>   arm64: dts: rockchip: enable cec pin for rk3399 firefly (2017-10-15 14:11:32 +0200)
>
> ----------------------------------------------------------------
> The biggest step forward is probably the enablement of display support
> on the rk3399-firefly, which got its default serial set as well and
> got cec support as well.
> Gru boards got their touchpad support refined to actually mark the button
> correctly and also git their rt5514 dsp added.
> And finally the rk3328 eval board got its cpu regulator and mmc nodes.

Pulled into next/dt, thanks!

      Arnd


From mark.yao at rock-chips.com  Thu Oct 19 18:38:57 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Fri, 20 Oct 2017 09:38:57 +0800
Subject: [PATCH v2] drm/rockchip: Use an enum to identify Rockchip VOPs
In-Reply-To: <CAOeoa-ebpsGbUoHBc_Ei5VZHHrvti3MCgReqrEw=SFTYna0cLg@mail.gmail.com>
References: <1478202408-11635-1-git-send-email-hoegsberg@chromium.org>
 <20171018175208.GA73666@google.com>
 <fad6657f-2bfa-c722-27a6-e29bb9fadb52@rock-chips.com>
 <CAOeoa-ebpsGbUoHBc_Ei5VZHHrvti3MCgReqrEw=SFTYna0cLg@mail.gmail.com>
Message-ID: <a7a23e72-2621-34f0-9535-4e0655f65a7b@rock-chips.com>

On 2017?10?20? 01:46, Kristian H?gsberg wrote:
> On Wed, Oct 18, 2017 at 5:49 PM, Mark yao <mark.yao at rock-chips.com> wrote:
>> On 2017?10?19? 01:52, Brian Norris wrote:
>>> Hi Kristian,
>>>
>>> On Thu, Nov 03, 2016 at 12:46:48PM -0700, Kristian H?gsberg wrote:
>>>> We used to call drm_of_encoder_active_endpoint_id() from
>>>> rockchip_dp_drm_encoder_atomic_check() to determine the endpoint for the
>>>> active encoder. However, the encoder isn't necessarily active at this
>>>> point or it may be connected to different crtc than what we're switching
>>>> to. Instead, look at the crtc from the drm_crtc_state.  This fixes wrong
>>>> colors when driving the eDP with the big VOP.  Further, we can identify
>>>> the type of VOP we're dealing with by just putting a VOP id enum in the
>>>> vop_data.
>>
>> Unfortunately, vop iomux and vop data are not one-to-one correspondence.
>>
>> Such as rk3288, vop big and vop little both use rk3288_vop data, if you use
>> vop data id will not be able
>> to distinguish between them.
> What would you suggest then? We need this to be able to drive eDP from
> the big VOP. We've been carrying this patch for quite a while and it
> hasn't regressed neither rk3288 nor rk3399 boards.
>
> Kristian
>
>> Mark
>>>>
>>>> On way to test this is to use the modetest tool from libdrm:
>>>>
>>>>     $ modetest -M rockchip -s 32 at 28:2400x1600
>>>>
>>>> which displays dark or black colors because we fail to look up the
>>>> endpoint and use default 0 (which is ROCKCHIP_OUT_MODE_P888) for big
>>>> VOP instead of RGB10 as required.

The display issue already be fixed, and your kernel seems old
See the patch: http://patchwork.freedesktop.org/patch/msgid/1495885416-22216-1-git-send-email-mark.yao at rock-chips.com

Now eDP always set its outmode as ROCKCHIP_OUT_MODE_AAAA.

And on vop driver, force RGB10 to RGB888 if vop not support rgb10bit.
drivers/gpu/drm/rockchip/rockchip_drm_vop.c:
     /*
      * if vop is not support RGB10 output, need force RGB10 to RGB888.
      */
     if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
         !(vop_data->feature & VOP_FEATURE_OUTPUT_RGB10))
         s->output_mode = ROCKCHIP_OUT_MODE_P888;

Thanks.
>>>>
>>>> For reference,
>>>>
>>>>     $ modetest -M rockchip -s 32 at 25:2400x1600
>>>>
>>>> drives the eDP from little VOP and displays correctly.
>>>>
>>>> Signed-off-by: Kristian H. Kristensen <hoegsberg at chromium.org>
>>>> ---
>>>> v2: Stripped chromeos annotations, fix compile errors for drivers I
>>>> didn't
>>>> compile when I first wrote the patch.
>>> Do you plan to fix the errors Guenter pointed out and resend? This is
>>> still causing conflicts between our ChromeOS kernel trees and upstream.
>>>
>>> Also, please CC linux-rockchip on Rockchip-related patches. It's much
>>> easier for me to find your work that way :)
>>>
>>> Brian
>>>
>>>> drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 45
>>>> ++++++++++---------------
>>>>    drivers/gpu/drm/rockchip/cdn-dp-core.c          | 19 +++++------
>>>>    drivers/gpu/drm/rockchip/dw-mipi-dsi.c          | 12 ++++---
>>>>    drivers/gpu/drm/rockchip/rockchip_drm_vop.c     |  7 ++++
>>>>    drivers/gpu/drm/rockchip/rockchip_drm_vop.h     | 10 ++++++
>>>>    drivers/gpu/drm/rockchip/rockchip_vop_reg.c     |  4 +++
>>>>    6 files changed, 56 insertions(+), 41 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>>>> b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>>>> index 558a3bc..9ae4a9c 100644
>>>> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>>>> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>>>> @@ -196,14 +196,16 @@ static void rockchip_dp_drm_encoder_enable(struct
>>>> drm_encoder *encoder)
>>>>          int ret;
>>>>          u32 val;
>>>>    -     ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node,
>>>> encoder);
>>>> -       if (ret < 0)
>>>> -               return;
>>>> -
>>>> -       if (ret)
>>>> +       switch (vop_get_crtc_vop_id(encoder->crtc)) {
>>>> +       case RK3399_VOP_LIT:
>>>>                  val = dp->data->lcdsel_lit;
>>>> -       else
>>>> +               break;
>>>> +       case RK3399_VOP_BIG:
>>>>                  val = dp->data->lcdsel_big;
>>>> +               break;
>>>> +       default:
>>>> +               return;
>>>> +       }
>>>>          dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
>>>>    @@ -231,34 +233,23 @@ rockchip_dp_drm_encoder_atomic_check(struct
>>>> drm_encoder *encoder,
>>>>                                        struct drm_connector_state
>>>> *conn_state)
>>>>    {
>>>>          struct rockchip_crtc_state *s =
>>>> to_rockchip_crtc_state(crtc_state);
>>>> -       struct rockchip_dp_device *dp = to_dp(encoder);
>>>> -       int ret;
>>>>    -     /*
>>>> -        * The hardware IC designed that VOP must output the RGB10 video
>>>> -        * format to eDP contoller, and if eDP panel only support RGB8,
>>>> -        * then eDP contoller should cut down the video data, not via VOP
>>>> -        * contoller, that's why we need to hardcode the VOP output mode
>>>> -        * to RGA10 here.
>>>> -        */
>>>> -
>>>> -       ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node,
>>>> encoder);
>>>> -       if (ret < 0)
>>>> -               return 0;
>>>> -
>>>> -       switch (dp->data->chip_type) {
>>>> -       case RK3399_EDP:
>>>> +       switch (vop_get_crtc_vop_id(crtc_state->crtc)) {
>>>> +       case RK3399_VOP_LIT:
>>>>                  /*
>>>>                   * For RK3399, VOP Lit must code the out mode to RGB888,
>>>>                   * VOP Big must code the out mode to RGB10.
>>>>                   */
>>>> -               if (ret)
>>>> -                       s->output_mode = ROCKCHIP_OUT_MODE_P888;
>>>> -               else
>>>> -                       s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>>>> +               s->output_mode = ROCKCHIP_OUT_MODE_P888;
>>>>                  break;
>>>> -
>>>>          default:
>>>> +               /*
>>>> +                * The hardware IC designed that VOP must output the
>>>> RGB10 video
>>>> +                * format to eDP contoller, and if eDP panel only support
>>>> RGB8,
>>>> +                * then eDP contoller should cut down the video data, not
>>>> via VOP
>>>> +                * contoller, that's why we need to hardcode the VOP
>>>> output mode
>>>> +                * to RGA10 here.
>>>> +                */
>>>>                  s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>>>>                  break;
>>>>          }
>>>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c
>>>> b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>>>> index f020e2e..b9e6184 100644
>>>> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
>>>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>>>> @@ -570,21 +570,20 @@ static void cdn_dp_encoder_mode_set(struct
>>>> drm_encoder *encoder,
>>>>          video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
>>>>          video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
>>>>    -     ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node,
>>>> encoder);
>>>> -       if (ret < 0) {
>>>> -               DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
>>>> -               return;
>>>> -       }
>>>> -
>>>> -       DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n",
>>>> -                         (ret) ? "LIT" : "BIG");
>>>>          state = to_rockchip_crtc_state(encoder->crtc->state);
>>>> -       if (ret) {
>>>> +       switch (vop_get_crtc_vop_id(encoder->crtc)) {
>>>> +       case RK3399_VOP_LIT:
>>>> +               DRM_DEV_DEBUG_KMS(dp->dev, "vop LIT output to cdn-dp\n");
>>>>                  val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16);
>>>>                  state->output_mode = ROCKCHIP_OUT_MODE_P888;
>>>> -       } else {
>>>> +               break;
>>>> +       case RK3399_VOP_BIG:
>>>> +               DRM_DEV_DEBUG_KMS(dp->dev, "vop BIG output to cdn-dp\n");
>>>>                  val = DP_SEL_VOP_LIT << 16;
>>>>                  state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>>>> +               break;
>>>> +       default:
>>>> +               break;
>>>>          }
>>>>          ret = cdn_dp_grf_write(dp, GRF_SOC_CON9, val);
>>>> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>>>> b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>>>> index dedc65b..b01a82a 100644
>>>> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>>>> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>>>> @@ -878,7 +878,6 @@ static void dw_mipi_dsi_encoder_disable(struct
>>>> drm_encoder *encoder)
>>>>    static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
>>>>    {
>>>>          struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
>>>> -       int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node,
>>>> encoder);
>>>>          u32 val;
>>>>          if (clk_prepare_enable(dsi->pclk)) {
>>>> @@ -894,13 +893,18 @@ static void dw_mipi_dsi_encoder_commit(struct
>>>> drm_encoder *encoder)
>>>>          clk_disable_unprepare(dsi->pclk);
>>>>    -     if (mux)
>>>> +       switch (vop_get_crtc_vop_id(encoder->crtc)) {
>>>> +       case RK3399_VOP_LIT:
>>>> +               dev_dbg(dsi->dev, "vop LIT output to dsi0\n");
>>>>                  val = DSI0_SEL_VOP_LIT | (DSI0_SEL_VOP_LIT << 16);
>>>> -       else
>>>> +               break;
>>>> +       default:
>>>> +               dev_dbg(dsi->dev, "vop BIG output to dsi0\n");
>>>>                  val = DSI0_SEL_VOP_LIT << 16;
>>>> +               break;
>>>> +       }
>>>>          regmap_write(dsi->grf_regmap, GRF_SOC_CON6, val);
>>>> -       dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" :
>>>> "BIG");
>>>>    }
>>>>      static int
>>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>> b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>> index d5ea4ab..e849f26 100644
>>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>> @@ -141,6 +141,13 @@ struct vop {
>>>>          struct vop_win win[];
>>>>    };
>>>>    +enum vop_id vop_get_crtc_vop_id(struct drm_crtc *crtc)
>>>> +{
>>>> +       struct vop *vop = to_vop(crtc);
>>>> +
>>>> +       return vop->data->id;
>>>> +}
>>>> +
>>>>    static inline void vop_writel(struct vop *vop, uint32_t offset,
>>>> uint32_t v)
>>>>    {
>>>>          writel(v, vop->regs + offset);
>>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>>>> b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>>>> index 5a4faa85..2c54bcc 100644
>>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
>>>> @@ -135,8 +135,16 @@ struct vop_win_data {
>>>>          enum drm_plane_type type;
>>>>    };
>>>>    +enum vop_id {
>>>> +       RK3036_VOP,
>>>> +       RK3288_VOP,
>>>> +       RK3399_VOP_BIG,
>>>> +       RK3399_VOP_LIT,
>>>> +};
>>>> +
>>>>    struct vop_data {
>>>>          const struct vop_reg_data *init_table;
>>>> +       uint32_t id;
>>>>          unsigned int table_size;
>>>>          const struct vop_ctrl *ctrl;
>>>>          const struct vop_intr *intr;
>>>> @@ -321,5 +329,7 @@ static inline int scl_vop_cal_lb_mode(int width, bool
>>>> is_yuv)
>>>>          return lb_mode;
>>>>    }
>>>>    +enum vop_id vop_get_crtc_vop_id(struct drm_crtc *crtc);
>>>> +
>>>>    extern const struct component_ops vop_component_ops;
>>>>    #endif /* _ROCKCHIP_DRM_VOP_H */
>>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>>>> b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>>>> index aaede6b..a46e2c8 100644
>>>> --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>>>> +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
>>>> @@ -131,6 +131,7 @@ static const struct vop_reg_data
>>>> rk3036_vop_init_reg_table[] = {
>>>>    };
>>>>      static const struct vop_data rk3036_vop = {
>>>> +       .id = RK3036_VOP,
>>>>          .init_table = rk3036_vop_init_reg_table,
>>>>          .table_size = ARRAY_SIZE(rk3036_vop_init_reg_table),
>>>>          .ctrl = &rk3036_ctrl_data,
>>>> @@ -272,6 +273,7 @@ static const struct vop_intr rk3288_vop_intr = {
>>>>    };
>>>>      static const struct vop_data rk3288_vop = {
>>>> +       .id = RK3288_VOP,
>>>>          .init_table = rk3288_init_reg_table,
>>>>          .table_size = ARRAY_SIZE(rk3288_init_reg_table),
>>>>          .intr = &rk3288_vop_intr,
>>>> @@ -340,6 +342,7 @@ static const struct vop_reg_data
>>>> rk3399_init_reg_table[] = {
>>>>    };
>>>>      static const struct vop_data rk3399_vop_big = {
>>>> +       .id = RK3399_VOP_BIG,
>>>>          .init_table = rk3399_init_reg_table,
>>>>          .table_size = ARRAY_SIZE(rk3399_init_reg_table),
>>>>          .intr = &rk3399_vop_intr,
>>>> @@ -359,6 +362,7 @@ static const struct vop_win_data
>>>> rk3399_vop_lit_win_data[] = {
>>>>    };
>>>>      static const struct vop_data rk3399_vop_lit = {
>>>> +       .id = RK3399_VOP_LIT,
>>>>          .init_table = rk3399_init_reg_table,
>>>>          .table_size = ARRAY_SIZE(rk3399_init_reg_table),
>>>>          .intr = &rk3399_vop_intr,
>>> _______________________________________________
>>> Linux-rockchip mailing list
>>> Linux-rockchip at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>>>
>>>
>>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip


-- 
?ark Yao




From mark.yao at rock-chips.com  Thu Oct 19 18:48:35 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Fri, 20 Oct 2017 09:48:35 +0800
Subject: [PATCH v6 02/10] drm/rockchip: analogix_dp: Remove unnecessary
 init code
In-Reply-To: <20171019034812.13768-3-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
 <20171019034812.13768-3-jeffy.chen@rock-chips.com>
Message-ID: <88902b60-d096-f828-6d5d-44d44b6f4c50@rock-chips.com>

On 2017?10?19? 11:48, Jeffy Chen wrote:
> Remove unnecessary init code, since we would do it in the power_on()
> callback.
>
> Also move of parse code to probe().
>
> Fixes: 9e32e16e9e98 ("drm: rockchip: dp: add rockchip platform dp driver")
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>

Looks good for me
Acked-by: Mark Yao <mark.yao at rock-chips.com>

> ---
>
> Changes in v6: None
> Changes in v5: None
>
>   drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 27 ++++++-------------------
>   1 file changed, 6 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index 4d3f6ad0abdd..8cae5ad926cd 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -269,7 +269,7 @@ static struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
>   	.destroy = rockchip_dp_drm_encoder_destroy,
>   };
>   
> -static int rockchip_dp_init(struct rockchip_dp_device *dp)
> +static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
>   {
>   	struct device *dev = dp->dev;
>   	struct device_node *np = dev->of_node;
> @@ -303,19 +303,6 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp)
>   		return PTR_ERR(dp->rst);
>   	}
>   
> -	ret = clk_prepare_enable(dp->pclk);
> -	if (ret < 0) {
> -		DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret);
> -		return ret;
> -	}
> -
> -	ret = rockchip_dp_pre_init(dp);
> -	if (ret < 0) {
> -		DRM_DEV_ERROR(dp->dev, "failed to pre init %d\n", ret);
> -		clk_disable_unprepare(dp->pclk);
> -		return ret;
> -	}
> -
>   	return 0;
>   }
>   
> @@ -361,10 +348,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
>   	if (!dp_data)
>   		return -ENODEV;
>   
> -	ret = rockchip_dp_init(dp);
> -	if (ret < 0)
> -		return ret;
> -
>   	dp->data = dp_data;
>   	dp->drm_dev = drm_dev;
>   
> @@ -398,7 +381,6 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
>   	rockchip_drm_psr_unregister(&dp->encoder);
>   
>   	analogix_dp_unbind(dev, master, data);
> -	clk_disable_unprepare(dp->pclk);
>   }
>   
>   static const struct component_ops rockchip_dp_component_ops = {
> @@ -414,7 +396,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
>   	int ret;
>   
>   	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
> -	if (ret)
> +	if (ret < 0)
>   		return ret;
>   
>   	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
> @@ -422,9 +404,12 @@ static int rockchip_dp_probe(struct platform_device *pdev)
>   		return -ENOMEM;
>   
>   	dp->dev = dev;
> -
>   	dp->plat_data.panel = panel;
>   
> +	ret = rockchip_dp_of_probe(dp);
> +	if (ret < 0)
> +		return ret;
> +
>   	/*
>   	 * We just use the drvdata until driver run into component
>   	 * add function, and then we would set drvdata to null, so



From mark.yao at rock-chips.com  Thu Oct 19 18:49:23 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Fri, 20 Oct 2017 09:49:23 +0800
Subject: [PATCH v6 05/10] drm/rockchip: analogix_dp: Add a sanity check
 for rockchip_drm_psr_register()
In-Reply-To: <20171019034812.13768-6-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
 <20171019034812.13768-6-jeffy.chen@rock-chips.com>
Message-ID: <1c7f4eaf-6fa2-58e1-a216-46ac039fffd5@rock-chips.com>

On 2017?10?19? 11:48, Jeffy Chen wrote:
> The rockchip_drm_psr_register() can fail, so add a sanity check for that.
>
> Also reorder the calls in unbind() to match bind().
>
> Signed-off-by: Jeffy Chen<jeffy.chen at rock-chips.com>

Looks good for me
Acked-by: Mark Yao <mark.yao at rock-chips.com>

Mark




From mark.yao at rock-chips.com  Thu Oct 19 18:50:01 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Fri, 20 Oct 2017 09:50:01 +0800
Subject: [PATCH v6 06/10] drm/rockchip: dw-mipi-dsi: Fix error handling
 path
In-Reply-To: <20171019034812.13768-7-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
 <20171019034812.13768-7-jeffy.chen@rock-chips.com>
Message-ID: <fc82d57d-5c41-0615-b391-39b20bc41024@rock-chips.com>

On 2017?10?19? 11:48, Jeffy Chen wrote:
> Add missing pm_runtime_disable() in bind()'s error handling path.
>
> Also cleanup encoder & connector in unbind().
>
> Fixes: 80a9a059d4e4 ("drm/rockchip/dsi: add dw-mipi power domain support")
> Signed-off-by: Jeffy Chen<jeffy.chen at rock-chips.com>

Looks good for me
Acked-by: Mark Yao <mark.yao at rock-chips.com>

Mark




From mark.yao at rock-chips.com  Thu Oct 19 18:50:36 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Fri, 20 Oct 2017 09:50:36 +0800
Subject: [PATCH v6 07/10] drm/rockchip: inno_hdmi: Fix error handling path
In-Reply-To: <20171019034812.13768-8-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
 <20171019034812.13768-8-jeffy.chen@rock-chips.com>
Message-ID: <c2fb9f07-dedf-44b9-66ed-01b3afac1f93@rock-chips.com>

On 2017?10?19? 11:48, Jeffy Chen wrote:
> Add missing error handling in bind().
>
> Fixes: 412d4ae6b7a5 ("drm/rockchip: hdmi: add Innosilicon HDMI support")
> Signed-off-by: Jeffy Chen<jeffy.chen at rock-chips.com>

Looks good for me
Acked-by: Mark Yao <mark.yao at rock-chips.com>

Mark




From mark.yao at rock-chips.com  Thu Oct 19 18:51:16 2017
From: mark.yao at rock-chips.com (Mark yao)
Date: Fri, 20 Oct 2017 09:51:16 +0800
Subject: [PATCH v6 10/10] drm/rockchip: dw_hdmi: Fix error handling path
In-Reply-To: <20171019034812.13768-11-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
 <20171019034812.13768-11-jeffy.chen@rock-chips.com>
Message-ID: <bd662144-78c8-b448-6dd0-36d68bacca44@rock-chips.com>

On 2017?10?19? 11:48, Jeffy Chen wrote:
> Add missing clk_disable_unprepare() in bind()'s error handling path and
> unbind().
>
> Also inline clk_prepare_enable() with bind().
>
> Fixes: 12b9f204e804 ("drm: bridge/dw_hdmi: add rockchip rk3288 support")
> Signed-off-by: Jeffy Chen<jeffy.chen at rock-chips.com>

Looks good for me
Acked-by: Mark Yao <mark.yao at rock-chips.com>

Mark




From hverkuil at xs4all.nl  Fri Oct 20 00:28:58 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 20 Oct 2017 09:28:58 +0200
Subject: [PATCH] pinctrl: rockchip: Add iomux-route switching support for
 rk3288
In-Reply-To: <13020229.tRmotBUImn@phil>
References: <20171013225337.5196-1-phh@phh.me>
 <CAJ-oXjQ3e1UHVGq=uV=yAK9Bu=ZoiNZaEbnHyvNtyc15RQQSKg@mail.gmail.com>
 <2009704.s5LEIeT6xV@phil> <13020229.tRmotBUImn@phil>
Message-ID: <52d1a9ee-a6c6-5c7f-330f-9b672be9c2c6@xs4all.nl>

On 14/10/17 17:39, Heiko Stuebner wrote:
> So far only the hdmi cec supports using one of two different pins
> as source, so add the route switching for it.
> 
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>

Just tested this on my firefly reload and it works great!

Tested-by: Hans Verkuil <hans.verkuil at cisco.com>

I'll post some dts patches later today to fully bring up the first HDMI
output on the Firefly Reload.

Will you process this patch further to get it mainlined?

Regards,

	Hans

> ---
> If I didn't mess up any numbering, the pinctrl change should look like
> the following patch.
> 
> Hope that helps
> Heiko
> 
>  drivers/pinctrl/pinctrl-rockchip.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
> index b5cb7858ffdc..8dd49e2e144b 100644
> --- a/drivers/pinctrl/pinctrl-rockchip.c
> +++ b/drivers/pinctrl/pinctrl-rockchip.c
> @@ -884,6 +884,24 @@ static struct rockchip_mux_route_data rk3228_mux_route_data[] = {
>  	},
>  };
>  
> +static struct rockchip_mux_route_data rk3288_mux_route_data[] = {
> +	{
> +		/* edphdmi_cecinoutt1 */
> +		.bank_num = 7,
> +		.pin = 16,
> +		.func = 2,
> +		.route_offset = 0x264,
> +		.route_val = BIT(16 + 12) | BIT(12),
> +	}, {
> +		/* edphdmi_cecinout */
> +		.bank_num = 7,
> +		.pin = 23,
> +		.func = 4,
> +		.route_offset = 0x264,
> +		.route_val = BIT(16 + 12),
> +	},
> +};
> +
>  static struct rockchip_mux_route_data rk3328_mux_route_data[] = {
>  	{
>  		/* uart2dbg_rxm0 */
> @@ -3391,6 +3409,8 @@ static struct rockchip_pin_ctrl rk3288_pin_ctrl = {
>  		.type			= RK3288,
>  		.grf_mux_offset		= 0x0,
>  		.pmu_mux_offset		= 0x84,
> +		.iomux_routes		= rk3288_mux_route_data,
> +		.niomux_routes		= ARRAY_SIZE(rk3288_mux_route_data),
>  		.pull_calc_reg		= rk3288_calc_pull_reg_and_bit,
>  		.drv_calc_reg		= rk3288_calc_drv_reg_and_bit,
>  };
> 



From heiko at sntech.de  Fri Oct 20 00:38:54 2017
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Fri, 20 Oct 2017 09:38:54 +0200
Subject: [PATCH] pinctrl: rockchip: Add iomux-route switching support for
 rk3288
In-Reply-To: <52d1a9ee-a6c6-5c7f-330f-9b672be9c2c6@xs4all.nl>
References: <20171013225337.5196-1-phh@phh.me> <13020229.tRmotBUImn@phil>
 <52d1a9ee-a6c6-5c7f-330f-9b672be9c2c6@xs4all.nl>
Message-ID: <2040825.vRYCsv903Y@diego>

Hi Hans,

Am Freitag, 20. Oktober 2017, 09:28:58 CEST schrieb Hans Verkuil:
> On 14/10/17 17:39, Heiko Stuebner wrote:
> > So far only the hdmi cec supports using one of two different pins
> > as source, so add the route switching for it.
> > 
> > Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> 
> Just tested this on my firefly reload and it works great!
> 
> Tested-by: Hans Verkuil <hans.verkuil at cisco.com>

oh cool. I really only wrote this based on the soc manual,
so it actually surprises me, that it works on the first try :-)

> I'll post some dts patches later today to fully bring up the first HDMI
> output on the Firefly Reload.
> 
> Will you process this patch further to get it mainlined?

Yep, I'll do that.


Heiko



From hverkuil at xs4all.nl  Fri Oct 20 00:44:55 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 20 Oct 2017 09:44:55 +0200
Subject: [PATCH] pinctrl: rockchip: Add iomux-route switching support for
 rk3288
In-Reply-To: <2040825.vRYCsv903Y@diego>
References: <20171013225337.5196-1-phh@phh.me> <13020229.tRmotBUImn@phil>
 <52d1a9ee-a6c6-5c7f-330f-9b672be9c2c6@xs4all.nl> <2040825.vRYCsv903Y@diego>
Message-ID: <68b8765d-3d55-3fdd-e23e-776e978c38bd@xs4all.nl>

On 20/10/17 09:38, Heiko St?bner wrote:
> Hi Hans,
> 
> Am Freitag, 20. Oktober 2017, 09:28:58 CEST schrieb Hans Verkuil:
>> On 14/10/17 17:39, Heiko Stuebner wrote:
>>> So far only the hdmi cec supports using one of two different pins
>>> as source, so add the route switching for it.
>>>
>>> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
>>
>> Just tested this on my firefly reload and it works great!
>>
>> Tested-by: Hans Verkuil <hans.verkuil at cisco.com>
> 
> oh cool. I really only wrote this based on the soc manual,
> so it actually surprises me, that it works on the first try :-)

One note though: I've only tested it on my Firefly Reload. I don't have a
regular Firefly, so I can't be certain it works there. Just covering my ass
here :-)

> 
>> I'll post some dts patches later today to fully bring up the first HDMI
>> output on the Firefly Reload.
>>
>> Will you process this patch further to get it mainlined?
> 
> Yep, I'll do that.

Thanks!

Regards,

	Hans



From hverkuil at xs4all.nl  Fri Oct 20 00:25:09 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 20 Oct 2017 09:25:09 +0200
Subject: [PATCH 1/3] drm: bridge: synopsys/dw-hdmi: Enable cec clock
In-Reply-To: <35b9fbe3-9859-03e2-173e-8cff5a90efdd@xs4all.nl>
References: <20171013225337.5196-1-phh@phh.me>
 <20171013225337.5196-2-phh@phh.me>
 <35b9fbe3-9859-03e2-173e-8cff5a90efdd@xs4all.nl>
Message-ID: <01c4773b-ec8b-5bdc-11ea-c4816b9c673a@xs4all.nl>

On 14/10/17 10:16, Hans Verkuil wrote:
> On 10/14/2017 12:53 AM, Pierre-Hugues Husson wrote:
>> The documentation already mentions "cec" optional clock, but
>> currently the driver doesn't enable it.
>>
>> Signed-off-by: Pierre-Hugues Husson <phh at phh.me>
> 
> Acked-by: Hans Verkuil <hans.verkuil at cisco.com>

Tested-by: Hans Verkuil <hans.verkuil at cisco.com>

> 
> Thanks!
> 
> 	Hans
> 
>> ---
>>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++
>>  1 file changed, 17 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> index bf14214fa464..5007cdf43131 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
>> @@ -138,6 +138,7 @@ struct dw_hdmi {
>>  	struct device *dev;
>>  	struct clk *isfr_clk;
>>  	struct clk *iahb_clk;
>> +	struct clk *cec_clk;
>>  	struct dw_hdmi_i2c *i2c;
>>  
>>  	struct hdmi_data_info hdmi_data;
>> @@ -2382,6 +2383,18 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>  		goto err_isfr;
>>  	}
>>  
>> +	hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec");
>> +	if (IS_ERR(hdmi->cec_clk)) {
>> +		hdmi->cec_clk = NULL;
>> +	} else {
>> +		ret = clk_prepare_enable(hdmi->cec_clk);
>> +		if (ret) {
>> +			dev_err(hdmi->dev, "Cannot enable HDMI cec clock: %d\n",
>> +					ret);
>> +			goto err_res;
>> +		}
>> +	}
>> +
>>  	/* Product and revision IDs */
>>  	hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
>>  		      | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
>> @@ -2518,6 +2531,8 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>  		cec_notifier_put(hdmi->cec_notifier);
>>  
>>  	clk_disable_unprepare(hdmi->iahb_clk);
>> +	if (hdmi->cec_clk)
>> +		clk_disable_unprepare(hdmi->cec_clk);
>>  err_isfr:
>>  	clk_disable_unprepare(hdmi->isfr_clk);
>>  err_res:
>> @@ -2541,6 +2556,8 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
>>  
>>  	clk_disable_unprepare(hdmi->iahb_clk);
>>  	clk_disable_unprepare(hdmi->isfr_clk);
>> +	if (hdmi->cec_clk)
>> +		clk_disable_unprepare(hdmi->cec_clk);
>>  
>>  	if (hdmi->i2c)
>>  		i2c_del_adapter(&hdmi->i2c->adap);
>>
> 



From linux at armlinux.org.uk  Fri Oct 20 01:12:04 2017
From: linux at armlinux.org.uk (Russell King - ARM Linux)
Date: Fri, 20 Oct 2017 09:12:04 +0100
Subject: [PATCH 1/3] drm: bridge: synopsys/dw-hdmi: Enable cec clock
In-Reply-To: <20171013225337.5196-2-phh@phh.me>
References: <20171013225337.5196-1-phh@phh.me>
 <20171013225337.5196-2-phh@phh.me>
Message-ID: <20171020081203.GD20805@n2100.armlinux.org.uk>

On Sat, Oct 14, 2017 at 12:53:35AM +0200, Pierre-Hugues Husson wrote:
> @@ -2382,6 +2383,18 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  		goto err_isfr;
>  	}
>  
> +	hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec");
> +	if (IS_ERR(hdmi->cec_clk)) {
> +		hdmi->cec_clk = NULL;

What if devm_clk_get() returns EPROBE_DEFER?  Does that really mean the
clock does not exist?

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up


From hverkuil at xs4all.nl  Fri Oct 20 02:06:21 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 20 Oct 2017 11:06:21 +0200
Subject: rk3288 Firefly Reload: 'reboot' doesn't work
Message-ID: <b88abf6d-d95f-3eca-91d1-65fcb749cb22@xs4all.nl>

Hi Heiko,

If I run 'reboot' to reboot my Firefly Reload board the last thing I see
on the serial port is "reboot: Restarting system", but it never actually
restarts.

This is really annoying, but I have no idea where to look. Any suggestions?

Regards,

    Hans


From hverkuil at xs4all.nl  Fri Oct 20 03:07:33 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 20 Oct 2017 12:07:33 +0200
Subject: [PATCH 3/4] arm: dts: rockchip: define the two possible CEC pins
In-Reply-To: <20171020100734.17064-1-hverkuil@xs4all.nl>
References: <20171020100734.17064-1-hverkuil@xs4all.nl>
Message-ID: <20171020100734.17064-4-hverkuil@xs4all.nl>

From: Hans Verkuil <hans.verkuil at cisco.com>

The CEC line can be routed to two possible pins. Define those pins.

Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
---
 arch/arm/boot/dts/rk3288.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index a48352aa1591..2421913bc1fd 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -1431,6 +1431,14 @@
 				rockchip,pins = <7 19 RK_FUNC_2 &pcfg_pull_none>,
 						<7 20 RK_FUNC_2 &pcfg_pull_none>;
 			};
+
+			hdmi_cec_c0: hdmi-cec-c0 {
+				rockchip,pins = <7 RK_PC0 RK_FUNC_2 &pcfg_pull_none>;
+			};
+
+			hdmi_cec_c7: hdmi-cec-c7 {
+				rockchip,pins = <7 RK_PC7 RK_FUNC_4 &pcfg_pull_none>;
+			};
 		};
 
 		pcfg_pull_up: pcfg-pull-up {
-- 
2.14.1



From hverkuil at xs4all.nl  Fri Oct 20 03:07:32 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 20 Oct 2017 12:07:32 +0200
Subject: [PATCH 2/4] arm: dts: rockchip: enable the first hdmi output
In-Reply-To: <20171020100734.17064-1-hverkuil@xs4all.nl>
References: <20171020100734.17064-1-hverkuil@xs4all.nl>
Message-ID: <20171020100734.17064-3-hverkuil@xs4all.nl>

From: Hans Verkuil <hans.verkuil at cisco.com>

The vdd10_lcd and vcc18_lcd regulators need to be enabled for HDMI output
to work, so add 'regulator-always-on', just as is done in rk3288-firefly.dtsi.

Also enable i2c5 and the hdmi block.

Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
---
 arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi | 2 ++
 arch/arm/boot/dts/rk3288-firefly-reload.dts       | 9 +++++++++
 2 files changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi b/arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi
index 5f05815f47e0..5f1e336dbaac 100644
--- a/arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi
+++ b/arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi
@@ -184,6 +184,7 @@
 				regulator-name = "vdd10_lcd";
 				regulator-min-microvolt = <1000000>;
 				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
 			};
 
 			vcca_18: REG7  {
@@ -223,6 +224,7 @@
 				regulator-name = "vcc18_lcd";
 				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
 			};
 		};
 	};
diff --git a/arch/arm/boot/dts/rk3288-firefly-reload.dts b/arch/arm/boot/dts/rk3288-firefly-reload.dts
index 7da0947ababb..859938d8832e 100644
--- a/arch/arm/boot/dts/rk3288-firefly-reload.dts
+++ b/arch/arm/boot/dts/rk3288-firefly-reload.dts
@@ -226,6 +226,11 @@
 	};
 };
 
+&hdmi {
+	ddc-i2c-bus = <&i2c5>;
+	status = "okay";
+};
+
 &i2c0 {
 	hym8563: hym8563 at 51 {
 		compatible = "haoyu,hym8563";
@@ -255,6 +260,10 @@
 	};
 };
 
+&i2c5 {
+	status = "okay";
+};
+
 &i2s {
 	status = "okay";
 };
-- 
2.14.1



From hverkuil at xs4all.nl  Fri Oct 20 03:07:34 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 20 Oct 2017 12:07:34 +0200
Subject: [PATCH 4/4] arm: dts: rockchip: select which CEC pin is used for the
 Firefly Reload
In-Reply-To: <20171020100734.17064-1-hverkuil@xs4all.nl>
References: <20171020100734.17064-1-hverkuil@xs4all.nl>
Message-ID: <20171020100734.17064-5-hverkuil@xs4all.nl>

From: Hans Verkuil <hans.verkuil at cisco.com>

The Firefly Reload uses PC7.

Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
Tested-by: Hans Verkuil <hans.verkuil at cisco.com>
---
 arch/arm/boot/dts/rk3288-firefly-reload.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-firefly-reload.dts b/arch/arm/boot/dts/rk3288-firefly-reload.dts
index 859938d8832e..eab176e3dfc3 100644
--- a/arch/arm/boot/dts/rk3288-firefly-reload.dts
+++ b/arch/arm/boot/dts/rk3288-firefly-reload.dts
@@ -228,6 +228,8 @@
 
 &hdmi {
 	ddc-i2c-bus = <&i2c5>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmi_cec_c0>;
 	status = "okay";
 };
 
-- 
2.14.1



From hverkuil at xs4all.nl  Fri Oct 20 03:07:31 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 20 Oct 2017 12:07:31 +0200
Subject: [PATCH 1/4] arm: dts: rockchip: add the cec clk for dw-hdmi on rk3288
In-Reply-To: <20171020100734.17064-1-hverkuil@xs4all.nl>
References: <20171020100734.17064-1-hverkuil@xs4all.nl>
Message-ID: <20171020100734.17064-2-hverkuil@xs4all.nl>

From: Hans Verkuil <hans.verkuil at cisco.com>

The dw-hdmi block needs the cec clk for the rk3288. Add it.

Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
---
 arch/arm/boot/dts/rk3288.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 356ed1e62452..a48352aa1591 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -1124,8 +1124,8 @@
 		reg-io-width = <4>;
 		rockchip,grf = <&grf>;
 		interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
-		clocks = <&cru  PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
-		clock-names = "iahb", "isfr";
+		clocks = <&cru  PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>, <&cru SCLK_HDMI_CEC>;
+		clock-names = "iahb", "isfr", "cec";
 		power-domains = <&power RK3288_PD_VIO>;
 		status = "disabled";
 
-- 
2.14.1



From hverkuil at xs4all.nl  Fri Oct 20 03:07:30 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Fri, 20 Oct 2017 12:07:30 +0200
Subject: [PATCH 0/4] arm: dts: rockchip: enable HDMI+CEC on Firefly Reload
Message-ID: <20171020100734.17064-1-hverkuil@xs4all.nl>

From: Hans Verkuil <hans.verkuil at cisco.com>

This patch series sits on top of these two patch series:

https://lkml.org/lkml/2017/10/13/971
https://lkml.org/lkml/2017/10/14/161

The first adds support for the cec clk in dw-hdmi, the second adds an
iomux-route for the CEC pin on the rk3288.

This patch series defines the cec clk for the rk3288, enables the
first HDMI output on the Firefly Reload. The second output isn't working,
I don't have enough knowledge to enable it. But I can test any patches
adding support for it!

The third patch defines the two possible CEC pins and the last selects
the correct pin for the Firefly Reload.

Likely the same thing can be done for the 'regular' Firefly, but I don't
have the hardware to test.

Regards,

	Hans


Hans Verkuil (4):
  arm: dts: rockchip: add the cec clk for dw-hdmi on rk3288
  arm: dts: rockchip: enable the first hdmi output
  arm: dts: rockchip: define the two possible CEC pins
  arm: dts: rockchip: select which CEC pin is used for the Firefly
    Reload

 arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi |  2 ++
 arch/arm/boot/dts/rk3288-firefly-reload.dts       | 11 +++++++++++
 arch/arm/boot/dts/rk3288.dtsi                     | 12 ++++++++++--
 3 files changed, 23 insertions(+), 2 deletions(-)

-- 
2.14.1



From seanpaul at chromium.org  Fri Oct 20 09:52:26 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Fri, 20 Oct 2017 12:52:26 -0400
Subject: [PATCH v6 03/10] drm/bridge: analogix: Do not use device's drvdata
In-Reply-To: <20171019034812.13768-4-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
 <20171019034812.13768-4-jeffy.chen@rock-chips.com>
Message-ID: <20171020165226.vqoeldcmreuc73le@art_vandelay>

On Thu, Oct 19, 2017 at 11:48:05AM +0800, Jeffy Chen wrote:

This patch has somehow lost it's original author. I assume this is not
intentional.

Sean

> The driver that instantiates the bridge should own the drvdata, as all
> driver model callbacks (probe, remove, shutdown, PM ops, etc.) are also
> owned by its driver struct. Moreover, storing two different pointer
> types in driver data depending on driver initialization status is barely
> a good practice and in fact has led to many bugs in this driver.
> 
> Let's clean up this mess and change Analogix entry points to simply
> accept some opaque struct pointer, adjusting their users at the same
> time to avoid breaking the compilation.
> 
> Signed-off-by: Tomasz Figa <tfiga at chromium.org>
> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> Reviewed-by: Andrzej Hajda <a.hajda at samsung.com>
> Reviewed-by: Sean Paul <seanpaul at chromium.org>
> Acked-by: Jingoo Han <jingoohan1 at gmail.com>
> Acked-by: Archit Taneja <architt at codeaurora.org>
> ---
> 
> Changes in v6: None
> Changes in v5: None
> 
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 50 +++++++++-------------
>  drivers/gpu/drm/exynos/exynos_dp.c                 | 26 ++++++-----
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 49 ++++++++++++---------
>  include/drm/bridge/analogix_dp.h                   | 19 ++++----
>  4 files changed, 74 insertions(+), 70 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 5dd3f1cd074a..74d274b6d31d 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -98,17 +98,15 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
>  	return 0;
>  }
>  
> -int analogix_dp_psr_supported(struct device *dev)
> +int analogix_dp_psr_supported(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
>  
>  	return dp->psr_support;
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
>  
> -int analogix_dp_enable_psr(struct device *dev)
> +int analogix_dp_enable_psr(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
>  	struct edp_vsc_psr psr_vsc;
>  
>  	if (!dp->psr_support)
> @@ -129,9 +127,8 @@ int analogix_dp_enable_psr(struct device *dev)
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
>  
> -int analogix_dp_disable_psr(struct device *dev)
> +int analogix_dp_disable_psr(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
>  	struct edp_vsc_psr psr_vsc;
>  	int ret;
>  
> @@ -1281,8 +1278,9 @@ static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux,
>  	return analogix_dp_transfer(dp, msg);
>  }
>  
> -int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
> -		     struct analogix_dp_plat_data *plat_data)
> +struct analogix_dp_device *
> +analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
> +		 struct analogix_dp_plat_data *plat_data)
>  {
>  	struct platform_device *pdev = to_platform_device(dev);
>  	struct analogix_dp_device *dp;
> @@ -1292,14 +1290,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  
>  	if (!plat_data) {
>  		dev_err(dev, "Invalided input plat_data\n");
> -		return -EINVAL;
> +		return ERR_PTR(-EINVAL);
>  	}
>  
>  	dp = devm_kzalloc(dev, sizeof(struct analogix_dp_device), GFP_KERNEL);
>  	if (!dp)
> -		return -ENOMEM;
> -
> -	dev_set_drvdata(dev, dp);
> +		return ERR_PTR(-ENOMEM);
>  
>  	dp->dev = &pdev->dev;
>  	dp->dpms_mode = DRM_MODE_DPMS_OFF;
> @@ -1316,7 +1312,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  
>  	ret = analogix_dp_dt_parse_pdata(dp);
>  	if (ret)
> -		return ret;
> +		return ERR_PTR(ret);
>  
>  	dp->phy = devm_phy_get(dp->dev, "dp");
>  	if (IS_ERR(dp->phy)) {
> @@ -1330,14 +1326,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  			if (ret == -ENOSYS || ret == -ENODEV)
>  				dp->phy = NULL;
>  			else
> -				return ret;
> +				return ERR_PTR(ret);
>  		}
>  	}
>  
>  	dp->clock = devm_clk_get(&pdev->dev, "dp");
>  	if (IS_ERR(dp->clock)) {
>  		dev_err(&pdev->dev, "failed to get clock\n");
> -		return PTR_ERR(dp->clock);
> +		return ERR_CAST(dp->clock);
>  	}
>  
>  	clk_prepare_enable(dp->clock);
> @@ -1346,7 +1342,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  
>  	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(dp->reg_base))
> -		return PTR_ERR(dp->reg_base);
> +		return ERR_CAST(dp->reg_base);
>  
>  	dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
>  
> @@ -1367,7 +1363,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  					    "hpd_gpio");
>  		if (ret) {
>  			dev_err(&pdev->dev, "failed to get hpd gpio\n");
> -			return ret;
> +			return ERR_PTR(ret);
>  		}
>  		dp->irq = gpio_to_irq(dp->hpd_gpio);
>  		irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
> @@ -1379,7 +1375,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  
>  	if (dp->irq == -ENXIO) {
>  		dev_err(&pdev->dev, "failed to get irq\n");
> -		return -ENODEV;
> +		return ERR_PTR(-ENODEV);
>  	}
>  
>  	pm_runtime_enable(dev);
> @@ -1420,7 +1416,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  	phy_power_off(dp->phy);
>  	pm_runtime_put(dev);
>  
> -	return 0;
> +	return dp;
>  
>  err_disable_pm_runtime:
>  
> @@ -1428,15 +1424,12 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
>  	pm_runtime_put(dev);
>  	pm_runtime_disable(dev);
>  
> -	return ret;
> +	return ERR_PTR(ret);
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_bind);
>  
> -void analogix_dp_unbind(struct device *dev, struct device *master,
> -			void *data)
> +void analogix_dp_unbind(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
> -
>  	analogix_dp_bridge_disable(dp->bridge);
>  	dp->connector.funcs->destroy(&dp->connector);
>  	dp->encoder->funcs->destroy(dp->encoder);
> @@ -1449,16 +1442,14 @@ void analogix_dp_unbind(struct device *dev, struct device *master,
>  	}
>  
>  	drm_dp_aux_unregister(&dp->aux);
> -	pm_runtime_disable(dev);
> +	pm_runtime_disable(dp->dev);
>  	clk_disable_unprepare(dp->clock);
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_unbind);
>  
>  #ifdef CONFIG_PM
> -int analogix_dp_suspend(struct device *dev)
> +int analogix_dp_suspend(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
> -
>  	clk_disable_unprepare(dp->clock);
>  
>  	if (dp->plat_data->panel) {
> @@ -1470,9 +1461,8 @@ int analogix_dp_suspend(struct device *dev)
>  }
>  EXPORT_SYMBOL_GPL(analogix_dp_suspend);
>  
> -int analogix_dp_resume(struct device *dev)
> +int analogix_dp_resume(struct analogix_dp_device *dp)
>  {
> -	struct analogix_dp_device *dp = dev_get_drvdata(dev);
>  	int ret;
>  
>  	ret = clk_prepare_enable(dp->clock);
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 39629e7a80b9..f7e5b2c405ed 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -41,6 +41,7 @@ struct exynos_dp_device {
>  	struct device              *dev;
>  
>  	struct videomode           vm;
> +	struct analogix_dp_device *adp;
>  	struct analogix_dp_plat_data plat_data;
>  };
>  
> @@ -157,13 +158,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
>  	struct drm_device *drm_dev = data;
>  	int ret;
>  
> -	/*
> -	 * Just like the probe function said, we don't need the
> -	 * device drvrate anymore, we should leave the charge to
> -	 * analogix dp driver, set the device drvdata to NULL.
> -	 */
> -	dev_set_drvdata(dev, NULL);
> -
>  	dp->dev = dev;
>  	dp->drm_dev = drm_dev;
>  
> @@ -190,13 +184,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
>  
>  	dp->plat_data.encoder = encoder;
>  
> -	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> +	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> +	if (IS_ERR(dp->adp))
> +		return PTR_ERR(dp->adp);
> +
> +	return 0;
>  }
>  
>  static void exynos_dp_unbind(struct device *dev, struct device *master,
>  			     void *data)
>  {
> -	return analogix_dp_unbind(dev, master, data);
> +	struct exynos_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_unbind(dp->adp);
>  }
>  
>  static const struct component_ops exynos_dp_ops = {
> @@ -257,12 +257,16 @@ static int exynos_dp_remove(struct platform_device *pdev)
>  #ifdef CONFIG_PM
>  static int exynos_dp_suspend(struct device *dev)
>  {
> -	return analogix_dp_suspend(dev);
> +	struct exynos_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_suspend(dp->adp);
>  }
>  
>  static int exynos_dp_resume(struct device *dev)
>  {
> -	return analogix_dp_resume(dev);
> +	struct exynos_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_resume(dp->adp);
>  }
>  #endif
>  
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index 8cae5ad926cd..fa0365de31d2 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -77,6 +77,7 @@ struct rockchip_dp_device {
>  
>  	const struct rockchip_dp_chip_data *data;
>  
> +	struct analogix_dp_device *adp;
>  	struct analogix_dp_plat_data plat_data;
>  };
>  
> @@ -85,7 +86,7 @@ static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
>  	struct rockchip_dp_device *dp = to_dp(encoder);
>  	unsigned long flags;
>  
> -	if (!analogix_dp_psr_supported(dp->dev))
> +	if (!analogix_dp_psr_supported(dp->adp))
>  		return;
>  
>  	DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
> @@ -116,9 +117,9 @@ static void analogix_dp_psr_work(struct work_struct *work)
>  
>  	spin_lock_irqsave(&dp->psr_lock, flags);
>  	if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
> -		analogix_dp_enable_psr(dp->dev);
> +		analogix_dp_enable_psr(dp->adp);
>  	else
> -		analogix_dp_disable_psr(dp->dev);
> +		analogix_dp_disable_psr(dp->adp);
>  	spin_unlock_irqrestore(&dp->psr_lock, flags);
>  }
>  
> @@ -273,7 +274,6 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
>  {
>  	struct device *dev = dp->dev;
>  	struct device_node *np = dev->of_node;
> -	int ret;
>  
>  	dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
>  	if (IS_ERR(dp->grf)) {
> @@ -337,13 +337,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
>  	struct drm_device *drm_dev = data;
>  	int ret;
>  
> -	/*
> -	 * Just like the probe function said, we don't need the
> -	 * device drvrate anymore, we should leave the charge to
> -	 * analogix dp driver, set the device drvdata to NULL.
> -	 */
> -	dev_set_drvdata(dev, NULL);
> -
>  	dp_data = of_device_get_match_data(dev);
>  	if (!dp_data)
>  		return -ENODEV;
> @@ -370,7 +363,11 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
>  
>  	rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
>  
> -	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> +	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
> +	if (IS_ERR(dp->adp))
> +		return PTR_ERR(dp->adp);
> +
> +	return 0;
>  }
>  
>  static void rockchip_dp_unbind(struct device *dev, struct device *master,
> @@ -379,8 +376,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
>  	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
>  
>  	rockchip_drm_psr_unregister(&dp->encoder);
> -
> -	analogix_dp_unbind(dev, master, data);
> +	analogix_dp_unbind(dp->adp);
>  }
>  
>  static const struct component_ops rockchip_dp_component_ops = {
> @@ -410,11 +406,6 @@ static int rockchip_dp_probe(struct platform_device *pdev)
>  	if (ret < 0)
>  		return ret;
>  
> -	/*
> -	 * We just use the drvdata until driver run into component
> -	 * add function, and then we would set drvdata to null, so
> -	 * that analogix dp driver could take charge of the drvdata.
> -	 */
>  	platform_set_drvdata(pdev, dp);
>  
>  	return component_add(dev, &rockchip_dp_component_ops);
> @@ -427,10 +418,26 @@ static int rockchip_dp_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_PM_SLEEP
> +static int rockchip_dp_suspend(struct device *dev)
> +{
> +	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_suspend(dp->adp);
> +}
> +
> +static int rockchip_dp_resume(struct device *dev)
> +{
> +	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
> +
> +	return analogix_dp_resume(dp->adp);
> +}
> +#endif
> +
>  static const struct dev_pm_ops rockchip_dp_pm_ops = {
>  #ifdef CONFIG_PM_SLEEP
> -	.suspend = analogix_dp_suspend,
> -	.resume_early = analogix_dp_resume,
> +	.suspend = rockchip_dp_suspend,
> +	.resume_early = rockchip_dp_resume,
>  #endif
>  };
>  
> diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
> index c99d6eaef1ac..5518fc75dd6e 100644
> --- a/include/drm/bridge/analogix_dp.h
> +++ b/include/drm/bridge/analogix_dp.h
> @@ -13,6 +13,8 @@
>  
>  #include <drm/drm_crtc.h>
>  
> +struct analogix_dp_device;
> +
>  enum analogix_dp_devtype {
>  	EXYNOS_DP,
>  	RK3288_DP,
> @@ -38,16 +40,17 @@ struct analogix_dp_plat_data {
>  			 struct drm_connector *);
>  };
>  
> -int analogix_dp_psr_supported(struct device *dev);
> -int analogix_dp_enable_psr(struct device *dev);
> -int analogix_dp_disable_psr(struct device *dev);
> +int analogix_dp_psr_supported(struct analogix_dp_device *dp);
> +int analogix_dp_enable_psr(struct analogix_dp_device *dp);
> +int analogix_dp_disable_psr(struct analogix_dp_device *dp);
>  
> -int analogix_dp_resume(struct device *dev);
> -int analogix_dp_suspend(struct device *dev);
> +int analogix_dp_resume(struct analogix_dp_device *dp);
> +int analogix_dp_suspend(struct analogix_dp_device *dp);
>  
> -int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
> -		     struct analogix_dp_plat_data *plat_data);
> -void analogix_dp_unbind(struct device *dev, struct device *master, void *data);
> +struct analogix_dp_device *
> +analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
> +		 struct analogix_dp_plat_data *plat_data);
> +void analogix_dp_unbind(struct analogix_dp_device *dp);
>  
>  int analogix_dp_start_crc(struct drm_connector *connector);
>  int analogix_dp_stop_crc(struct drm_connector *connector);
> -- 
> 2.11.0
> 
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From heiko at sntech.de  Fri Oct 20 09:58:58 2017
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Fri, 20 Oct 2017 18:58:58 +0200
Subject: [PATCH] pinctrl: rockchip: Add iomux-route switching support for
 rk3288
In-Reply-To: <68b8765d-3d55-3fdd-e23e-776e978c38bd@xs4all.nl>
References: <20171013225337.5196-1-phh@phh.me> <2040825.vRYCsv903Y@diego>
 <68b8765d-3d55-3fdd-e23e-776e978c38bd@xs4all.nl>
Message-ID: <40786265.ZDfztTY44U@diego>

Am Freitag, 20. Oktober 2017, 09:44:55 CEST schrieb Hans Verkuil:
> On 20/10/17 09:38, Heiko St?bner wrote:
> > Hi Hans,
> > 
> > Am Freitag, 20. Oktober 2017, 09:28:58 CEST schrieb Hans Verkuil:
> >> On 14/10/17 17:39, Heiko Stuebner wrote:
> >>> So far only the hdmi cec supports using one of two different pins
> >>> as source, so add the route switching for it.
> >>> 
> >>> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> >> 
> >> Just tested this on my firefly reload and it works great!
> >> 
> >> Tested-by: Hans Verkuil <hans.verkuil at cisco.com>
> > 
> > oh cool. I really only wrote this based on the soc manual,
> > so it actually surprises me, that it works on the first try :-)
> 
> One note though: I've only tested it on my Firefly Reload. I don't have a
> regular Firefly, so I can't be certain it works there. Just covering my ass
> here :-)

Haha ... I guess the only thing I could have messed up would be the
ordering (valu0 -> gpio0, value1 -> gpio7 ... and reverse), so if it were
really wrong, you shouldn've have seen any results at all.



From seanpaul at chromium.org  Fri Oct 20 10:05:54 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Fri, 20 Oct 2017 13:05:54 -0400
Subject: [PATCH v6 02/10] drm/rockchip: analogix_dp: Remove unnecessary
 init code
In-Reply-To: <88902b60-d096-f828-6d5d-44d44b6f4c50@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
 <20171019034812.13768-3-jeffy.chen@rock-chips.com>
 <88902b60-d096-f828-6d5d-44d44b6f4c50@rock-chips.com>
Message-ID: <20171020170554.uhhctvhx2igwdotw@art_vandelay>

On Fri, Oct 20, 2017 at 09:48:35AM +0800, Mark yao wrote:
> On 2017?10?19? 11:48, Jeffy Chen wrote:
> > Remove unnecessary init code, since we would do it in the power_on()
> > callback.
> > 
> > Also move of parse code to probe().
> > 
> > Fixes: 9e32e16e9e98 ("drm: rockchip: dp: add rockchip platform dp driver")
> > Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> 
> Looks good for me
> Acked-by: Mark Yao <mark.yao at rock-chips.com>

Pushed to -misc-next

Thanks,

Sean

> 
> > ---
> > 
> > Changes in v6: None
> > Changes in v5: None
> > 
> >   drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 27 ++++++-------------------
> >   1 file changed, 6 insertions(+), 21 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> > index 4d3f6ad0abdd..8cae5ad926cd 100644
> > --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> > +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> > @@ -269,7 +269,7 @@ static struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
> >   	.destroy = rockchip_dp_drm_encoder_destroy,
> >   };
> > -static int rockchip_dp_init(struct rockchip_dp_device *dp)
> > +static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
> >   {
> >   	struct device *dev = dp->dev;
> >   	struct device_node *np = dev->of_node;
> > @@ -303,19 +303,6 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp)
> >   		return PTR_ERR(dp->rst);
> >   	}
> > -	ret = clk_prepare_enable(dp->pclk);
> > -	if (ret < 0) {
> > -		DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret);
> > -		return ret;
> > -	}
> > -
> > -	ret = rockchip_dp_pre_init(dp);
> > -	if (ret < 0) {
> > -		DRM_DEV_ERROR(dp->dev, "failed to pre init %d\n", ret);
> > -		clk_disable_unprepare(dp->pclk);
> > -		return ret;
> > -	}
> > -
> >   	return 0;
> >   }
> > @@ -361,10 +348,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
> >   	if (!dp_data)
> >   		return -ENODEV;
> > -	ret = rockchip_dp_init(dp);
> > -	if (ret < 0)
> > -		return ret;
> > -
> >   	dp->data = dp_data;
> >   	dp->drm_dev = drm_dev;
> > @@ -398,7 +381,6 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
> >   	rockchip_drm_psr_unregister(&dp->encoder);
> >   	analogix_dp_unbind(dev, master, data);
> > -	clk_disable_unprepare(dp->pclk);
> >   }
> >   static const struct component_ops rockchip_dp_component_ops = {
> > @@ -414,7 +396,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
> >   	int ret;
> >   	ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
> > -	if (ret)
> > +	if (ret < 0)
> >   		return ret;
> >   	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
> > @@ -422,9 +404,12 @@ static int rockchip_dp_probe(struct platform_device *pdev)
> >   		return -ENOMEM;
> >   	dp->dev = dev;
> > -
> >   	dp->plat_data.panel = panel;
> > +	ret = rockchip_dp_of_probe(dp);
> > +	if (ret < 0)
> > +		return ret;
> > +
> >   	/*
> >   	 * We just use the drvdata until driver run into component
> >   	 * add function, and then we would set drvdata to null, so
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Fri Oct 20 10:07:35 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Fri, 20 Oct 2017 13:07:35 -0400
Subject: [PATCH v6 00/10] rockchip: kevin: Enable edp display
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <20171020170735.yahyoshwsewttjvy@art_vandelay>

On Thu, Oct 19, 2017 at 11:48:02AM +0800, Jeffy Chen wrote:
> 
> Make edp display works on chromebook kevin(at least for boot animation).
> 
> Also solve some issues i meet during the bringup.
> 
> Changes in v6:
> Don't change order of rockchip_drm_psr_register().
> 
> Changes in v5:
> Call the destroy hook in the error handling path like in unbind().
> Call the destroy hook in the error handling path like in unbind().
> Update cleanup order in unbind().
> Add disable to unbind(), and inline clk_prepare_enable() with bind().
> 
> Jeffy Chen (10):
>   arm64: dts: rockchip: Enable edp disaplay on kevin
>   drm/rockchip: analogix_dp: Remove unnecessary init code
>   drm/bridge: analogix: Do not use device's drvdata
>   drm/bridge: analogix_dp: Fix connector and encoder cleanup
>   drm/rockchip: analogix_dp: Add a sanity check for
>     rockchip_drm_psr_register()
>   drm/rockchip: dw-mipi-dsi: Fix error handling path
>   drm/rockchip: inno_hdmi: Fix error handling path
>   drm/bridge/synopsys: dw-hdmi: Add missing bridge detach
>   drm/bridge/synopsys: dw-hdmi: Do not use device's drvdata
>   drm/rockchip: dw_hdmi: Fix error handling path

Hi Jeffy,
I've pushed 2/10. Once you fix 3/10, I can push 3-7. I'd like someone familiar
with synopsys to review 8-9 before pushing those. Since 10 depends on 9, it'll
be blocked on synopsys review.

Sean

> 
>  arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts  | 29 +++++++
>  arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi       | 16 ++++
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 52 +++++-------
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          | 53 ++++++------
>  drivers/gpu/drm/exynos/exynos_dp.c                 | 29 ++++---
>  drivers/gpu/drm/imx/dw_hdmi-imx.c                  | 22 +++--
>  drivers/gpu/drm/meson/meson_dw_hdmi.c              | 20 +++--
>  drivers/gpu/drm/rcar-du/rcar_dw_hdmi.c             | 14 +++-
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 95 +++++++++++-----------
>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c             | 21 +++--
>  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c        | 39 +++++----
>  drivers/gpu/drm/rockchip/inno_hdmi.c               | 22 +++--
>  include/drm/bridge/analogix_dp.h                   | 19 +++--
>  include/drm/bridge/dw_hdmi.h                       | 17 ++--
>  14 files changed, 265 insertions(+), 183 deletions(-)
> 
> -- 
> 2.11.0
> 
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Fri Oct 20 10:25:48 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Fri, 20 Oct 2017 13:25:48 -0400
Subject: [PATCH] drm/rockchip: Fix build warning in analogix_dp-rockchip.c
Message-ID: <20171020172557.54900-1-seanpaul@chromium.org>

I didn't catch this before applying, just right after (of course).

Fixes:
../drivers/gpu/drm/rockchip/analogix_dp-rockchip.c: In function
?rockchip_dp_of_probe?:
../drivers/gpu/drm/rockchip/analogix_dp-rockchip.c:276:6: warning:
unused variable ?ret? [-Wunused-variable]
  int ret;
        ^~~

Fixes: 102712a32ff5 ("drm/rockchip: analogix_dp: Remove unnecessary init
code")
Cc: Jeffy Chen <jeffy.chen at rock-chips.com>
Cc: Mark Yao <mark.yao at rock-chips.com>
Cc: Sean Paul <seanpaul at chromium.org>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: dri-devel at lists.freedesktop.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-rockchip at lists.infradead.org
Signed-off-by: Sean Paul <seanpaul at chromium.org>
---
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 8cae5ad926cd..39944c0f1c0b 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -273,7 +273,6 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
 {
 	struct device *dev = dp->dev;
 	struct device_node *np = dev->of_node;
-	int ret;
 
 	dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
 	if (IS_ERR(dp->grf)) {
-- 
2.15.0.rc0.271.g36b669edcc-goog



From phh at phh.me  Fri Oct 20 12:18:38 2017
From: phh at phh.me (Pierre-Hugues Husson)
Date: Fri, 20 Oct 2017 21:18:38 +0200
Subject: [PATCH v2] drm: bridge: synopsys/dw-hdmi: Enable cec clock
Message-ID: <20171020191838.392-1-phh@phh.me>

The documentation already mentions "cec" optional clock, but
currently the driver doesn't enable it.

Changes:
v2:
- Separate ENOENT errors from others
- Propagate other errors (especially -EPROBE_DEFER)

Signed-off-by: Pierre-Hugues Husson <phh at phh.me>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index bf14214fa464..b31fc95d5fef 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -138,6 +138,7 @@ struct dw_hdmi {
 	struct device *dev;
 	struct clk *isfr_clk;
 	struct clk *iahb_clk;
+	struct clk *cec_clk;
 	struct dw_hdmi_i2c *i2c;
 
 	struct hdmi_data_info hdmi_data;
@@ -2382,6 +2383,27 @@ __dw_hdmi_probe(struct platform_device *pdev,
 		goto err_isfr;
 	}
 
+	hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec");
+	if (PTR_ERR(hdmi->cec_clk) == -ENOENT) {
+		hdmi->cec_clk = NULL;
+	} else if (IS_ERR(hdmi->cec_clk)) {
+		ret = PTR_ERR(hdmi->cec_clk);
+		if (ret != -EPROBE_DEFER) {
+			dev_err(hdmi->dev, "Cannot get HDMI cec clock: %d\n",
+					ret);
+		}
+
+		hdmi->cec_clk = NULL;
+		goto err_iahb;
+	} else {
+		ret = clk_prepare_enable(hdmi->cec_clk);
+		if (ret) {
+			dev_err(hdmi->dev, "Cannot enable HDMI cec clock: %d\n",
+					ret);
+			goto err_iahb;
+		}
+	}
+
 	/* Product and revision IDs */
 	hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
 		      | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
@@ -2518,6 +2540,8 @@ __dw_hdmi_probe(struct platform_device *pdev,
 		cec_notifier_put(hdmi->cec_notifier);
 
 	clk_disable_unprepare(hdmi->iahb_clk);
+	if (hdmi->cec_clk)
+		clk_disable_unprepare(hdmi->cec_clk);
 err_isfr:
 	clk_disable_unprepare(hdmi->isfr_clk);
 err_res:
@@ -2541,6 +2565,8 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
 
 	clk_disable_unprepare(hdmi->iahb_clk);
 	clk_disable_unprepare(hdmi->isfr_clk);
+	if (hdmi->cec_clk)
+		clk_disable_unprepare(hdmi->cec_clk);
 
 	if (hdmi->i2c)
 		i2c_del_adapter(&hdmi->i2c->adap);
-- 
2.14.1



From phh at phh.me  Fri Oct 20 12:21:14 2017
From: phh at phh.me (Pierre-Hugues Husson)
Date: Fri, 20 Oct 2017 21:21:14 +0200
Subject: [PATCH 1/3] drm: bridge: synopsys/dw-hdmi: Enable cec clock
In-Reply-To: <20171020081203.GD20805@n2100.armlinux.org.uk>
References: <20171013225337.5196-1-phh@phh.me>
 <20171013225337.5196-2-phh@phh.me>
 <20171020081203.GD20805@n2100.armlinux.org.uk>
Message-ID: <CAJ-oXjR7OyGjppoGReiaibLaZa6427ppwnbEQ2pvxMV2PKOHjA@mail.gmail.com>

2017-10-20 10:12 GMT+02:00 Russell King - ARM Linux <linux at armlinux.org.uk>:
> On Sat, Oct 14, 2017 at 12:53:35AM +0200, Pierre-Hugues Husson wrote:
>> @@ -2382,6 +2383,18 @@ __dw_hdmi_probe(struct platform_device *pdev,
>>               goto err_isfr;
>>       }
>>
>> +     hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec");
>> +     if (IS_ERR(hdmi->cec_clk)) {
>> +             hdmi->cec_clk = NULL;
>
> What if devm_clk_get() returns EPROBE_DEFER?  Does that really mean the
> clock does not exist?
Should be fixed in v2.
Thanks


From jeffy.chen at rock-chips.com  Fri Oct 20 16:14:19 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Sat, 21 Oct 2017 07:14:19 +0800
Subject: [PATCH] drm/rockchip: Fix build warning in analogix_dp-rockchip.c
In-Reply-To: <20171020172557.54900-1-seanpaul@chromium.org>
References: <20171020172557.54900-1-seanpaul@chromium.org>
Message-ID: <59EA834B.4090807@rock-chips.com>

Hi Sean,

On 10/21/2017 01:25 AM, Sean Paul wrote:
> I didn't catch this before applying, just right after (of course).
>
> Fixes:
> ../drivers/gpu/drm/rockchip/analogix_dp-rockchip.c: In function
> ?rockchip_dp_of_probe?:
> ../drivers/gpu/drm/rockchip/analogix_dp-rockchip.c:276:6: warning:
> unused variable ?ret? [-Wunused-variable]
>    int ret;
>          ^~~

sorry, i thought i fixed that, but it looks like i amended it to the 
wrong commit by mistake...
>
> Fixes: 102712a32ff5 ("drm/rockchip: analogix_dp: Remove unnecessary init
> code")
> Cc: Jeffy Chen <jeffy.chen at rock-chips.com>
> Cc: Mark Yao <mark.yao at rock-chips.com>
> Cc: Sean Paul <seanpaul at chromium.org>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: dri-devel at lists.freedesktop.org
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-rockchip at lists.infradead.org
> Signed-off-by: Sean Paul <seanpaul at chromium.org>
> ---
>   drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 1 -
>   1 file changed, 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index 8cae5ad926cd..39944c0f1c0b 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -273,7 +273,6 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
>   {
>   	struct device *dev = dp->dev;
>   	struct device_node *np = dev->of_node;
> -	int ret;
>
>   	dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
>   	if (IS_ERR(dp->grf)) {
>




From jeffy.chen at rock-chips.com  Fri Oct 20 16:14:39 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Sat, 21 Oct 2017 07:14:39 +0800
Subject: [PATCH v6 03/10] drm/bridge: analogix: Do not use device's drvdata
In-Reply-To: <20171020165226.vqoeldcmreuc73le@art_vandelay>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
 <20171019034812.13768-4-jeffy.chen@rock-chips.com>
 <20171020165226.vqoeldcmreuc73le@art_vandelay>
Message-ID: <59EA835F.3090508@rock-chips.com>

Hi Sean,

On 10/21/2017 12:52 AM, Sean Paul wrote:
> On Thu, Oct 19, 2017 at 11:48:05AM +0800, Jeffy Chen wrote:
>
> This patch has somehow lost it's original author. I assume this is not
> intentional.

oops, sorry, guess i used some wrongly command during the rebasing... 
will fix that.



From heiko at sntech.de  Sat Oct 21 01:53:10 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 Oct 2017 10:53:10 +0200
Subject: [PATCH] pinctrl: rockchip: Add iomux-route switching support for
 rk3288
Message-ID: <20171021085310.16246-1-heiko@sntech.de>

The rk3288 also has one function that can be routed to one of two pins,
the hdmi cec functionality can use either gpio7c0 or gpio7c7.
So add the route switching support for it.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
Tested-by: Hans Verkuil <hans.verkuil at cisco.com>
---
 drivers/pinctrl/pinctrl-rockchip.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index b5cb7858ffdc..8dd49e2e144b 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -884,6 +884,24 @@ static struct rockchip_mux_route_data rk3228_mux_route_data[] = {
 	},
 };
 
+static struct rockchip_mux_route_data rk3288_mux_route_data[] = {
+	{
+		/* edphdmi_cecinoutt1 */
+		.bank_num = 7,
+		.pin = 16,
+		.func = 2,
+		.route_offset = 0x264,
+		.route_val = BIT(16 + 12) | BIT(12),
+	}, {
+		/* edphdmi_cecinout */
+		.bank_num = 7,
+		.pin = 23,
+		.func = 4,
+		.route_offset = 0x264,
+		.route_val = BIT(16 + 12),
+	},
+};
+
 static struct rockchip_mux_route_data rk3328_mux_route_data[] = {
 	{
 		/* uart2dbg_rxm0 */
@@ -3391,6 +3409,8 @@ static struct rockchip_pin_ctrl rk3288_pin_ctrl = {
 		.type			= RK3288,
 		.grf_mux_offset		= 0x0,
 		.pmu_mux_offset		= 0x84,
+		.iomux_routes		= rk3288_mux_route_data,
+		.niomux_routes		= ARRAY_SIZE(rk3288_mux_route_data),
 		.pull_calc_reg		= rk3288_calc_pull_reg_and_bit,
 		.drv_calc_reg		= rk3288_calc_drv_reg_and_bit,
 };
-- 
2.14.2



From heiko at sntech.de  Sat Oct 21 12:29:02 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 Oct 2017 21:29:02 +0200
Subject: [PATCH 1/4] arm: dts: rockchip: add the cec clk for dw-hdmi on
 rk3288
In-Reply-To: <20171020100734.17064-2-hverkuil@xs4all.nl>
References: <20171020100734.17064-1-hverkuil@xs4all.nl>
 <20171020100734.17064-2-hverkuil@xs4all.nl>
Message-ID: <1702489.CpKZRm6uOh@phil>

Am Freitag, 20. Oktober 2017, 12:07:31 CEST schrieb Hans Verkuil:
> From: Hans Verkuil <hans.verkuil at cisco.com>
> 
> The dw-hdmi block needs the cec clk for the rk3288. Add it.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>

applied for 4.15, after s/arm:/ARM:/ in the subject


Thanks
Heiko


From heiko at sntech.de  Sat Oct 21 12:36:42 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 Oct 2017 21:36:42 +0200
Subject: [PATCH 3/4] arm: dts: rockchip: define the two possible CEC pins
In-Reply-To: <20171020100734.17064-4-hverkuil@xs4all.nl>
References: <20171020100734.17064-1-hverkuil@xs4all.nl>
 <20171020100734.17064-4-hverkuil@xs4all.nl>
Message-ID: <10200758.Ac6vYunJn0@phil>

Am Freitag, 20. Oktober 2017, 12:07:33 CEST schrieb Hans Verkuil:
> From: Hans Verkuil <hans.verkuil at cisco.com>
> 
> The CEC line can be routed to two possible pins. Define those pins.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>

applied for 4.15, after massaging the subject a bit and moving
hdmi-cec above the hdmi-ddc subnode (alphabetical ordering)


Thanks
Heiko


From heiko at sntech.de  Sat Oct 21 13:06:56 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 Oct 2017 22:06:56 +0200
Subject: [PATCH 2/4] arm: dts: rockchip: enable the first hdmi output
In-Reply-To: <20171020100734.17064-3-hverkuil@xs4all.nl>
References: <20171020100734.17064-1-hverkuil@xs4all.nl>
 <20171020100734.17064-3-hverkuil@xs4all.nl>
Message-ID: <2074014.EmavDXF96e@phil>

Am Freitag, 20. Oktober 2017, 12:07:32 CEST schrieb Hans Verkuil:
> From: Hans Verkuil <hans.verkuil at cisco.com>
> 
> The vdd10_lcd and vcc18_lcd regulators need to be enabled for HDMI output
> to work, so add 'regulator-always-on', just as is done in rk3288-firefly.dtsi.
> 
> Also enable i2c5 and the hdmi block.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>

applied for 4.15, after adapting the subject and moving it
to position 3 in the series.


Heiko


From heiko at sntech.de  Sat Oct 21 13:07:23 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 Oct 2017 22:07:23 +0200
Subject: [PATCH 4/4] arm: dts: rockchip: select which CEC pin is used for
 the Firefly Reload
In-Reply-To: <20171020100734.17064-5-hverkuil@xs4all.nl>
References: <20171020100734.17064-1-hverkuil@xs4all.nl>
 <20171020100734.17064-5-hverkuil@xs4all.nl>
Message-ID: <10557182.bKeG4DrKl5@phil>

Am Freitag, 20. Oktober 2017, 12:07:34 CEST schrieb Hans Verkuil:
> From: Hans Verkuil <hans.verkuil at cisco.com>
> 
> The Firefly Reload uses PC7.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
> Tested-by: Hans Verkuil <hans.verkuil at cisco.com>

folded into "[PATCH 2/4] arm: dts: rockchip: enable the first hdmi output"


Heiko


From hverkuil at xs4all.nl  Sun Oct 22 00:40:53 2017
From: hverkuil at xs4all.nl (Hans Verkuil)
Date: Sun, 22 Oct 2017 09:40:53 +0200
Subject: [PATCH 0/4] arm: dts: rockchip: enable HDMI+CEC on Firefly Reload
In-Reply-To: <20171020100734.17064-1-hverkuil@xs4all.nl>
References: <20171020100734.17064-1-hverkuil@xs4all.nl>
Message-ID: <2d624a0f-ff2c-7d18-3e13-ff5f766bf5c8@xs4all.nl>

Hi Heiko,

On 20/10/17 12:07, Hans Verkuil wrote:
> From: Hans Verkuil <hans.verkuil at cisco.com>
> 
> This patch series sits on top of these two patch series:
> 
> https://lkml.org/lkml/2017/10/13/971
> https://lkml.org/lkml/2017/10/14/161
> 
> The first adds support for the cec clk in dw-hdmi, the second adds an
> iomux-route for the CEC pin on the rk3288.
> 
> This patch series defines the cec clk for the rk3288, enables the
> first HDMI output on the Firefly Reload. The second output isn't working,
> I don't have enough knowledge to enable it. But I can test any patches
> adding support for it!
> 
> The third patch defines the two possible CEC pins and the last selects
> the correct pin for the Firefly Reload.
> 
> Likely the same thing can be done for the 'regular' Firefly, but I don't
> have the hardware to test.

My Firefly Reload thanks you for merging this series! :-)

Regards,

	Hans


From kishon at ti.com  Sun Oct 22 22:05:54 2017
From: kishon at ti.com (Kishon Vijay Abraham I)
Date: Mon, 23 Oct 2017 10:35:54 +0530
Subject: [PATCH v2] extcon: Split out extcon header file for consumer and
 provider device
In-Reply-To: <59E6B90F.8000808@samsung.com>
References: <CGME20171010101758epcas2p3b3f379076f5be5e81edee2bd00354c28@epcas2p3.samsung.com>
 <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>
 <59DEE429.2000608@samsung.com> <59E6B90F.8000808@samsung.com>
Message-ID: <fc19204f-c3a8-eccc-98df-e08aa27934fe@ti.com>



On Wednesday 18 October 2017 07:44 AM, Chanwoo Choi wrote:
> Gently Ping.
> 
> Dear Kishon,
> 
> Could you please review this patch for 'drivers/phy/*'?

sorry for the delay.. here it is

Acked-by: Kishon Vijay Abraham I <kishon at ti.com>
> 
> Regards,
> Chanwoo Choi
> 
> On 2017? 10? 12? 12:40, Chanwoo Choi wrote:
>> Dear Kishon,
>>
>> Could you please review this patch?
>> After that, I'll make the immutable brand and then send the pull request
>> for power_supply, mfd, phy, usb and extcon framework.
>>
>> On 2017? 10? 10? 19:17, Chanwoo Choi wrote:
>>> The extcon has two type of extcon devices as following.
>>> - 'extcon provider deivce' adds new extcon device and detect the
>>>    state/properties of external connector. Also, it notifies the
>>>    state/properties to the extcon consumer device.
>>> - 'extcon consumer device' gets the change state/properties
>>>    from extcon provider device.
>>> Prior to that, include/linux/extcon.h contains all exported API for
>>> both provider and consumer device driver. To clarify the meaning of
>>> header file and to remove the wrong use-case on consumer device,
>>> this patch separates into extcon.h and extcon-provider.h.
>>>
>>> [Description for include/linux/{extcon.h|extcon-provider.h}]
>>> - extcon.h includes the extcon API and data structure for extcon consumer
>>>   device driver. This header file contains the following APIs:
>>>   : Register/unregister the notifier to catch the change of extcon device
>>>   : Get the extcon device instance
>>>   : Get the extcon device name
>>>   : Get the state of each external connector
>>>   : Get the property value of each external connector
>>>   : Get the property capability of each external connector
>>>
>>> - extcon-provider.h includes the extcon API and data structure for extcon
>>>   provider device driver. This header file contains the following APIs:
>>>   : Include 'include/linux/extcon.h'
>>>   : Allocate the memory for extcon device instance
>>>   : Register/unregister extcon device
>>>   : Set the state of each external connector
>>>   : Set the property value of each external connector
>>>   : Set the property capability of each external connector
>>>
>>> Cc: Felipe Balbi <balbi at kernel.org>
>>> Cc: Kishon Vijay Abraham I <kishon at ti.com>
>>> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
>>> Acked-by: Sebastian Reichel <sebastian.reichel at collabora.co.uk>
>>> Acked-by: Chen-Yu Tsai <wens at csie.org>
>>> Acked-by: Charles Keepax <ckeepax at opensource.cirrus.com>
>>> Acked-by: Lee Jones <lee.jones at linaro.org>
>>> Signed-off-by: Chanwoo Choi <cw00.choi at samsung.com>
>>> ---
>>> Changes from v1:
>>> - Don't touch drivers/usb/renesas_usbhs/common.h.
>>> - Add acked-by from Sebastian Reichel (for drivers/power/supply/)
>>> - Add acked-by from Chen-Yu Tsai (for phy-sun4i-usb.c & extcon-axp288.c)
>>> - Add acked-by from Charles Keepax (for drivers/extcon/extcon-arizona.c)
>>> - Add acked-by from Lee Jones (fo include/linux/mfd/palmas.h)
>>>
>>>  drivers/extcon/extcon-adc-jack.c              |   2 +-
>>>  drivers/extcon/extcon-arizona.c               |   2 +-
>>>  drivers/extcon/extcon-axp288.c                |   2 +-
>>>  drivers/extcon/extcon-gpio.c                  |   2 +-
>>>  drivers/extcon/extcon-intel-cht-wc.c          |   2 +-
>>>  drivers/extcon/extcon-intel-int3496.c         |   2 +-
>>>  drivers/extcon/extcon-max14577.c              |   2 +-
>>>  drivers/extcon/extcon-max3355.c               |   2 +-
>>>  drivers/extcon/extcon-max77693.c              |   2 +-
>>>  drivers/extcon/extcon-max77843.c              |   2 +-
>>>  drivers/extcon/extcon-max8997.c               |   2 +-
>>>  drivers/extcon/extcon-qcom-spmi-misc.c        |   2 +-
>>>  drivers/extcon/extcon-rt8973a.c               |   2 +-
>>>  drivers/extcon/extcon-sm5502.c                |   2 +-
>>>  drivers/extcon/extcon-usb-gpio.c              |   2 +-
>>>  drivers/extcon/extcon-usbc-cros-ec.c          |   2 +-
>>>  drivers/extcon/extcon.h                       |   2 +-
>>>  drivers/phy/allwinner/phy-sun4i-usb.c         |   2 +-
>>>  drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c     |   2 +-
>>>  drivers/phy/renesas/phy-rcar-gen3-usb2.c      |   2 +-
>>>  drivers/phy/rockchip/phy-rockchip-inno-usb2.c |   2 +-
>>>  drivers/power/supply/qcom_smbb.c              |   2 +-
>>>  drivers/usb/gadget/udc/renesas_usb3.c         |   2 +-
>>>  drivers/usb/phy/phy-tahvo.c                   |   2 +-
>>>  include/linux/extcon-provider.h               | 142 ++++++++++++++++++++++++++
>>>  include/linux/extcon.h                        | 109 +-------------------
>>>  include/linux/mfd/palmas.h                    |   2 +-
>>>  27 files changed, 172 insertions(+), 129 deletions(-)
>>>  create mode 100644 include/linux/extcon-provider.h
>>>
>>> diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
>>> index 6f6537ab0a79..3877d86c746a 100644
>>> --- a/drivers/extcon/extcon-adc-jack.c
>>> +++ b/drivers/extcon/extcon-adc-jack.c
>>> @@ -26,7 +26,7 @@
>>>  #include <linux/workqueue.h>
>>>  #include <linux/iio/consumer.h>
>>>  #include <linux/extcon/extcon-adc-jack.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  
>>>  /**
>>>   * struct adc_jack_data - internal data for adc_jack device driver
>>> diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
>>> index f84da4a17724..da0e9bc4262f 100644
>>> --- a/drivers/extcon/extcon-arizona.c
>>> +++ b/drivers/extcon/extcon-arizona.c
>>> @@ -27,7 +27,7 @@
>>>  #include <linux/pm_runtime.h>
>>>  #include <linux/property.h>
>>>  #include <linux/regulator/consumer.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  
>>>  #include <sound/soc.h>
>>>  
>>> diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c
>>> index f4fd03e58e37..981fba56bc18 100644
>>> --- a/drivers/extcon/extcon-axp288.c
>>> +++ b/drivers/extcon/extcon-axp288.c
>>> @@ -22,7 +22,7 @@
>>>  #include <linux/platform_device.h>
>>>  #include <linux/property.h>
>>>  #include <linux/notifier.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/regmap.h>
>>>  #include <linux/gpio.h>
>>>  #include <linux/gpio/consumer.h>
>>> diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
>>> index ebed22f22d75..ab770adcca7e 100644
>>> --- a/drivers/extcon/extcon-gpio.c
>>> +++ b/drivers/extcon/extcon-gpio.c
>>> @@ -17,7 +17,7 @@
>>>   * GNU General Public License for more details.
>>>   */
>>>  
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/extcon/extcon-gpio.h>
>>>  #include <linux/gpio.h>
>>>  #include <linux/gpio/consumer.h>
>>> diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c
>>> index 91a0023074af..7c4bc8c44c3f 100644
>>> --- a/drivers/extcon/extcon-intel-cht-wc.c
>>> +++ b/drivers/extcon/extcon-intel-cht-wc.c
>>> @@ -15,7 +15,7 @@
>>>   * more details.
>>>   */
>>>  
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/kernel.h>
>>>  #include <linux/mfd/intel_soc_pmic.h>
>>> diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
>>> index 1a45e745717d..c8691b5a9cb0 100644
>>> --- a/drivers/extcon/extcon-intel-int3496.c
>>> +++ b/drivers/extcon/extcon-intel-int3496.c
>>> @@ -19,7 +19,7 @@
>>>   */
>>>  
>>>  #include <linux/acpi.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/gpio.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/module.h>
>>> diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c
>>> index f6414b7fa5bc..6c2c9996eb71 100644
>>> --- a/drivers/extcon/extcon-max14577.c
>>> +++ b/drivers/extcon/extcon-max14577.c
>>> @@ -23,7 +23,7 @@
>>>  #include <linux/platform_device.h>
>>>  #include <linux/mfd/max14577.h>
>>>  #include <linux/mfd/max14577-private.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  
>>>  #define	DELAY_MS_DEFAULT		17000		/* unit: millisecond */
>>>  
>>> diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c
>>> index 533e16a952b8..0aa410836f4e 100644
>>> --- a/drivers/extcon/extcon-max3355.c
>>> +++ b/drivers/extcon/extcon-max3355.c
>>> @@ -9,7 +9,7 @@
>>>   * may be copied, distributed, and modified under those terms.
>>>   */
>>>  
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/gpio.h>
>>>  #include <linux/gpio/consumer.h>
>>>  #include <linux/interrupt.h>
>>> diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
>>> index 7a5856809047..643411066ad9 100644
>>> --- a/drivers/extcon/extcon-max77693.c
>>> +++ b/drivers/extcon/extcon-max77693.c
>>> @@ -26,7 +26,7 @@
>>>  #include <linux/mfd/max77693.h>
>>>  #include <linux/mfd/max77693-common.h>
>>>  #include <linux/mfd/max77693-private.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/regmap.h>
>>>  #include <linux/irqdomain.h>
>>>  
>>> diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
>>> index 6e722d552cf1..28f251ff0fa2 100644
>>> --- a/drivers/extcon/extcon-max77843.c
>>> +++ b/drivers/extcon/extcon-max77843.c
>>> @@ -11,7 +11,7 @@
>>>   * (at your option) any later version.
>>>   */
>>>  
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/i2c.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/kernel.h>
>>> diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
>>> index 4a0612fb9c07..8152790d72e1 100644
>>> --- a/drivers/extcon/extcon-max8997.c
>>> +++ b/drivers/extcon/extcon-max8997.c
>>> @@ -25,7 +25,7 @@
>>>  #include <linux/kobject.h>
>>>  #include <linux/mfd/max8997.h>
>>>  #include <linux/mfd/max8997-private.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/irqdomain.h>
>>>  
>>>  #define	DEV_NAME			"max8997-muic"
>>> diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c
>>> index b8cde096a808..660bbf163bf5 100644
>>> --- a/drivers/extcon/extcon-qcom-spmi-misc.c
>>> +++ b/drivers/extcon/extcon-qcom-spmi-misc.c
>>> @@ -15,7 +15,7 @@
>>>   * GNU General Public License for more details.
>>>   */
>>>  
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/init.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/kernel.h>
>>> diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c
>>> index eaa355e7d9e4..e059bd5f2041 100644
>>> --- a/drivers/extcon/extcon-rt8973a.c
>>> +++ b/drivers/extcon/extcon-rt8973a.c
>>> @@ -20,7 +20,7 @@
>>>  #include <linux/platform_device.h>
>>>  #include <linux/regmap.h>
>>>  #include <linux/slab.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  
>>>  #include "extcon-rt8973a.h"
>>>  
>>> diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c
>>> index 106ef0297b53..0cfb5a3efdf6 100644
>>> --- a/drivers/extcon/extcon-sm5502.c
>>> +++ b/drivers/extcon/extcon-sm5502.c
>>> @@ -19,7 +19,7 @@
>>>  #include <linux/platform_device.h>
>>>  #include <linux/regmap.h>
>>>  #include <linux/slab.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  
>>>  #include "extcon-sm5502.h"
>>>  
>>> diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
>>> index 9c925b05b7aa..53762864a9f7 100644
>>> --- a/drivers/extcon/extcon-usb-gpio.c
>>> +++ b/drivers/extcon/extcon-usb-gpio.c
>>> @@ -14,7 +14,7 @@
>>>   * GNU General Public License for more details.
>>>   */
>>>  
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/gpio.h>
>>>  #include <linux/gpio/consumer.h>
>>>  #include <linux/init.h>
>>> diff --git a/drivers/extcon/extcon-usbc-cros-ec.c b/drivers/extcon/extcon-usbc-cros-ec.c
>>> index 598956f1dcae..6187f731b29d 100644
>>> --- a/drivers/extcon/extcon-usbc-cros-ec.c
>>> +++ b/drivers/extcon/extcon-usbc-cros-ec.c
>>> @@ -14,7 +14,7 @@
>>>   * GNU General Public License for more details.
>>>   */
>>>  
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/kernel.h>
>>>  #include <linux/mfd/cros_ec.h>
>>>  #include <linux/module.h>
>>> diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h
>>> index dddddcfa0587..cc1b436eb66a 100644
>>> --- a/drivers/extcon/extcon.h
>>> +++ b/drivers/extcon/extcon.h
>>> @@ -1,7 +1,7 @@
>>>  #ifndef __LINUX_EXTCON_INTERNAL_H__
>>>  #define __LINUX_EXTCON_INTERNAL_H__
>>>  
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  
>>>  /**
>>>   * struct extcon_dev - An extcon device represents one external connector.
>>> diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
>>> index 1161e11fb3cf..ef34f97f214b 100644
>>> --- a/drivers/phy/allwinner/phy-sun4i-usb.c
>>> +++ b/drivers/phy/allwinner/phy-sun4i-usb.c
>>> @@ -24,7 +24,7 @@
>>>  #include <linux/clk.h>
>>>  #include <linux/delay.h>
>>>  #include <linux/err.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/io.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/kernel.h>
>>> diff --git a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
>>> index d099a0c8cee5..7ceea5ae2704 100644
>>> --- a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
>>> +++ b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c
>>> @@ -12,7 +12,7 @@
>>>   */
>>>  
>>>  #include <linux/delay.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/gpio.h>
>>>  #include <linux/gpio/consumer.h>
>>>  #include <linux/init.h>
>>> diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
>>> index 54c34298a000..b33e2994ccce 100644
>>> --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
>>> +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
>>> @@ -12,7 +12,7 @@
>>>   * published by the Free Software Foundation.
>>>   */
>>>  
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/io.h>
>>>  #include <linux/module.h>
>>> diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
>>> index ee7ce5ee53f9..5049dac79bd0 100644
>>> --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
>>> +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
>>> @@ -17,7 +17,7 @@
>>>  #include <linux/clk.h>
>>>  #include <linux/clk-provider.h>
>>>  #include <linux/delay.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/io.h>
>>>  #include <linux/gpio/consumer.h>
>>> diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c
>>> index f6a0d245731d..11de691b9a71 100644
>>> --- a/drivers/power/supply/qcom_smbb.c
>>> +++ b/drivers/power/supply/qcom_smbb.c
>>> @@ -34,7 +34,7 @@
>>>  #include <linux/power_supply.h>
>>>  #include <linux/regmap.h>
>>>  #include <linux/slab.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/regulator/driver.h>
>>>  
>>>  #define SMBB_CHG_VMAX		0x040
>>> diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
>>> index df37c1e6e9d5..8b4d051fdbed 100644
>>> --- a/drivers/usb/gadget/udc/renesas_usb3.c
>>> +++ b/drivers/usb/gadget/udc/renesas_usb3.c
>>> @@ -12,7 +12,7 @@
>>>  #include <linux/delay.h>
>>>  #include <linux/dma-mapping.h>
>>>  #include <linux/err.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/interrupt.h>
>>>  #include <linux/io.h>
>>>  #include <linux/module.h>
>>> diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c
>>> index 8babd318c0ed..354e8c98af05 100644
>>> --- a/drivers/usb/phy/phy-tahvo.c
>>> +++ b/drivers/usb/phy/phy-tahvo.c
>>> @@ -23,7 +23,7 @@
>>>  #include <linux/io.h>
>>>  #include <linux/clk.h>
>>>  #include <linux/usb.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/kernel.h>
>>>  #include <linux/module.h>
>>>  #include <linux/usb/otg.h>
>>> diff --git a/include/linux/extcon-provider.h b/include/linux/extcon-provider.h
>>> new file mode 100644
>>> index 000000000000..2feca5881fa7
>>> --- /dev/null
>>> +++ b/include/linux/extcon-provider.h
>>> @@ -0,0 +1,142 @@
>>> +/*
>>> + * External Connector (extcon) framework
>>> + * - linux/include/linux/extcon-provider.h for extcon provider device driver.
>>> + *
>>> + * Copyright (C) 2017 Samsung Electronics
>>> + * Author: Chanwoo Choi <cw00.choi at samsung.com>
>>> + *
>>> + * This software is licensed under the terms of the GNU General Public
>>> + * License version 2, as published by the Free Software Foundation, and
>>> + * may be copied, distributed, and modified under those terms.
>>> + *
>>> + * 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 __LINUX_EXTCON_PROVIDER_H__
>>> +#define __LINUX_EXTCON_PROVIDER_H__
>>> +
>>> +#include <linux/extcon.h>
>>> +
>>> +struct extcon_dev;
>>> +
>>> +#if IS_ENABLED(CONFIG_EXTCON)
>>> +
>>> +/* Following APIs register/unregister the extcon device. */
>>> +extern int extcon_dev_register(struct extcon_dev *edev);
>>> +extern void extcon_dev_unregister(struct extcon_dev *edev);
>>> +extern int devm_extcon_dev_register(struct device *dev,
>>> +				struct extcon_dev *edev);
>>> +extern void devm_extcon_dev_unregister(struct device *dev,
>>> +				struct extcon_dev *edev);
>>> +
>>> +/* Following APIs allocate/free the memory of the extcon device. */
>>> +extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable);
>>> +extern void extcon_dev_free(struct extcon_dev *edev);
>>> +extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
>>> +				const unsigned int *cable);
>>> +extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
>>> +
>>> +/* Synchronize the state and property value for each external connector. */
>>> +extern int extcon_sync(struct extcon_dev *edev, unsigned int id);
>>> +
>>> +/*
>>> + * Following APIs set the connected state of each external connector.
>>> + * The 'id' argument indicates the defined external connector.
>>> + */
>>> +extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>>> +				bool state);
>>> +extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
>>> +				bool state);
>>> +
>>> +/*
>>> + * Following APIs set the property of each external connector.
>>> + * The 'id' argument indicates the defined external connector
>>> + * and the 'prop' indicates the extcon property.
>>> + *
>>> + * And extcon_set_property_capability() set the capability of the property
>>> + * for each external connector. They are used to set the capability of the
>>> + * property of each external connector based on the id and property.
>>> + */
>>> +extern int extcon_set_property(struct extcon_dev *edev, unsigned int id,
>>> +				unsigned int prop,
>>> +				union extcon_property_value prop_val);
>>> +extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
>>> +				unsigned int prop,
>>> +				union extcon_property_value prop_val);
>>> +extern int extcon_set_property_capability(struct extcon_dev *edev,
>>> +				unsigned int id, unsigned int prop);
>>> +
>>> +#else /* CONFIG_EXTCON */
>>> +static inline int extcon_dev_register(struct extcon_dev *edev)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
>>> +
>>> +static inline int devm_extcon_dev_register(struct device *dev,
>>> +				struct extcon_dev *edev)
>>> +{
>>> +	return -EINVAL;
>>> +}
>>> +
>>> +static inline void devm_extcon_dev_unregister(struct device *dev,
>>> +				struct extcon_dev *edev) { }
>>> +
>>> +static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable)
>>> +{
>>> +	return ERR_PTR(-ENOSYS);
>>> +}
>>> +
>>> +static inline void extcon_dev_free(struct extcon_dev *edev) { }
>>> +
>>> +static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
>>> +				const unsigned int *cable)
>>> +{
>>> +	return ERR_PTR(-ENOSYS);
>>> +}
>>> +
>>> +static inline void devm_extcon_dev_free(struct extcon_dev *edev) { }
>>> +
>>> +
>>> +static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>>> +				bool state)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
>>> +				bool state)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
>>> +				unsigned int prop,
>>> +				union extcon_property_value prop_val)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static inline int extcon_set_property_sync(struct extcon_dev *edev,
>>> +				unsigned int id, unsigned int prop,
>>> +				union extcon_property_value prop_val)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static inline int extcon_set_property_capability(struct extcon_dev *edev,
>>> +				unsigned int id, unsigned int prop)
>>> +{
>>> +	return 0;
>>> +}
>>> +#endif /* CONFIG_EXTCON */
>>> +#endif /* __LINUX_EXTCON_PROVIDER_H__ */
>>> diff --git a/include/linux/extcon.h b/include/linux/extcon.h
>>> index 744d60ca80c3..6d94e82c8ad9 100644
>>> --- a/include/linux/extcon.h
>>> +++ b/include/linux/extcon.h
>>> @@ -1,5 +1,6 @@
>>>  /*
>>>   * External Connector (extcon) framework
>>> + * - linux/include/linux/extcon.h for extcon consumer device driver.
>>>   *
>>>   * Copyright (C) 2015 Samsung Electronics
>>>   * Author: Chanwoo Choi <cw00.choi at samsung.com>
>>> @@ -170,61 +171,29 @@
>>>  	int intval;	/* type : integer (intval) */
>>>  };
>>>  
>>> -struct extcon_cable;
>>>  struct extcon_dev;
>>>  
>>>  #if IS_ENABLED(CONFIG_EXTCON)
>>> -
>>> -/* Following APIs register/unregister the extcon device. */
>>> -extern int extcon_dev_register(struct extcon_dev *edev);
>>> -extern void extcon_dev_unregister(struct extcon_dev *edev);
>>> -extern int devm_extcon_dev_register(struct device *dev,
>>> -				struct extcon_dev *edev);
>>> -extern void devm_extcon_dev_unregister(struct device *dev,
>>> -				struct extcon_dev *edev);
>>> -
>>> -/* Following APIs allocate/free the memory of the extcon device. */
>>> -extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable);
>>> -extern void extcon_dev_free(struct extcon_dev *edev);
>>> -extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
>>> -				const unsigned int *cable);
>>> -extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
>>> -
>>> -/* Synchronize the state and property value for each external connector. */
>>> -extern int extcon_sync(struct extcon_dev *edev, unsigned int id);
>>> -
>>>  /*
>>> - * Following APIs get/set the connected state of each external connector.
>>> + * Following APIs get the connected state of each external connector.
>>>   * The 'id' argument indicates the defined external connector.
>>>   */
>>>  extern int extcon_get_state(struct extcon_dev *edev, unsigned int id);
>>> -extern int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>>> -				bool state);
>>> -extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
>>> -				bool state);
>>>  
>>>  /*
>>> - * Following APIs get/set the property of each external connector.
>>> + * Following APIs get the property of each external connector.
>>>   * The 'id' argument indicates the defined external connector
>>>   * and the 'prop' indicates the extcon property.
>>>   *
>>> - * And extcon_get/set_property_capability() set the capability of the property
>>> - * for each external connector. They are used to set the capability of the
>>> + * And extcon_get_property_capability() get the capability of the property
>>> + * for each external connector. They are used to get the capability of the
>>>   * property of each external connector based on the id and property.
>>>   */
>>>  extern int extcon_get_property(struct extcon_dev *edev, unsigned int id,
>>>  				unsigned int prop,
>>>  				union extcon_property_value *prop_val);
>>> -extern int extcon_set_property(struct extcon_dev *edev, unsigned int id,
>>> -				unsigned int prop,
>>> -				union extcon_property_value prop_val);
>>> -extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id,
>>> -				unsigned int prop,
>>> -				union extcon_property_value prop_val);
>>>  extern int extcon_get_property_capability(struct extcon_dev *edev,
>>>  				unsigned int id, unsigned int prop);
>>> -extern int extcon_set_property_capability(struct extcon_dev *edev,
>>> -				unsigned int id, unsigned int prop);
>>>  
>>>  /*
>>>   * Following APIs register the notifier block in order to detect
>>> @@ -268,79 +237,17 @@ extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev,
>>>  extern const char *extcon_get_edev_name(struct extcon_dev *edev);
>>>  
>>>  #else /* CONFIG_EXTCON */
>>> -static inline int extcon_dev_register(struct extcon_dev *edev)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>> -static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
>>> -
>>> -static inline int devm_extcon_dev_register(struct device *dev,
>>> -				struct extcon_dev *edev)
>>> -{
>>> -	return -EINVAL;
>>> -}
>>> -
>>> -static inline void devm_extcon_dev_unregister(struct device *dev,
>>> -				struct extcon_dev *edev) { }
>>> -
>>> -static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable)
>>> -{
>>> -	return ERR_PTR(-ENOSYS);
>>> -}
>>> -
>>> -static inline void extcon_dev_free(struct extcon_dev *edev) { }
>>> -
>>> -static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
>>> -				const unsigned int *cable)
>>> -{
>>> -	return ERR_PTR(-ENOSYS);
>>> -}
>>> -
>>> -static inline void devm_extcon_dev_free(struct extcon_dev *edev) { }
>>> -
>>> -
>>>  static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id)
>>>  {
>>>  	return 0;
>>>  }
>>>  
>>> -static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id,
>>> -				bool state)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>> -static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id,
>>> -				bool state)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>> -static inline int extcon_sync(struct extcon_dev *edev, unsigned int id)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>>  static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id,
>>>  				unsigned int prop,
>>>  				union extcon_property_value *prop_val)
>>>  {
>>>  	return 0;
>>>  }
>>> -static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id,
>>> -				unsigned int prop,
>>> -				union extcon_property_value prop_val)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>> -static inline int extcon_set_property_sync(struct extcon_dev *edev,
>>> -				unsigned int id, unsigned int prop,
>>> -				union extcon_property_value prop_val)
>>> -{
>>> -	return 0;
>>> -}
>>>  
>>>  static inline int extcon_get_property_capability(struct extcon_dev *edev,
>>>  				unsigned int id, unsigned int prop)
>>> @@ -348,12 +255,6 @@ static inline int extcon_get_property_capability(struct extcon_dev *edev,
>>>  	return 0;
>>>  }
>>>  
>>> -static inline int extcon_set_property_capability(struct extcon_dev *edev,
>>> -				unsigned int id, unsigned int prop)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>>  static inline int extcon_register_notifier(struct extcon_dev *edev,
>>>  				unsigned int id, struct notifier_block *nb)
>>>  {
>>> diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
>>> index 6dec43826303..3c8568aa82a5 100644
>>> --- a/include/linux/mfd/palmas.h
>>> +++ b/include/linux/mfd/palmas.h
>>> @@ -20,7 +20,7 @@
>>>  #include <linux/leds.h>
>>>  #include <linux/regmap.h>
>>>  #include <linux/regulator/driver.h>
>>> -#include <linux/extcon.h>
>>> +#include <linux/extcon-provider.h>
>>>  #include <linux/of_gpio.h>
>>>  #include <linux/usb/phy_companion.h>
>>>  
>>>
>>
>>


From cw00.choi at samsung.com  Sun Oct 22 22:31:51 2017
From: cw00.choi at samsung.com (Chanwoo Choi)
Date: Mon, 23 Oct 2017 14:31:51 +0900
Subject: [PATCH v2] extcon: Split out extcon header file for consumer
 and provider device
In-Reply-To: <fc19204f-c3a8-eccc-98df-e08aa27934fe@ti.com>
References: <CGME20171010101758epcas2p3b3f379076f5be5e81edee2bd00354c28@epcas2p3.samsung.com>
 <1507630671-23536-1-git-send-email-cw00.choi@samsung.com>
 <59DEE429.2000608@samsung.com> <59E6B90F.8000808@samsung.com>
 <fc19204f-c3a8-eccc-98df-e08aa27934fe@ti.com>
Message-ID: <59ED7EC7.3030204@samsung.com>

Dear all,

I got the reviews from all maintainers related to this patch.
So, I make the immutable branch on extcon.git and then send
the pull request in order to prevent the possible merge conflict.

Best Regards,
Chanwoo Choi
Samsung Electronics


The following changes since commit 2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e:

  Linux 4.14-rc1 (2017-09-16 15:47:51 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git ib-extcon-v4.15

for you to fetch changes up to 176aa36012135d172394a928a03fb03dfecd83f9:

  extcon: Split out extcon header file for consumer and provider device (2017-10-23 14:07:58 +0900)

----------------------------------------------------------------
Chanwoo Choi (1):
      extcon: Split out extcon header file for consumer and provider device

 drivers/extcon/extcon-adc-jack.c              |   2 +-
 drivers/extcon/extcon-arizona.c               |   2 +-
 drivers/extcon/extcon-axp288.c                |   2 +-
 drivers/extcon/extcon-gpio.c                  |   2 +-
 drivers/extcon/extcon-intel-cht-wc.c          |   2 +-
 drivers/extcon/extcon-intel-int3496.c         |   2 +-
 drivers/extcon/extcon-max14577.c              |   2 +-
 drivers/extcon/extcon-max3355.c               |   2 +-
 drivers/extcon/extcon-max77693.c              |   2 +-
 drivers/extcon/extcon-max77843.c              |   2 +-
 drivers/extcon/extcon-max8997.c               |   2 +-
 drivers/extcon/extcon-qcom-spmi-misc.c        |   2 +-
 drivers/extcon/extcon-rt8973a.c               |   2 +-
 drivers/extcon/extcon-sm5502.c                |   2 +-
 drivers/extcon/extcon-usb-gpio.c              |   2 +-
 drivers/extcon/extcon-usbc-cros-ec.c          |   2 +-
 drivers/extcon/extcon.h                       |   2 +-
 drivers/phy/allwinner/phy-sun4i-usb.c         |   2 +-
 drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c     |   2 +-
 drivers/phy/renesas/phy-rcar-gen3-usb2.c      |   2 +-
 drivers/phy/rockchip/phy-rockchip-inno-usb2.c |   2 +-
 drivers/power/supply/qcom_smbb.c              |   2 +-
 drivers/usb/gadget/udc/renesas_usb3.c         |   2 +-
 drivers/usb/phy/phy-tahvo.c                   |   2 +-
 include/linux/extcon-provider.h               | 142 ++++++++++++++++++++++++++
 include/linux/extcon.h                        | 109 +-------------------
 include/linux/mfd/palmas.h                    |   2 +-
 27 files changed, 172 insertions(+), 129 deletions(-)
 create mode 100644 include/linux/extcon-provider.h


On 2017? 10? 23? 14:05, Kishon Vijay Abraham I wrote:
> 
> 
> On Wednesday 18 October 2017 07:44 AM, Chanwoo Choi wrote:
>> Gently Ping.
>>
>> Dear Kishon,
>>
>> Could you please review this patch for 'drivers/phy/*'?
> 
> sorry for the delay.. here it is
> 
> Acked-by: Kishon Vijay Abraham I <kishon at ti.com>
>>
>> Regards,
>> Chanwoo Choi
>>
>> On 2017? 10? 12? 12:40, Chanwoo Choi wrote:
>>> Dear Kishon,
>>>
>>> Could you please review this patch?
>>> After that, I'll make the immutable brand and then send the pull request
>>> for power_supply, mfd, phy, usb and extcon framework.
>>>
>>> On 2017? 10? 10? 19:17, Chanwoo Choi wrote:
>>>> The extcon has two type of extcon devices as following.
>>>> - 'extcon provider deivce' adds new extcon device and detect the
>>>>    state/properties of external connector. Also, it notifies the
>>>>    state/properties to the extcon consumer device.
>>>> - 'extcon consumer device' gets the change state/properties
>>>>    from extcon provider device.
>>>> Prior to that, include/linux/extcon.h contains all exported API for
>>>> both provider and consumer device driver. To clarify the meaning of
>>>> header file and to remove the wrong use-case on consumer device,
>>>> this patch separates into extcon.h and extcon-provider.h.
>>>>
>>>> [Description for include/linux/{extcon.h|extcon-provider.h}]
>>>> - extcon.h includes the extcon API and data structure for extcon consumer
>>>>   device driver. This header file contains the following APIs:
>>>>   : Register/unregister the notifier to catch the change of extcon device
>>>>   : Get the extcon device instance
>>>>   : Get the extcon device name
>>>>   : Get the state of each external connector
>>>>   : Get the property value of each external connector
>>>>   : Get the property capability of each external connector
>>>>
>>>> - extcon-provider.h includes the extcon API and data structure for extcon
>>>>   provider device driver. This header file contains the following APIs:
>>>>   : Include 'include/linux/extcon.h'
>>>>   : Allocate the memory for extcon device instance
>>>>   : Register/unregister extcon device
>>>>   : Set the state of each external connector
>>>>   : Set the property value of each external connector
>>>>   : Set the property capability of each external connector
>>>>
>>>> Cc: Felipe Balbi <balbi at kernel.org>
>>>> Cc: Kishon Vijay Abraham I <kishon at ti.com>
>>>> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
>>>> Acked-by: Sebastian Reichel <sebastian.reichel at collabora.co.uk>
>>>> Acked-by: Chen-Yu Tsai <wens at csie.org>
>>>> Acked-by: Charles Keepax <ckeepax at opensource.cirrus.com>
>>>> Acked-by: Lee Jones <lee.jones at linaro.org>
>>>> Signed-off-by: Chanwoo Choi <cw00.choi at samsung.com>
>>>> ---
>>>> Changes from v1:
>>>> - Don't touch drivers/usb/renesas_usbhs/common.h.
>>>> - Add acked-by from Sebastian Reichel (for drivers/power/supply/)
>>>> - Add acked-by from Chen-Yu Tsai (for phy-sun4i-usb.c & extcon-axp288.c)
>>>> - Add acked-by from Charles Keepax (for drivers/extcon/extcon-arizona.c)
>>>> - Add acked-by from Lee Jones (fo include/linux/mfd/palmas.h)
>>>>
>>>>  drivers/extcon/extcon-adc-jack.c              |   2 +-
>>>>  drivers/extcon/extcon-arizona.c               |   2 +-
>>>>  drivers/extcon/extcon-axp288.c                |   2 +-
>>>>  drivers/extcon/extcon-gpio.c                  |   2 +-
>>>>  drivers/extcon/extcon-intel-cht-wc.c          |   2 +-
>>>>  drivers/extcon/extcon-intel-int3496.c         |   2 +-
>>>>  drivers/extcon/extcon-max14577.c              |   2 +-
>>>>  drivers/extcon/extcon-max3355.c               |   2 +-
>>>>  drivers/extcon/extcon-max77693.c              |   2 +-
>>>>  drivers/extcon/extcon-max77843.c              |   2 +-
>>>>  drivers/extcon/extcon-max8997.c               |   2 +-
>>>>  drivers/extcon/extcon-qcom-spmi-misc.c        |   2 +-
>>>>  drivers/extcon/extcon-rt8973a.c               |   2 +-
>>>>  drivers/extcon/extcon-sm5502.c                |   2 +-
>>>>  drivers/extcon/extcon-usb-gpio.c              |   2 +-
>>>>  drivers/extcon/extcon-usbc-cros-ec.c          |   2 +-
>>>>  drivers/extcon/extcon.h                       |   2 +-
>>>>  drivers/phy/allwinner/phy-sun4i-usb.c         |   2 +-
>>>>  drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c     |   2 +-
>>>>  drivers/phy/renesas/phy-rcar-gen3-usb2.c      |   2 +-
>>>>  drivers/phy/rockchip/phy-rockchip-inno-usb2.c |   2 +-
>>>>  drivers/power/supply/qcom_smbb.c              |   2 +-
>>>>  drivers/usb/gadget/udc/renesas_usb3.c         |   2 +-
>>>>  drivers/usb/phy/phy-tahvo.c                   |   2 +-
>>>>  include/linux/extcon-provider.h               | 142 ++++++++++++++++++++++++++
>>>>  include/linux/extcon.h                        | 109 +-------------------
>>>>  include/linux/mfd/palmas.h                    |   2 +-
>>>>  27 files changed, 172 insertions(+), 129 deletions(-)
>>>>  create mode 100644 include/linux/extcon-provider.h

[snip]



From dianders at chromium.org  Mon Oct 23 10:59:02 2017
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 Oct 2017 10:59:02 -0700
Subject: [PATCH v2 3/5] mmc: dw_mmc: Add locking to the CTO timer
In-Reply-To: <CAD=FV=W7u0_kr9HXHpKmw=Hgco2P=u3jeSb8v0OoVvD+2kJorw@mail.gmail.com>
References: <20171012201118.23570-1-dianders@chromium.org>
 <20171012201118.23570-4-dianders@chromium.org>
 <41ae1571-4723-2700-1f03-7215e874c42e@rock-chips.com>
 <CAD=FV=UMuJBKV2-pNo4yiyfxXxYJo_tX6RkxCCzm_UFg9XyjyQ@mail.gmail.com>
 <d6acce96-b292-ee4e-8f9b-1d524c14e0fc@rock-chips.com>
 <CAD=FV=W7u0_kr9HXHpKmw=Hgco2P=u3jeSb8v0OoVvD+2kJorw@mail.gmail.com>
Message-ID: <CAD=FV=XdWD1dk67yixy+5U7RubxKY2WAh-jhZfTOmb4ndf3b5g@mail.gmail.com>

Hi,

On Tue, Oct 17, 2017 at 9:40 AM, Doug Anderson <dianders at chromium.org> wrote:
> ...
> ...
>> Yes, it looks hard to get concurrency right. I have a comment for your
>> DRTO case(patch 5). Let's do some brainstorm there.
>
> Since your comments in this patch are positive and you've now added
> your Reviewed-by to patch #5, I'm going to assume that you'd also like
> your Reviewed-by on this patch?
>
>
> Jaehoon: I think I have Shawn's review on all this series.  It would
> be great if you could review them yourself and/or pick them up in your
> tree.  Since they fix a regression on 4.14 we really don't want to
> delay too long.  If you're busy, please yell and we can figure out a
> way to get these in (either through Ulf directly or we should find
> someone else to make a git tree and send a pull request).

Ulf: I still haven't heard anything for Jaehoon.  Do you have any
interest in landing this series directly to your tree?  I think the
whole series has been reviewed by Shawn.  I'm happy to re-post with
collected tags or anything else you'd like.  It would be nice to get
the regression fixed sooner rather than later...

Thanks!  :)

-Doug


From david.wu at rock-chips.com  Mon Oct 23 18:23:41 2017
From: david.wu at rock-chips.com (David.Wu)
Date: Tue, 24 Oct 2017 09:23:41 +0800
Subject: pinctrl: rockchip: Add iomux-route switching support for rk3288
In-Reply-To: <20171021085310.16246-1-heiko@sntech.de>
References: <20171021085310.16246-1-heiko@sntech.de>
Message-ID: <63f59d2b-01f2-3484-f3cc-fec63d546f11@rock-chips.com>

Hi Heiko,

? 2017/10/21 16:53, Heiko Stuebner ??:
> The rk3288 also has one function that can be routed to one of two pins,
> the hdmi cec functionality can use either gpio7c0 or gpio7c7.
> So add the route switching support for it.
> 
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> Tested-by: Hans Verkuil <hans.verkuil at cisco.com>

Reviewed-by: David Wu <david.wu at rock-chips.com>
Thanks.



From briannorris at chromium.org  Mon Oct 23 18:27:46 2017
From: briannorris at chromium.org (Brian Norris)
Date: Mon, 23 Oct 2017 18:27:46 -0700
Subject: [PATCH v7 3/3] arm64: dts: rockchip: Handle pcie wake in pcie
 driver for Gru
In-Reply-To: <20171019111007.25234-4-jeffy.chen@rock-chips.com>
References: <20171019111007.25234-1-jeffy.chen@rock-chips.com>
 <20171019111007.25234-4-jeffy.chen@rock-chips.com>
Message-ID: <20171024012744.GA103893@google.com>

+ linux-pm

On Thu, Oct 19, 2017 at 07:10:07PM +0800, Jeffy Chen wrote:
> Currently we are handling pcie wake irq in mrvl wifi driver.
> Move it to rockchip pcie driver for Gru boards.

It might be worth documenting one of the reasons for this patch, which
I'll comment on below:

> Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
> ---
> 
> Changes in v7: None
> Changes in v6: None
> Changes in v5:
> Use "wakeup" instead of "wake"
> 
> Changes in v3: None
> Changes in v2: None
> 
>  arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 15 +++++++++------
>  1 file changed, 9 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
> index 470105d651c2..04499714f541 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
> @@ -708,7 +708,15 @@ ap_i2c_audio: &i2c8 {
>  
>  	ep-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
>  	pinctrl-names = "default";
> -	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wifi_perst_l>;
> +	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wlan_host_wake_l>, <&wifi_perst_l>;
> +
> +	interrupts-extended = <&gic GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
> +			      <&gic GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
> +			      <&gic GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>,
> +			      <&gpio0 8 IRQ_TYPE_LEVEL_LOW>;
> +	interrupt-names = "sys", "legacy", "client", "wakeup";
> +	/delete-property/ interrupts;
> +
>  	vpcie3v3-supply = <&pp3300_wifi_bt>;
>  	vpcie1v8-supply = <&wlan_pd_n>; /* HACK: see &wlan_pd_n */
>  	vpcie0v9-supply = <&pp900_pcie>;
> @@ -723,11 +731,6 @@ ap_i2c_audio: &i2c8 {
>  			compatible = "pci1b4b,2b42";
>  			reg = <0x83010000 0x0 0x00000000 0x0 0x00100000
>  			       0x83010000 0x0 0x00100000 0x0 0x00100000>;
> -			interrupt-parent = <&gpio0>;
> -			interrupts = <8 IRQ_TYPE_LEVEL_LOW>;

One of the problems here is that this is a definition for a WAKE#
interrupt, not for a legacy INTx interrupt. So this creates a conflict
when both of these happen:

(a) the PCI bus sets up this interrupt for use as INTx support (as a
    shared interrupt), instead of using the actual PCI controller
    interrupt and
(b) the mwifiex driver requests this interrupt as a non-shared wake
    interrupt, and fails to get it (and so fails to probe).

IOW, non-MSI interrupts are broken today on these devices. Jeffy's patch
fixes that.

If we want to support something like the existing binding, we should
clarify/update
Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt.
Personally, I would just declare that binding invalid for the PCI
version. (It might still be valid for SDIO.)

Also, if for some reason we *do* want WAKE# handling to be supported on
a per-device basis (part of the discussion on patch 1), we should look
at extending the existing PCI interrupt bindings in a way that doesn't
break legacy interrupts.

Brian

> -			pinctrl-names = "default";
> -			pinctrl-0 = <&wlan_host_wake_l>;
> -			wakeup-source;
>  		};
>  	};
>  };
> -- 
> 2.11.0
> 
> 


From jh80.chung at samsung.com  Mon Oct 23 18:41:16 2017
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Tue, 24 Oct 2017 10:41:16 +0900
Subject: [PATCH v2 3/5] mmc: dw_mmc: Add locking to the CTO timer
In-Reply-To: <CAD=FV=XdWD1dk67yixy+5U7RubxKY2WAh-jhZfTOmb4ndf3b5g@mail.gmail.com>
References: <20171012201118.23570-1-dianders@chromium.org>
 <20171012201118.23570-4-dianders@chromium.org>
 <41ae1571-4723-2700-1f03-7215e874c42e@rock-chips.com>
 <CAD=FV=UMuJBKV2-pNo4yiyfxXxYJo_tX6RkxCCzm_UFg9XyjyQ@mail.gmail.com>
 <d6acce96-b292-ee4e-8f9b-1d524c14e0fc@rock-chips.com>
 <CAD=FV=W7u0_kr9HXHpKmw=Hgco2P=u3jeSb8v0OoVvD+2kJorw@mail.gmail.com>
 <CGME20171023181414epcas3p4bfa2214e53fa1f741a36b674c81ebd9c@epcas3p4.samsung.com>
 <CAD=FV=XdWD1dk67yixy+5U7RubxKY2WAh-jhZfTOmb4ndf3b5g@mail.gmail.com>
Message-ID: <fa8cff11-9c22-1751-0dff-414ad902c1e9@samsung.com>

On 10/24/2017 02:59 AM, Doug Anderson wrote:
> Hi,
> 
> On Tue, Oct 17, 2017 at 9:40 AM, Doug Anderson <dianders at chromium.org> wrote:
>> ...
>> ...
>>> Yes, it looks hard to get concurrency right. I have a comment for your
>>> DRTO case(patch 5). Let's do some brainstorm there.
>>
>> Since your comments in this patch are positive and you've now added
>> your Reviewed-by to patch #5, I'm going to assume that you'd also like
>> your Reviewed-by on this patch?
>>
>>
>> Jaehoon: I think I have Shawn's review on all this series.  It would
>> be great if you could review them yourself and/or pick them up in your
>> tree.  Since they fix a regression on 4.14 we really don't want to
>> delay too long.  If you're busy, please yell and we can figure out a
>> way to get these in (either through Ulf directly or we should find
>> someone else to make a git tree and send a pull request).
> 
> Ulf: I still haven't heard anything for Jaehoon.  Do you have any
> interest in landing this series directly to your tree?  I think the
> whole series has been reviewed by Shawn.  I'm happy to re-post with
> collected tags or anything else you'd like.  It would be nice to get
> the regression fixed sooner rather than later...

Sorry. I didn't find this email in my mail-box. so i lost this.
Current i'm reading the comment history..Sorry for late. 

Best Regards,
Jaehoon Chung

> 
> Thanks!  :)
> 
> -Doug
> 
> 
> 



From heiko at sntech.de  Tue Oct 24 06:37:33 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 24 Oct 2017 15:37:33 +0200
Subject: [PATCH v2 4/4] arm64: dts: rockchip: add efuse for RK3368 SoCs
In-Reply-To: <20170904085119.25981-5-romain.perier@collabora.com>
References: <20170904085119.25981-1-romain.perier@collabora.com>
 <20170904085119.25981-5-romain.perier@collabora.com>
Message-ID: <5744497.0PmpLyO0rR@phil>

Am Montag, 4. September 2017, 10:51:19 CEST schrieb Romain Perier:
> This adds the definition for eFuse that is found on RK3368 SoCs with the
> corresponding data cells.
> 
> Signed-off-by: Romain Perier <romain.perier at collabora.com>

applied for 4.15 after the following changes
- moved efuse node to its correct position (determined by register address)
- use correct clock-id as added by patch1 (efuse256 without the underscore)
- added the #address- and #size-cells properties for the subnodes
  to make dtc happy

Please pay a bit more attention for future patches.


Thanks
Heiko


From heiko at sntech.de  Tue Oct 24 07:28:12 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 24 Oct 2017 16:28:12 +0200
Subject: [PATCH v2] drm: bridge: synopsys/dw-hdmi: Enable cec clock
In-Reply-To: <20171020191838.392-1-phh@phh.me>
References: <20171020191838.392-1-phh@phh.me>
Message-ID: <2960167.0GRUE104rh@phil>

Hi Pierre,

Am Freitag, 20. Oktober 2017, 21:18:38 CEST schrieb Pierre-Hugues Husson:
> The documentation already mentions "cec" optional clock, but
> currently the driver doesn't enable it.
> 
> Changes:
> v2:
> - Separate ENOENT errors from others
> - Propagate other errors (especially -EPROBE_DEFER)
> 
> Signed-off-by: Pierre-Hugues Husson <phh at phh.me>
> ---

it looks like you might be missing some important people in your recipient list.
get_maintainer.pl shows me:
- Archit Taneja <architt at codeaurora.org> (maintainer:DRM DRIVERS FOR BRIDGE CHIPS)
- Andrzej Hajda <a.hajda at samsung.com> (maintainer:DRM DRIVERS FOR BRIDGE CHIPS)
- dri-devel at lists.freedesktop.org (open list:DRM DRIVERS)

So these should definitly be included in your recipients, as they're the
ones that will apply your patch :-)

One further nit below.


>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index bf14214fa464..b31fc95d5fef 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -138,6 +138,7 @@ struct dw_hdmi {
>  	struct device *dev;
>  	struct clk *isfr_clk;
>  	struct clk *iahb_clk;
> +	struct clk *cec_clk;
>  	struct dw_hdmi_i2c *i2c;
>  
>  	struct hdmi_data_info hdmi_data;
> @@ -2382,6 +2383,27 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  		goto err_isfr;
>  	}
>  
> +	hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec");
> +	if (PTR_ERR(hdmi->cec_clk) == -ENOENT) {
> +		hdmi->cec_clk = NULL;
> +	} else if (IS_ERR(hdmi->cec_clk)) {
> +		ret = PTR_ERR(hdmi->cec_clk);
> +		if (ret != -EPROBE_DEFER) {
> +			dev_err(hdmi->dev, "Cannot get HDMI cec clock: %d\n",
> +					ret);
> +		}

braces around the single dev_err are not necessary.

Heiko


From nickey.yang at rock-chips.com  Tue Oct 24 20:50:58 2017
From: nickey.yang at rock-chips.com (Nickey Yang)
Date: Wed, 25 Oct 2017 11:50:58 +0800
Subject: [PATCH v3 1/6] drm/rockchip/dsi: Define and use macros for PHY
 register addresses
Message-ID: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>

Replace the hardcoded register address numerical values with macros to
clarify the code.

Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
---
 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 129 ++++++++++++++++++++++-----------
 1 file changed, 85 insertions(+), 44 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index b15755b..95ce253 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -254,6 +254,28 @@
 #define DW_MIPI_NEEDS_PHY_CFG_CLK	BIT(0)
 #define DW_MIPI_NEEDS_GRF_CLK		BIT(1)
 
+#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL	0x10
+#define PLL_CP_CONTROL_PLL_LOCK_BYPASS	0x11
+#define PLL_LPF_AND_CP_CONTROL	0x12
+#define PLL_INPUT_DIVIDER_RATIO	0x17
+#define PLL_LOOP_DIVIDER_RATIO	0x18
+#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL	0x19
+#define BANDGAP_AND_BIAS_CONTROL	0x20
+#define TERMINATION_RESISTER_CONTROL	0x21
+#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY	0x22
+#define HS_RX_CONTROL_OF_LANE_0	0x44
+#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL	0x60
+#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL	0x61
+#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL	0x62
+#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL	0x63
+#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL	0x64
+#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL	0x65
+#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL	0x70
+#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL	0x71
+#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL	0x72
+#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL	0x73
+#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL	0x74
+
 enum {
 	BANDGAP_97_07,
 	BANDGAP_98_05,
@@ -447,53 +469,72 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
 		return ret;
 	}
 
-	dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
-					 VCO_RANGE_CON_SEL(vco) |
-					 VCO_IN_CAP_CON_LOW |
-					 REF_BIAS_CUR_SEL);
-
-	dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
-	dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
-					 LPF_RESISTORS_20_KOHM);
-
-	dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
-
-	dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
-	dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
-					 LOW_PROGRAM_EN);
-	dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
-					 HIGH_PROGRAM_EN);
-	dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
-
-	dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
-					 BIASEXTR_SEL(BIASEXTR_127_7));
-	dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
-					 BANDGAP_SEL(BANDGAP_96_10));
-
-	dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
-					 BIAS_BLOCK_ON | BANDGAP_ON);
-
-	dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
-					 SETRD_MAX | TER_RESISTORS_ON);
-	dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
-					 SETRD_MAX | POWER_MANAGE |
-					 TER_RESISTORS_ON);
-
-	dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
-	dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
-	dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
-	dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
-	dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
-	dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
-
-	dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
-	dw_mipi_dsi_phy_write(dsi, 0x71,
+	dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
+			      BYPASS_VCO_RANGE |
+			      VCO_RANGE_CON_SEL(vco) |
+			      VCO_IN_CAP_CON_LOW |
+			      REF_BIAS_CUR_SEL);
+
+	dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
+			      CP_CURRENT_3MA);
+	dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
+			      CP_PROGRAM_EN | LPF_PROGRAM_EN |
+			      LPF_RESISTORS_20_KOHM);
+
+	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
+			      HSFREQRANGE_SEL(testdin));
+
+	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
+			      INPUT_DIVIDER(dsi->input_div));
+	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
+			      LOOP_DIV_LOW_SEL(dsi->feedback_div) |
+			      LOW_PROGRAM_EN);
+	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
+			      LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
+			      HIGH_PROGRAM_EN);
+	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
+			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
+
+	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
+			      LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
+	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
+			      HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
+
+	dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
+			      POWER_CONTROL | INTERNAL_REG_CURRENT |
+			      BIAS_BLOCK_ON | BANDGAP_ON);
+
+	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
+			      TER_RESISTOR_LOW | TER_CAL_DONE |
+			      SETRD_MAX | TER_RESISTORS_ON);
+	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
+			      TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
+			      SETRD_MAX | POWER_MANAGE |
+			      TER_RESISTORS_ON);
+
+	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
+			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
+	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
+			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
+	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
+			      THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
+	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
+			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
+	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
+			      BIT(5) | ns2bc(dsi, 100));
+	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
+			      BIT(5) | (ns2bc(dsi, 60) + 7));
+
+	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
+			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
+	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
 			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
-	dw_mipi_dsi_phy_write(dsi, 0x72,
+	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
 			      THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
-	dw_mipi_dsi_phy_write(dsi, 0x73,
+	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
 			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
-	dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
+	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
+			      BIT(5) | ns2bc(dsi, 100));
 
 	dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
 				     PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
-- 
1.9.1



From nickey.yang at rock-chips.com  Tue Oct 24 20:50:59 2017
From: nickey.yang at rock-chips.com (Nickey Yang)
Date: Wed, 25 Oct 2017 11:50:59 +0800
Subject: [PATCH v3 2/6] drm/rockchip/dsi: correct phy parameter setting
In-Reply-To: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <1508903463-7254-2-git-send-email-nickey.yang@rock-chips.com>

As MIPI PHY document show, icpctrl<3..0> and lpfctrl<5..0>
should depend on frequency,so fix it.

Reviewed-by: Sean Paul <seanpaul at chromium.org>
Reviewed-by: Matthias Kaehlcke <mka at chromium.org>
Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
---
 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 98 ++++++++++++++++++++++++----------
 1 file changed, 70 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 95ce253..09e7bfe 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -217,10 +217,21 @@
 #define VCO_IN_CAP_CON_HIGH	(0x2 << 1)
 #define REF_BIAS_CUR_SEL	BIT(0)
 
-#define CP_CURRENT_3MA		BIT(3)
+#define CP_CURRENT_1_5UA	0x1
+#define CP_CURRENT_4_5UA	0x2
+#define CP_CURRENT_7_5UA	0x6
+#define CP_CURRENT_6UA	0x9
+#define CP_CURRENT_12UA	0xb
+#define CP_CURRENT_SEL(val)	((val) & 0xf)
 #define CP_PROGRAM_EN		BIT(7)
+
+#define LPF_RESISTORS_15_5KOHM	0x1
+#define LPF_RESISTORS_13KOHM	0x2
+#define LPF_RESISTORS_11_5KOHM	0x4
+#define LPF_RESISTORS_10_5KOHM	0x8
+#define LPF_RESISTORS_8KOHM	0x10
 #define LPF_PROGRAM_EN		BIT(6)
-#define LPF_RESISTORS_20_KOHM	0
+#define LPF_RESISTORS_SEL(val)	((val) & 0x3f)
 
 #define HSFREQRANGE_SEL(val)	(((val) & 0x3f) << 1)
 
@@ -339,32 +350,63 @@ enum dw_mipi_dsi_mode {
 	DW_MIPI_DSI_VID_MODE,
 };
 
-struct dphy_pll_testdin_map {
+struct dphy_pll_parameter_map {
 	unsigned int max_mbps;
-	u8 testdin;
+	u8 hsfreqrange;
+	u8 icpctrl;
+	u8 lpfctrl;
 };
 
 /* The table is based on 27MHz DPHY pll reference clock. */
-static const struct dphy_pll_testdin_map dptdin_map[] = {
-	{  90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
-	{ 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
-	{ 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
-	{ 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
-	{ 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
-	{ 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
-	{ 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
-	{1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
-	{1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
-	{1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
+static const struct dphy_pll_parameter_map dppa_map[] = {
+	{  89, 0x00, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
+	{  99, 0x10, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
+	{ 109, 0x20, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
+	{ 129, 0x01, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+	{ 139, 0x11, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+	{ 149, 0x21, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+	{ 169, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
+	{ 179, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
+	{ 199, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
+	{ 219, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
+	{ 239, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
+	{ 249, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
+	{ 269, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
+	{ 299, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
+	{ 329, 0x05, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+	{ 359, 0x15, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+	{ 399, 0x25, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+	{ 449, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+	{ 499, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+	{ 549, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
+	{ 599, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
+	{ 649, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+	{ 699, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+	{ 749, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+	{ 799, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+	{ 849, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+	{ 899, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+	{ 949, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
+	{ 999, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
+	{1049, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
+	{1099, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
+	{1149, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+	{1199, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+	{1249, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+	{1299, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+	{1349, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+	{1399, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+	{1449, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+	{1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM}
 };
 
-static int max_mbps_to_testdin(unsigned int max_mbps)
+static int max_mbps_to_parameter(unsigned int max_mbps)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
-		if (dptdin_map[i].max_mbps > max_mbps)
-			return dptdin_map[i].testdin;
+	for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
+		if (dppa_map[i].max_mbps >= max_mbps)
+			return i;
 
 	return -EINVAL;
 }
@@ -446,16 +488,16 @@ static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns)
 
 static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
 {
-	int ret, testdin, vco, val;
+	int ret, i, vco, val;
 
 	vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
 
-	testdin = max_mbps_to_testdin(dsi->lane_mbps);
-	if (testdin < 0) {
+	i = max_mbps_to_parameter(dsi->lane_mbps);
+	if (i < 0) {
 		DRM_DEV_ERROR(dsi->dev,
-			      "failed to get testdin for %dmbps lane clock\n",
+			      "failed to get parameter for %dmbps clock\n",
 			      dsi->lane_mbps);
-		return testdin;
+		return i;
 	}
 
 	/* Start by clearing PHY state */
@@ -476,13 +518,13 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
 			      REF_BIAS_CUR_SEL);
 
 	dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
-			      CP_CURRENT_3MA);
+			      CP_CURRENT_SEL(dppa_map[i].icpctrl));
 	dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
 			      CP_PROGRAM_EN | LPF_PROGRAM_EN |
-			      LPF_RESISTORS_20_KOHM);
+			      LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
 
 	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
-			      HSFREQRANGE_SEL(testdin));
+			      HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
 
 	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
 			      INPUT_DIVIDER(dsi->input_div));
@@ -565,7 +607,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
 	unsigned int i, pre;
 	unsigned long mpclk, pllref, tmp;
 	unsigned int m = 1, n = 1, target_mbps = 1000;
-	unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
+	unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
 	int bpp;
 
 	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
-- 
1.9.1



From nickey.yang at rock-chips.com  Tue Oct 24 20:51:00 2017
From: nickey.yang at rock-chips.com (Nickey Yang)
Date: Wed, 25 Oct 2017 11:51:00 +0800
Subject: [PATCH v3 3/6] drm/rockchip/dsi: correct Feedback divider setting
In-Reply-To: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <1508903463-7254-3-git-send-email-nickey.yang@rock-chips.com>

This patch correct Feedback divider setting:
1?Set Feedback divider [8:5] when HIGH_PROGRAM_EN
2?Due to the use of a "by 2 pre-scaler," the range of the
feedback multiplication Feedback divider is limited to even
division numbers, and Feedback divider must be greater than
12, less than 1000.
3?Make the previously configured Feedback divider(LSB)
factors effective

Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
---
 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 93 ++++++++++++++++++++++------------
 1 file changed, 62 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 09e7bfe..589b420 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -239,7 +239,7 @@
 #define LOW_PROGRAM_EN		0
 #define HIGH_PROGRAM_EN		BIT(7)
 #define LOOP_DIV_LOW_SEL(val)	(((val) - 1) & 0x1f)
-#define LOOP_DIV_HIGH_SEL(val)	((((val) - 1) >> 5) & 0x1f)
+#define LOOP_DIV_HIGH_SEL(val)	((((val) - 1) >> 5) & 0xf)
 #define PLL_LOOP_DIV_EN		BIT(5)
 #define PLL_INPUT_DIV_EN	BIT(4)
 
@@ -531,6 +531,14 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
 	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
 			      LOOP_DIV_LOW_SEL(dsi->feedback_div) |
 			      LOW_PROGRAM_EN);
+	/*
+	 * we need set PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL immediately
+	 * to make the configrued LSB effective according to IP simulation
+	 * and lab test results.
+	 * Only in this way can we get correct mipi phy pll frequency.
+	 */
+	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
+			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
 	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
 			      LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
 			      HIGH_PROGRAM_EN);
@@ -604,11 +612,16 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
 static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
 				    struct drm_display_mode *mode)
 {
-	unsigned int i, pre;
-	unsigned long mpclk, pllref, tmp;
-	unsigned int m = 1, n = 1, target_mbps = 1000;
+	unsigned long mpclk, tmp;
+	unsigned int target_mbps = 1000;
 	unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
 	int bpp;
+	unsigned long best_freq = 0;
+	unsigned long fvco_min, fvco_max, fin, fout;
+	unsigned int min_prediv, max_prediv;
+	unsigned int _prediv, uninitialized_var(best_prediv);
+	unsigned long _fbdiv, uninitialized_var(best_fbdiv);
+	unsigned long min_delta = ULONG_MAX;
 
 	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
 	if (bpp < 0) {
@@ -629,35 +642,53 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
 				      "DPHY clock frequency is out of range\n");
 	}
 
-	pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
-	tmp = pllref;
-
-	/*
-	 * The limits on the PLL divisor are:
-	 *
-	 *	5MHz <= (pllref / n) <= 40MHz
-	 *
-	 * we walk over these values in descreasing order so that if we hit
-	 * an exact match for target_mbps it is more likely that "m" will be
-	 * even.
-	 *
-	 * TODO: ensure that "m" is even after this loop.
-	 */
-	for (i = pllref / 5; i > (pllref / 40); i--) {
-		pre = pllref / i;
-		if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
-			tmp = target_mbps % pre;
-			n = i;
-			m = target_mbps / pre;
+	fin = clk_get_rate(dsi->pllref_clk);
+	fout = target_mbps * USEC_PER_SEC;
+
+	/* constraint: 5Mhz <= Fref / N <= 40MHz */
+	min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
+	max_prediv = fin / (5 * USEC_PER_SEC);
+
+	/* constraint: 80MHz <= Fvco <= 1500Mhz */
+	fvco_min = 80 * USEC_PER_SEC;
+	fvco_max = 1500 * USEC_PER_SEC;
+
+	for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
+		u64 tmp;
+		u32 delta;
+		/* Fvco = Fref * M / N */
+		tmp = (u64)fout * _prediv;
+		do_div(tmp, fin);
+		_fbdiv = tmp;
+		/*
+		 * Due to the use of a "by 2 pre-scaler," the range of the
+		 * feedback multiplication value M is limited to even division
+		 * numbers, and m must be greater than 12, less than 1000.
+		 */
+		if (_fbdiv <= 12 || _fbdiv >= 1000)
+			continue;
+
+		_fbdiv += _fbdiv % 2;
+
+		tmp = (u64)_fbdiv * fin;
+		do_div(tmp, _prediv);
+		if (tmp < fvco_min || tmp > fvco_max)
+			continue;
+
+		delta = abs(fout - tmp);
+		if (delta < min_delta) {
+			best_prediv = _prediv;
+			best_fbdiv = _fbdiv;
+			min_delta = delta;
+			best_freq = tmp;
 		}
-		if (tmp == 0)
-			break;
 	}
-
-	dsi->lane_mbps = pllref / n * m;
-	dsi->input_div = n;
-	dsi->feedback_div = m;
-
+	if (best_freq) {
+		dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
+		dsi->input_div = best_prediv;
+		dsi->feedback_div = best_fbdiv;
+	} else
+		DRM_DEV_ERROR(dsi->dev, "Can not find best_freq for DPHY\n");
 	return 0;
 }
 
-- 
1.9.1



From nickey.yang at rock-chips.com  Tue Oct 24 20:51:01 2017
From: nickey.yang at rock-chips.com (Nickey Yang)
Date: Wed, 25 Oct 2017 11:51:01 +0800
Subject: [PATCH v3 4/6] drm/rockchip/dsi: add dual mipi channel support
In-Reply-To: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <1508903463-7254-4-git-send-email-nickey.yang@rock-chips.com>

This patch add dual mipi channel support:
1.add definition of dsi1 register and grf operation.
2.dsi0 and dsi1 will work in master and slave mode
when driving dual mipi panel.

Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
---
 drivers/gpu/drm/rockchip/dw-mipi-dsi.c      | 377 ++++++++++++++++++++--------
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   1 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |   2 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   3 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   1 +
 5 files changed, 279 insertions(+), 105 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 589b420..25e7b77 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -39,8 +39,42 @@
 #define RK3399_DSI1_SEL_VOP_LIT		BIT(4)
 
 /* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
-#define RK3399_GRF_SOC_CON22		0x6258
-#define RK3399_GRF_DSI_MODE		0xffff0000
+#define RK3399_GRF_SOC_CON22			0x6258
+#define DPHY_TX0_TURNREQUEST_ENABLE		(0xf << 12)
+#define DPHY_TX0_TURNREQUEST_SET		(DPHY_TX0_TURNREQUEST_ENABLE << 16)
+#define DPHY_TX0_TURNDISABLE_ENABLE		(0xf << 8)
+#define DPHY_TX0_TURNDISABLE_SET		(DPHY_TX0_TURNDISABLE_ENABLE << 16)
+#define DPHY_TX0_FORCETXSTOPMODE_ENABLE		(0xf << 4)
+#define DPHY_TX0_FORCETXSTOPMODE_SET		(DPHY_TX0_FORCETXSTOPMODE_ENABLE << 16)
+#define DPHY_TX0_FORCETRXMODE_ENABLE		0xf
+#define DPHY_TX0_FORCETRXMODE_SET		(DPHY_TX0_FORCETRXMODE_ENABLE << 16)
+#define RK3399_GRF_DSI_MODE			(DPHY_TX0_TURNREQUEST_SET | \
+						 DPHY_TX0_TURNDISABLE_SET | \
+						 DPHY_TX0_FORCETXSTOPMODE_SET | \
+						 DPHY_TX0_FORCETRXMODE_SET)
+
+
+/* disable turndisable, forcetxstopmode, forcerxmode, enable */
+#define RK3399_GRF_SOC_CON23			0x625c
+#define DPHY_TX1RX1_TURNDISABLE_ENABLE		(0xf << 12)
+#define DPHY_TX1RX1_TURNDISABLE_SET		(DPHY_TX1RX1_TURNDISABLE_ENABLE << 16)
+#define DPHY_TX1RX1_FORCETXSTOPMODE_ENABLE	(0xf << 8)
+#define DPHY_TX1RX1_FORCETXSTOPMODE_SET		(DPHY_TX1RX1_FORCETXSTOPMODE_ENABLE << 16)
+#define DPHY_TX1RX1_FORCERXMODE_ENABLE		(0xf << 4)
+#define DPHY_TX1RX1_FORCERXMODE_SET		(DPHY_TX1RX1_FORCERXMODE_ENABLE << 16)
+#define DPHY_TX1RX1_ENABLE_ENABLE		0xf
+#define DPHY_TX1RX1_ENABLE_SET			(DPHY_TX1RX1_ENABLE_ENABLE << 16)
+#define RK3399_GRF_DSI1_MODE			(DPHY_TX1RX1_TURNDISABLE_SET | \
+						 DPHY_TX1RX1_FORCETXSTOPMODE_SET | \
+						 DPHY_TX1RX1_FORCERXMODE_SET | \
+						 DPHY_TX1RX1_ENABLE_SET)
+#define RK3399_GRF_DSI1_ENABLE			((DPHY_TX1RX1_ENABLE_SET | \
+						  DPHY_TX1RX1_ENABLE_ENABLE))
+
+#define RK3399_GRF_SOC_CON24		0x6260
+#define RK3399_TXRX_MASTERSLAVEZ	BIT(7)
+#define RK3399_TXRX_ENABLECLK		BIT(6)
+#define RK3399_TXRX_BASEDIR		BIT(5)
 
 #define DSI_VERSION			0x00
 #define DSI_PWR_UP			0x04
@@ -315,6 +349,13 @@ struct dw_mipi_dsi_plat_data {
 	u32 grf_switch_reg;
 	u32 grf_dsi0_mode;
 	u32 grf_dsi0_mode_reg;
+	u32 grf_dsi1_mode;
+	u32 grf_dsi1_enable;
+	u32 grf_dsi1_mode_reg1;
+	u32 dsi1_basedir;
+	u32 dsi1_masterslavez;
+	u32 dsi1_enableclk;
+	u32 grf_dsi1_mode_reg2;
 	unsigned int flags;
 	unsigned int max_data_lanes;
 };
@@ -333,6 +374,10 @@ struct dw_mipi_dsi {
 	struct clk *pclk;
 	struct clk *phy_cfg_clk;
 
+	/* dual-channel */
+	struct dw_mipi_dsi *master;
+	struct dw_mipi_dsi *slave;
+
 	int dpms_mode;
 	unsigned int lane_mbps; /* per lane */
 	u32 channel;
@@ -617,6 +662,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
 	unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
 	int bpp;
 	unsigned long best_freq = 0;
+	int lanes = dsi->lanes;
 	unsigned long fvco_min, fvco_max, fin, fout;
 	unsigned int min_prediv, max_prediv;
 	unsigned int _prediv, uninitialized_var(best_prediv);
@@ -631,10 +677,13 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
 		return bpp;
 	}
 
+	if (dsi->slave || dsi->master)
+		lanes = dsi->lanes * 2;
+
 	mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
 	if (mpclk) {
 		/* take 1 / 0.8, since mbps must big than bandwidth of RGB */
-		tmp = mpclk * (bpp / dsi->lanes) * 10 / 8;
+		tmp = mpclk * (bpp / lanes) * 10 / 8;
 		if (tmp < max_mbps)
 			target_mbps = tmp;
 		else
@@ -683,12 +732,14 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
 			best_freq = tmp;
 		}
 	}
+
 	if (best_freq) {
 		dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
 		dsi->input_div = best_prediv;
 		dsi->feedback_div = best_fbdiv;
 	} else
 		DRM_DEV_ERROR(dsi->dev, "Can not find best_freq for DPHY\n");
+
 	return 0;
 }
 
@@ -696,18 +747,25 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 				   struct mipi_dsi_device *device)
 {
 	struct dw_mipi_dsi *dsi = host_to_dsi(host);
+	int lanes = dsi->slave ? device->lanes / 2 : device->lanes;
 
-	if (device->lanes > dsi->pdata->max_data_lanes) {
+	if (lanes > dsi->pdata->max_data_lanes) {
 		DRM_DEV_ERROR(dsi->dev,
 			      "the number of data lanes(%u) is too many\n",
-			      device->lanes);
+			      lanes);
 		return -EINVAL;
 	}
 
-	dsi->lanes = device->lanes;
+	dsi->lanes = lanes;
 	dsi->channel = device->channel;
 	dsi->format = device->format;
 	dsi->mode_flags = device->mode_flags;
+	if (dsi->slave) {
+		dsi->slave->lanes = lanes;
+		dsi->slave->channel = device->channel;
+		dsi->slave->format = device->format;
+		dsi->slave->mode_flags = device->mode_flags;
+	}
 	dsi->panel = of_drm_find_panel(device->dev.of_node);
 	if (dsi->panel)
 		return drm_panel_attach(dsi->panel, &dsi->connector);
@@ -840,15 +898,22 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
 	int ret;
 
 	dw_mipi_message_config(dsi, msg);
+	if (dsi->slave)
+		dw_mipi_message_config(dsi->slave, msg);
 
 	switch (msg->type) {
 	case MIPI_DSI_DCS_SHORT_WRITE:
 	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
 	case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
 		ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
+		if (dsi->slave)
+			ret = dw_mipi_dsi_dcs_short_write(dsi->slave, msg);
 		break;
 	case MIPI_DSI_DCS_LONG_WRITE:
 		ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
+		if (dsi->slave)
+			ret = dw_mipi_dsi_dcs_long_write(dsi->slave, msg);
 		break;
 	default:
 		DRM_DEV_ERROR(dsi->dev, "unsupported message type 0x%02x\n",
@@ -922,6 +987,56 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
 		  TX_ESC_CLK_DIVIDSION(esc_clk_division));
 }
 
+static void rockchip_dsi_grf_config(struct dw_mipi_dsi *dsi, int vop_id)
+{
+	const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
+	int val = 0;
+	int ret;
+
+	/*
+	 * For the RK3399, the clk of grf must be enabled before writing grf
+	 * register. And for RK3288 or other soc, this grf_clk must be NULL,
+	 * the clk_prepare_enable return true directly.
+	 */
+	ret = clk_prepare_enable(dsi->grf_clk);
+	if (ret) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+		return;
+	}
+
+	val = pdata->dsi0_en_bit << 16;
+	if (dsi->slave)
+		val |= pdata->dsi1_en_bit << 16;
+	if (vop_id) {
+		val |= pdata->dsi0_en_bit;
+		if (dsi->slave)
+			val |= pdata->dsi1_en_bit;
+	}
+	regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
+
+	if (pdata->grf_dsi0_mode_reg)
+		regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
+			     pdata->grf_dsi0_mode);
+
+	if (dsi->slave) {
+		if (pdata->grf_dsi1_mode_reg1)
+			regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
+				     pdata->grf_dsi1_mode);
+		if (pdata->grf_dsi1_mode_reg2) {
+			val = pdata->dsi1_masterslavez |
+			      (pdata->dsi1_masterslavez << 16) |
+			      (pdata->dsi1_basedir << 16);
+			regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg2,
+				     val);
+		}
+		if (pdata->grf_dsi1_mode_reg1)
+			regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
+				     pdata->grf_dsi1_enable);
+	}
+
+	clk_disable_unprepare(dsi->grf_clk);
+}
+
 static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
 				   struct drm_display_mode *mode)
 {
@@ -962,7 +1077,14 @@ static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
 static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
 					    struct drm_display_mode *mode)
 {
-	dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
+	int pkt_size;
+
+	if (dsi->slave || dsi->master)
+		pkt_size = VID_PKT_SIZE(mode->hdisplay / 2);
+	else
+		pkt_size = VID_PKT_SIZE(mode->hdisplay);
+
+	dsi_write(dsi, DSI_VID_PKT_SIZE, pkt_size);
 }
 
 static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
@@ -1067,24 +1189,27 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
 	dw_mipi_dsi_disable(dsi);
 	pm_runtime_put(dsi->dev);
 	clk_disable_unprepare(dsi->pclk);
+	if (dsi->slave) {
+		if (clk_prepare_enable(dsi->slave->pclk)) {
+			DRM_DEV_ERROR(dsi->slave->dev,
+				      "Failed to enable pclk\n");
+			return;
+		}
+		dw_mipi_dsi_disable(dsi->slave);
+		pm_runtime_put(dsi->slave->dev);
+		clk_disable_unprepare(dsi->slave->pclk);
+	}
+
 	dsi->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
-static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
+static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi,
+			       struct drm_display_mode *mode)
 {
-	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
-	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
-	const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
-	int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
-	u32 val;
-	int ret;
-
-	ret = dw_mipi_dsi_get_lane_bps(dsi, mode);
-	if (ret < 0)
-		return;
-
-	if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
+	if (dw_mipi_dsi_get_lane_bps(dsi, mode) < 0) {
+		DRM_DEV_ERROR(dsi->dev, "Failed to get lane bps\n");
 		return;
+	}
 
 	if (clk_prepare_enable(dsi->pclk)) {
 		DRM_DEV_ERROR(dsi->dev, "Failed to enable pclk\n");
@@ -1104,44 +1229,43 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
 	dw_mipi_dsi_dphy_interface_config(dsi);
 	dw_mipi_dsi_clear_err(dsi);
 
-	/*
-	 * For the RK3399, the clk of grf must be enabled before writing grf
-	 * register. And for RK3288 or other soc, this grf_clk must be NULL,
-	 * the clk_prepare_enable return true directly.
-	 */
-	ret = clk_prepare_enable(dsi->grf_clk);
-	if (ret) {
-		DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
-		return;
-	}
-
-	if (pdata->grf_dsi0_mode_reg)
-		regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
-			     pdata->grf_dsi0_mode);
-
 	dw_mipi_dsi_phy_init(dsi);
 	dw_mipi_dsi_wait_for_two_frames(mode);
 
 	dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
+}
+
+static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
+	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
+	int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
+
+	if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
+		return;
+
+	rockchip_dsi_grf_config(dsi, mux);
+	DRM_DEV_DEBUG(dsi->dev,
+		      "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
+
+	dw_mipi_dsi_enable(dsi, mode);
+	if (dsi->slave)
+		dw_mipi_dsi_enable(dsi->slave, mode);
+
 	if (drm_panel_prepare(dsi->panel))
 		DRM_DEV_ERROR(dsi->dev, "failed to prepare panel\n");
 
 	dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
+	if (dsi->slave)
+		dw_mipi_dsi_set_mode(dsi->slave, DW_MIPI_DSI_VID_MODE);
+
 	drm_panel_enable(dsi->panel);
 
 	clk_disable_unprepare(dsi->pclk);
+	if (dsi->slave)
+		clk_disable_unprepare(dsi->slave->pclk);
 
-	if (mux)
-		val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
-	else
-		val = pdata->dsi0_en_bit << 16;
-
-	regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
-	DRM_DEV_DEBUG(dsi->dev,
-		      "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
 	dsi->dpms_mode = DRM_MODE_DPMS_ON;
-
-	clk_disable_unprepare(dsi->grf_clk);
 }
 
 static int
@@ -1169,6 +1293,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
 
 	s->output_type = DRM_MODE_CONNECTOR_DSI;
 
+	if (dsi->slave)
+		s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL;
+
 	return 0;
 }
 
@@ -1274,6 +1401,13 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
 	.grf_switch_reg = RK3399_GRF_SOC_CON20,
 	.grf_dsi0_mode = RK3399_GRF_DSI_MODE,
 	.grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
+	.grf_dsi1_mode = RK3399_GRF_DSI1_MODE,
+	.grf_dsi1_enable = RK3399_GRF_DSI1_ENABLE,
+	.grf_dsi1_mode_reg1 = RK3399_GRF_SOC_CON23,
+	.dsi1_basedir = RK3399_TXRX_BASEDIR,
+	.dsi1_masterslavez = RK3399_TXRX_MASTERSLAVEZ,
+	.dsi1_enableclk = RK3399_TXRX_ENABLECLK,
+	.grf_dsi1_mode_reg2 = RK3399_GRF_SOC_CON24,
 	.flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
 	.max_data_lanes = 4,
 };
@@ -1290,17 +1424,106 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
 };
 MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
 
+static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
+{
+	struct device_node *np;
+	struct platform_device *secondary;
+
+	np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
+	if (np) {
+		secondary = of_find_device_by_node(np);
+		dsi->slave = platform_get_drvdata(secondary);
+		of_node_put(np);
+
+		if (!dsi->slave)
+			return -EPROBE_DEFER;
+
+		dsi->slave->master = dsi;
+	}
+
+	return 0;
+}
+
 static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 			    void *data)
 {
+	struct drm_device *drm = data;
+	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
+	int ret;
+
+	ret = rockchip_dsi_dual_channel_probe(dsi);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(dsi->pllref_clk);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_enable(dev);
+
+	if (dsi->master)
+		return 0;
+
+	ret = dw_mipi_dsi_register(drm, dsi);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
+		goto err_pllref;
+	}
+
+	dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
+	dsi->dsi_host.dev = dev;
+	ret = mipi_dsi_host_register(&dsi->dsi_host);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
+		goto err_cleanup;
+	}
+
+	if (!dsi->panel) {
+		ret = -EPROBE_DEFER;
+		goto err_mipi_dsi_host;
+	}
+
+	return 0;
+
+err_mipi_dsi_host:
+	mipi_dsi_host_unregister(&dsi->dsi_host);
+err_cleanup:
+	drm_encoder_cleanup(&dsi->encoder);
+	drm_connector_cleanup(&dsi->connector);
+err_pllref:
+	pm_runtime_disable(dev);
+	clk_disable_unprepare(dsi->pllref_clk);
+	return ret;
+}
+
+static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
+			       void *data)
+{
+	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
+
+	mipi_dsi_host_unregister(&dsi->dsi_host);
+	pm_runtime_disable(dev);
+	if (dsi->slave)
+		pm_runtime_disable(dsi->slave->dev);
+	clk_disable_unprepare(dsi->pllref_clk);
+}
+
+static const struct component_ops dw_mipi_dsi_ops = {
+	.bind	= dw_mipi_dsi_bind,
+	.unbind	= dw_mipi_dsi_unbind,
+};
+
+static int dw_mipi_dsi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
 	const struct of_device_id *of_id =
 			of_match_device(dw_mipi_dsi_dt_ids, dev);
 	const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
-	struct platform_device *pdev = to_platform_device(dev);
-	struct reset_control *apb_rst;
-	struct drm_device *drm = data;
 	struct dw_mipi_dsi *dsi;
 	struct resource *res;
+	struct reset_control *apb_rst;
 	int ret;
 
 	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
@@ -1310,6 +1533,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	dsi->dev = dev;
 	dsi->pdata = pdata;
 	dsi->dpms_mode = DRM_MODE_DPMS_OFF;
+	dev_set_drvdata(dev, dsi);
 
 	ret = rockchip_mipi_parse_dt(dsi);
 	if (ret)
@@ -1387,63 +1611,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 		}
 	}
 
-	ret = clk_prepare_enable(dsi->pllref_clk);
-	if (ret) {
-		DRM_DEV_ERROR(dev, "Failed to enable pllref_clk\n");
-		return ret;
-	}
-
-	ret = dw_mipi_dsi_register(drm, dsi);
-	if (ret) {
-		DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
-		goto err_pllref;
-	}
-
-	pm_runtime_enable(dev);
-
-	dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
-	dsi->dsi_host.dev = dev;
-	ret = mipi_dsi_host_register(&dsi->dsi_host);
-	if (ret) {
-		DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
-		goto err_cleanup;
-	}
-
-	if (!dsi->panel) {
-		ret = -EPROBE_DEFER;
-		goto err_mipi_dsi_host;
-	}
-
-	dev_set_drvdata(dev, dsi);
-	return 0;
-
-err_mipi_dsi_host:
-	mipi_dsi_host_unregister(&dsi->dsi_host);
-err_cleanup:
-	drm_encoder_cleanup(&dsi->encoder);
-	drm_connector_cleanup(&dsi->connector);
-err_pllref:
-	clk_disable_unprepare(dsi->pllref_clk);
-	return ret;
-}
-
-static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
-			       void *data)
-{
-	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
-
-	mipi_dsi_host_unregister(&dsi->dsi_host);
-	pm_runtime_disable(dev);
-	clk_disable_unprepare(dsi->pllref_clk);
-}
-
-static const struct component_ops dw_mipi_dsi_ops = {
-	.bind	= dw_mipi_dsi_bind,
-	.unbind	= dw_mipi_dsi_unbind,
-};
-
-static int dw_mipi_dsi_probe(struct platform_device *pdev)
-{
 	return component_add(&pdev->dev, &dw_mipi_dsi_ops);
 }
 
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 498dfbc..f20fba2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -36,6 +36,7 @@ struct rockchip_crtc_state {
 	struct drm_crtc_state base;
 	int output_type;
 	int output_mode;
+	int output_flags;
 };
 #define to_rockchip_crtc_state(s) \
 		container_of(s, struct rockchip_crtc_state, base)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 19128b4..bb98bfc 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -918,6 +918,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
 	case DRM_MODE_CONNECTOR_DSI:
 		VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
 		VOP_REG_SET(vop, output, mipi_en, 1);
+		VOP_REG_SET(vop, output, mipi_dual_channel_en,
+			!!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL));
 		break;
 	case DRM_MODE_CONNECTOR_DisplayPort:
 		pin_pol &= ~BIT(DCLK_INVERT);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 56bbd2e..d184531 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -60,6 +60,7 @@ struct vop_output {
 	struct vop_reg edp_en;
 	struct vop_reg hdmi_en;
 	struct vop_reg mipi_en;
+	struct vop_reg mipi_dual_channel_en;
 	struct vop_reg rgb_en;
 };
 
@@ -212,6 +213,8 @@ struct vop_data {
 /* for use special outface */
 #define ROCKCHIP_OUT_MODE_AAAA	15
 
+#define ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL	BIT(0)
+
 enum alpha_mode {
 	ALPHA_STRAIGHT,
 	ALPHA_INVERSE,
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 4a39049..1e0c07b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -392,6 +392,7 @@
 	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
 	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
 	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
+	.mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
 };
 
 static const struct vop_data rk3399_vop_big = {
-- 
1.9.1



From nickey.yang at rock-chips.com  Tue Oct 24 20:51:02 2017
From: nickey.yang at rock-chips.com (Nickey Yang)
Date: Wed, 25 Oct 2017 11:51:02 +0800
Subject: [PATCH v3 5/6] dt-bindings: add the rockchip,
 dual-channel for dw-mipi-dsi
In-Reply-To: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <1508903463-7254-5-git-send-email-nickey.yang@rock-chips.com>

Configure dsi slave channel when driving a panel
which needs 2 DSI links.

Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
---
 .../devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt       | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
index 6bb59ab..a2bea22 100644
--- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
@@ -19,6 +19,8 @@ Optional properties:
 - power-domains: a phandle to mipi dsi power domain node.
 - resets: list of phandle + reset specifier pairs, as described in [3].
 - reset-names: string reset name, must be "apb".
+- rockchip,dual-channel: phandle to a 2nd DSI channel, useful as a slave
+channel when driving a panel which needs 2 DSI links.
 
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 [2] Documentation/devicetree/bindings/media/video-interfaces.txt
-- 
1.9.1



From nickey.yang at rock-chips.com  Tue Oct 24 20:51:03 2017
From: nickey.yang at rock-chips.com (Nickey Yang)
Date: Wed, 25 Oct 2017 11:51:03 +0800
Subject: [PATCH v3 6/6] arm64: dts: rockchip: add mipi_dsi1 support for rk3399
In-Reply-To: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <1508903463-7254-6-git-send-email-nickey.yang@rock-chips.com>

This patch adds the mipi_dsi1 related needed information.
e.g.: interrupts, grf, clocks, ports and so on.

Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 39 ++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index a65f7f7..48e2695 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1515,6 +1515,11 @@
 				reg = <2>;
 				remote-endpoint = <&hdmi_in_vopl>;
 			};
+
+			vopl_out_mipi1: endpoint at 3 {
+				reg = <3>;
+				remote-endpoint = <&mipi1_in_vopl>;
+			};
 		};
 	};
 
@@ -1562,6 +1567,11 @@
 				reg = <2>;
 				remote-endpoint = <&hdmi_in_vopb>;
 			};
+
+			vopb_out_mipi1: endpoint at 3 {
+				reg = <3>;
+				remote-endpoint = <&mipi1_in_vopb>;
+			};
 		};
 	};
 
@@ -1657,6 +1667,35 @@
 		};
 	};
 
+	mipi_dsi1: mipi at ff968000 {
+		compatible = "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi";
+		reg = <0x0 0xff968000 0x0 0x8000>;
+		interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH 0>;
+		clocks = <&cru SCLK_DPHY_PLL>, <&cru PCLK_MIPI_DSI1>,
+			 <&cru SCLK_DPHY_TX1RX1_CFG>, <&cru PCLK_VIO_GRF>;
+		clock-names = "ref", "pclk", "phy_cfg", "grf";
+		power-domains = <&power RK3399_PD_VIO>;
+		rockchip,grf = <&grf>;
+		status = "disabled";
+
+		ports {
+			mipi1_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mipi1_in_vopb: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&vopb_out_mipi1>;
+				};
+
+				mipi1_in_vopl: endpoint at 1 {
+					reg = <1>;
+					remote-endpoint = <&vopl_out_mipi1>;
+				};
+			};
+		};
+	};
+
 	edp: edp at ff970000 {
 		compatible = "rockchip,rk3399-edp";
 		reg = <0x0 0xff970000 0x0 0x8000>;
-- 
1.9.1



From seanpaul at chromium.org  Wed Oct 25 00:47:49 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Wed, 25 Oct 2017 03:47:49 -0400
Subject: [PATCH v3 1/6] drm/rockchip/dsi: Define and use macros for PHY
 register addresses
In-Reply-To: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <20171025074749.vzhutgc2infhq3ga@art_vandelay>

On Wed, Oct 25, 2017 at 11:50:58AM +0800, Nickey Yang wrote:
> Replace the hardcoded register address numerical values with macros to
> clarify the code.
> 
> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>

Reviewed-by: Sean Paul <seanpaul at chromium.org>

> ---
>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 129 ++++++++++++++++++++++-----------
>  1 file changed, 85 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index b15755b..95ce253 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -254,6 +254,28 @@
>  #define DW_MIPI_NEEDS_PHY_CFG_CLK	BIT(0)
>  #define DW_MIPI_NEEDS_GRF_CLK		BIT(1)
>  
> +#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL	0x10
> +#define PLL_CP_CONTROL_PLL_LOCK_BYPASS	0x11
> +#define PLL_LPF_AND_CP_CONTROL	0x12
> +#define PLL_INPUT_DIVIDER_RATIO	0x17
> +#define PLL_LOOP_DIVIDER_RATIO	0x18
> +#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL	0x19
> +#define BANDGAP_AND_BIAS_CONTROL	0x20
> +#define TERMINATION_RESISTER_CONTROL	0x21
> +#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY	0x22
> +#define HS_RX_CONTROL_OF_LANE_0	0x44
> +#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL	0x60
> +#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL	0x61
> +#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL	0x62
> +#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL	0x63
> +#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL	0x64
> +#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL	0x65
> +#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL	0x70
> +#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL	0x71
> +#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL	0x72
> +#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL	0x73
> +#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL	0x74
> +
>  enum {
>  	BANDGAP_97_07,
>  	BANDGAP_98_05,
> @@ -447,53 +469,72 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>  		return ret;
>  	}
>  
> -	dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
> -					 VCO_RANGE_CON_SEL(vco) |
> -					 VCO_IN_CAP_CON_LOW |
> -					 REF_BIAS_CUR_SEL);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
> -	dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
> -					 LPF_RESISTORS_20_KOHM);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
> -	dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> -					 LOW_PROGRAM_EN);
> -	dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> -					 HIGH_PROGRAM_EN);
> -	dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
> -					 BIASEXTR_SEL(BIASEXTR_127_7));
> -	dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
> -					 BANDGAP_SEL(BANDGAP_96_10));
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
> -					 BIAS_BLOCK_ON | BANDGAP_ON);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
> -					 SETRD_MAX | TER_RESISTORS_ON);
> -	dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> -					 SETRD_MAX | POWER_MANAGE |
> -					 TER_RESISTORS_ON);
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> -	dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> -	dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> -	dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> -	dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
> -	dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
> -
> -	dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> -	dw_mipi_dsi_phy_write(dsi, 0x71,
> +	dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
> +			      BYPASS_VCO_RANGE |
> +			      VCO_RANGE_CON_SEL(vco) |
> +			      VCO_IN_CAP_CON_LOW |
> +			      REF_BIAS_CUR_SEL);
> +
> +	dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> +			      CP_CURRENT_3MA);
> +	dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
> +			      CP_PROGRAM_EN | LPF_PROGRAM_EN |
> +			      LPF_RESISTORS_20_KOHM);
> +
> +	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> +			      HSFREQRANGE_SEL(testdin));
> +
> +	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
> +			      INPUT_DIVIDER(dsi->input_div));
> +	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> +			      LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> +			      LOW_PROGRAM_EN);
> +	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> +			      LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> +			      HIGH_PROGRAM_EN);
> +	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> +			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> +
> +	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> +			      LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
> +	dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> +			      HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
> +
> +	dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
> +			      POWER_CONTROL | INTERNAL_REG_CURRENT |
> +			      BIAS_BLOCK_ON | BANDGAP_ON);
> +
> +	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> +			      TER_RESISTOR_LOW | TER_CAL_DONE |
> +			      SETRD_MAX | TER_RESISTORS_ON);
> +	dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> +			      TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> +			      SETRD_MAX | POWER_MANAGE |
> +			      TER_RESISTORS_ON);
> +
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
> +			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
> +			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
> +			      THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
> +			      THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
> +			      BIT(5) | ns2bc(dsi, 100));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
> +			      BIT(5) | (ns2bc(dsi, 60) + 7));
> +
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
> +			      TLP_PROGRAM_EN | ns2bc(dsi, 500));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
>  			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
> -	dw_mipi_dsi_phy_write(dsi, 0x72,
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
>  			      THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
> -	dw_mipi_dsi_phy_write(dsi, 0x73,
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
>  			      THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
> -	dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
> +	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
> +			      BIT(5) | ns2bc(dsi, 100));
>  
>  	dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
>  				     PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
> -- 
> 1.9.1
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Wed Oct 25 00:49:39 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Wed, 25 Oct 2017 03:49:39 -0400
Subject: [PATCH v3 2/6] drm/rockchip/dsi: correct phy parameter setting
In-Reply-To: <1508903463-7254-2-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
 <1508903463-7254-2-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <20171025074939.4erys47vx6hoe2ms@art_vandelay>

On Wed, Oct 25, 2017 at 11:50:59AM +0800, Nickey Yang wrote:
> As MIPI PHY document show, icpctrl<3..0> and lpfctrl<5..0>
> should depend on frequency,so fix it.
> 
> Reviewed-by: Sean Paul <seanpaul at chromium.org>
> Reviewed-by: Matthias Kaehlcke <mka at chromium.org>
> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
> ---

In future, please list the differences between versions. It makes reviewing much
easier.

Thanks,

Sean

>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 98 ++++++++++++++++++++++++----------
>  1 file changed, 70 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 95ce253..09e7bfe 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -217,10 +217,21 @@
>  #define VCO_IN_CAP_CON_HIGH	(0x2 << 1)
>  #define REF_BIAS_CUR_SEL	BIT(0)
>  
> -#define CP_CURRENT_3MA		BIT(3)
> +#define CP_CURRENT_1_5UA	0x1
> +#define CP_CURRENT_4_5UA	0x2
> +#define CP_CURRENT_7_5UA	0x6
> +#define CP_CURRENT_6UA	0x9
> +#define CP_CURRENT_12UA	0xb
> +#define CP_CURRENT_SEL(val)	((val) & 0xf)
>  #define CP_PROGRAM_EN		BIT(7)
> +
> +#define LPF_RESISTORS_15_5KOHM	0x1
> +#define LPF_RESISTORS_13KOHM	0x2
> +#define LPF_RESISTORS_11_5KOHM	0x4
> +#define LPF_RESISTORS_10_5KOHM	0x8
> +#define LPF_RESISTORS_8KOHM	0x10
>  #define LPF_PROGRAM_EN		BIT(6)
> -#define LPF_RESISTORS_20_KOHM	0
> +#define LPF_RESISTORS_SEL(val)	((val) & 0x3f)
>  
>  #define HSFREQRANGE_SEL(val)	(((val) & 0x3f) << 1)
>  
> @@ -339,32 +350,63 @@ enum dw_mipi_dsi_mode {
>  	DW_MIPI_DSI_VID_MODE,
>  };
>  
> -struct dphy_pll_testdin_map {
> +struct dphy_pll_parameter_map {
>  	unsigned int max_mbps;
> -	u8 testdin;
> +	u8 hsfreqrange;
> +	u8 icpctrl;
> +	u8 lpfctrl;
>  };
>  
>  /* The table is based on 27MHz DPHY pll reference clock. */
> -static const struct dphy_pll_testdin_map dptdin_map[] = {
> -	{  90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
> -	{ 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
> -	{ 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
> -	{ 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
> -	{ 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
> -	{ 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
> -	{ 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
> -	{1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
> -	{1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
> -	{1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
> +static const struct dphy_pll_parameter_map dppa_map[] = {
> +	{  89, 0x00, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> +	{  99, 0x10, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> +	{ 109, 0x20, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> +	{ 129, 0x01, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 139, 0x11, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 149, 0x21, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 169, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> +	{ 179, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> +	{ 199, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> +	{ 219, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> +	{ 239, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> +	{ 249, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> +	{ 269, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
> +	{ 299, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
> +	{ 329, 0x05, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 359, 0x15, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 399, 0x25, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> +	{ 449, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 499, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 549, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
> +	{ 599, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
> +	{ 649, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 699, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 749, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 799, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 849, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 899, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> +	{ 949, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> +	{ 999, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> +	{1049, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> +	{1099, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> +	{1149, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1199, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1249, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1299, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1349, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1399, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1449, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> +	{1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM}
>  };
>  
> -static int max_mbps_to_testdin(unsigned int max_mbps)
> +static int max_mbps_to_parameter(unsigned int max_mbps)
>  {
>  	int i;
>  
> -	for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
> -		if (dptdin_map[i].max_mbps > max_mbps)
> -			return dptdin_map[i].testdin;
> +	for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
> +		if (dppa_map[i].max_mbps >= max_mbps)
> +			return i;
>  
>  	return -EINVAL;
>  }
> @@ -446,16 +488,16 @@ static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns)
>  
>  static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>  {
> -	int ret, testdin, vco, val;
> +	int ret, i, vco, val;
>  
>  	vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
>  
> -	testdin = max_mbps_to_testdin(dsi->lane_mbps);
> -	if (testdin < 0) {
> +	i = max_mbps_to_parameter(dsi->lane_mbps);
> +	if (i < 0) {
>  		DRM_DEV_ERROR(dsi->dev,
> -			      "failed to get testdin for %dmbps lane clock\n",
> +			      "failed to get parameter for %dmbps clock\n",
>  			      dsi->lane_mbps);
> -		return testdin;
> +		return i;
>  	}
>  
>  	/* Start by clearing PHY state */
> @@ -476,13 +518,13 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>  			      REF_BIAS_CUR_SEL);
>  
>  	dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> -			      CP_CURRENT_3MA);
> +			      CP_CURRENT_SEL(dppa_map[i].icpctrl));
>  	dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
>  			      CP_PROGRAM_EN | LPF_PROGRAM_EN |
> -			      LPF_RESISTORS_20_KOHM);
> +			      LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
>  
>  	dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> -			      HSFREQRANGE_SEL(testdin));
> +			      HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
>  
>  	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
>  			      INPUT_DIVIDER(dsi->input_div));
> @@ -565,7 +607,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>  	unsigned int i, pre;
>  	unsigned long mpclk, pllref, tmp;
>  	unsigned int m = 1, n = 1, target_mbps = 1000;
> -	unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> +	unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
>  	int bpp;
>  
>  	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> -- 
> 1.9.1
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Wed Oct 25 00:57:19 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Wed, 25 Oct 2017 03:57:19 -0400
Subject: [PATCH v3 3/6] drm/rockchip/dsi: correct Feedback divider setting
In-Reply-To: <1508903463-7254-3-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
 <1508903463-7254-3-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <20171025075719.4tt7lomec5x7guon@art_vandelay>

On Wed, Oct 25, 2017 at 11:51:00AM +0800, Nickey Yang wrote:
> This patch correct Feedback divider setting:
> 1?Set Feedback divider [8:5] when HIGH_PROGRAM_EN
> 2?Due to the use of a "by 2 pre-scaler," the range of the
> feedback multiplication Feedback divider is limited to even
> division numbers, and Feedback divider must be greater than
> 12, less than 1000.
> 3?Make the previously configured Feedback divider(LSB)
> factors effective
> 
> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
> ---

You don't list the changes between this version and the previous ones, so I looked
at the feedback from the last time. Archit asked a question about moving to
dw-mipi-dsi, and Kristian asked you to split the patch for each line item in the
above list. I know you split out the register definitions, but an explanation
about why you didn't split the rest would be helpful.

In future, list the changes between patches and Cc people who have given you
review on your previous versions (I've cc'd Archit and Kristian).

Sean


>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 93 ++++++++++++++++++++++------------
>  1 file changed, 62 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 09e7bfe..589b420 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -239,7 +239,7 @@
>  #define LOW_PROGRAM_EN		0
>  #define HIGH_PROGRAM_EN		BIT(7)
>  #define LOOP_DIV_LOW_SEL(val)	(((val) - 1) & 0x1f)
> -#define LOOP_DIV_HIGH_SEL(val)	((((val) - 1) >> 5) & 0x1f)
> +#define LOOP_DIV_HIGH_SEL(val)	((((val) - 1) >> 5) & 0xf)
>  #define PLL_LOOP_DIV_EN		BIT(5)
>  #define PLL_INPUT_DIV_EN	BIT(4)
>  
> @@ -531,6 +531,14 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>  	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
>  			      LOOP_DIV_LOW_SEL(dsi->feedback_div) |
>  			      LOW_PROGRAM_EN);
> +	/*
> +	 * we need set PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL immediately
> +	 * to make the configrued LSB effective according to IP simulation
> +	 * and lab test results.
> +	 * Only in this way can we get correct mipi phy pll frequency.
> +	 */
> +	dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> +			      PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
>  	dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
>  			      LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
>  			      HIGH_PROGRAM_EN);
> @@ -604,11 +612,16 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
>  static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>  				    struct drm_display_mode *mode)
>  {
> -	unsigned int i, pre;
> -	unsigned long mpclk, pllref, tmp;
> -	unsigned int m = 1, n = 1, target_mbps = 1000;
> +	unsigned long mpclk, tmp;
> +	unsigned int target_mbps = 1000;
>  	unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
>  	int bpp;
> +	unsigned long best_freq = 0;
> +	unsigned long fvco_min, fvco_max, fin, fout;
> +	unsigned int min_prediv, max_prediv;
> +	unsigned int _prediv, uninitialized_var(best_prediv);
> +	unsigned long _fbdiv, uninitialized_var(best_fbdiv);
> +	unsigned long min_delta = ULONG_MAX;
>  
>  	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
>  	if (bpp < 0) {
> @@ -629,35 +642,53 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
>  				      "DPHY clock frequency is out of range\n");
>  	}
>  
> -	pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
> -	tmp = pllref;
> -
> -	/*
> -	 * The limits on the PLL divisor are:
> -	 *
> -	 *	5MHz <= (pllref / n) <= 40MHz
> -	 *
> -	 * we walk over these values in descreasing order so that if we hit
> -	 * an exact match for target_mbps it is more likely that "m" will be
> -	 * even.
> -	 *
> -	 * TODO: ensure that "m" is even after this loop.
> -	 */
> -	for (i = pllref / 5; i > (pllref / 40); i--) {
> -		pre = pllref / i;
> -		if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
> -			tmp = target_mbps % pre;
> -			n = i;
> -			m = target_mbps / pre;
> +	fin = clk_get_rate(dsi->pllref_clk);
> +	fout = target_mbps * USEC_PER_SEC;
> +
> +	/* constraint: 5Mhz <= Fref / N <= 40MHz */
> +	min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
> +	max_prediv = fin / (5 * USEC_PER_SEC);
> +
> +	/* constraint: 80MHz <= Fvco <= 1500Mhz */
> +	fvco_min = 80 * USEC_PER_SEC;
> +	fvco_max = 1500 * USEC_PER_SEC;
> +
> +	for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
> +		u64 tmp;
> +		u32 delta;
> +		/* Fvco = Fref * M / N */
> +		tmp = (u64)fout * _prediv;
> +		do_div(tmp, fin);
> +		_fbdiv = tmp;
> +		/*
> +		 * Due to the use of a "by 2 pre-scaler," the range of the
> +		 * feedback multiplication value M is limited to even division
> +		 * numbers, and m must be greater than 12, less than 1000.
> +		 */
> +		if (_fbdiv <= 12 || _fbdiv >= 1000)
> +			continue;
> +
> +		_fbdiv += _fbdiv % 2;
> +
> +		tmp = (u64)_fbdiv * fin;
> +		do_div(tmp, _prediv);
> +		if (tmp < fvco_min || tmp > fvco_max)
> +			continue;
> +
> +		delta = abs(fout - tmp);
> +		if (delta < min_delta) {
> +			best_prediv = _prediv;
> +			best_fbdiv = _fbdiv;
> +			min_delta = delta;
> +			best_freq = tmp;
>  		}
> -		if (tmp == 0)
> -			break;
>  	}
> -
> -	dsi->lane_mbps = pllref / n * m;
> -	dsi->input_div = n;
> -	dsi->feedback_div = m;
> -
> +	if (best_freq) {
> +		dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
> +		dsi->input_div = best_prediv;
> +		dsi->feedback_div = best_fbdiv;
> +	} else
> +		DRM_DEV_ERROR(dsi->dev, "Can not find best_freq for DPHY\n");
>  	return 0;
>  }
>  
> -- 
> 1.9.1
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From seanpaul at chromium.org  Wed Oct 25 01:04:48 2017
From: seanpaul at chromium.org (Sean Paul)
Date: Wed, 25 Oct 2017 04:04:48 -0400
Subject: [PATCH v3 4/6] drm/rockchip/dsi: add dual mipi channel support
In-Reply-To: <1508903463-7254-4-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
 <1508903463-7254-4-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <20171025080448.pa465q5jofxhqdn4@art_vandelay>

On Wed, Oct 25, 2017 at 11:51:01AM +0800, Nickey Yang wrote:
> This patch add dual mipi channel support:
> 1.add definition of dsi1 register and grf operation.
> 2.dsi0 and dsi1 will work in master and slave mode
> when driving dual mipi panel.
> 
> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
> ---

In the last revision, I asked you to provide changelog between revisions,
*please* do this. You received review on the last version and a bunch of the
feedback hasn't been taken into account with no explanation as to why. Please go
back to the last version, read the reviews that people were generous enough to
give and either fix the code or explain why you're not.

>  drivers/gpu/drm/rockchip/dw-mipi-dsi.c      | 377 ++++++++++++++++++++--------
>  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   1 +
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.c |   2 +
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   3 +
>  drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   1 +
>  5 files changed, 279 insertions(+), 105 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 589b420..25e7b77 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c

<snip />

> +static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
> +{
> +	struct device_node *np;
> +	struct platform_device *secondary;
> +
> +	np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
> +	if (np) {
> +		secondary = of_find_device_by_node(np);
> +		dsi->slave = platform_get_drvdata(secondary);
> +		of_node_put(np);
> +
> +		if (!dsi->slave)
> +			return -EPROBE_DEFER;

Archit asked you not to do this in the previous review.

> +
> +		dsi->slave->master = dsi;
> +	}
> +
> +	return 0;
> +}

<snip />

> -- 
> 1.9.1
> 

-- 
Sean Paul, Software Engineer, Google / Chromium OS


From dianders at chromium.org  Wed Oct 25 14:08:57 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Wed, 25 Oct 2017 14:08:57 -0700
Subject: [PATCH] usb: dwc2: host: Don't retry NAKed transactions right away
Message-ID: <20171025210857.13443-1-dianders@chromium.org>

On rk3288-veyron devices on Chrome OS it was found that plugging in an
Arduino-based USB device could cause the system to lockup, especially
if the CPU Frequency was at one of the slower operating points (like
100 MHz / 200 MHz).

Upon tracing, I found that the following was happening:
* The USB device (full speed) was connected to a high speed hub and
  then to the rk3288.  Thus, we were dealing with split transactions,
  which is all handled in software on dwc2.
* Userspace was initiating a BULK IN transfer
* When we sent the SSPLIT (to start the split transaction), we got an
  ACK.  Good.  Then we issued the CSPLIT.
* When we sent the CSPLIT, we got back a NAK.  We immediately (from
  the interrupt handler) started to retry and sent another SSPLIT.
* The device kept NAKing our CSPLIT, so we kept ping-ponging between
  sending a SSPLIT and a CSPLIT, each time sending from the interrupt
  handler.
* The handling of the interrupts was (because of the low CPU speed and
  the inefficiency of the dwc2 interrupt handler) was actually taking
  _longer_ than it took the other side to send the ACK/NAK.  Thus we
  were _always_ in the USB interrupt routine.
* The fact that USB interrupts were always going off was preventing
  other things from happening in the system.  This included preventing
  the system from being able to transition to a higher CPU frequency.

As I understand it, there is no requirement to retry super quickly
after a NAK, we just have to retry sometime in the future.  Thus one
solution to the above is to just add a delay between getting a NAK and
retrying the transmission.  If this delay is sufficiently long to get
out of the interrupt routine then the rest of the system will be able
to make forward progress.  Even a 25 us delay would probably be
enough, but we'll be extra conservative and try to delay 1 ms (the
exact amount depends on HZ and the accuracy of the jiffy and how close
the current jiffy is to ticking, but could be as much as 20 ms or as
little as 1 ms).

Presumably adding a delay like this could impact the USB throughput,
so we only add the delay with repeated NAKs.

NOTE: Upon further testing of a pl2303 serial adapter, I found that
this fix may help with problems there.  Specifically I found that the
pl2303 serial adapters tend to respond with a NAK when they have
nothing to say and thus we end with this same sequence.

Signed-off-by: Douglas Anderson <dianders at chromium.org>
---

 drivers/usb/dwc2/core.h      |  1 +
 drivers/usb/dwc2/hcd.c       |  7 ++++
 drivers/usb/dwc2/hcd.h       |  9 +++++
 drivers/usb/dwc2/hcd_intr.c  | 12 +++++++
 drivers/usb/dwc2/hcd_queue.c | 81 +++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 106 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 8367d4f985c1..c0807e558726 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -962,6 +962,7 @@ struct dwc2_hsotg {
 	} flags;
 
 	struct list_head non_periodic_sched_inactive;
+	struct list_head non_periodic_sched_waiting;
 	struct list_head non_periodic_sched_active;
 	struct list_head *non_periodic_qh_ptr;
 	struct list_head periodic_sched_inactive;
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index c2631145f404..ed92ae78dcf9 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -653,6 +653,10 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
 	list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
 			    qh_list_entry)
 		dev_dbg(hsotg->dev, "    %p\n", qh);
+	dev_dbg(hsotg->dev, "  NP waiting sched:\n");
+	list_for_each_entry(qh, &hsotg->non_periodic_sched_waiting,
+			    qh_list_entry)
+		dev_dbg(hsotg->dev, "    %p\n", qh);
 	dev_dbg(hsotg->dev, "  NP active sched:\n");
 	list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
 			    qh_list_entry)
@@ -1812,6 +1816,7 @@ static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
 static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
 {
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
+	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_waiting);
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
@@ -4989,6 +4994,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
 
 	/* Free memory for QH/QTD lists */
 	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
+	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_waiting);
 	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
 	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
 	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
@@ -5151,6 +5157,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
 
 	/* Initialize the non-periodic schedule */
 	INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
+	INIT_LIST_HEAD(&hsotg->non_periodic_sched_waiting);
 	INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
 
 	/* Initialize the periodic schedule */
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index 11c3c145b793..aad6c22252d5 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -313,6 +313,10 @@ struct dwc2_hs_transfer_time {
  *                      descriptor and indicates original XferSize value for the
  *                      descriptor
  * @unreserve_timer:    Timer for releasing periodic reservation.
+ * @wait_timer:         Timer used to wait before re-queuing.
+ * @want_wait:          We should wait before re-queuing; only matters for non-
+ *                      periodic transfers and is ignored for periodic ones.
+ * @wait_timer_cancel:  Set to true to cancel the wait_timer.
  * @dwc2_tt:            Pointer to our tt info (or NULL if no tt).
  * @ttport:             Port number within our tt.
  * @tt_buffer_dirty     True if clear_tt_buffer_complete is pending
@@ -353,6 +357,9 @@ struct dwc2_qh {
 	u32 desc_list_sz;
 	u32 *n_bytes;
 	struct timer_list unreserve_timer;
+	struct timer_list wait_timer;
+	bool want_wait;
+	bool wait_timer_cancel;
 	struct dwc2_tt *dwc_tt;
 	int ttport;
 	unsigned tt_buffer_dirty:1;
@@ -388,6 +395,7 @@ struct dwc2_qh {
  * @n_desc:             Number of DMA descriptors for this QTD
  * @isoc_frame_index_last: Last activated frame (packet) index, used in
  *                      descriptor DMA mode only
+ * @num_naks:           Number of NAKs received on this QTD.
  * @urb:                URB for this transfer
  * @qh:                 Queue head for this QTD
  * @qtd_list_entry:     For linking to the QH's list of QTDs
@@ -418,6 +426,7 @@ struct dwc2_qtd {
 	u8 error_count;
 	u8 n_desc;
 	u16 isoc_frame_index_last;
+	u16 num_naks;
 	struct dwc2_hcd_urb *urb;
 	struct dwc2_qh *qh;
 	struct list_head qtd_list_entry;
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index 28a8210710b1..50941166aa16 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -52,6 +52,12 @@
 #include "core.h"
 #include "hcd.h"
 
+/*
+ * If we get this many NAKs on a split transaction we'll slow down
+ * retransmission.  A 1 here means delay after the first NAK.
+ */
+#define DWC2_NAKS_BEFORE_DELAY		3
+
 /* This function is for debug only */
 static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
 {
@@ -1200,11 +1206,17 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
 	/*
 	 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
 	 * interrupt. Re-start the SSPLIT transfer.
+	 *
+	 * Normally for non-periodic transfers we'll retry right away, but to
+	 * avoid interrupt storms we'll wait before retrying if we've got
+	 * several NAKs.
 	 */
 	if (chan->do_split) {
 		if (chan->complete_split)
 			qtd->error_count = 0;
 		qtd->complete_split = 0;
+		qtd->num_naks++;
+		qtd->qh->want_wait = qtd->num_naks >= DWC2_NAKS_BEFORE_DELAY;
 		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
 		goto handle_nak_done;
 	}
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 3ae8b1bbaa55..679827cd4925 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -57,6 +57,9 @@
 /* Wait this long before releasing periodic reservation */
 #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
 
+/* If we get a NAK, wait this long before retrying */
+#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1))
+
 /**
  * dwc2_periodic_channel_available() - Checks that a channel is available for a
  * periodic transfer
@@ -1439,6 +1442,55 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
 	list_del_init(&qh->qh_list_entry);
 }
 
+/**
+ * dwc2_wait_timer_fn() - Timer function to re-queue after waiting
+ *
+ * As per the spec, a NAK indicates that "a function is temporarily unable to
+ * transmit or receive data, but will eventually be able to do so without need
+ * of host intervention".
+ *
+ * That means that when we encounter a NAK we're supposed to retry.
+ *
+ * ...but if we retry right away (from the interrupt handler that saw the NAK)
+ * then we can end up with an interrupt storm (if the other side keeps NAKing
+ * us) because on slow enough CPUs it could take us longer to get out of the
+ * interrupt routine than it takes for the device to send another NAK.  That
+ * leads to a constant stream of NAK interrupts and the CPU locks.
+ *
+ * ...so instead of retrying right away in the case of a NAK we'll set a timer
+ * to retry some time later.  This function handles that timer and moves the
+ * qh back to the "inactive" list, then queues transactions.
+ *
+ * @work: Pointer to a qh unreserve_work.
+ */
+static void dwc2_wait_timer_fn(unsigned long data)
+{
+	struct dwc2_qh *qh = (struct dwc2_qh *)data;
+	struct dwc2_hsotg *hsotg = qh->hsotg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+
+	/*
+	 * We'll set wait_timer_cancel to true if we want to cancel this
+	 * operation in dwc2_hcd_qh_unlink().
+	 */
+	if (!qh->wait_timer_cancel) {
+		enum dwc2_transaction_type tr_type;
+
+		qh->want_wait = false;
+
+		list_move(&qh->qh_list_entry,
+			  &hsotg->non_periodic_sched_inactive);
+
+		tr_type = dwc2_hcd_select_transactions(hsotg);
+		if (tr_type != DWC2_TRANSACTION_NONE)
+			dwc2_hcd_queue_transactions(hsotg, tr_type);
+	}
+
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
 /**
  * dwc2_qh_init() - Initializes a QH structure
  *
@@ -1468,6 +1520,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 	qh->hsotg = hsotg;
 	setup_timer(&qh->unreserve_timer, dwc2_unreserve_timer_fn,
 		    (unsigned long)qh);
+	setup_timer(&qh->wait_timer, dwc2_wait_timer_fn, (unsigned long)qh);
 	qh->ep_type = ep_type;
 	qh->ep_is_in = ep_is_in;
 
@@ -1628,6 +1681,16 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 		dwc2_do_unreserve(hsotg, qh);
 		spin_unlock_irqrestore(&hsotg->lock, flags);
 	}
+
+	/*
+	 * We don't have the lock so we can safely wait until the wait timer
+	 * finishes.  Of course, at this point in time we'd better have set
+	 * wait_timer_active to false so if this timer was still pending it
+	 * won't do anything anyway, but we want it to finish before we free
+	 * memory.
+	 */
+	del_timer_sync(&qh->wait_timer);
+
 	dwc2_host_put_tt_info(hsotg, qh->dwc_tt);
 
 	if (qh->desc_list)
@@ -1663,9 +1726,16 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 		qh->start_active_frame = hsotg->frame_number;
 		qh->next_active_frame = qh->start_active_frame;
 
-		/* Always start in inactive schedule */
-		list_add_tail(&qh->qh_list_entry,
-			      &hsotg->non_periodic_sched_inactive);
+		if (qh->want_wait) {
+			list_add_tail(&qh->qh_list_entry,
+				      &hsotg->non_periodic_sched_waiting);
+			qh->wait_timer_cancel = false;
+			mod_timer(&qh->wait_timer,
+				  jiffies + DWC2_RETRY_WAIT_DELAY + 1);
+		} else {
+			list_add_tail(&qh->qh_list_entry,
+				      &hsotg->non_periodic_sched_inactive);
+		}
 		return 0;
 	}
 
@@ -1695,6 +1765,9 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 
 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
+	/* If the wait_timer is pending, this will stop it from acting */
+	qh->wait_timer_cancel = true;
+
 	if (list_empty(&qh->qh_list_entry))
 		/* QH is not in a schedule */
 		return;
@@ -1903,7 +1976,7 @@ void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 	if (dwc2_qh_is_non_per(qh)) {
 		dwc2_hcd_qh_unlink(hsotg, qh);
 		if (!list_empty(&qh->qtd_list))
-			/* Add back to inactive non-periodic schedule */
+			/* Add back to inactive/waiting non-periodic schedule */
 			dwc2_hcd_qh_add(hsotg, qh);
 		return;
 	}
-- 
2.15.0.rc2.357.g7e34df9404-goog



From dianders at chromium.org  Wed Oct 25 16:01:43 2017
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 25 Oct 2017 16:01:43 -0700
Subject: [PATCH] usb: dwc2: host: Don't retry NAKed transactions right away
In-Reply-To: <20171025210857.13443-1-dianders@chromium.org>
References: <20171025210857.13443-1-dianders@chromium.org>
Message-ID: <CAD=FV=UJC5d+uH7FiHvfLWZ7p1e5A5iiFMGPF6DFo0DjcY2Kxg@mail.gmail.com>

Hi,

On Wed, Oct 25, 2017 at 2:08 PM, Douglas Anderson <dianders at chromium.org> wrote:
> On rk3288-veyron devices on Chrome OS it was found that plugging in an
> Arduino-based USB device could cause the system to lockup, especially
> if the CPU Frequency was at one of the slower operating points (like
> 100 MHz / 200 MHz).
>
> Upon tracing, I found that the following was happening:
> * The USB device (full speed) was connected to a high speed hub and
>   then to the rk3288.  Thus, we were dealing with split transactions,
>   which is all handled in software on dwc2.
> * Userspace was initiating a BULK IN transfer
> * When we sent the SSPLIT (to start the split transaction), we got an
>   ACK.  Good.  Then we issued the CSPLIT.
> * When we sent the CSPLIT, we got back a NAK.  We immediately (from
>   the interrupt handler) started to retry and sent another SSPLIT.
> * The device kept NAKing our CSPLIT, so we kept ping-ponging between
>   sending a SSPLIT and a CSPLIT, each time sending from the interrupt
>   handler.
> * The handling of the interrupts was (because of the low CPU speed and
>   the inefficiency of the dwc2 interrupt handler) was actually taking
>   _longer_ than it took the other side to send the ACK/NAK.  Thus we
>   were _always_ in the USB interrupt routine.
> * The fact that USB interrupts were always going off was preventing
>   other things from happening in the system.  This included preventing
>   the system from being able to transition to a higher CPU frequency.
>
> As I understand it, there is no requirement to retry super quickly
> after a NAK, we just have to retry sometime in the future.  Thus one
> solution to the above is to just add a delay between getting a NAK and
> retrying the transmission.  If this delay is sufficiently long to get
> out of the interrupt routine then the rest of the system will be able
> to make forward progress.  Even a 25 us delay would probably be
> enough, but we'll be extra conservative and try to delay 1 ms (the
> exact amount depends on HZ and the accuracy of the jiffy and how close
> the current jiffy is to ticking, but could be as much as 20 ms or as
> little as 1 ms).
>
> Presumably adding a delay like this could impact the USB throughput,
> so we only add the delay with repeated NAKs.
>
> NOTE: Upon further testing of a pl2303 serial adapter, I found that
> this fix may help with problems there.  Specifically I found that the
> pl2303 serial adapters tend to respond with a NAK when they have
> nothing to say and thus we end with this same sequence.
>
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
>
>  drivers/usb/dwc2/core.h      |  1 +
>  drivers/usb/dwc2/hcd.c       |  7 ++++
>  drivers/usb/dwc2/hcd.h       |  9 +++++
>  drivers/usb/dwc2/hcd_intr.c  | 12 +++++++
>  drivers/usb/dwc2/hcd_queue.c | 81 +++++++++++++++++++++++++++++++++++++++++---
>  5 files changed, 106 insertions(+), 4 deletions(-)

One note is that I got some review feedback on the Chrome OS gerrit at
<http://crosreview.com/737520>.  I'll plan to spin with that feedback
tomorrow unless I hear otherwise.  Thanks!  :)

-Doug


From briannorris at chromium.org  Wed Oct 25 18:09:47 2017
From: briannorris at chromium.org (Brian Norris)
Date: Wed, 25 Oct 2017 18:09:47 -0700
Subject: [PATCH v3 3/6] drm/rockchip/dsi: correct Feedback divider setting
In-Reply-To: <20171025075719.4tt7lomec5x7guon@art_vandelay>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
 <1508903463-7254-3-git-send-email-nickey.yang@rock-chips.com>
 <20171025075719.4tt7lomec5x7guon@art_vandelay>
Message-ID: <20171026010946.GA33225@google.com>

On Wed, Oct 25, 2017 at 03:57:19AM -0400, Sean Paul wrote:
> Archit asked a question about moving to
> dw-mipi-dsi

That question made me think though: this approach seems backwards. It
seems like someone did copy/paste/fork, and then we're asking the
authors of the original driver to un-fork? It seems like this should
happen the other way around -- those trying to support a new incarnation
should have looked to try to abstract the original driver for their
uses first.

IIUC, that's exactly what Rockchip did for much of their Analogix eDP
code -- they reworked the Exynos DP driver to split common Analogix code
from any Exynos-specific bits.

And actually, the current stuff in
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c is completely unused. It
exports some functions, but I see no users of it. Is that intended? Is
somebody already working on refactoring existing Rockchip code to use
this?

Brian


From architt at codeaurora.org  Wed Oct 25 21:13:12 2017
From: architt at codeaurora.org (Archit Taneja)
Date: Thu, 26 Oct 2017 09:43:12 +0530
Subject: [PATCH v3 3/6] drm/rockchip/dsi: correct Feedback divider setting
In-Reply-To: <20171026010946.GA33225@google.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
 <1508903463-7254-3-git-send-email-nickey.yang@rock-chips.com>
 <20171025075719.4tt7lomec5x7guon@art_vandelay>
 <20171026010946.GA33225@google.com>
Message-ID: <c1f17f1e-6e4f-d44d-348e-43157474f3c9@codeaurora.org>

Hi,

On 10/26/2017 06:39 AM, Brian Norris wrote:
> On Wed, Oct 25, 2017 at 03:57:19AM -0400, Sean Paul wrote:
>> Archit asked a question about moving to
>> dw-mipi-dsi
> 
> That question made me think though: this approach seems backwards. It
> seems like someone did copy/paste/fork, and then we're asking the
> authors of the original driver to un-fork? It seems like this should
> happen the other way around -- those trying to support a new incarnation
> should have looked to try to abstract the original driver for their
> uses first.

Yes, ST wanted to replicate rockchip's version of the mipi DSI driver and
put it in their folder. If they did that, their KMS driver would have been
the third driver to implement a third instance of the DW DSI controller driver.
Hisilicon and Rockchip being the other 2.

It was either that or attempt at a common DSI DW bridge driver. I suggested
the latter.

The ST guys have abstracted out the PHY pieces, which they knew varied between
rockchip and ST. Ideally, they should have also tried to create a RFC patch to
make the rockchip driver use the bridge too. But they didn't do that, and
the rockchip or hisilicon people were interested in even looking at it,
even after I CC'ed them.

> 
> IIUC, that's exactly what Rockchip did for much of their Analogix eDP
> code -- they reworked the Exynos DP driver to split common Analogix code
> from any Exynos-specific bits.

I get that. I had hoped either ST or Rockchip guys would have done the similar
thing, but no one volunteered.

> 
> And actually, the current stuff in
> drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c is completely unused. It
> exports some functions, but I see no users of it. Is that intended? Is

The ST kms driver uses it:

drivers/gpu/drm/stm/dw_mipi_dsi-stm.c

> somebody already working on refactoring existing Rockchip code to use
> this?

I don't know. If rockchip isn't interested in doing it, we can check with
Philippe from ST if he can try creating a RFC that converts the rockchip
driver to use the dw-mipi-dsi driver.

Thanks,
Archit

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From architt at codeaurora.org  Wed Oct 25 21:53:29 2017
From: architt at codeaurora.org (Archit Taneja)
Date: Thu, 26 Oct 2017 10:23:29 +0530
Subject: [PATCH v3 5/6] dt-bindings: add the rockchip, dual-channel for
 dw-mipi-dsi
In-Reply-To: <1508903463-7254-5-git-send-email-nickey.yang@rock-chips.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
 <1508903463-7254-5-git-send-email-nickey.yang@rock-chips.com>
Message-ID: <816a1d2d-d213-709d-f357-63e7c5248ad3@codeaurora.org>



On 10/25/2017 09:21 AM, Nickey Yang wrote:
> Configure dsi slave channel when driving a panel
> which needs 2 DSI links.
> 
> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
> ---
>   .../devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt       | 2 ++
>   1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
> index 6bb59ab..a2bea22 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
> +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
> @@ -19,6 +19,8 @@ Optional properties:
>   - power-domains: a phandle to mipi dsi power domain node.
>   - resets: list of phandle + reset specifier pairs, as described in [3].
>   - reset-names: string reset name, must be "apb".
> +- rockchip,dual-channel: phandle to a 2nd DSI channel, useful as a slave
> +channel when driving a panel which needs 2 DSI links.
The example below is how dual DSI bindings could look like. Let me know what
you think of it.

If both DSI outputs drive the same device (i.e, point to the same panel DT
node), then I think it's reasonable enough to assume that the DSIs are
operating in a 'dual-channel' mode. That being said, we still need DT to
describe which of the DSIs generates the clock for both the channels. This
is done with the 'clock-master' DT binding.

Thanks,
Archit

mipi_dsi: mipi at ff960000 {
	...
	...

	clock-master;	/* implies that this DSI instance drivers the clock
			 * for both the DSIs.
			 */

	ports {
		mipi_in: port {
			...
			...
		};

		/* add extra output ports for both DSIs */
		mipi_out: port {
			mipi_panel_out: endpoint {
				remote-endpoint = <&panel_in_channel0>;
			};
		};
	};

	panel {
		...
		...
		/*
		 * panel node can describe its input ports, if both the DSIs output
		 * ports are connected to the same device (i.e, the same DSI panel),
		 * we can assume that the DSIs need to operate in dual DSI mode
		 */
		ports {
			...
			port at 0 {
				panel_in_channel0: endpoint {
					remote-endpoint = <&mipi_panel_out>;
				};
			};

			port at 1 {
				panel_in_channel1: endpoint {
					remote-endpoint = <&mipi1_panel_out>;
				};
	
			};
		};
	};
};


mipi_dsi1: mipi at ff968000 {
	...
	...

	ports {
		mipi1_in: port {
			...
			...
		};

		mipi1_out: port {
			mipi1_panel_out: endpoint {
				remote-endpoint = <&panel_in_channel1>;
			};
		};
	};
};

>   
>   [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>   [2] Documentation/devicetree/bindings/media/video-interfaces.txt
> 

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From architt at codeaurora.org  Wed Oct 25 22:11:26 2017
From: architt at codeaurora.org (Archit Taneja)
Date: Thu, 26 Oct 2017 10:41:26 +0530
Subject: [PATCH v3 4/6] drm/rockchip/dsi: add dual mipi channel support
In-Reply-To: <20171025080448.pa465q5jofxhqdn4@art_vandelay>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
 <1508903463-7254-4-git-send-email-nickey.yang@rock-chips.com>
 <20171025080448.pa465q5jofxhqdn4@art_vandelay>
Message-ID: <bfb92284-fa18-ab3e-1f15-6d8344d2a0ee@codeaurora.org>



On 10/25/2017 01:34 PM, Sean Paul wrote:
> On Wed, Oct 25, 2017 at 11:51:01AM +0800, Nickey Yang wrote:
>> This patch add dual mipi channel support:
>> 1.add definition of dsi1 register and grf operation.
>> 2.dsi0 and dsi1 will work in master and slave mode
>> when driving dual mipi panel.
>>
>> Signed-off-by: Nickey Yang <nickey.yang at rock-chips.com>
>> ---
> 
> In the last revision, I asked you to provide changelog between revisions,
> *please* do this. You received review on the last version and a bunch of the
> feedback hasn't been taken into account with no explanation as to why. Please go
> back to the last version, read the reviews that people were generous enough to
> give and either fix the code or explain why you're not.
> 
>>   drivers/gpu/drm/rockchip/dw-mipi-dsi.c      | 377 ++++++++++++++++++++--------
>>   drivers/gpu/drm/rockchip/rockchip_drm_drv.h |   1 +
>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.c |   2 +
>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   3 +
>>   drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   1 +
>>   5 files changed, 279 insertions(+), 105 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>> index 589b420..25e7b77 100644
>> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
>> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> 
> <snip />
> 
>> +static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
>> +{
>> +	struct device_node *np;
>> +	struct platform_device *secondary;
>> +
>> +	np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
>> +	if (np) {
>> +		secondary = of_find_device_by_node(np);
>> +		dsi->slave = platform_get_drvdata(secondary);
>> +		of_node_put(np);
>> +
>> +		if (!dsi->slave)
>> +			return -EPROBE_DEFER;
> 
> Archit asked you not to do this in the previous review.

I've replied with some more details to the patch which adds this in the DT
binding doc.

Thanks,
Archit

> 
>> +
>> +		dsi->slave->master = dsi;
>> +	}
>> +
>> +	return 0;
>> +}
> 
> <snip />
> 
>> -- 
>> 1.9.1
>>
> 

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From heiko at sntech.de  Thu Oct 26 00:18:45 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Thu, 26 Oct 2017 09:18:45 +0200
Subject: [GIT PULL] Rockchip clock updates for 4.15 round 1
In-Reply-To: <14384670.j3hM3TuojQ@phil>
References: <14384670.j3hM3TuojQ@phil>
Message-ID: <4948420.5FYpQAHkKj@phil>

Hi Mike, Stephen,

Am Dienstag, 17. Oktober 2017, 19:43:31 CEST schrieb Heiko Stuebner:
> Hi Mike, Stephen,
> 
> please find below the (tiny) first round of Rockchip clock changes for 4.15.
> Right now there isn't any more in the pipeline, but who knows that may
> change yet.
> 
> Please pull.

just a little ping for post-conference motivation :-)

Thanks in advance
Heiko



> The following changes since commit 2bd6bf03f4c1c59381d62c61d03f6cc3fe71f66e:
> 
>   Linux 4.14-rc1 (2017-09-16 15:47:51 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.15-rockchip-clk-1
> 
> for you to fetch changes up to 47e3ec0e4dae1714cc76596e38d16913f0e574e2:
> 
>   clk: rockchip: use new cif/vdpu clock ids on rk3188 (2017-10-14 21:32:11 +0200)
> 
> ----------------------------------------------------------------
> Some new clock ids for rk3188 and rk3368 as well as removal of a
> superfluous memory allocation error message.
> 
> ----------------------------------------------------------------
> Heiko Stuebner (3):
>       clk: rockchip: add more rk3188 graphics clock ids
>       Merge branch 'v4.15-shared/clkids' into v4.15-clk/next
>       clk: rockchip: use new cif/vdpu clock ids on rk3188
> 
> Markus Elfring (1):
>       clk: rockchip: Remove superfluous error message in rockchip_clk_register_cpuclk()
> 
> Romain Perier (2):
>       clk: rockchip: add clock id for PCLK_EFUSE256 of RK3368 SoCs
>       clk: rockchip: export clock pclk_efuse_256 for RK3368 SoCs
> 
>  drivers/clk/rockchip/clk-cpu.c                |  2 --
>  drivers/clk/rockchip/clk-rk3188.c             | 12 ++++++------
>  drivers/clk/rockchip/clk-rk3368.c             |  2 +-
>  include/dt-bindings/clock/rk3188-cru-common.h |  9 +++++++--
>  include/dt-bindings/clock/rk3368-cru.h        |  1 +
>  5 files changed, 15 insertions(+), 11 deletions(-)
> 




From philippe.cornu at st.com  Thu Oct 26 02:44:14 2017
From: philippe.cornu at st.com (Philippe CORNU)
Date: Thu, 26 Oct 2017 09:44:14 +0000
Subject: [PATCH v3 3/6] drm/rockchip/dsi: correct Feedback divider setting
In-Reply-To: <c1f17f1e-6e4f-d44d-348e-43157474f3c9@codeaurora.org>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
 <1508903463-7254-3-git-send-email-nickey.yang@rock-chips.com>
 <20171025075719.4tt7lomec5x7guon@art_vandelay>
 <20171026010946.GA33225@google.com>
 <c1f17f1e-6e4f-d44d-348e-43157474f3c9@codeaurora.org>
Message-ID: <39862e7a-b03f-f5d9-54db-ff9aef294a9c@st.com>

Hi,

On 10/26/2017 06:13 AM, Archit Taneja wrote:
> Hi,
> 
> On 10/26/2017 06:39 AM, Brian Norris wrote:
>> On Wed, Oct 25, 2017 at 03:57:19AM -0400, Sean Paul wrote:
>>> Archit asked a question about moving to
>>> dw-mipi-dsi
>>
>> That question made me think though: this approach seems backwards. It
>> seems like someone did copy/paste/fork, and then we're asking the
>> authors of the original driver to un-fork? It seems like this should
>> happen the other way around -- those trying to support a new incarnation
>> should have looked to try to abstract the original driver for their
>> uses first.
> 
> Yes, ST wanted to replicate rockchip's version of the mipi DSI driver and
> put it in their folder. If they did that, their KMS driver would have been
> the third driver to implement a third instance of the DW DSI controller 
> driver.
> Hisilicon and Rockchip being the other 2.
> 
> It was either that or attempt at a common DSI DW bridge driver. I suggested
> the latter.
> 
> The ST guys have abstracted out the PHY pieces, which they knew varied 
> between
> rockchip and ST. Ideally, they should have also tried to create a RFC 
> patch to
> make the rockchip driver use the bridge too. But they didn't do that, and
> the rockchip or hisilicon people were interested in even looking at it,
> even after I CC'ed them.
> 
>>
>> IIUC, that's exactly what Rockchip did for much of their Analogix eDP
>> code -- they reworked the Exynos DP driver to split common Analogix code
>> from any Exynos-specific bits.
> 
> I get that. I had hoped either ST or Rockchip guys would have done the 
> similar
> thing, but no one volunteered.
> 
>>
>> And actually, the current stuff in
>> drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c is completely unused. It
>> exports some functions, but I see no users of it. Is that intended? Is
> 
> The ST kms driver uses it:
> 
> drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
> 

I confirm STM32 chipsets use the Synopsys dw dsi bridge driver.

I plan to improve this bridge driver by adding new features (see todos + 
dsi read, command mode with bta & gpio...).

For the first commit, I did my best to keep the source code as close as 
possible to the Rockchip version, in order to ease the port for Rockchip 
guys.

>> somebody already working on refactoring existing Rockchip code to use
>> this?
> 
> I don't know. If rockchip isn't interested in doing it, we can check with
> Philippe from ST if he can try creating a RFC that converts the rockchip
> driver to use the dw-mipi-dsi driver.

I am not really interested in doing this port for Rockchip (or Hisilicon 
or i.MX...) but happy to help anyone that wants to use the dw-mipi-dsi 
bridge driver :)

Many thanks,
Philippe :)

> 
> Thanks,
> Archit
> 

From jeffy.chen at rock-chips.com  Thu Oct 26 06:28:33 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 26 Oct 2017 21:28:33 +0800
Subject: [RFC PATCH v8 0/7] PCI: rockchip: Move PCIe WAKE# handling into pci
 core
Message-ID: <20171026132840.20946-1-jeffy.chen@rock-chips.com>


Currently we are handling wake irq in mrvl wifi driver. Move it into
pci core.

Tested on my chromebook bob(with cros 4.4 kernel and mrvl wifi).


Changes in v8:
Add optional "pci", and rewrite commit message.
Rewrite the commit message.
Add pci-of.c and use platform_pm_ops to handle the PCIe WAKE# signal.

Changes in v7:
Move PCIE_WAKE handling into pci core.

Changes in v6:
Fix device_init_wake error handling, and add some comments.

Changes in v5:
Move to pci.txt
Use "wakeup" instead of "wake"
Rebase.

Changes in v3:
Fix error handling.

Changes in v2:
Use dev_pm_set_dedicated_wake_irq.

Jeffy Chen (7):
  dt-bindings: PCI: Add definition of PCIe WAKE# irq and PCI irq
  mwifiex: Disable wakeup irq handling for pcie
  arm64: dts: rockchip: Handle PCIe WAKE# signal in pcie driver for Gru
  of/irq: Adjust of pci irq parsing for multiple interrupts
  PCI: Make pci_platform_pm_ops's callbacks optional
  PCI / PM: Move acpi wakeup code to pci core
  PCI / PM: Add support for the PCIe WAKE# signal for OF

 Documentation/devicetree/bindings/pci/pci.txt |   3 +
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi  |  15 +--
 drivers/net/wireless/marvell/mwifiex/main.c   |   4 +
 drivers/of/of_pci_irq.c                       |  13 ++-
 drivers/pci/Makefile                          |   2 +-
 drivers/pci/pci-acpi.c                        | 121 +++++++++++------------
 drivers/pci/pci-driver.c                      |   9 ++
 drivers/pci/pci-of.c                          | 136 ++++++++++++++++++++++++++
 drivers/pci/pci.c                             | 112 +++++++++++++++++----
 drivers/pci/pci.h                             |  31 ++++--
 drivers/pci/probe.c                           |  12 ++-
 drivers/pci/remove.c                          |   2 +
 include/linux/pci.h                           |   2 +
 13 files changed, 365 insertions(+), 97 deletions(-)
 create mode 100644 drivers/pci/pci-of.c

-- 
2.11.0




From jeffy.chen at rock-chips.com  Thu Oct 26 06:28:36 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Thu, 26 Oct 2017 21:28:36 +0800
Subject: [RFC PATCH v8 3/7] arm64: dts: rockchip: Handle PCIe WAKE# signal in
 pcie driver for Gru
In-Reply-To: <20171026132840.20946-1-jeffy.chen@rock-chips.com>
References: <20171026132840.20946-1-jeffy.chen@rock-chips.com>
Message-ID: <20171026132840.20946-4-jeffy.chen@rock-chips.com>

Currently we are handling PCIe WAKE# signal in mrvl wifi driver.
Move it to rockchip pcie driver for Gru boards.

Also avoid this irq been considered as the PCI interrupt pin in the
of_irq_parse_pci().

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v8:
Rewrite the commit message.

Changes in v7: None
Changes in v6: None
Changes in v5:
Use "wakeup" instead of "wake"

Changes in v3: None
Changes in v2: None

 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..8e37da69f693 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -708,7 +708,15 @@ ap_i2c_audio: &i2c8 {
 
 	ep-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wifi_perst_l>;
+	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wlan_host_wake_l>, <&wifi_perst_l>;
+
+	interrupts-extended = <&gic GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gpio0 8 IRQ_TYPE_LEVEL_LOW>;
+	interrupt-names = "sys", "legacy", "client", "wakeup";
+	/delete-property/ interrupts;
+
 	vpcie3v3-supply = <&pp3300_wifi_bt>;
 	vpcie1v8-supply = <&wlan_pd_n>; /* HACK: see &wlan_pd_n */
 	vpcie0v9-supply = <&pp900_pcie>;
@@ -723,11 +731,6 @@ ap_i2c_audio: &i2c8 {
 			compatible = "pci1b4b,2b42";
 			reg = <0x83010000 0x0 0x00000000 0x0 0x00100000
 			       0x83010000 0x0 0x00100000 0x0 0x00100000>;
-			interrupt-parent = <&gpio0>;
-			interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
-			pinctrl-names = "default";
-			pinctrl-0 = <&wlan_host_wake_l>;
-			wakeup-source;
 		};
 	};
 };
-- 
2.11.0




From phh at phh.me  Thu Oct 26 11:19:42 2017
From: phh at phh.me (Pierre-Hugues Husson)
Date: Thu, 26 Oct 2017 20:19:42 +0200
Subject: [PATCH v3] drm: bridge: synopsys/dw-hdmi: Enable cec clock
Message-ID: <20171026181942.9516-1-phh@phh.me>

The documentation already mentions "cec" optional clock, but
currently the driver doesn't enable it.

Changes:
v3:
- Drop useless braces

v2:
- Separate ENOENT errors from others
- Propagate other errors (especially -EPROBE_DEFER)

Signed-off-by: Pierre-Hugues Husson <phh at phh.me>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index bf14214fa464..d82b9747a979 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -138,6 +138,7 @@ struct dw_hdmi {
 	struct device *dev;
 	struct clk *isfr_clk;
 	struct clk *iahb_clk;
+	struct clk *cec_clk;
 	struct dw_hdmi_i2c *i2c;
 
 	struct hdmi_data_info hdmi_data;
@@ -2382,6 +2383,26 @@ __dw_hdmi_probe(struct platform_device *pdev,
 		goto err_isfr;
 	}
 
+	hdmi->cec_clk = devm_clk_get(hdmi->dev, "cec");
+	if (PTR_ERR(hdmi->cec_clk) == -ENOENT) {
+		hdmi->cec_clk = NULL;
+	} else if (IS_ERR(hdmi->cec_clk)) {
+		ret = PTR_ERR(hdmi->cec_clk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(hdmi->dev, "Cannot get HDMI cec clock: %d\n",
+					ret);
+
+		hdmi->cec_clk = NULL;
+		goto err_iahb;
+	} else {
+		ret = clk_prepare_enable(hdmi->cec_clk);
+		if (ret) {
+			dev_err(hdmi->dev, "Cannot enable HDMI cec clock: %d\n",
+					ret);
+			goto err_iahb;
+		}
+	}
+
 	/* Product and revision IDs */
 	hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
 		      | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
@@ -2518,6 +2539,8 @@ __dw_hdmi_probe(struct platform_device *pdev,
 		cec_notifier_put(hdmi->cec_notifier);
 
 	clk_disable_unprepare(hdmi->iahb_clk);
+	if (hdmi->cec_clk)
+		clk_disable_unprepare(hdmi->cec_clk);
 err_isfr:
 	clk_disable_unprepare(hdmi->isfr_clk);
 err_res:
@@ -2541,6 +2564,8 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
 
 	clk_disable_unprepare(hdmi->iahb_clk);
 	clk_disable_unprepare(hdmi->isfr_clk);
+	if (hdmi->cec_clk)
+		clk_disable_unprepare(hdmi->cec_clk);
 
 	if (hdmi->i2c)
 		i2c_del_adapter(&hdmi->i2c->adap);
-- 
2.14.2



From dianders at chromium.org  Thu Oct 26 13:22:00 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 26 Oct 2017 13:22:00 -0700
Subject: [PATCH v2] usb: dwc2: host: Don't retry NAKed transactions right away
Message-ID: <20171026202200.6417-1-dianders@chromium.org>

On rk3288-veyron devices on Chrome OS it was found that plugging in an
Arduino-based USB device could cause the system to lockup, especially
if the CPU Frequency was at one of the slower operating points (like
100 MHz / 200 MHz).

Upon tracing, I found that the following was happening:
* The USB device (full speed) was connected to a high speed hub and
  then to the rk3288.  Thus, we were dealing with split transactions,
  which is all handled in software on dwc2.
* Userspace was initiating a BULK IN transfer
* When we sent the SSPLIT (to start the split transaction), we got an
  ACK.  Good.  Then we issued the CSPLIT.
* When we sent the CSPLIT, we got back a NAK.  We immediately (from
  the interrupt handler) started to retry and sent another SSPLIT.
* The device kept NAKing our CSPLIT, so we kept ping-ponging between
  sending a SSPLIT and a CSPLIT, each time sending from the interrupt
  handler.
* The handling of the interrupts was (because of the low CPU speed and
  the inefficiency of the dwc2 interrupt handler) was actually taking
  _longer_ than it took the other side to send the ACK/NAK.  Thus we
  were _always_ in the USB interrupt routine.
* The fact that USB interrupts were always going off was preventing
  other things from happening in the system.  This included preventing
  the system from being able to transition to a higher CPU frequency.

As I understand it, there is no requirement to retry super quickly
after a NAK, we just have to retry sometime in the future.  Thus one
solution to the above is to just add a delay between getting a NAK and
retrying the transmission.  If this delay is sufficiently long to get
out of the interrupt routine then the rest of the system will be able
to make forward progress.  Even a 25 us delay would probably be
enough, but we'll be extra conservative and try to delay 1 ms (the
exact amount depends on HZ and the accuracy of the jiffy and how close
the current jiffy is to ticking, but could be as much as 20 ms or as
little as 1 ms).

Presumably adding a delay like this could impact the USB throughput,
so we only add the delay with repeated NAKs.

NOTE: Upon further testing of a pl2303 serial adapter, I found that
this fix may help with problems there.  Specifically I found that the
pl2303 serial adapters tend to respond with a NAK when they have
nothing to say and thus we end with this same sequence.

Signed-off-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Julius Werner <jwerner at chromium.org>
---

Changes in v2:
- Address http://crosreview.com/737520 feedback

 drivers/usb/dwc2/core.h      |  1 +
 drivers/usb/dwc2/hcd.c       |  7 ++++
 drivers/usb/dwc2/hcd.h       |  9 +++++
 drivers/usb/dwc2/hcd_intr.c  | 20 +++++++++++
 drivers/usb/dwc2/hcd_queue.c | 81 +++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 8367d4f985c1..c0807e558726 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -962,6 +962,7 @@ struct dwc2_hsotg {
 	} flags;
 
 	struct list_head non_periodic_sched_inactive;
+	struct list_head non_periodic_sched_waiting;
 	struct list_head non_periodic_sched_active;
 	struct list_head *non_periodic_qh_ptr;
 	struct list_head periodic_sched_inactive;
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index c2631145f404..ed92ae78dcf9 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -653,6 +653,10 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
 	list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
 			    qh_list_entry)
 		dev_dbg(hsotg->dev, "    %p\n", qh);
+	dev_dbg(hsotg->dev, "  NP waiting sched:\n");
+	list_for_each_entry(qh, &hsotg->non_periodic_sched_waiting,
+			    qh_list_entry)
+		dev_dbg(hsotg->dev, "    %p\n", qh);
 	dev_dbg(hsotg->dev, "  NP active sched:\n");
 	list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
 			    qh_list_entry)
@@ -1812,6 +1816,7 @@ static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
 static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
 {
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
+	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_waiting);
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
@@ -4989,6 +4994,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
 
 	/* Free memory for QH/QTD lists */
 	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
+	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_waiting);
 	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
 	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
 	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
@@ -5151,6 +5157,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
 
 	/* Initialize the non-periodic schedule */
 	INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
+	INIT_LIST_HEAD(&hsotg->non_periodic_sched_waiting);
 	INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
 
 	/* Initialize the periodic schedule */
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index 11c3c145b793..af4f4360e8b7 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -313,12 +313,16 @@ struct dwc2_hs_transfer_time {
  *                      descriptor and indicates original XferSize value for the
  *                      descriptor
  * @unreserve_timer:    Timer for releasing periodic reservation.
+ * @wait_timer:         Timer used to wait before re-queuing.
  * @dwc2_tt:            Pointer to our tt info (or NULL if no tt).
  * @ttport:             Port number within our tt.
  * @tt_buffer_dirty     True if clear_tt_buffer_complete is pending
  * @unreserve_pending:  True if we planned to unreserve but haven't yet.
  * @schedule_low_speed: True if we have a low/full speed component (either the
  *			host is in low/full speed mode or do_split).
+ * @want_wait:          We should wait before re-queuing; only matters for non-
+ *                      periodic transfers and is ignored for periodic ones.
+ * @wait_timer_cancel:  Set to true to cancel the wait_timer.
  *
  * A Queue Head (QH) holds the static characteristics of an endpoint and
  * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
@@ -353,11 +357,14 @@ struct dwc2_qh {
 	u32 desc_list_sz;
 	u32 *n_bytes;
 	struct timer_list unreserve_timer;
+	struct timer_list wait_timer;
 	struct dwc2_tt *dwc_tt;
 	int ttport;
 	unsigned tt_buffer_dirty:1;
 	unsigned unreserve_pending:1;
 	unsigned schedule_low_speed:1;
+	unsigned want_wait:1;
+	unsigned wait_timer_cancel:1;
 };
 
 /**
@@ -388,6 +395,7 @@ struct dwc2_qh {
  * @n_desc:             Number of DMA descriptors for this QTD
  * @isoc_frame_index_last: Last activated frame (packet) index, used in
  *                      descriptor DMA mode only
+ * @num_naks:           Number of NAKs received on this QTD.
  * @urb:                URB for this transfer
  * @qh:                 Queue head for this QTD
  * @qtd_list_entry:     For linking to the QH's list of QTDs
@@ -418,6 +426,7 @@ struct dwc2_qtd {
 	u8 error_count;
 	u8 n_desc;
 	u16 isoc_frame_index_last;
+	u16 num_naks;
 	struct dwc2_hcd_urb *urb;
 	struct dwc2_qh *qh;
 	struct list_head qtd_list_entry;
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index 28a8210710b1..aad3abd2ddf2 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -52,6 +52,12 @@
 #include "core.h"
 #include "hcd.h"
 
+/*
+ * If we get this many NAKs on a split transaction we'll slow down
+ * retransmission.  A 1 here means delay after the first NAK.
+ */
+#define DWC2_NAKS_BEFORE_DELAY		3
+
 /* This function is for debug only */
 static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
 {
@@ -1200,11 +1206,25 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
 	/*
 	 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
 	 * interrupt. Re-start the SSPLIT transfer.
+	 *
+	 * Normally for non-periodic transfers we'll retry right away, but to
+	 * avoid interrupt storms we'll wait before retrying if we've got
+	 * several NAKs. If we didn't do this we'd retry directly from the
+	 * interrupt handler and could end up quickly getting another
+	 * interrupt (another NAK), which we'd retry.
+	 *
+	 * Note that in DMA mode software only gets involved to re-send NAKed
+	 * transfers for split transactions, so we only need to apply this
+	 * delaying logic when handling splits. In non-DMA mode presumably we
+	 * might want a similar delay if someone can demonstrate this problem
+	 * affects that code path too.
 	 */
 	if (chan->do_split) {
 		if (chan->complete_split)
 			qtd->error_count = 0;
 		qtd->complete_split = 0;
+		qtd->num_naks++;
+		qtd->qh->want_wait = qtd->num_naks >= DWC2_NAKS_BEFORE_DELAY;
 		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
 		goto handle_nak_done;
 	}
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 3ae8b1bbaa55..bea0aadd756e 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -57,6 +57,9 @@
 /* Wait this long before releasing periodic reservation */
 #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
 
+/* If we get a NAK, wait this long before retrying */
+#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1))
+
 /**
  * dwc2_periodic_channel_available() - Checks that a channel is available for a
  * periodic transfer
@@ -1439,6 +1442,55 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
 	list_del_init(&qh->qh_list_entry);
 }
 
+/**
+ * dwc2_wait_timer_fn() - Timer function to re-queue after waiting
+ *
+ * As per the spec, a NAK indicates that "a function is temporarily unable to
+ * transmit or receive data, but will eventually be able to do so without need
+ * of host intervention".
+ *
+ * That means that when we encounter a NAK we're supposed to retry.
+ *
+ * ...but if we retry right away (from the interrupt handler that saw the NAK)
+ * then we can end up with an interrupt storm (if the other side keeps NAKing
+ * us) because on slow enough CPUs it could take us longer to get out of the
+ * interrupt routine than it takes for the device to send another NAK.  That
+ * leads to a constant stream of NAK interrupts and the CPU locks.
+ *
+ * ...so instead of retrying right away in the case of a NAK we'll set a timer
+ * to retry some time later.  This function handles that timer and moves the
+ * qh back to the "inactive" list, then queues transactions.
+ *
+ * @data: Pointer to a qh to re-schedule.
+ */
+static void dwc2_wait_timer_fn(unsigned long data)
+{
+	struct dwc2_qh *qh = (struct dwc2_qh *)data;
+	struct dwc2_hsotg *hsotg = qh->hsotg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+
+	/*
+	 * We'll set wait_timer_cancel to true if we want to cancel this
+	 * operation in dwc2_hcd_qh_unlink().
+	 */
+	if (!qh->wait_timer_cancel) {
+		enum dwc2_transaction_type tr_type;
+
+		qh->want_wait = false;
+
+		list_move(&qh->qh_list_entry,
+			  &hsotg->non_periodic_sched_inactive);
+
+		tr_type = dwc2_hcd_select_transactions(hsotg);
+		if (tr_type != DWC2_TRANSACTION_NONE)
+			dwc2_hcd_queue_transactions(hsotg, tr_type);
+	}
+
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
 /**
  * dwc2_qh_init() - Initializes a QH structure
  *
@@ -1468,6 +1520,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 	qh->hsotg = hsotg;
 	setup_timer(&qh->unreserve_timer, dwc2_unreserve_timer_fn,
 		    (unsigned long)qh);
+	setup_timer(&qh->wait_timer, dwc2_wait_timer_fn, (unsigned long)qh);
 	qh->ep_type = ep_type;
 	qh->ep_is_in = ep_is_in;
 
@@ -1628,6 +1681,16 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 		dwc2_do_unreserve(hsotg, qh);
 		spin_unlock_irqrestore(&hsotg->lock, flags);
 	}
+
+	/*
+	 * We don't have the lock so we can safely wait until the wait timer
+	 * finishes.  Of course, at this point in time we'd better have set
+	 * wait_timer_active to false so if this timer was still pending it
+	 * won't do anything anyway, but we want it to finish before we free
+	 * memory.
+	 */
+	del_timer_sync(&qh->wait_timer);
+
 	dwc2_host_put_tt_info(hsotg, qh->dwc_tt);
 
 	if (qh->desc_list)
@@ -1663,9 +1726,16 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 		qh->start_active_frame = hsotg->frame_number;
 		qh->next_active_frame = qh->start_active_frame;
 
-		/* Always start in inactive schedule */
-		list_add_tail(&qh->qh_list_entry,
-			      &hsotg->non_periodic_sched_inactive);
+		if (qh->want_wait) {
+			list_add_tail(&qh->qh_list_entry,
+				      &hsotg->non_periodic_sched_waiting);
+			qh->wait_timer_cancel = false;
+			mod_timer(&qh->wait_timer,
+				  jiffies + DWC2_RETRY_WAIT_DELAY + 1);
+		} else {
+			list_add_tail(&qh->qh_list_entry,
+				      &hsotg->non_periodic_sched_inactive);
+		}
 		return 0;
 	}
 
@@ -1695,6 +1765,9 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 
 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
+	/* If the wait_timer is pending, this will stop it from acting */
+	qh->wait_timer_cancel = true;
+
 	if (list_empty(&qh->qh_list_entry))
 		/* QH is not in a schedule */
 		return;
@@ -1903,7 +1976,7 @@ void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 	if (dwc2_qh_is_non_per(qh)) {
 		dwc2_hcd_qh_unlink(hsotg, qh);
 		if (!list_empty(&qh->qtd_list))
-			/* Add back to inactive non-periodic schedule */
+			/* Add back to inactive/waiting non-periodic schedule */
 			dwc2_hcd_qh_add(hsotg, qh);
 		return;
 	}
-- 
2.15.0.rc2.357.g7e34df9404-goog



From briannorris at chromium.org  Thu Oct 26 14:32:05 2017
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 26 Oct 2017 14:32:05 -0700
Subject: [PATCH v3 3/6] drm/rockchip/dsi: correct Feedback divider setting
In-Reply-To: <39862e7a-b03f-f5d9-54db-ff9aef294a9c@st.com>
References: <1508903463-7254-1-git-send-email-nickey.yang@rock-chips.com>
 <1508903463-7254-3-git-send-email-nickey.yang@rock-chips.com>
 <20171025075719.4tt7lomec5x7guon@art_vandelay>
 <20171026010946.GA33225@google.com>
 <c1f17f1e-6e4f-d44d-348e-43157474f3c9@codeaurora.org>
 <39862e7a-b03f-f5d9-54db-ff9aef294a9c@st.com>
Message-ID: <20171026213204.GA55212@google.com>

(correction zyw's email ".comg" is not a TLD!)

Hi,

On Thu, Oct 26, 2017 at 09:44:14AM +0000, Philippe CORNU wrote:
> On 10/26/2017 06:13 AM, Archit Taneja wrote:
> > On 10/26/2017 06:39 AM, Brian Norris wrote:
> >> On Wed, Oct 25, 2017 at 03:57:19AM -0400, Sean Paul wrote:
> >>> Archit asked a question about moving to
> >>> dw-mipi-dsi
> >>
> >> That question made me think though: this approach seems backwards. It
> >> seems like someone did copy/paste/fork, and then we're asking the
> >> authors of the original driver to un-fork? It seems like this should
> >> happen the other way around -- those trying to support a new incarnation
> >> should have looked to try to abstract the original driver for their
> >> uses first.
> > 
> > Yes, ST wanted to replicate rockchip's version of the mipi DSI driver and
> > put it in their folder. If they did that, their KMS driver would have been
> > the third driver to implement a third instance of the DW DSI controller 
> > driver.
> > Hisilicon and Rockchip being the other 2.

I hadn't noticed Hisilicon's version. That's an unfortunate start :(

> > It was either that or attempt at a common DSI DW bridge driver. I suggested
> > the latter.
> > 
> > The ST guys have abstracted out the PHY pieces, which they knew varied 
> > between
> > rockchip and ST. Ideally, they should have also tried to create a RFC 
> > patch to
> > make the rockchip driver use the bridge too. But they didn't do that, and
> > the rockchip or hisilicon people were interested in even looking at it,
> > even after I CC'ed them.

I see. At least the current code from Philippe isn't that big, and it is
indeed fairly similar.

But I still think the way to get cooperation upstream is to enforce it;
so there was a 3rd option to the above -- don't merge *any* new driver
without posting at least an attempt to unify the existing drivers.

> >> IIUC, that's exactly what Rockchip did for much of their Analogix eDP
> >> code -- they reworked the Exynos DP driver to split common Analogix code
> >> from any Exynos-specific bits.
> > 
> > I get that. I had hoped either ST or Rockchip guys would have done the 
> > similar
> > thing, but no one volunteered.

:(

Nickey, can you confirm that you or someone on your team will look at
utilizing the common driver? Please reply to this email thread before
sending another version of this series.

> >> And actually, the current stuff in
> >> drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c is completely unused. It
> >> exports some functions, but I see no users of it. Is that intended? Is
> > 
> > The ST kms driver uses it:
> > 
> > drivers/gpu/drm/stm/dw_mipi_dsi-stm.c
> > 
> 
> I confirm STM32 chipsets use the Synopsys dw dsi bridge driver.
> 
> I plan to improve this bridge driver by adding new features (see todos + 
> dsi read, command mode with bta & gpio...).
> 
> For the first commit, I did my best to keep the source code as close as 
> possible to the Rockchip version, in order to ease the port for Rockchip 
> guys.

That's nice to see, even if it still isn't ideal.

> >> somebody already working on refactoring existing Rockchip code to use
> >> this?
> > 
> > I don't know. If rockchip isn't interested in doing it, we can check with
> > Philippe from ST if he can try creating a RFC that converts the rockchip
> > driver to use the dw-mipi-dsi driver.
> 
> I am not really interested in doing this port for Rockchip (or Hisilicon 
> or i.MX...) but happy to help anyone that wants to use the dw-mipi-dsi 
> bridge driver :)

Well, see my comments above. Your "interest" is obviously in merging
code to support your own IP, but the community can *make* it your
interest by requiring you do the unification before your code goes
upstream. Apparently that's not the policy here though.

Brian


From jeffy.chen at rock-chips.com  Fri Oct 27 00:17:32 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Fri, 27 Oct 2017 15:17:32 +0800
Subject: [RFC PATCH v9 0/7] PCI: rockchip: Move PCIe WAKE# handling into pci
 core
Message-ID: <20171027071739.21927-1-jeffy.chen@rock-chips.com>


Currently we are handling wake irq in mrvl wifi driver. Move it into
pci core.

Tested on my chromebook bob(with cros 4.4 kernel and mrvl wifi).


Changes in v9:
Add section for PCI devices and rewrite the commit message.
Rewrite the commit message.
Fix check error in .cleanup().
Move dedicated wakeirq setup to setup() callback and use
device_set_wakeup_enable() to enable/disable.

Changes in v8:
Add optional "pci", and rewrite commit message.
Rewrite the commit message.
Add pci-of.c and use platform_pm_ops to handle the PCIe WAKE# signal.

Changes in v7:
Move PCIE_WAKE handling into pci core.

Changes in v6:
Fix device_init_wake error handling, and add some comments.

Changes in v5:
Move to pci.txt
Use "wakeup" instead of "wake"
Rebase.

Changes in v3:
Fix error handling.

Changes in v2:
Use dev_pm_set_dedicated_wake_irq.

Jeffy Chen (7):
  dt-bindings: PCI: Add definition of PCIe WAKE# irq and PCI irq
  of/irq: Adjust of_pci_irq parsing for multiple interrupts
  mwifiex: Disable wakeup irq handling for pcie
  arm64: dts: rockchip: Move PCIe WAKE# irq to pcie driver for Gru
  PCI: Make pci_platform_pm_ops's callbacks optional
  PCI / PM: Move acpi wakeup code to pci core
  PCI / PM: Add support for the PCIe WAKE# signal for OF

 Documentation/devicetree/bindings/pci/pci.txt |   8 ++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi  |  15 +--
 drivers/net/wireless/marvell/mwifiex/main.c   |   4 +
 drivers/of/of_pci_irq.c                       |  13 ++-
 drivers/pci/Makefile                          |   2 +-
 drivers/pci/pci-acpi.c                        | 121 ++++++++++++-------------
 drivers/pci/pci-driver.c                      |   9 ++
 drivers/pci/pci-of.c                          | 126 ++++++++++++++++++++++++++
 drivers/pci/pci.c                             | 112 +++++++++++++++++++----
 drivers/pci/pci.h                             |  31 +++++--
 drivers/pci/probe.c                           |  12 ++-
 drivers/pci/remove.c                          |   2 +
 include/linux/pci.h                           |   2 +
 13 files changed, 360 insertions(+), 97 deletions(-)
 create mode 100644 drivers/pci/pci-of.c

-- 
2.11.0




From jeffy.chen at rock-chips.com  Fri Oct 27 00:17:36 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Fri, 27 Oct 2017 15:17:36 +0800
Subject: [RFC PATCH v9 4/7] arm64: dts: rockchip: Move PCIe WAKE# irq to pcie
 driver for Gru
In-Reply-To: <20171027071739.21927-1-jeffy.chen@rock-chips.com>
References: <20171027071739.21927-1-jeffy.chen@rock-chips.com>
Message-ID: <20171027071739.21927-5-jeffy.chen@rock-chips.com>

Currently we are handling PCIe WAKE# irq in mrvl wifi driver.

Move it to rockchip pcie driver since we are going to handle it in the
pci core.

Also avoid this irq been considered as the PCI interrupt pin in the
of_irq_parse_pci().

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v9:
Rewrite the commit message.

Changes in v8:
Rewrite the commit message.

Changes in v7: None
Changes in v6: None
Changes in v5:
Use "wakeup" instead of "wake"

Changes in v3: None
Changes in v2: None

 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..8e37da69f693 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -708,7 +708,15 @@ ap_i2c_audio: &i2c8 {
 
 	ep-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wifi_perst_l>;
+	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wlan_host_wake_l>, <&wifi_perst_l>;
+
+	interrupts-extended = <&gic GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gpio0 8 IRQ_TYPE_LEVEL_LOW>;
+	interrupt-names = "sys", "legacy", "client", "wakeup";
+	/delete-property/ interrupts;
+
 	vpcie3v3-supply = <&pp3300_wifi_bt>;
 	vpcie1v8-supply = <&wlan_pd_n>; /* HACK: see &wlan_pd_n */
 	vpcie0v9-supply = <&pp900_pcie>;
@@ -723,11 +731,6 @@ ap_i2c_audio: &i2c8 {
 			compatible = "pci1b4b,2b42";
 			reg = <0x83010000 0x0 0x00000000 0x0 0x00100000
 			       0x83010000 0x0 0x00100000 0x0 0x00100000>;
-			interrupt-parent = <&gpio0>;
-			interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
-			pinctrl-names = "default";
-			pinctrl-0 = <&wlan_host_wake_l>;
-			wakeup-source;
 		};
 	};
 };
-- 
2.11.0




From jeffy.chen at rock-chips.com  Fri Oct 27 00:26:05 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Fri, 27 Oct 2017 15:26:05 +0800
Subject: [RFC PATCH v10 0/7] PCI: rockchip: Move PCIe WAKE# handling into pci
 core
Message-ID: <20171027072612.26565-1-jeffy.chen@rock-chips.com>


Currently we are handling wake irq in mrvl wifi driver. Move it into
pci core.

Tested on my chromebook bob(with cros 4.4 kernel and mrvl wifi).


Changes in v10:
Use device_set_wakeup_capable() instead of device_set_wakeup_enable(),
since dedicated wakeirq will be lost in device_set_wakeup_enable(false).

Changes in v9:
Add section for PCI devices and rewrite the commit message.
Rewrite the commit message.
Fix check error in .cleanup().
Move dedicated wakeirq setup to setup() callback and use
device_set_wakeup_enable() to enable/disable.

Changes in v8:
Add optional "pci", and rewrite commit message.
Rewrite the commit message.
Add pci-of.c and use platform_pm_ops to handle the PCIe WAKE# signal.

Changes in v7:
Move PCIE_WAKE handling into pci core.

Changes in v6:
Fix device_init_wake error handling, and add some comments.

Changes in v5:
Move to pci.txt
Use "wakeup" instead of "wake"
Rebase.

Changes in v3:
Fix error handling.

Changes in v2:
Use dev_pm_set_dedicated_wake_irq.

Jeffy Chen (7):
  dt-bindings: PCI: Add definition of PCIe WAKE# irq and PCI irq
  of/irq: Adjust of_pci_irq parsing for multiple interrupts
  mwifiex: Disable wakeup irq handling for pcie
  arm64: dts: rockchip: Move PCIe WAKE# irq to pcie driver for Gru
  PCI: Make pci_platform_pm_ops's callbacks optional
  PCI / PM: Move acpi wakeup code to pci core
  PCI / PM: Add support for the PCIe WAKE# signal for OF

 Documentation/devicetree/bindings/pci/pci.txt |   8 ++
 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi  |  15 +--
 drivers/net/wireless/marvell/mwifiex/main.c   |   4 +
 drivers/of/of_pci_irq.c                       |  13 ++-
 drivers/pci/Makefile                          |   2 +-
 drivers/pci/pci-acpi.c                        | 121 ++++++++++++------------
 drivers/pci/pci-driver.c                      |   9 ++
 drivers/pci/pci-of.c                          | 127 ++++++++++++++++++++++++++
 drivers/pci/pci.c                             | 112 +++++++++++++++++++----
 drivers/pci/pci.h                             |  31 +++++--
 drivers/pci/probe.c                           |  12 ++-
 drivers/pci/remove.c                          |   2 +
 include/linux/pci.h                           |   2 +
 13 files changed, 361 insertions(+), 97 deletions(-)
 create mode 100644 drivers/pci/pci-of.c

-- 
2.11.0




From jeffy.chen at rock-chips.com  Fri Oct 27 00:26:09 2017
From: jeffy.chen at rock-chips.com (Jeffy Chen)
Date: Fri, 27 Oct 2017 15:26:09 +0800
Subject: [RFC PATCH v10 4/7] arm64: dts: rockchip: Move PCIe WAKE# irq to pcie
 driver for Gru
In-Reply-To: <20171027072612.26565-1-jeffy.chen@rock-chips.com>
References: <20171027072612.26565-1-jeffy.chen@rock-chips.com>
Message-ID: <20171027072612.26565-5-jeffy.chen@rock-chips.com>

Currently we are handling PCIe WAKE# irq in mrvl wifi driver.

Move it to rockchip pcie driver since we are going to handle it in the
pci core.

Also avoid this irq been considered as the PCI interrupt pin in the
of_irq_parse_pci().

Signed-off-by: Jeffy Chen <jeffy.chen at rock-chips.com>
---

Changes in v10: None
Changes in v9:
Rewrite the commit message.

Changes in v8:
Rewrite the commit message.

Changes in v7: None
Changes in v6: None
Changes in v5:
Use "wakeup" instead of "wake"

Changes in v3: None
Changes in v2: None

 arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 5772c52fbfd3..8e37da69f693 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -708,7 +708,15 @@ ap_i2c_audio: &i2c8 {
 
 	ep-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wifi_perst_l>;
+	pinctrl-0 = <&pcie_clkreqn_cpm>, <&wlan_host_wake_l>, <&wifi_perst_l>;
+
+	interrupts-extended = <&gic GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gic GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>,
+			      <&gpio0 8 IRQ_TYPE_LEVEL_LOW>;
+	interrupt-names = "sys", "legacy", "client", "wakeup";
+	/delete-property/ interrupts;
+
 	vpcie3v3-supply = <&pp3300_wifi_bt>;
 	vpcie1v8-supply = <&wlan_pd_n>; /* HACK: see &wlan_pd_n */
 	vpcie0v9-supply = <&pp900_pcie>;
@@ -723,11 +731,6 @@ ap_i2c_audio: &i2c8 {
 			compatible = "pci1b4b,2b42";
 			reg = <0x83010000 0x0 0x00000000 0x0 0x00100000
 			       0x83010000 0x0 0x00100000 0x0 0x00100000>;
-			interrupt-parent = <&gpio0>;
-			interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
-			pinctrl-names = "default";
-			pinctrl-0 = <&wlan_host_wake_l>;
-			wakeup-source;
 		};
 	};
 };
-- 
2.11.0




From sakari.ailus at iki.fi  Fri Oct 27 03:08:24 2017
From: sakari.ailus at iki.fi (Sakari Ailus)
Date: Fri, 27 Oct 2017 13:08:24 +0300
Subject: [PATCH] [media] rockchip/rga: annotate PM functions as
 __maybe_unused
In-Reply-To: <20171019093044.531871-1-arnd@arndb.de>
References: <20171019093044.531871-1-arnd@arndb.de>
Message-ID: <20171027100823.ao3hytbe4kdfossy@valkosipuli.retiisi.org.uk>

On Thu, Oct 19, 2017 at 11:30:34AM +0200, Arnd Bergmann wrote:
> The newly added driver has incorrect #ifdef annotations on its
> PM functions, leading to a harmless compile-time warning when
> CONFIG_PM is disabled:
> 
> drivers/media/platform/rockchip/rga/rga.c:760:13: error: 'rga_disable_clocks' defined but not used [-Werror=unused-function]
>  static void rga_disable_clocks(struct rockchip_rga *rga)
>              ^~~~~~~~~~~~~~~~~~
> drivers/media/platform/rockchip/rga/rga.c:728:12: error: 'rga_enable_clocks' defined but not used [-Werror=unused-function]
> 
> This removes the #ifdef and marks the functions as __maybe_unused,
> so gcc can silently drop all the unused code.
> 
> Fixes: f7e7b48e6d79 ("[media] rockchip/rga: v4l2 m2m support")
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>

Acked-by: Sakari Ailus <sakari.ailus at linux.intel.com>

-- 
Sakari Ailus
e-mail: sakari.ailus at iki.fi


From rjw at rjwysocki.net  Sat Oct 28 02:07:30 2017
From: rjw at rjwysocki.net (Rafael J. Wysocki)
Date: Sat, 28 Oct 2017 11:07:30 +0200
Subject: [RFC PATCH v10 0/7] PCI: rockchip: Move PCIe WAKE# handling into
 pci core
In-Reply-To: <20171027072612.26565-1-jeffy.chen@rock-chips.com>
References: <20171027072612.26565-1-jeffy.chen@rock-chips.com>
Message-ID: <1872710.P2f02irZl9@aspire.rjw.lan>

On Friday, October 27, 2017 9:26:05 AM CEST Jeffy Chen wrote:
> 
> Currently we are handling wake irq in mrvl wifi driver. Move it into
> pci core.
> 
> Tested on my chromebook bob(with cros 4.4 kernel and mrvl wifi).
> 
> 
> Changes in v10:
> Use device_set_wakeup_capable() instead of device_set_wakeup_enable(),
> since dedicated wakeirq will be lost in device_set_wakeup_enable(false).
> 
> Changes in v9:
> Add section for PCI devices and rewrite the commit message.
> Rewrite the commit message.
> Fix check error in .cleanup().
> Move dedicated wakeirq setup to setup() callback and use
> device_set_wakeup_enable() to enable/disable.
> 
> Changes in v8:
> Add optional "pci", and rewrite commit message.
> Rewrite the commit message.
> Add pci-of.c and use platform_pm_ops to handle the PCIe WAKE# signal.
> 
> Changes in v7:
> Move PCIE_WAKE handling into pci core.
> 
> Changes in v6:
> Fix device_init_wake error handling, and add some comments.
> 
> Changes in v5:
> Move to pci.txt
> Use "wakeup" instead of "wake"
> Rebase.
> 
> Changes in v3:
> Fix error handling.
> 
> Changes in v2:
> Use dev_pm_set_dedicated_wake_irq.
> 
> Jeffy Chen (7):
>   dt-bindings: PCI: Add definition of PCIe WAKE# irq and PCI irq
>   of/irq: Adjust of_pci_irq parsing for multiple interrupts
>   mwifiex: Disable wakeup irq handling for pcie
>   arm64: dts: rockchip: Move PCIe WAKE# irq to pcie driver for Gru
>   PCI: Make pci_platform_pm_ops's callbacks optional
>   PCI / PM: Move acpi wakeup code to pci core
>   PCI / PM: Add support for the PCIe WAKE# signal for OF

Overall, I don't quite like the direction this is going into, but I need to
have a deeper look.  Which may take some time, so please bear with me.

Thanks,
Rafael



From stefan.wahren at i2se.com  Sat Oct 28 08:51:47 2017
From: stefan.wahren at i2se.com (Stefan Wahren)
Date: Sat, 28 Oct 2017 17:51:47 +0200 (CEST)
Subject: [PATCH v2] usb: dwc2: host: Don't retry NAKed transactions
 right away
In-Reply-To: <20171026202200.6417-1-dianders@chromium.org>
References: <20171026202200.6417-1-dianders@chromium.org>
Message-ID: <60370001.40630.1509205907119@email.1und1.de>

Hi Doug,

[add Felipe since this should go through his tree]

i'm back from vacation and happy to see this patch.

> Douglas Anderson <dianders at chromium.org> hat am 26. Oktober 2017 um 22:22 geschrieben:
> 
> 
> On rk3288-veyron devices on Chrome OS it was found that plugging in an
> Arduino-based USB device could cause the system to lockup, especially
> if the CPU Frequency was at one of the slower operating points (like
> 100 MHz / 200 MHz).
> 
> Upon tracing, I found that the following was happening:
> * The USB device (full speed) was connected to a high speed hub and
>   then to the rk3288.  Thus, we were dealing with split transactions,
>   which is all handled in software on dwc2.
> * Userspace was initiating a BULK IN transfer
> * When we sent the SSPLIT (to start the split transaction), we got an
>   ACK.  Good.  Then we issued the CSPLIT.
> * When we sent the CSPLIT, we got back a NAK.  We immediately (from
>   the interrupt handler) started to retry and sent another SSPLIT.
> * The device kept NAKing our CSPLIT, so we kept ping-ponging between
>   sending a SSPLIT and a CSPLIT, each time sending from the interrupt
>   handler.
> * The handling of the interrupts was (because of the low CPU speed and
>   the inefficiency of the dwc2 interrupt handler) was actually taking
>   _longer_ than it took the other side to send the ACK/NAK.  Thus we
>   were _always_ in the USB interrupt routine.
> * The fact that USB interrupts were always going off was preventing
>   other things from happening in the system.  This included preventing
>   the system from being able to transition to a higher CPU frequency.
> 
> As I understand it, there is no requirement to retry super quickly
> after a NAK, we just have to retry sometime in the future.  Thus one
> solution to the above is to just add a delay between getting a NAK and
> retrying the transmission.  If this delay is sufficiently long to get
> out of the interrupt routine then the rest of the system will be able
> to make forward progress.  Even a 25 us delay would probably be
> enough, but we'll be extra conservative and try to delay 1 ms (the
> exact amount depends on HZ and the accuracy of the jiffy and how close
> the current jiffy is to ticking, but could be as much as 20 ms or as
> little as 1 ms).
> 
> Presumably adding a delay like this could impact the USB throughput,
> so we only add the delay with repeated NAKs.
> 
> NOTE: Upon further testing of a pl2303 serial adapter, I found that
> this fix may help with problems there.  Specifically I found that the
> pl2303 serial adapters tend to respond with a NAK when they have
> nothing to say and thus we end with this same sequence.

This patch fixes "dwc2: NMI watchdog: BUG: soft lockup - CPU#0 stuck for 146s" on bcm2835. After applying your patch on linux-next plus "mm: drop migrate type checks from has_unmovable_pages" i'm able to open 3 PL2303 serial adapters parallel on a Raspberry Pi 1 B without any issues.

Tested-by: Stefan Wahren <stefan.wahren at i2se.com>

Please see my comment below

> 
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> Reviewed-by: Julius Werner <jwerner at chromium.org>
> ---
> 
> Changes in v2:
> - Address http://crosreview.com/737520 feedback
> 
>  drivers/usb/dwc2/core.h      |  1 +
>  drivers/usb/dwc2/hcd.c       |  7 ++++
>  drivers/usb/dwc2/hcd.h       |  9 +++++
>  drivers/usb/dwc2/hcd_intr.c  | 20 +++++++++++
>  drivers/usb/dwc2/hcd_queue.c | 81 +++++++++++++++++++++++++++++++++++++++++---
>  5 files changed, 114 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
> index 8367d4f985c1..c0807e558726 100644
> --- a/drivers/usb/dwc2/core.h
> +++ b/drivers/usb/dwc2/core.h
> @@ -962,6 +962,7 @@ struct dwc2_hsotg {
>  	} flags;
>  
>  	struct list_head non_periodic_sched_inactive;
> +	struct list_head non_periodic_sched_waiting;
>  	struct list_head non_periodic_sched_active;
>  	struct list_head *non_periodic_qh_ptr;
>  	struct list_head periodic_sched_inactive;
> diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
> index c2631145f404..ed92ae78dcf9 100644
> --- a/drivers/usb/dwc2/hcd.c
> +++ b/drivers/usb/dwc2/hcd.c
> @@ -653,6 +653,10 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
>  	list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
>  			    qh_list_entry)
>  		dev_dbg(hsotg->dev, "    %p\n", qh);
> +	dev_dbg(hsotg->dev, "  NP waiting sched:\n");
> +	list_for_each_entry(qh, &hsotg->non_periodic_sched_waiting,
> +			    qh_list_entry)
> +		dev_dbg(hsotg->dev, "    %p\n", qh);
>  	dev_dbg(hsotg->dev, "  NP active sched:\n");
>  	list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
>  			    qh_list_entry)
> @@ -1812,6 +1816,7 @@ static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
>  static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
>  {
>  	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
> +	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_waiting);
>  	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
>  	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
>  	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
> @@ -4989,6 +4994,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
>  
>  	/* Free memory for QH/QTD lists */
>  	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
> +	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_waiting);
>  	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
>  	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
>  	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
> @@ -5151,6 +5157,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
>  
>  	/* Initialize the non-periodic schedule */
>  	INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
> +	INIT_LIST_HEAD(&hsotg->non_periodic_sched_waiting);
>  	INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
>  
>  	/* Initialize the periodic schedule */
> diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
> index 11c3c145b793..af4f4360e8b7 100644
> --- a/drivers/usb/dwc2/hcd.h
> +++ b/drivers/usb/dwc2/hcd.h
> @@ -313,12 +313,16 @@ struct dwc2_hs_transfer_time {
>   *                      descriptor and indicates original XferSize value for the
>   *                      descriptor
>   * @unreserve_timer:    Timer for releasing periodic reservation.
> + * @wait_timer:         Timer used to wait before re-queuing.
>   * @dwc2_tt:            Pointer to our tt info (or NULL if no tt).
>   * @ttport:             Port number within our tt.
>   * @tt_buffer_dirty     True if clear_tt_buffer_complete is pending
>   * @unreserve_pending:  True if we planned to unreserve but haven't yet.
>   * @schedule_low_speed: True if we have a low/full speed component (either the
>   *			host is in low/full speed mode or do_split).
> + * @want_wait:          We should wait before re-queuing; only matters for non-
> + *                      periodic transfers and is ignored for periodic ones.
> + * @wait_timer_cancel:  Set to true to cancel the wait_timer.
>   *
>   * A Queue Head (QH) holds the static characteristics of an endpoint and
>   * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
> @@ -353,11 +357,14 @@ struct dwc2_qh {
>  	u32 desc_list_sz;
>  	u32 *n_bytes;
>  	struct timer_list unreserve_timer;
> +	struct timer_list wait_timer;
>  	struct dwc2_tt *dwc_tt;
>  	int ttport;
>  	unsigned tt_buffer_dirty:1;
>  	unsigned unreserve_pending:1;
>  	unsigned schedule_low_speed:1;
> +	unsigned want_wait:1;
> +	unsigned wait_timer_cancel:1;
>  };
>  
>  /**
> @@ -388,6 +395,7 @@ struct dwc2_qh {
>   * @n_desc:             Number of DMA descriptors for this QTD
>   * @isoc_frame_index_last: Last activated frame (packet) index, used in
>   *                      descriptor DMA mode only
> + * @num_naks:           Number of NAKs received on this QTD.
>   * @urb:                URB for this transfer
>   * @qh:                 Queue head for this QTD
>   * @qtd_list_entry:     For linking to the QH's list of QTDs
> @@ -418,6 +426,7 @@ struct dwc2_qtd {
>  	u8 error_count;
>  	u8 n_desc;
>  	u16 isoc_frame_index_last;
> +	u16 num_naks;
>  	struct dwc2_hcd_urb *urb;
>  	struct dwc2_qh *qh;
>  	struct list_head qtd_list_entry;
> diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
> index 28a8210710b1..aad3abd2ddf2 100644
> --- a/drivers/usb/dwc2/hcd_intr.c
> +++ b/drivers/usb/dwc2/hcd_intr.c
> @@ -52,6 +52,12 @@
>  #include "core.h"
>  #include "hcd.h"
>  
> +/*
> + * If we get this many NAKs on a split transaction we'll slow down
> + * retransmission.  A 1 here means delay after the first NAK.
> + */
> +#define DWC2_NAKS_BEFORE_DELAY		3
> +
>  /* This function is for debug only */
>  static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
>  {
> @@ -1200,11 +1206,25 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
>  	/*
>  	 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
>  	 * interrupt. Re-start the SSPLIT transfer.
> +	 *
> +	 * Normally for non-periodic transfers we'll retry right away, but to
> +	 * avoid interrupt storms we'll wait before retrying if we've got
> +	 * several NAKs. If we didn't do this we'd retry directly from the
> +	 * interrupt handler and could end up quickly getting another
> +	 * interrupt (another NAK), which we'd retry.
> +	 *
> +	 * Note that in DMA mode software only gets involved to re-send NAKed
> +	 * transfers for split transactions, so we only need to apply this
> +	 * delaying logic when handling splits. In non-DMA mode presumably we
> +	 * might want a similar delay if someone can demonstrate this problem
> +	 * affects that code path too.
>  	 */
>  	if (chan->do_split) {
>  		if (chan->complete_split)
>  			qtd->error_count = 0;
>  		qtd->complete_split = 0;
> +		qtd->num_naks++;
> +		qtd->qh->want_wait = qtd->num_naks >= DWC2_NAKS_BEFORE_DELAY;
>  		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
>  		goto handle_nak_done;
>  	}
> diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
> index 3ae8b1bbaa55..bea0aadd756e 100644
> --- a/drivers/usb/dwc2/hcd_queue.c
> +++ b/drivers/usb/dwc2/hcd_queue.c
> @@ -57,6 +57,9 @@
>  /* Wait this long before releasing periodic reservation */
>  #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
>  
> +/* If we get a NAK, wait this long before retrying */
> +#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1))
> +
>  /**
>   * dwc2_periodic_channel_available() - Checks that a channel is available for a
>   * periodic transfer
> @@ -1439,6 +1442,55 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
>  	list_del_init(&qh->qh_list_entry);
>  }
>  
> +/**
> + * dwc2_wait_timer_fn() - Timer function to re-queue after waiting
> + *
> + * As per the spec, a NAK indicates that "a function is temporarily unable to
> + * transmit or receive data, but will eventually be able to do so without need
> + * of host intervention".
> + *
> + * That means that when we encounter a NAK we're supposed to retry.
> + *
> + * ...but if we retry right away (from the interrupt handler that saw the NAK)
> + * then we can end up with an interrupt storm (if the other side keeps NAKing
> + * us) because on slow enough CPUs it could take us longer to get out of the
> + * interrupt routine than it takes for the device to send another NAK.  That
> + * leads to a constant stream of NAK interrupts and the CPU locks.
> + *
> + * ...so instead of retrying right away in the case of a NAK we'll set a timer
> + * to retry some time later.  This function handles that timer and moves the
> + * qh back to the "inactive" list, then queues transactions.
> + *
> + * @data: Pointer to a qh to re-schedule.
> + */
> +static void dwc2_wait_timer_fn(unsigned long data)
> +{
> +	struct dwc2_qh *qh = (struct dwc2_qh *)data;
> +	struct dwc2_hsotg *hsotg = qh->hsotg;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&hsotg->lock, flags);
> +
> +	/*
> +	 * We'll set wait_timer_cancel to true if we want to cancel this
> +	 * operation in dwc2_hcd_qh_unlink().
> +	 */
> +	if (!qh->wait_timer_cancel) {
> +		enum dwc2_transaction_type tr_type;
> +
> +		qh->want_wait = false;
> +
> +		list_move(&qh->qh_list_entry,
> +			  &hsotg->non_periodic_sched_inactive);
> +
> +		tr_type = dwc2_hcd_select_transactions(hsotg);
> +		if (tr_type != DWC2_TRANSACTION_NONE)
> +			dwc2_hcd_queue_transactions(hsotg, tr_type);
> +	}
> +
> +	spin_unlock_irqrestore(&hsotg->lock, flags);
> +}
> +
>  /**
>   * dwc2_qh_init() - Initializes a QH structure
>   *
> @@ -1468,6 +1520,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
>  	qh->hsotg = hsotg;
>  	setup_timer(&qh->unreserve_timer, dwc2_unreserve_timer_fn,
>  		    (unsigned long)qh);
> +	setup_timer(&qh->wait_timer, dwc2_wait_timer_fn, (unsigned long)qh);

Kees Cook started to replace setup_timer() with the new timer_setup(). I'm not sure if it's okay to use the deprecated function and replace all of them later.

Best regards


From dianders at chromium.org  Sun Oct 29 13:07:57 2017
From: dianders at chromium.org (Doug Anderson)
Date: Sun, 29 Oct 2017 13:07:57 -0700
Subject: [PATCH v2] usb: dwc2: host: Don't retry NAKed transactions right
 away
In-Reply-To: <60370001.40630.1509205907119@email.1und1.de>
References: <20171026202200.6417-1-dianders@chromium.org>
 <60370001.40630.1509205907119@email.1und1.de>
Message-ID: <CAD=FV=WK_9AsutYhOTh9HMXwac1PJEXtHvXUYnztGmp6H3gbWg@mail.gmail.com>

Hi,

On Sat, Oct 28, 2017 at 8:51 AM, Stefan Wahren <stefan.wahren at i2se.com> wrote:
> Hi Doug,
>
> [add Felipe since this should go through his tree]

Ah.  Sorry Felipe!  I know you've landed some dwc2 stuff in the past
but for some reason get_maintainer didn't ID you so I thought maybe
you weren't doing it anymore.  Please let me know if you'd like me to
send this to you again with collected Reviewed-by and Tested-by tags.


> i'm back from vacation and happy to see this patch.
>
>> Douglas Anderson <dianders at chromium.org> hat am 26. Oktober 2017 um 22:22 geschrieben:
>>
>>
>> On rk3288-veyron devices on Chrome OS it was found that plugging in an
>> Arduino-based USB device could cause the system to lockup, especially
>> if the CPU Frequency was at one of the slower operating points (like
>> 100 MHz / 200 MHz).
>>
>> Upon tracing, I found that the following was happening:
>> * The USB device (full speed) was connected to a high speed hub and
>>   then to the rk3288.  Thus, we were dealing with split transactions,
>>   which is all handled in software on dwc2.
>> * Userspace was initiating a BULK IN transfer
>> * When we sent the SSPLIT (to start the split transaction), we got an
>>   ACK.  Good.  Then we issued the CSPLIT.
>> * When we sent the CSPLIT, we got back a NAK.  We immediately (from
>>   the interrupt handler) started to retry and sent another SSPLIT.
>> * The device kept NAKing our CSPLIT, so we kept ping-ponging between
>>   sending a SSPLIT and a CSPLIT, each time sending from the interrupt
>>   handler.
>> * The handling of the interrupts was (because of the low CPU speed and
>>   the inefficiency of the dwc2 interrupt handler) was actually taking
>>   _longer_ than it took the other side to send the ACK/NAK.  Thus we
>>   were _always_ in the USB interrupt routine.
>> * The fact that USB interrupts were always going off was preventing
>>   other things from happening in the system.  This included preventing
>>   the system from being able to transition to a higher CPU frequency.
>>
>> As I understand it, there is no requirement to retry super quickly
>> after a NAK, we just have to retry sometime in the future.  Thus one
>> solution to the above is to just add a delay between getting a NAK and
>> retrying the transmission.  If this delay is sufficiently long to get
>> out of the interrupt routine then the rest of the system will be able
>> to make forward progress.  Even a 25 us delay would probably be
>> enough, but we'll be extra conservative and try to delay 1 ms (the
>> exact amount depends on HZ and the accuracy of the jiffy and how close
>> the current jiffy is to ticking, but could be as much as 20 ms or as
>> little as 1 ms).
>>
>> Presumably adding a delay like this could impact the USB throughput,
>> so we only add the delay with repeated NAKs.
>>
>> NOTE: Upon further testing of a pl2303 serial adapter, I found that
>> this fix may help with problems there.  Specifically I found that the
>> pl2303 serial adapters tend to respond with a NAK when they have
>> nothing to say and thus we end with this same sequence.
>
> This patch fixes "dwc2: NMI watchdog: BUG: soft lockup - CPU#0 stuck for 146s" on bcm2835. After applying your patch on linux-next plus "mm: drop migrate type checks from has_unmovable_pages" i'm able to open 3 PL2303 serial adapters parallel on a Raspberry Pi 1 B without any issues.

Woohoo!  It only took a year from your report of this issue to getting
a fix.  ;)  It sounds as if Julius found something the other day too
(dealing better with stalls), so any day now we'll have a mainline
kernel that can keep up with "blazingly fast" UART connections.  :-P


> Tested-by: Stefan Wahren <stefan.wahren at i2se.com>


Thank you so much for the testing!


> Please see my comment below
>
>>
>> Signed-off-by: Douglas Anderson <dianders at chromium.org>
>> Reviewed-by: Julius Werner <jwerner at chromium.org>
>> ---
>>
>> Changes in v2:
>> - Address http://crosreview.com/737520 feedback
>>
>>  drivers/usb/dwc2/core.h      |  1 +
>>  drivers/usb/dwc2/hcd.c       |  7 ++++
>>  drivers/usb/dwc2/hcd.h       |  9 +++++
>>  drivers/usb/dwc2/hcd_intr.c  | 20 +++++++++++
>>  drivers/usb/dwc2/hcd_queue.c | 81 +++++++++++++++++++++++++++++++++++++++++---
>>  5 files changed, 114 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
>> index 8367d4f985c1..c0807e558726 100644
>> --- a/drivers/usb/dwc2/core.h
>> +++ b/drivers/usb/dwc2/core.h
>> @@ -962,6 +962,7 @@ struct dwc2_hsotg {
>>       } flags;
>>
>>       struct list_head non_periodic_sched_inactive;
>> +     struct list_head non_periodic_sched_waiting;
>>       struct list_head non_periodic_sched_active;
>>       struct list_head *non_periodic_qh_ptr;
>>       struct list_head periodic_sched_inactive;
>> diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
>> index c2631145f404..ed92ae78dcf9 100644
>> --- a/drivers/usb/dwc2/hcd.c
>> +++ b/drivers/usb/dwc2/hcd.c
>> @@ -653,6 +653,10 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
>>       list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
>>                           qh_list_entry)
>>               dev_dbg(hsotg->dev, "    %p\n", qh);
>> +     dev_dbg(hsotg->dev, "  NP waiting sched:\n");
>> +     list_for_each_entry(qh, &hsotg->non_periodic_sched_waiting,
>> +                         qh_list_entry)
>> +             dev_dbg(hsotg->dev, "    %p\n", qh);
>>       dev_dbg(hsotg->dev, "  NP active sched:\n");
>>       list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
>>                           qh_list_entry)
>> @@ -1812,6 +1816,7 @@ static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
>>  static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
>>  {
>>       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
>> +     dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_waiting);
>>       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
>>       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
>>       dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
>> @@ -4989,6 +4994,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
>>
>>       /* Free memory for QH/QTD lists */
>>       dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
>> +     dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_waiting);
>>       dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
>>       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
>>       dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
>> @@ -5151,6 +5157,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
>>
>>       /* Initialize the non-periodic schedule */
>>       INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
>> +     INIT_LIST_HEAD(&hsotg->non_periodic_sched_waiting);
>>       INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
>>
>>       /* Initialize the periodic schedule */
>> diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
>> index 11c3c145b793..af4f4360e8b7 100644
>> --- a/drivers/usb/dwc2/hcd.h
>> +++ b/drivers/usb/dwc2/hcd.h
>> @@ -313,12 +313,16 @@ struct dwc2_hs_transfer_time {
>>   *                      descriptor and indicates original XferSize value for the
>>   *                      descriptor
>>   * @unreserve_timer:    Timer for releasing periodic reservation.
>> + * @wait_timer:         Timer used to wait before re-queuing.
>>   * @dwc2_tt:            Pointer to our tt info (or NULL if no tt).
>>   * @ttport:             Port number within our tt.
>>   * @tt_buffer_dirty     True if clear_tt_buffer_complete is pending
>>   * @unreserve_pending:  True if we planned to unreserve but haven't yet.
>>   * @schedule_low_speed: True if we have a low/full speed component (either the
>>   *                   host is in low/full speed mode or do_split).
>> + * @want_wait:          We should wait before re-queuing; only matters for non-
>> + *                      periodic transfers and is ignored for periodic ones.
>> + * @wait_timer_cancel:  Set to true to cancel the wait_timer.
>>   *
>>   * A Queue Head (QH) holds the static characteristics of an endpoint and
>>   * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
>> @@ -353,11 +357,14 @@ struct dwc2_qh {
>>       u32 desc_list_sz;
>>       u32 *n_bytes;
>>       struct timer_list unreserve_timer;
>> +     struct timer_list wait_timer;
>>       struct dwc2_tt *dwc_tt;
>>       int ttport;
>>       unsigned tt_buffer_dirty:1;
>>       unsigned unreserve_pending:1;
>>       unsigned schedule_low_speed:1;
>> +     unsigned want_wait:1;
>> +     unsigned wait_timer_cancel:1;
>>  };
>>
>>  /**
>> @@ -388,6 +395,7 @@ struct dwc2_qh {
>>   * @n_desc:             Number of DMA descriptors for this QTD
>>   * @isoc_frame_index_last: Last activated frame (packet) index, used in
>>   *                      descriptor DMA mode only
>> + * @num_naks:           Number of NAKs received on this QTD.
>>   * @urb:                URB for this transfer
>>   * @qh:                 Queue head for this QTD
>>   * @qtd_list_entry:     For linking to the QH's list of QTDs
>> @@ -418,6 +426,7 @@ struct dwc2_qtd {
>>       u8 error_count;
>>       u8 n_desc;
>>       u16 isoc_frame_index_last;
>> +     u16 num_naks;
>>       struct dwc2_hcd_urb *urb;
>>       struct dwc2_qh *qh;
>>       struct list_head qtd_list_entry;
>> diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
>> index 28a8210710b1..aad3abd2ddf2 100644
>> --- a/drivers/usb/dwc2/hcd_intr.c
>> +++ b/drivers/usb/dwc2/hcd_intr.c
>> @@ -52,6 +52,12 @@
>>  #include "core.h"
>>  #include "hcd.h"
>>
>> +/*
>> + * If we get this many NAKs on a split transaction we'll slow down
>> + * retransmission.  A 1 here means delay after the first NAK.
>> + */
>> +#define DWC2_NAKS_BEFORE_DELAY               3
>> +
>>  /* This function is for debug only */
>>  static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
>>  {
>> @@ -1200,11 +1206,25 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
>>       /*
>>        * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
>>        * interrupt. Re-start the SSPLIT transfer.
>> +      *
>> +      * Normally for non-periodic transfers we'll retry right away, but to
>> +      * avoid interrupt storms we'll wait before retrying if we've got
>> +      * several NAKs. If we didn't do this we'd retry directly from the
>> +      * interrupt handler and could end up quickly getting another
>> +      * interrupt (another NAK), which we'd retry.
>> +      *
>> +      * Note that in DMA mode software only gets involved to re-send NAKed
>> +      * transfers for split transactions, so we only need to apply this
>> +      * delaying logic when handling splits. In non-DMA mode presumably we
>> +      * might want a similar delay if someone can demonstrate this problem
>> +      * affects that code path too.
>>        */
>>       if (chan->do_split) {
>>               if (chan->complete_split)
>>                       qtd->error_count = 0;
>>               qtd->complete_split = 0;
>> +             qtd->num_naks++;
>> +             qtd->qh->want_wait = qtd->num_naks >= DWC2_NAKS_BEFORE_DELAY;
>>               dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
>>               goto handle_nak_done;
>>       }
>> diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
>> index 3ae8b1bbaa55..bea0aadd756e 100644
>> --- a/drivers/usb/dwc2/hcd_queue.c
>> +++ b/drivers/usb/dwc2/hcd_queue.c
>> @@ -57,6 +57,9 @@
>>  /* Wait this long before releasing periodic reservation */
>>  #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
>>
>> +/* If we get a NAK, wait this long before retrying */
>> +#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1))
>> +
>>  /**
>>   * dwc2_periodic_channel_available() - Checks that a channel is available for a
>>   * periodic transfer
>> @@ -1439,6 +1442,55 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
>>       list_del_init(&qh->qh_list_entry);
>>  }
>>
>> +/**
>> + * dwc2_wait_timer_fn() - Timer function to re-queue after waiting
>> + *
>> + * As per the spec, a NAK indicates that "a function is temporarily unable to
>> + * transmit or receive data, but will eventually be able to do so without need
>> + * of host intervention".
>> + *
>> + * That means that when we encounter a NAK we're supposed to retry.
>> + *
>> + * ...but if we retry right away (from the interrupt handler that saw the NAK)
>> + * then we can end up with an interrupt storm (if the other side keeps NAKing
>> + * us) because on slow enough CPUs it could take us longer to get out of the
>> + * interrupt routine than it takes for the device to send another NAK.  That
>> + * leads to a constant stream of NAK interrupts and the CPU locks.
>> + *
>> + * ...so instead of retrying right away in the case of a NAK we'll set a timer
>> + * to retry some time later.  This function handles that timer and moves the
>> + * qh back to the "inactive" list, then queues transactions.
>> + *
>> + * @data: Pointer to a qh to re-schedule.
>> + */
>> +static void dwc2_wait_timer_fn(unsigned long data)
>> +{
>> +     struct dwc2_qh *qh = (struct dwc2_qh *)data;
>> +     struct dwc2_hsotg *hsotg = qh->hsotg;
>> +     unsigned long flags;
>> +
>> +     spin_lock_irqsave(&hsotg->lock, flags);
>> +
>> +     /*
>> +      * We'll set wait_timer_cancel to true if we want to cancel this
>> +      * operation in dwc2_hcd_qh_unlink().
>> +      */
>> +     if (!qh->wait_timer_cancel) {
>> +             enum dwc2_transaction_type tr_type;
>> +
>> +             qh->want_wait = false;
>> +
>> +             list_move(&qh->qh_list_entry,
>> +                       &hsotg->non_periodic_sched_inactive);
>> +
>> +             tr_type = dwc2_hcd_select_transactions(hsotg);
>> +             if (tr_type != DWC2_TRANSACTION_NONE)
>> +                     dwc2_hcd_queue_transactions(hsotg, tr_type);
>> +     }
>> +
>> +     spin_unlock_irqrestore(&hsotg->lock, flags);
>> +}
>> +
>>  /**
>>   * dwc2_qh_init() - Initializes a QH structure
>>   *
>> @@ -1468,6 +1520,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
>>       qh->hsotg = hsotg;
>>       setup_timer(&qh->unreserve_timer, dwc2_unreserve_timer_fn,
>>                   (unsigned long)qh);
>> +     setup_timer(&qh->wait_timer, dwc2_wait_timer_fn, (unsigned long)qh);
>
> Kees Cook started to replace setup_timer() with the new timer_setup(). I'm not sure if it's okay to use the deprecated function and replace all of them later.

I'm happy to do it either way.  Personally I'd rather see my patch
land as-is and then have a followup patch that converts to
timer_setup().  That makes it easier for people like me who are always
backporting to older kernels.  I'm also happy to either post that
patch myself or have someone else do it.


-Doug


From daniel.lezcano at linaro.org  Sun Oct 29 14:20:27 2017
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Sun, 29 Oct 2017 22:20:27 +0100
Subject: [PATCH 10/17] clocksource/drivers/rockchip: pr_err() strings should
 end with newlines
In-Reply-To: <1509312035-17368-1-git-send-email-daniel.lezcano@linaro.org>
References: <c4d8b83b-b884-415b-8c92-b195de1dae7f@linaro.org>
 <1509312035-17368-1-git-send-email-daniel.lezcano@linaro.org>
Message-ID: <1509312035-17368-10-git-send-email-daniel.lezcano@linaro.org>

From: Arvind Yadav <arvind.yadav.cs at gmail.com>

pr_err() messages should end with a new-line to avoid other messages being
concatenated.

Signed-off-by: Arvind Yadav <arvind.yadav.cs at gmail.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano at linaro.org>
---
 drivers/clocksource/rockchip_timer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index c27f4c8..33f370d 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -274,7 +274,7 @@ static int __init rk_clksrc_init(struct device_node *np)
 		TIMER_NAME, rk_clksrc->freq, 250, 32,
 		clocksource_mmio_readl_down);
 	if (ret) {
-		pr_err("Failed to register clocksource");
+		pr_err("Failed to register clocksource\n");
 		goto out_clocksource;
 	}
 
-- 
2.7.4



From jeffy.chen at rock-chips.com  Sun Oct 29 19:15:28 2017
From: jeffy.chen at rock-chips.com (jeffy)
Date: Mon, 30 Oct 2017 10:15:28 +0800
Subject: [RFC PATCH v10 0/7] PCI: rockchip: Move PCIe WAKE# handling into
 pci core
In-Reply-To: <1872710.P2f02irZl9@aspire.rjw.lan>
References: <20171027072612.26565-1-jeffy.chen@rock-chips.com>
 <1872710.P2f02irZl9@aspire.rjw.lan>
Message-ID: <59F68B40.8050506@rock-chips.com>

Hi Rafael,

thanks for your reply.

On 10/28/2017 05:07 PM, Rafael J. Wysocki wrote:
> Overall, I don't quite like the direction this is going into, but I need to
> have a deeper look.  Which may take some time, so please bear with me.
>
ok, i'll wait for your comments, thanks :)

> Thanks,
> Rafael




From balbi at kernel.org  Mon Oct 30 01:32:17 2017
From: balbi at kernel.org (Felipe Balbi)
Date: Mon, 30 Oct 2017 10:32:17 +0200
Subject: [PATCH v2] usb: dwc2: host: Don't retry NAKed transactions right
 away
In-Reply-To: <CAD=FV=WK_9AsutYhOTh9HMXwac1PJEXtHvXUYnztGmp6H3gbWg@mail.gmail.com>
References: <20171026202200.6417-1-dianders@chromium.org>
 <60370001.40630.1509205907119@email.1und1.de>
 <CAD=FV=WK_9AsutYhOTh9HMXwac1PJEXtHvXUYnztGmp6H3gbWg@mail.gmail.com>
Message-ID: <87h8uhdoj2.fsf@linux.intel.com>


Hi,

Doug Anderson <dianders at chromium.org> writes:
> Hi,
>
> On Sat, Oct 28, 2017 at 8:51 AM, Stefan Wahren <stefan.wahren at i2se.com> wrote:
>> Hi Doug,
>>
>> [add Felipe since this should go through his tree]
>
> Ah.  Sorry Felipe!  I know you've landed some dwc2 stuff in the past

No problems :-)

> but for some reason get_maintainer didn't ID you so I thought maybe
> you weren't doing it anymore.  Please let me know if you'd like me to
> send this to you again with collected Reviewed-by and Tested-by tags.

Yeah, please resend with all tags collected, however let's wait for a
week or so and give other people time to catch up. I already sent my
pull request to Greg, this would, anyway, go into the -rc cycle.

Please add a Cc stable tag too, if necessary.

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 832 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20171030/da3c9ba5/attachment-0001.sig>

From ulf.hansson at linaro.org  Mon Oct 30 04:40:08 2017
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Mon, 30 Oct 2017 12:40:08 +0100
Subject: [PATCH v2 0/5] mmc: dw_mmc: Fix the CTO timer patch,
 plus the DTO timer
In-Reply-To: <20171012201118.23570-1-dianders@chromium.org>
References: <20171012201118.23570-1-dianders@chromium.org>
Message-ID: <CAPDyKFqaZxGJyJRB36-K3zVK_-V637ge1S6bpiQjbfDe_5PhLw@mail.gmail.com>

On 12 October 2017 at 22:11, Douglas Anderson <dianders at chromium.org> wrote:
> Recently we landed 03de19212ea3 ("mmc: dw_mmc: introduce timer for
> broken command transfer over scheme").  I found a bunch of problems
> with that patch, so this series attempts to solve some of them.
>
> This also fixes the DTO timer in some of the same ways even though I
> haven't personally seen problems with the DTO timer.
>
> NOTE: this series has only been lighly tested so far.  I can at least
> reproduce the need for the CTO timer on one of my devices and so I can
> confirm that part still works.  As mentioned in the 3rd patch I also
> ran the mmc_test kernel module on this and did manage to see the 3rd
> patch doing something useful.
>
> Changes in v2:
> - Removed extra "int i"
> - Fix the DTO timeout calculation new for v2
> - Cleanup the DTO timer new for v2
>
> Douglas Anderson (5):
>   mmc: dw_mmc: cancel the CTO timer after a voltage switch
>   mmc: dw_mmc: Fix the CTO timeout calculation
>   mmc: dw_mmc: Add locking to the CTO timer
>   mmc: dw_mmc: Fix the DTO timeout calculation
>   mmc: dw_mmc: Cleanup the DTO timer like the CTO one
>
>  drivers/mmc/host/dw_mmc.c | 162 +++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 146 insertions(+), 16 deletions(-)
>

Douglas, Jaehoon,

I decided to pick patch 1->4 for fixes and the patch 5 for next, that
should help us to get them more tested, while Jaehoon is still
catching up.

I can add ack/drop patches for yet a couple of days this week.

Kind regards
Uffe


From dianders at chromium.org  Mon Oct 30 10:08:01 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Mon, 30 Oct 2017 10:08:01 -0700
Subject: [PATCH v3 2/2] usb: dwc2: host: Convert hcd_queue to timer_setup
In-Reply-To: <20171030170802.14489-1-dianders@chromium.org>
References: <20171030170802.14489-1-dianders@chromium.org>
Message-ID: <20171030170802.14489-2-dianders@chromium.org>

Convert the timers in hcd_queue to use the new timer_setup() call
introduced in commit 686fef928bba ("timer: Prepare to change timer
callback argument type").

Suggested-by: Stefan Wahren <stefan.wahren at i2se.com>
Signed-off-by: Douglas Anderson <dianders at chromium.org>
Cc: Kees Cook <keescook at chromium.org>
---

Changes in v3:
- Convert hcd_queue to timer_setup new for v3

 drivers/usb/dwc2/hcd_queue.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index bea0aadd756e..6f5b5c8b0467 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -1275,11 +1275,11 @@ static void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
  * release the reservation.  This worker is called after the appropriate
  * delay.
  *
- * @work: Pointer to a qh unreserve_work.
+ * @t: Pointer to unreserve_timer in a qh.
  */
-static void dwc2_unreserve_timer_fn(unsigned long data)
+static void dwc2_unreserve_timer_fn(struct timer_list *t)
 {
-	struct dwc2_qh *qh = (struct dwc2_qh *)data;
+	struct dwc2_qh *qh = from_timer(qh, t, unreserve_timer);
 	struct dwc2_hsotg *hsotg = qh->hsotg;
 	unsigned long flags;
 
@@ -1461,11 +1461,11 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
  * to retry some time later.  This function handles that timer and moves the
  * qh back to the "inactive" list, then queues transactions.
  *
- * @data: Pointer to a qh to re-schedule.
+ * @t: Pointer to wait_timer in a qh.
  */
-static void dwc2_wait_timer_fn(unsigned long data)
+static void dwc2_wait_timer_fn(struct timer_list *t)
 {
-	struct dwc2_qh *qh = (struct dwc2_qh *)data;
+	struct dwc2_qh *qh = from_timer(qh, t, wait_timer);
 	struct dwc2_hsotg *hsotg = qh->hsotg;
 	unsigned long flags;
 
@@ -1518,9 +1518,8 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 
 	/* Initialize QH */
 	qh->hsotg = hsotg;
-	setup_timer(&qh->unreserve_timer, dwc2_unreserve_timer_fn,
-		    (unsigned long)qh);
-	setup_timer(&qh->wait_timer, dwc2_wait_timer_fn, (unsigned long)qh);
+	timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0);
+	timer_setup(&qh->wait_timer, dwc2_wait_timer_fn, 0);
 	qh->ep_type = ep_type;
 	qh->ep_is_in = ep_is_in;
 
-- 
2.15.0.rc2.357.g7e34df9404-goog



From dianders at chromium.org  Mon Oct 30 10:08:00 2017
From: dianders at chromium.org (Douglas Anderson)
Date: Mon, 30 Oct 2017 10:08:00 -0700
Subject: [PATCH v3 1/2] usb: dwc2: host: Don't retry NAKed transactions right
 away
Message-ID: <20171030170802.14489-1-dianders@chromium.org>

On rk3288-veyron devices on Chrome OS it was found that plugging in an
Arduino-based USB device could cause the system to lockup, especially
if the CPU Frequency was at one of the slower operating points (like
100 MHz / 200 MHz).

Upon tracing, I found that the following was happening:
* The USB device (full speed) was connected to a high speed hub and
  then to the rk3288.  Thus, we were dealing with split transactions,
  which is all handled in software on dwc2.
* Userspace was initiating a BULK IN transfer
* When we sent the SSPLIT (to start the split transaction), we got an
  ACK.  Good.  Then we issued the CSPLIT.
* When we sent the CSPLIT, we got back a NAK.  We immediately (from
  the interrupt handler) started to retry and sent another SSPLIT.
* The device kept NAKing our CSPLIT, so we kept ping-ponging between
  sending a SSPLIT and a CSPLIT, each time sending from the interrupt
  handler.
* The handling of the interrupts was (because of the low CPU speed and
  the inefficiency of the dwc2 interrupt handler) was actually taking
  _longer_ than it took the other side to send the ACK/NAK.  Thus we
  were _always_ in the USB interrupt routine.
* The fact that USB interrupts were always going off was preventing
  other things from happening in the system.  This included preventing
  the system from being able to transition to a higher CPU frequency.

As I understand it, there is no requirement to retry super quickly
after a NAK, we just have to retry sometime in the future.  Thus one
solution to the above is to just add a delay between getting a NAK and
retrying the transmission.  If this delay is sufficiently long to get
out of the interrupt routine then the rest of the system will be able
to make forward progress.  Even a 25 us delay would probably be
enough, but we'll be extra conservative and try to delay 1 ms (the
exact amount depends on HZ and the accuracy of the jiffy and how close
the current jiffy is to ticking, but could be as much as 20 ms or as
little as 1 ms).

Presumably adding a delay like this could impact the USB throughput,
so we only add the delay with repeated NAKs.

NOTE: Upon further testing of a pl2303 serial adapter, I found that
this fix may help with problems there.  Specifically I found that the
pl2303 serial adapters tend to respond with a NAK when they have
nothing to say and thus we end with this same sequence.

Signed-off-by: Douglas Anderson <dianders at chromium.org>
Cc: stable at vger.kernel.org
Reviewed-by: Julius Werner <jwerner at chromium.org>
Tested-by: Stefan Wahren <stefan.wahren at i2se.com>
---

Changes in v3:
- Add tested-by for Stefan Wahren
- Sent to Felipe Balbi as candiate to land this.
- Add Cc for stable (it's always been broken so go as far is as easy)

Changes in v2:
- Address http://crosreview.com/737520 feedback

 drivers/usb/dwc2/core.h      |  1 +
 drivers/usb/dwc2/hcd.c       |  7 ++++
 drivers/usb/dwc2/hcd.h       |  9 +++++
 drivers/usb/dwc2/hcd_intr.c  | 20 +++++++++++
 drivers/usb/dwc2/hcd_queue.c | 81 +++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 8367d4f985c1..c0807e558726 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -962,6 +962,7 @@ struct dwc2_hsotg {
 	} flags;
 
 	struct list_head non_periodic_sched_inactive;
+	struct list_head non_periodic_sched_waiting;
 	struct list_head non_periodic_sched_active;
 	struct list_head *non_periodic_qh_ptr;
 	struct list_head periodic_sched_inactive;
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index c2631145f404..ed92ae78dcf9 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -653,6 +653,10 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
 	list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
 			    qh_list_entry)
 		dev_dbg(hsotg->dev, "    %p\n", qh);
+	dev_dbg(hsotg->dev, "  NP waiting sched:\n");
+	list_for_each_entry(qh, &hsotg->non_periodic_sched_waiting,
+			    qh_list_entry)
+		dev_dbg(hsotg->dev, "    %p\n", qh);
 	dev_dbg(hsotg->dev, "  NP active sched:\n");
 	list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
 			    qh_list_entry)
@@ -1812,6 +1816,7 @@ static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
 static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
 {
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
+	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_waiting);
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
 	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
@@ -4989,6 +4994,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
 
 	/* Free memory for QH/QTD lists */
 	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
+	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_waiting);
 	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
 	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
 	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
@@ -5151,6 +5157,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
 
 	/* Initialize the non-periodic schedule */
 	INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
+	INIT_LIST_HEAD(&hsotg->non_periodic_sched_waiting);
 	INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
 
 	/* Initialize the periodic schedule */
diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h
index 11c3c145b793..af4f4360e8b7 100644
--- a/drivers/usb/dwc2/hcd.h
+++ b/drivers/usb/dwc2/hcd.h
@@ -313,12 +313,16 @@ struct dwc2_hs_transfer_time {
  *                      descriptor and indicates original XferSize value for the
  *                      descriptor
  * @unreserve_timer:    Timer for releasing periodic reservation.
+ * @wait_timer:         Timer used to wait before re-queuing.
  * @dwc2_tt:            Pointer to our tt info (or NULL if no tt).
  * @ttport:             Port number within our tt.
  * @tt_buffer_dirty     True if clear_tt_buffer_complete is pending
  * @unreserve_pending:  True if we planned to unreserve but haven't yet.
  * @schedule_low_speed: True if we have a low/full speed component (either the
  *			host is in low/full speed mode or do_split).
+ * @want_wait:          We should wait before re-queuing; only matters for non-
+ *                      periodic transfers and is ignored for periodic ones.
+ * @wait_timer_cancel:  Set to true to cancel the wait_timer.
  *
  * A Queue Head (QH) holds the static characteristics of an endpoint and
  * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
@@ -353,11 +357,14 @@ struct dwc2_qh {
 	u32 desc_list_sz;
 	u32 *n_bytes;
 	struct timer_list unreserve_timer;
+	struct timer_list wait_timer;
 	struct dwc2_tt *dwc_tt;
 	int ttport;
 	unsigned tt_buffer_dirty:1;
 	unsigned unreserve_pending:1;
 	unsigned schedule_low_speed:1;
+	unsigned want_wait:1;
+	unsigned wait_timer_cancel:1;
 };
 
 /**
@@ -388,6 +395,7 @@ struct dwc2_qh {
  * @n_desc:             Number of DMA descriptors for this QTD
  * @isoc_frame_index_last: Last activated frame (packet) index, used in
  *                      descriptor DMA mode only
+ * @num_naks:           Number of NAKs received on this QTD.
  * @urb:                URB for this transfer
  * @qh:                 Queue head for this QTD
  * @qtd_list_entry:     For linking to the QH's list of QTDs
@@ -418,6 +426,7 @@ struct dwc2_qtd {
 	u8 error_count;
 	u8 n_desc;
 	u16 isoc_frame_index_last;
+	u16 num_naks;
 	struct dwc2_hcd_urb *urb;
 	struct dwc2_qh *qh;
 	struct list_head qtd_list_entry;
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index 28a8210710b1..aad3abd2ddf2 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -52,6 +52,12 @@
 #include "core.h"
 #include "hcd.h"
 
+/*
+ * If we get this many NAKs on a split transaction we'll slow down
+ * retransmission.  A 1 here means delay after the first NAK.
+ */
+#define DWC2_NAKS_BEFORE_DELAY		3
+
 /* This function is for debug only */
 static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
 {
@@ -1200,11 +1206,25 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
 	/*
 	 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
 	 * interrupt. Re-start the SSPLIT transfer.
+	 *
+	 * Normally for non-periodic transfers we'll retry right away, but to
+	 * avoid interrupt storms we'll wait before retrying if we've got
+	 * several NAKs. If we didn't do this we'd retry directly from the
+	 * interrupt handler and could end up quickly getting another
+	 * interrupt (another NAK), which we'd retry.
+	 *
+	 * Note that in DMA mode software only gets involved to re-send NAKed
+	 * transfers for split transactions, so we only need to apply this
+	 * delaying logic when handling splits. In non-DMA mode presumably we
+	 * might want a similar delay if someone can demonstrate this problem
+	 * affects that code path too.
 	 */
 	if (chan->do_split) {
 		if (chan->complete_split)
 			qtd->error_count = 0;
 		qtd->complete_split = 0;
+		qtd->num_naks++;
+		qtd->qh->want_wait = qtd->num_naks >= DWC2_NAKS_BEFORE_DELAY;
 		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
 		goto handle_nak_done;
 	}
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 3ae8b1bbaa55..bea0aadd756e 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -57,6 +57,9 @@
 /* Wait this long before releasing periodic reservation */
 #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
 
+/* If we get a NAK, wait this long before retrying */
+#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1))
+
 /**
  * dwc2_periodic_channel_available() - Checks that a channel is available for a
  * periodic transfer
@@ -1439,6 +1442,55 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
 	list_del_init(&qh->qh_list_entry);
 }
 
+/**
+ * dwc2_wait_timer_fn() - Timer function to re-queue after waiting
+ *
+ * As per the spec, a NAK indicates that "a function is temporarily unable to
+ * transmit or receive data, but will eventually be able to do so without need
+ * of host intervention".
+ *
+ * That means that when we encounter a NAK we're supposed to retry.
+ *
+ * ...but if we retry right away (from the interrupt handler that saw the NAK)
+ * then we can end up with an interrupt storm (if the other side keeps NAKing
+ * us) because on slow enough CPUs it could take us longer to get out of the
+ * interrupt routine than it takes for the device to send another NAK.  That
+ * leads to a constant stream of NAK interrupts and the CPU locks.
+ *
+ * ...so instead of retrying right away in the case of a NAK we'll set a timer
+ * to retry some time later.  This function handles that timer and moves the
+ * qh back to the "inactive" list, then queues transactions.
+ *
+ * @data: Pointer to a qh to re-schedule.
+ */
+static void dwc2_wait_timer_fn(unsigned long data)
+{
+	struct dwc2_qh *qh = (struct dwc2_qh *)data;
+	struct dwc2_hsotg *hsotg = qh->hsotg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+
+	/*
+	 * We'll set wait_timer_cancel to true if we want to cancel this
+	 * operation in dwc2_hcd_qh_unlink().
+	 */
+	if (!qh->wait_timer_cancel) {
+		enum dwc2_transaction_type tr_type;
+
+		qh->want_wait = false;
+
+		list_move(&qh->qh_list_entry,
+			  &hsotg->non_periodic_sched_inactive);
+
+		tr_type = dwc2_hcd_select_transactions(hsotg);
+		if (tr_type != DWC2_TRANSACTION_NONE)
+			dwc2_hcd_queue_transactions(hsotg, tr_type);
+	}
+
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
 /**
  * dwc2_qh_init() - Initializes a QH structure
  *
@@ -1468,6 +1520,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 	qh->hsotg = hsotg;
 	setup_timer(&qh->unreserve_timer, dwc2_unreserve_timer_fn,
 		    (unsigned long)qh);
+	setup_timer(&qh->wait_timer, dwc2_wait_timer_fn, (unsigned long)qh);
 	qh->ep_type = ep_type;
 	qh->ep_is_in = ep_is_in;
 
@@ -1628,6 +1681,16 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 		dwc2_do_unreserve(hsotg, qh);
 		spin_unlock_irqrestore(&hsotg->lock, flags);
 	}
+
+	/*
+	 * We don't have the lock so we can safely wait until the wait timer
+	 * finishes.  Of course, at this point in time we'd better have set
+	 * wait_timer_active to false so if this timer was still pending it
+	 * won't do anything anyway, but we want it to finish before we free
+	 * memory.
+	 */
+	del_timer_sync(&qh->wait_timer);
+
 	dwc2_host_put_tt_info(hsotg, qh->dwc_tt);
 
 	if (qh->desc_list)
@@ -1663,9 +1726,16 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 		qh->start_active_frame = hsotg->frame_number;
 		qh->next_active_frame = qh->start_active_frame;
 
-		/* Always start in inactive schedule */
-		list_add_tail(&qh->qh_list_entry,
-			      &hsotg->non_periodic_sched_inactive);
+		if (qh->want_wait) {
+			list_add_tail(&qh->qh_list_entry,
+				      &hsotg->non_periodic_sched_waiting);
+			qh->wait_timer_cancel = false;
+			mod_timer(&qh->wait_timer,
+				  jiffies + DWC2_RETRY_WAIT_DELAY + 1);
+		} else {
+			list_add_tail(&qh->qh_list_entry,
+				      &hsotg->non_periodic_sched_inactive);
+		}
 		return 0;
 	}
 
@@ -1695,6 +1765,9 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 
 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
+	/* If the wait_timer is pending, this will stop it from acting */
+	qh->wait_timer_cancel = true;
+
 	if (list_empty(&qh->qh_list_entry))
 		/* QH is not in a schedule */
 		return;
@@ -1903,7 +1976,7 @@ void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 	if (dwc2_qh_is_non_per(qh)) {
 		dwc2_hcd_qh_unlink(hsotg, qh);
 		if (!list_empty(&qh->qtd_list))
-			/* Add back to inactive non-periodic schedule */
+			/* Add back to inactive/waiting non-periodic schedule */
 			dwc2_hcd_qh_add(hsotg, qh);
 		return;
 	}
-- 
2.15.0.rc2.357.g7e34df9404-goog



From dianders at chromium.org  Mon Oct 30 10:14:54 2017
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 30 Oct 2017 10:14:54 -0700
Subject: [PATCH v2] usb: dwc2: host: Don't retry NAKed transactions right
 away
In-Reply-To: <87h8uhdoj2.fsf@linux.intel.com>
References: <20171026202200.6417-1-dianders@chromium.org>
 <60370001.40630.1509205907119@email.1und1.de>
 <CAD=FV=WK_9AsutYhOTh9HMXwac1PJEXtHvXUYnztGmp6H3gbWg@mail.gmail.com>
 <87h8uhdoj2.fsf@linux.intel.com>
Message-ID: <CAD=FV=UsYccsvicnce8wDpt3LaLQE23wdc7a4-m7OOhNS2JKgA@mail.gmail.com>

Hi,

On Mon, Oct 30, 2017 at 1:32 AM, Felipe Balbi <balbi at kernel.org> wrote:
>
> Hi,
>
> Doug Anderson <dianders at chromium.org> writes:
>> Hi,
>>
>> On Sat, Oct 28, 2017 at 8:51 AM, Stefan Wahren <stefan.wahren at i2se.com> wrote:
>>> Hi Doug,
>>>
>>> [add Felipe since this should go through his tree]
>>
>> Ah.  Sorry Felipe!  I know you've landed some dwc2 stuff in the past
>
> No problems :-)
>
>> but for some reason get_maintainer didn't ID you so I thought maybe
>> you weren't doing it anymore.  Please let me know if you'd like me to
>> send this to you again with collected Reviewed-by and Tested-by tags.
>
> Yeah, please resend with all tags collected, however let's wait for a
> week or so and give other people time to catch up. I already sent my
> pull request to Greg, this would, anyway, go into the -rc cycle.

Doh!  I just re-read this one more time (after sending v3) and
realized I had read it incorrectly.  I read it as "please send the
patch with the tags and I'll wait a week before landing", but you
actually said "please wait a week before re-sending".  Sorry for the
noise.  In the very least, you should be on the "To" line now so if
anyone else has any extra tags it should be very easy for you to see
them.

Right that there's no massive urgency.  It's been broken forever.


> Please add a Cc stable tag too, if necessary.

Good point.  It's a little weird since it doesn't "fix" any specific
commit, so I guess it will be up to stable folks to decide how far to
go back.  The dwc2 devices I work with are actually on 3.14, but we
have some pretty massive backports related to dwc2 there...


-Doug


From keescook at chromium.org  Mon Oct 30 14:25:06 2017
From: keescook at chromium.org (Kees Cook)
Date: Mon, 30 Oct 2017 14:25:06 -0700
Subject: [PATCH v3 2/2] usb: dwc2: host: Convert hcd_queue to timer_setup
In-Reply-To: <20171030170802.14489-2-dianders@chromium.org>
References: <20171030170802.14489-1-dianders@chromium.org>
 <20171030170802.14489-2-dianders@chromium.org>
Message-ID: <CAGXu5jK08M=LXuMo2rRzxHwYOokC0ua2pXCHnxR4DOW5Wb73BA@mail.gmail.com>

On Mon, Oct 30, 2017 at 10:08 AM, Douglas Anderson
<dianders at chromium.org> wrote:
> Convert the timers in hcd_queue to use the new timer_setup() call
> introduced in commit 686fef928bba ("timer: Prepare to change timer
> callback argument type").
>
> Suggested-by: Stefan Wahren <stefan.wahren at i2se.com>
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> Cc: Kees Cook <keescook at chromium.org>

Acked-by: Kees Cook <keescook at chromium.org>

This matches my automated Coccinelle output for this code. (Actually,
it's better because it fixes the documentation too.) Please feel free
to take the patch into -next in advance of the global replacement.

Thanks!

-Kees

> ---
>
> Changes in v3:
> - Convert hcd_queue to timer_setup new for v3
>
>  drivers/usb/dwc2/hcd_queue.c | 17 ++++++++---------
>  1 file changed, 8 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
> index bea0aadd756e..6f5b5c8b0467 100644
> --- a/drivers/usb/dwc2/hcd_queue.c
> +++ b/drivers/usb/dwc2/hcd_queue.c
> @@ -1275,11 +1275,11 @@ static void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
>   * release the reservation.  This worker is called after the appropriate
>   * delay.
>   *
> - * @work: Pointer to a qh unreserve_work.
> + * @t: Pointer to unreserve_timer in a qh.
>   */
> -static void dwc2_unreserve_timer_fn(unsigned long data)
> +static void dwc2_unreserve_timer_fn(struct timer_list *t)
>  {
> -       struct dwc2_qh *qh = (struct dwc2_qh *)data;
> +       struct dwc2_qh *qh = from_timer(qh, t, unreserve_timer);
>         struct dwc2_hsotg *hsotg = qh->hsotg;
>         unsigned long flags;
>
> @@ -1461,11 +1461,11 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
>   * to retry some time later.  This function handles that timer and moves the
>   * qh back to the "inactive" list, then queues transactions.
>   *
> - * @data: Pointer to a qh to re-schedule.
> + * @t: Pointer to wait_timer in a qh.
>   */
> -static void dwc2_wait_timer_fn(unsigned long data)
> +static void dwc2_wait_timer_fn(struct timer_list *t)
>  {
> -       struct dwc2_qh *qh = (struct dwc2_qh *)data;
> +       struct dwc2_qh *qh = from_timer(qh, t, wait_timer);
>         struct dwc2_hsotg *hsotg = qh->hsotg;
>         unsigned long flags;
>
> @@ -1518,9 +1518,8 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
>
>         /* Initialize QH */
>         qh->hsotg = hsotg;
> -       setup_timer(&qh->unreserve_timer, dwc2_unreserve_timer_fn,
> -                   (unsigned long)qh);
> -       setup_timer(&qh->wait_timer, dwc2_wait_timer_fn, (unsigned long)qh);
> +       timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0);
> +       timer_setup(&qh->wait_timer, dwc2_wait_timer_fn, 0);
>         qh->ep_type = ep_type;
>         qh->ep_is_in = ep_is_in;
>
> --
> 2.15.0.rc2.357.g7e34df9404-goog
>



-- 
Kees Cook
Pixel Security


From heiko at sntech.de  Mon Oct 30 16:01:08 2017
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 31 Oct 2017 00:01:08 +0100
Subject: [PATCH v6 00/10] rockchip: kevin: Enable edp display
In-Reply-To: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
Message-ID: <2449324.8EdsLz1NaV@phil>

Hi Jeffy, Sean,

Am Donnerstag, 19. Oktober 2017, 11:48:02 CET schrieb Jeffy Chen:
> 
> Make edp display works on chromebook kevin(at least for boot animation).
> 
> Also solve some issues i meet during the bringup.
> 
> Changes in v6:
> Don't change order of rockchip_drm_psr_register().
> 
> Changes in v5:
> Call the destroy hook in the error handling path like in unbind().
> Call the destroy hook in the error handling path like in unbind().
> Update cleanup order in unbind().
> Add disable to unbind(), and inline clk_prepare_enable() with bind().
> 
> Jeffy Chen (10):
>   arm64: dts: rockchip: Enable edp disaplay on kevin
>   drm/rockchip: analogix_dp: Remove unnecessary init code
>   drm/bridge: analogix: Do not use device's drvdata
>   drm/bridge: analogix_dp: Fix connector and encoder cleanup
>   drm/rockchip: analogix_dp: Add a sanity check for
>     rockchip_drm_psr_register()
>   drm/rockchip: dw-mipi-dsi: Fix error handling path
>   drm/rockchip: inno_hdmi: Fix error handling path
>   drm/bridge/synopsys: dw-hdmi: Add missing bridge detach
>   drm/bridge/synopsys: dw-hdmi: Do not use device's drvdata
>   drm/rockchip: dw_hdmi: Fix error handling path

As I was just looking at the edp dts change in patch1 again, does this
series also contain a fix for the issue below [0] ?

I'm still seeing this on 4.14-rc6 with the most recent drm tree merged in.


Heiko

[0]

[   27.960120] BUG: scheduling while atomic: kworker/1:1/68/0x00000002
[   27.974429] Modules linked in: rockchipdrm dw_hdmi analogix_dp drm_kms_helper panel_simple crc32_ce drm crct10dif_ce rockchip_saradc pwm_bl pwm_cros_ec rockchip_thermal ip_tables x_tabl
es ipv6 smsc95xx smsc75xx ax88179_178a asix usbnet phy_rockchip_pcie pcie_rockchip
[   28.008769] CPU: 1 PID: 68 Comm: kworker/1:1 Tainted: G        W       4.14.0-rc7-03201-g12490811b353 #559
[   28.008774] Hardware name: Google Kevin (DT)
[   28.008825] Workqueue: events analogix_dp_psr_work [rockchipdrm]
[   28.008828] Call trace:
[   28.008838] [<ffff000008088d60>] dump_backtrace+0x0/0x378
[   28.008842] [<ffff0000080890ec>] show_stack+0x14/0x20
[   28.008847] [<ffff0000089b04d8>] dump_stack+0x9c/0xbc
[   28.008852] [<ffff0000080ec4b4>] __schedule_bug+0x4c/0x70
[   28.008856] [<ffff0000089c4828>] __schedule+0x558/0x5e8
[   28.008859] [<ffff0000089c48f0>] schedule+0x38/0xa0
[   28.008864] [<ffff0000089c8194>] schedule_hrtimeout_range_clock+0x84/0xe8
[   28.008867] [<ffff0000089c8208>] schedule_hrtimeout_range+0x10/0x18
[   28.008870] [<ffff0000089c7c74>] usleep_range+0x64/0x78
[   28.008882] [<ffff000000ef56e4>] analogix_dp_transfer+0x16c/0xa88 [analogix_dp]
[   28.008891] [<ffff000000ef2190>] analogix_dpaux_transfer+0x10/0x18 [analogix_dp]
[   28.008950] [<ffff000000ddbb1c>] drm_dp_dpcd_access+0x4c/0xf8 [drm_kms_helper]
[   28.008994] [<ffff000000ddbbe4>] drm_dp_dpcd_write+0x1c/0x28 [drm_kms_helper]
[   28.009002] [<ffff000000ef2130>] analogix_dp_disable_psr+0x60/0xb0 [analogix_dp]
[   28.009036] [<ffff000000f8398c>] analogix_dp_psr_work+0x4c/0xc0 [rockchipdrm]
[   28.009040] [<ffff0000080dff44>] process_one_work+0x1d4/0x348
[   28.009043] [<ffff0000080e0100>] worker_thread+0x48/0x470
[   28.009048] [<ffff0000080e63d4>] kthread+0x12c/0x130
[   28.009052] [<ffff000008084b88>] ret_from_fork+0x10/0x18



From jeffy.chen at rock-chips.com  Mon Oct 30 21:37:43 2017
From: jeffy.chen at rock-chips.com (JeffyChen)
Date: Tue, 31 Oct 2017 12:37:43 +0800
Subject: [PATCH v6 00/10] rockchip: kevin: Enable edp display
In-Reply-To: <2449324.8EdsLz1NaV@phil>
References: <20171019034812.13768-1-jeffy.chen@rock-chips.com>
 <2449324.8EdsLz1NaV@phil>
Message-ID: <59F7FE17.80405@rock-chips.com>

Hi Heiko,

On 10/31/2017 07:01 AM, Heiko Stuebner wrote:
> As I was just looking at the edp dts change in patch1 again, does this
> series also contain a fix for the issue below [0] ?
>
> I'm still seeing this on 4.14-rc6 with the most recent drm tree merged in.
>
i saw that too, it should due to our psr code...i think Zain has solved 
these in chromeos kernel, i will ask Zain if he have time to upstream 
them, or maybe i'll try to upstream them.
>
> Heiko
>
> [0]
>
> [   27.960120] BUG: scheduling while atomic: kworker/1:1/68/0x00000002
> [   27.974429] Modules linked in: rockchipdrm dw_hdmi analogix_dp drm_kms_helper panel_simple crc32_ce drm crct10dif_ce rockchip_saradc pwm_bl pwm_cros_ec rockchip_thermal ip_tables x_tabl
> es ipv6 smsc95xx smsc75xx ax88179_178a asix usbnet phy_rockchip_pcie pcie_rockchip
> [   28.008769] CPU: 1 PID: 68 Comm: kworker/1:1 Tainted: G        W       4.14.0-rc7-03201-g12490811b353 #559
> [   28.008774] Hardware name: Google Kevin (DT)
> [   28.008825] Workqueue: events analogix_dp_psr_work [rockchipdrm]
> [   28.008828] Call trace:
> [   28.008838] [<ffff000008088d60>] dump_backtrace+0x0/0x378
> [   28.008842] [<ffff0000080890ec>] show_stack+0x14/0x20
> [   28.008847] [<ffff0000089b04d8>] dump_stack+0x9c/0xbc
> [   28.008852] [<ffff0000080ec4b4>] __schedule_bug+0x4c/0x70
> [   28.008856] [<ffff0000089c4828>] __schedule+0x558/0x5e8
> [   28.008859] [<ffff0000089c48f0>] schedule+0x38/0xa0
> [   28.008864] [<ffff0000089c8194>] schedule_hrtimeout_range_clock+0x84/0xe8
> [   28.008867] [<ffff0000089c8208>] schedule_hrtimeout_range+0x10/0x18
> [   28.008870] [<ffff0000089c7c74>] usleep_range+0x64/0x78
> [   28.008882] [<ffff000000ef56e4>] analogix_dp_transfer+0x16c/0xa88 [analogix_dp]
> [   28.008891] [<ffff000000ef2190>] analogix_dpaux_transfer+0x10/0x18 [analogix_dp]
> [   28.008950] [<ffff000000ddbb1c>] drm_dp_dpcd_access+0x4c/0xf8 [drm_kms_helper]
> [   28.008994] [<ffff000000ddbbe4>] drm_dp_dpcd_write+0x1c/0x28 [drm_kms_helper]
> [   28.009002] [<ffff000000ef2130>] analogix_dp_disable_psr+0x60/0xb0 [analogix_dp]
> [   28.009036] [<ffff000000f8398c>] analogix_dp_psr_work+0x4c/0xc0 [rockchipdrm]
> [   28.009040] [<ffff0000080dff44>] process_one_work+0x1d4/0x348
> [   28.009043] [<ffff0000080e0100>] worker_thread+0x48/0x470
> [   28.009048] [<ffff0000080e63d4>] kthread+0x12c/0x130
> [   28.009052] [<ffff000008084b88>] ret_from_fork+0x10/0x18
>
>
>
>




From shawn.lin at rock-chips.com  Tue Oct 31 00:05:20 2017
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 31 Oct 2017 15:05:20 +0800
Subject: [PATCH v2 0/5] mmc: dw_mmc: Fix the CTO timer patch, plus the DTO
 timer
In-Reply-To: <CAPDyKFqaZxGJyJRB36-K3zVK_-V637ge1S6bpiQjbfDe_5PhLw@mail.gmail.com>
References: <20171012201118.23570-1-dianders@chromium.org>
 <CAPDyKFqaZxGJyJRB36-K3zVK_-V637ge1S6bpiQjbfDe_5PhLw@mail.gmail.com>
Message-ID: <da14d1a3-c85f-b415-1cb6-b5d1f3a1ed7a@rock-chips.com>

Hi Ulf,

On 2017/10/30 19:40, Ulf Hansson wrote:
> On 12 October 2017 at 22:11, Douglas Anderson <dianders at chromium.org> wrote:
>> Recently we landed 03de19212ea3 ("mmc: dw_mmc: introduce timer for
>> broken command transfer over scheme").  I found a bunch of problems
>> with that patch, so this series attempts to solve some of them.
>>
>> This also fixes the DTO timer in some of the same ways even though I
>> haven't personally seen problems with the DTO timer.
>>
>> NOTE: this series has only been lighly tested so far.  I can at least
>> reproduce the need for the CTO timer on one of my devices and so I can
>> confirm that part still works.  As mentioned in the 3rd patch I also
>> ran the mmc_test kernel module on this and did manage to see the 3rd
>> patch doing something useful.
>>
>> Changes in v2:
>> - Removed extra "int i"
>> - Fix the DTO timeout calculation new for v2
>> - Cleanup the DTO timer new for v2
>>
>> Douglas Anderson (5):
>>    mmc: dw_mmc: cancel the CTO timer after a voltage switch
>>    mmc: dw_mmc: Fix the CTO timeout calculation
>>    mmc: dw_mmc: Add locking to the CTO timer
>>    mmc: dw_mmc: Fix the DTO timeout calculation
>>    mmc: dw_mmc: Cleanup the DTO timer like the CTO one
>>
>>   drivers/mmc/host/dw_mmc.c | 162 +++++++++++++++++++++++++++++++++++++++++-----
>>   1 file changed, 146 insertions(+), 16 deletions(-)
>>
> 
> Douglas, Jaehoon,
> 
> I decided to pick patch 1->4 for fixes and the patch 5 for next, that
> should help us to get them more tested, while Jaehoon is still
> catching up.
> 
> I can add ack/drop patches for yet a couple of days this week.

Patch 4 introduce a warning:

warning: unused variable ?irqflags? [-Wunused-variable]

irqflags should be introduced in patch 5 in the same place.
As it seems patch 5 will be candidate for 4.15, so could you please
help fix patch 4 and 5 manually? Or Doug need to resend patch 4 and 5?



> 
> Kind regards
> Uffe
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
> 



From linus.walleij at linaro.org  Tue Oct 31 02:14:22 2017
From: linus.walleij at linaro.org (Linus Walleij)
Date: Tue, 31 Oct 2017 10:14:22 +0100
Subject: [PATCH] pinctrl: rockchip: Add iomux-route switching support for
 rk3288
In-Reply-To: <20171021085310.16246-1-heiko@sntech.de>
References: <20171021085310.16246-1-heiko@sntech.de>
Message-ID: <CACRpkdazu_ESJNZQJe-LEMn51mLFmrO33Y7RNjF0i_Pp=67-nw@mail.gmail.com>

On Sat, Oct 21, 2017 at 10:53 AM, Heiko Stuebner <heiko at sntech.de> wrote:

> The rk3288 also has one function that can be routed to one of two pins,
> the hdmi cec functionality can use either gpio7c0 or gpio7c7.
> So add the route switching support for it.
>
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> Tested-by: Hans Verkuil <hans.verkuil at cisco.com>

Patch applied with David's review tag.

Yours,
Linus Walleij


From balbi at kernel.org  Tue Oct 31 03:22:36 2017
From: balbi at kernel.org (Felipe Balbi)
Date: Tue, 31 Oct 2017 12:22:36 +0200
Subject: [PATCH v2] usb: dwc2: host: Don't retry NAKed transactions right
 away
In-Reply-To: <CAD=FV=UsYccsvicnce8wDpt3LaLQE23wdc7a4-m7OOhNS2JKgA@mail.gmail.com>
References: <20171026202200.6417-1-dianders@chromium.org>
 <60370001.40630.1509205907119@email.1und1.de>
 <CAD=FV=WK_9AsutYhOTh9HMXwac1PJEXtHvXUYnztGmp6H3gbWg@mail.gmail.com>
 <87h8uhdoj2.fsf@linux.intel.com>
 <CAD=FV=UsYccsvicnce8wDpt3LaLQE23wdc7a4-m7OOhNS2JKgA@mail.gmail.com>
Message-ID: <87lgjrd3bn.fsf@linux.intel.com>

Doug Anderson <dianders at chromium.org> writes:

> Hi,
>
> On Mon, Oct 30, 2017 at 1:32 AM, Felipe Balbi <balbi at kernel.org> wrote:
>>
>> Hi,
>>
>> Doug Anderson <dianders at chromium.org> writes:
>>> Hi,
>>>
>>> On Sat, Oct 28, 2017 at 8:51 AM, Stefan Wahren <stefan.wahren at i2se.com> wrote:
>>>> Hi Doug,
>>>>
>>>> [add Felipe since this should go through his tree]
>>>
>>> Ah.  Sorry Felipe!  I know you've landed some dwc2 stuff in the past
>>
>> No problems :-)
>>
>>> but for some reason get_maintainer didn't ID you so I thought maybe
>>> you weren't doing it anymore.  Please let me know if you'd like me to
>>> send this to you again with collected Reviewed-by and Tested-by tags.
>>
>> Yeah, please resend with all tags collected, however let's wait for a
>> week or so and give other people time to catch up. I already sent my
>> pull request to Greg, this would, anyway, go into the -rc cycle.
>
> Doh!  I just re-read this one more time (after sending v3) and
> realized I had read it incorrectly.  I read it as "please send the

that's okay :-) s**t happens

> patch with the tags and I'll wait a week before landing", but you
> actually said "please wait a week before re-sending".  Sorry for the
> noise.  In the very least, you should be on the "To" line now so if
> anyone else has any extra tags it should be very easy for you to see
> them.
>
> Right that there's no massive urgency.  It's been broken forever.

alright then :-)

>> Please add a Cc stable tag too, if necessary.
>
> Good point.  It's a little weird since it doesn't "fix" any specific
> commit, so I guess it will be up to stable folks to decide how far to
> go back.  The dwc2 devices I work with are actually on 3.14, but we
> have some pretty massive backports related to dwc2 there...

fair enough

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 832 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20171031/7c5c4e72/attachment.sig>

From heiko at sntech.de  Tue Oct 31 09:31:18 2017
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Tue, 31 Oct 2017 17:31:18 +0100
Subject: rk3288 Firefly Reload: 'reboot' doesn't work
In-Reply-To: <b88abf6d-d95f-3eca-91d1-65fcb749cb22@xs4all.nl>
References: <b88abf6d-d95f-3eca-91d1-65fcb749cb22@xs4all.nl>
Message-ID: <1729506.TeohltKTGL@diego>

Hi Hans,

sorry this took a bit longer,

Am Freitag, 20. Oktober 2017, 11:06:21 CET schrieb Hans Verkuil:
> If I run 'reboot' to reboot my Firefly Reload board the last thing I see
> on the serial port is "reboot: Restarting system", but it never actually
> restarts.
> 
> This is really annoying, but I have no idea where to look. Any suggestions?

I just ran reboot on my original rk3288-firefly with 4.14-rc6 and reboot worked 
just fine. So it looks like at least on the kernel side it seems to check out.
Especially, as we do use the cold-reset mode on Rockchip socs so everything
should get set to its correct reset-state.

-- What bootloader do you use on the board?

I'm using mainline uboot from somewhere last year right now
[ U-Boot 2016.11-01442-g5699f71-dirty (Nov 29 2016 - 23:23:39 +0100) ]


-- What happens when you turn off cpufreq in your kernel?

I.e. one possible thing I could think of would be your cpu frequency
being low and the regulator not having the right voltage for the 600MHz
boot frequency. 

But that would make me wonder, why it would work at all. I.e. while
the default for vdd_cpu is 1.0V, the lowest in the opp-table is 0.9V
which _is_ the correct voltage even for the 600MHz reset frequency.


Heiko


From geert+renesas at glider.be  Tue Oct 31 11:11:32 2017
From: geert+renesas at glider.be (Geert Uytterhoeven)
Date: Tue, 31 Oct 2017 19:11:32 +0100
Subject: [PATCH v2 3/5] [RFC] soc: mediatek: Use GENPD_FLAG_ACTIVE_WAKEUP
In-Reply-To: <1509473494-19740-1-git-send-email-geert+renesas@glider.be>
References: <1509473494-19740-1-git-send-email-geert+renesas@glider.be>
Message-ID: <1509473494-19740-4-git-send-email-geert+renesas@glider.be>

Set the newly introduced GENPD_FLAG_ACTIVE_WAKEUP, which allows to
remove the driver's own flag-based callback.

Signed-off-by: Geert Uytterhoeven <geert+renesas at glider.be>
---
This must not be applied before "PM / Domain: Enable genpd users to
specify default active wakeup behavior" has landed upstream, hence the
"RFC".

Compile-tested only.

v2:
  - New.
---
 drivers/soc/mediatek/mtk-scpsys.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index e1ce8b1b5090aa0a..e570b6af2e6ffbdd 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -361,17 +361,6 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
 	return ret;
 }
 
-static bool scpsys_active_wakeup(struct device *dev)
-{
-	struct generic_pm_domain *genpd;
-	struct scp_domain *scpd;
-
-	genpd = pd_to_genpd(dev->pm_domain);
-	scpd = container_of(genpd, struct scp_domain, genpd);
-
-	return scpd->data->active_wakeup;
-}
-
 static void init_clks(struct platform_device *pdev, struct clk **clk)
 {
 	int i;
@@ -466,7 +455,8 @@ static struct scp *init_scp(struct platform_device *pdev,
 		genpd->name = data->name;
 		genpd->power_off = scpsys_power_off;
 		genpd->power_on = scpsys_power_on;
-		genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
+		if (scpd->data->active_wakeup)
+			genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP;
 	}
 
 	return scp;
-- 
2.7.4



From dianders at chromium.org  Tue Oct 31 11:14:53 2017
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 31 Oct 2017 11:14:53 -0700
Subject: [PATCH v2 0/5] mmc: dw_mmc: Fix the CTO timer patch,
 plus the DTO timer
In-Reply-To: <da14d1a3-c85f-b415-1cb6-b5d1f3a1ed7a@rock-chips.com>
References: <20171012201118.23570-1-dianders@chromium.org>
 <CAPDyKFqaZxGJyJRB36-K3zVK_-V637ge1S6bpiQjbfDe_5PhLw@mail.gmail.com>
 <da14d1a3-c85f-b415-1cb6-b5d1f3a1ed7a@rock-chips.com>
Message-ID: <CAD=FV=UFmKBonWJVRT-OPb-FY0GzHgf0HZo=NAZuxSk0e6URWA@mail.gmail.com>

Hi,

On Tue, Oct 31, 2017 at 12:05 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Hi Ulf,
>
>
> On 2017/10/30 19:40, Ulf Hansson wrote:
>>
>> On 12 October 2017 at 22:11, Douglas Anderson <dianders at chromium.org>
>> wrote:
>>>
>>> Recently we landed 03de19212ea3 ("mmc: dw_mmc: introduce timer for
>>> broken command transfer over scheme").  I found a bunch of problems
>>> with that patch, so this series attempts to solve some of them.
>>>
>>> This also fixes the DTO timer in some of the same ways even though I
>>> haven't personally seen problems with the DTO timer.
>>>
>>> NOTE: this series has only been lighly tested so far.  I can at least
>>> reproduce the need for the CTO timer on one of my devices and so I can
>>> confirm that part still works.  As mentioned in the 3rd patch I also
>>> ran the mmc_test kernel module on this and did manage to see the 3rd
>>> patch doing something useful.
>>>
>>> Changes in v2:
>>> - Removed extra "int i"
>>> - Fix the DTO timeout calculation new for v2
>>> - Cleanup the DTO timer new for v2
>>>
>>> Douglas Anderson (5):
>>>    mmc: dw_mmc: cancel the CTO timer after a voltage switch
>>>    mmc: dw_mmc: Fix the CTO timeout calculation
>>>    mmc: dw_mmc: Add locking to the CTO timer
>>>    mmc: dw_mmc: Fix the DTO timeout calculation
>>>    mmc: dw_mmc: Cleanup the DTO timer like the CTO one
>>>
>>>   drivers/mmc/host/dw_mmc.c | 162
>>> +++++++++++++++++++++++++++++++++++++++++-----
>>>   1 file changed, 146 insertions(+), 16 deletions(-)
>>>
>>
>> Douglas, Jaehoon,
>>
>> I decided to pick patch 1->4 for fixes and the patch 5 for next, that
>> should help us to get them more tested, while Jaehoon is still
>> catching up.
>>
>> I can add ack/drop patches for yet a couple of days this week.
>
>
> Patch 4 introduce a warning:
>
> warning: unused variable ?irqflags? [-Wunused-variable]
>
> irqflags should be introduced in patch 5 in the same place.
> As it seems patch 5 will be candidate for 4.15, so could you please
> help fix patch 4 and 5 manually? Or Doug need to resend patch 4 and 5?

Thanks for catching this and sorry for the dumb screwup.  Ulf: I'm
happy to do do whatever makes it easiest for you.  If you want me to
re-post it should be very quick.

-Doug


