<div dir="ltr"><div dir="ltr"><div>Hi Emil,<br></div><div>Thanks for your feedback</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Feb 25, 2020 at 1:35 AM Emil Velikov <<a href="mailto:emil.l.velikov@gmail.com">emil.l.velikov@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Fri, 21 Feb 2020 at 11:15, Kevin Tang <<a href="mailto:kevin3.tang@gmail.com" target="_blank">kevin3.tang@gmail.com</a>> wrote:<br>
><br>
> Adds DPU(Display Processor Unit) support for the Unisoc's display subsystem.<br>
> It's support multi planes, scaler, rotation, PQ(Picture Quality) and more.<br>
><br>
> Cc: Orson Zhai <<a href="mailto:orsonzhai@gmail.com" target="_blank">orsonzhai@gmail.com</a>><br>
> Cc: Baolin Wang <<a href="mailto:baolin.wang@linaro.org" target="_blank">baolin.wang@linaro.org</a>><br>
> Cc: Chunyan Zhang <<a href="mailto:zhang.lyra@gmail.com" target="_blank">zhang.lyra@gmail.com</a>><br>
> Signed-off-by: Kevin Tang <<a href="mailto:kevin.tang@unisoc.com" target="_blank">kevin.tang@unisoc.com</a>><br>
> ---<br>
>  drivers/gpu/drm/sprd/Makefile       |   6 +-<br>
>  drivers/gpu/drm/sprd/disp_lib.c     |  59 +++<br>
>  drivers/gpu/drm/sprd/disp_lib.h     |  21 +<br>
>  drivers/gpu/drm/sprd/dpu/Makefile   |   7 +<br>
>  drivers/gpu/drm/sprd/dpu/dpu_r2p0.c | 787 ++++++++++++++++++++++++++++++++++++<br>
>  drivers/gpu/drm/sprd/sprd_dpu.c     | 678 +++++++++++++++++++++++++++++++<br>
>  drivers/gpu/drm/sprd/sprd_dpu.h     | 130 ++++++<br>
>  drivers/gpu/drm/sprd/sprd_drm.c     |   1 +<br>
>  drivers/gpu/drm/sprd/sprd_drm.h     |   2 +<br>
>  9 files changed, 1690 insertions(+), 1 deletion(-)<br>
>  create mode 100644 drivers/gpu/drm/sprd/disp_lib.c<br>
>  create mode 100644 drivers/gpu/drm/sprd/disp_lib.h<br>
>  create mode 100644 drivers/gpu/drm/sprd/dpu/Makefile<br>
>  create mode 100644 drivers/gpu/drm/sprd/dpu/dpu_r2p0.c<br>
>  create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.c<br>
>  create mode 100644 drivers/gpu/drm/sprd/sprd_dpu.h<br>
><br>
> diff --git a/drivers/gpu/drm/sprd/Makefile b/drivers/gpu/drm/sprd/Makefile<br>
> index 63b8751..c94c8ac 100644<br>
> --- a/drivers/gpu/drm/sprd/Makefile<br>
> +++ b/drivers/gpu/drm/sprd/Makefile<br>
> @@ -4,4 +4,8 @@ ccflags-y += -Iinclude/drm<br>
><br>
>  subdir-ccflags-y += -I$(src)<br>
><br>
> -obj-y := sprd_drm.o<br>
> +obj-y := sprd_drm.o \<br>
> +       sprd_dpu.o<br>
> +<br>
> +obj-y += disp_lib.o<br>
> +obj-y += dpu/<br>
> diff --git a/drivers/gpu/drm/sprd/disp_lib.c b/drivers/gpu/drm/sprd/disp_lib.c<br>
> new file mode 100644<br>
> index 0000000..c887822<br>
> +++ b/drivers/gpu/drm/sprd/disp_lib.c<br>
> +++ b/drivers/gpu/drm/sprd/disp_lib.h<br>
<br>
These are completely unused. Drop them for now as well as their Makefile hunk.<br></blockquote><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">These function will be used in the encoder driver, i commit it with encoder driver.</span></span> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
> --- /dev/null<br>
> +++ b/drivers/gpu/drm/sprd/dpu/Makefile<br>
> @@ -0,0 +1,7 @@<br>
> +# SPDX-License-Identifier: GPL-2.0<br>
> +<br>
> +ifdef CONFIG_ARM64<br>
> +KBUILD_CFLAGS += -mstrict-align<br>
> +endif<br>
> +<br>
There is only a single case of this in the whole kernel. This is a strong<br>
indication that there is something wrong, perhaps. Why do we need this?<br></blockquote><div>Our HW controller registers(32bit) map to struct "dpu_reg",</div><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">so we can directly access the registers through the struct "dpu_reg",<span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"> rather than through</span></span> I/O(readl&writel).<br></span></span></div><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"><br></span></span></div><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">But we found </span></span>on ARM64, <span class="gmail-tlid-translation gmail-translation" lang="en"><span title="">if two adjacent member variables have the same value,</span></span></span></span></div><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"><span class="gmail-tlid-translation gmail-translation" lang="en"><span title=""><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">the gcc compiler maybe optimize them into a 64-bit value when compiling, <span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">access io registers with 64bit?<br></span></span></span></span></span></span></span></span></div><div><br></div><div>So we add "mstrict-align", do not permit unaligned accesses</div><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">We need to strictly follow the 32bit width to access the struct "dpu_reg", not 64bit.</span></span><br><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"><span class="gmail-tlid-translation gmail-translation" lang="en"><span title=""><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"></span></span><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"></span></span></span></span></span></span></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
> +obj-y += dpu_r2p0.o<br>
> diff --git a/drivers/gpu/drm/sprd/dpu/dpu_r2p0.c b/drivers/gpu/drm/sprd/dpu/dpu_r2p0.c<br>
> new file mode 100644<br>
> index 0000000..b96e2e2<br>
> --- /dev/null<br>
> +++ b/drivers/gpu/drm/sprd/dpu/dpu_r2p0.c<br>
> @@ -0,0 +1,787 @@<br>
> +// SPDX-License-Identifier: GPL-2.0<br>
> +/*<br>
> + * Copyright (C) 2019 Unisoc Inc.<br>
> + */<br>
> +<br>
> +#include <linux/delay.h><br>
> +#include <linux/wait.h><br>
> +#include <linux/workqueue.h><br>
> +#include "sprd_dpu.h"<br>
> +<br>
> +#define DISPC_INT_FBC_PLD_ERR_MASK     BIT(8)<br>
> +#define DISPC_INT_FBC_HDR_ERR_MASK     BIT(9)<br>
> +<br>
> +#define DISPC_INT_MMU_INV_WR_MASK      BIT(19)<br>
> +#define DISPC_INT_MMU_INV_RD_MASK      BIT(18)<br>
> +#define DISPC_INT_MMU_VAOR_WR_MASK     BIT(17)<br>
> +#define DISPC_INT_MMU_VAOR_RD_MASK     BIT(16)<br>
> +<br>
> +struct layer_reg {<br>
> +       u32 addr[4];<br>
> +       u32 ctrl;<br>
> +       u32 size;<br>
> +       u32 pitch;<br>
> +       u32 pos;<br>
> +       u32 alpha;<br>
> +       u32 ck;<br>
> +       u32 pallete;<br>
> +       u32 crop_start;<br>
> +};<br>
> +<br>
> +struct wb_region_reg {<br>
> +       u32 pos;<br>
> +       u32 size;<br>
> +};<br>
> +<br>
> +struct dpu_reg {<br>
...<br>
<br>
There are actual HW registers and we get the base via ioremap_nocache().<br>
Please add a small comment. <br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
> +static DECLARE_WAIT_QUEUE_HEAD(wait_queue);<br>
> +static bool panel_ready = true;<br>
> +static bool evt_update;<br>
> +static bool evt_stop;<br>
> +<br>
Using static variables tend to be an example of badly designed code.<br>
<br>
<br>
...<br>
<br>
> +static void dpu_uninit(struct dpu_context *ctx)<br>
<br>
Normally people use init - for initialization and fini for "uninitialization"<br>
<br>
<br>
> +enum {<br>
> +       DPU_LAYER_FORMAT_YUV422_2PLANE,<br>
> +       DPU_LAYER_FORMAT_YUV420_2PLANE,<br>
> +       DPU_LAYER_FORMAT_YUV420_3PLANE,<br>
> +       DPU_LAYER_FORMAT_ARGB8888,<br>
> +       DPU_LAYER_FORMAT_RGB565,<br>
> +       DPU_LAYER_FORMAT_XFBC_ARGB8888 = 8,<br>
> +       DPU_LAYER_FORMAT_XFBC_RGB565,<br>
> +       DPU_LAYER_FORMAT_MAX_TYPES,<br>
> +};<br>
> +<br>
> +enum {<br>
> +       DPU_LAYER_ROTATION_0,<br>
> +       DPU_LAYER_ROTATION_90,<br>
> +       DPU_LAYER_ROTATION_180,<br>
> +       DPU_LAYER_ROTATION_270,<br>
> +       DPU_LAYER_ROTATION_0_M,<br>
> +       DPU_LAYER_ROTATION_90_M,<br>
> +       DPU_LAYER_ROTATION_180_M,<br>
> +       DPU_LAYER_ROTATION_270_M,<br>
> +};<br>
> +<br>
<br>
<br>
Starting with one format and rotation is good. Others can be added as follow-up.<br>
Especially since FBC is something that is just becoming fashionable.<br></blockquote><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">FBC will be remove later.</span></span></div><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">All other options are required for layer format and rotation, <span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">these are the basic functions.</span></span></span></span></span></span></div><div>Why need to split it?<br></div><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"></span></span></span></span><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"></span></span></span></span></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
> +static void dpu_dpi_init(struct dpu_context *ctx)<br>
> +{<br>
<br>
...<br>
<br>
> +       } else if (ctx->if_type == SPRD_DISPC_IF_EDPI) {<br>
> +               /* use edpi as interface */<br>
> +               reg->dpu_cfg0 |= BIT(0);<br>
> +<br>
> +               /* use external te */<br>
> +               reg->dpi_ctrl |= BIT(10);<br>
> +<br>
> +               /* enable te */<br>
> +               reg->dpi_ctrl |= BIT(8);<br>
<br>
Try to avoid using BIT() randomly. A well chosen name, removes the need for a<br>
comment. Perhaps it's just me but the "enable foo" comments do not help much.<br>
<br>
...<br>
<br>
<br>
> +struct dpu_core_ops sharkl3_dpu_core_ops = {<br>
In general ops should be const.<br>
<br>
> +       .version = dpu_get_version,<br>
> +       .init = dpu_init,<br>
> +       .uninit = dpu_uninit,<br>
> +       .run = dpu_run,<br>
> +       .stop = dpu_stop,<br>
> +       .isr = dpu_isr,<br>
> +       .ifconfig = dpu_dpi_init,<br>
> +       .capability = dpu_capability,<br>
> +       .flip = dpu_flip,<br>
> +       .bg_color = dpu_bgcolor,<br>
> +       .enable_vsync = enable_vsync,<br>
> +       .disable_vsync = disable_vsync,<br>
<br>
... then again, we have only a single set of dpu_core_ops. So the whole<br>
abstraction layer seems unnessesary.<br></blockquote><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">Currently we only submitted one crtc(dsi), the crtc of DP(DisplayPort) will be added as follow-up.</span></span></div><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-"><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">So I hope to keep the current design</span></span></span></span></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
<br>
<br>
> +};<br>
> diff --git a/drivers/gpu/drm/sprd/sprd_dpu.c b/drivers/gpu/drm/sprd/sprd_dpu.c<br>
> new file mode 100644<br>
> index 0000000..331f236<br>
> --- /dev/null<br>
> +++ b/drivers/gpu/drm/sprd/sprd_dpu.c<br>
<br>
<br>
<br>
> +static int sprd_plane_atomic_check(struct drm_plane *plane,<br>
> +                                 struct drm_plane_state *state)<br>
> +{<br>
> +       DRM_DEBUG("%s()\n", __func__);<br>
> +<br>
This does not feel right. Here the driver must ensure that the state given will<br>
always work.<br>
<br>
Is the hardware so versatile that any permutation (given by userspace)<br>
will work?<br>
<br>
Same goes for the other atomic_check functions that are no-op.<br></blockquote><div>In fact, plane state check, we put in our HW abstraction layer, include</div><div>layer format, layer addr, rotation... so maybe there is no need to impliment atomic_check</div><div>funtion. I will remove later...<br> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
> +static void sprd_plane_atomic_disable(struct drm_plane *plane,<br>
> +                                    struct drm_plane_state *old_state)<br>
> +{<br>
> +       struct sprd_plane *p = to_sprd_plane(plane);<br>
> +<br>
> +       /*<br>
> +        * NOTE:<br>
> +        * The dpu->core->flip() will disable all the planes each time.<br>
> +        * So there is no need to impliment the atomic_disable() function.<br>
> +        * But this function can not be removed, because it will change<br>
> +        * to call atomic_update() callback instead. Which will cause<br>
> +        * kernel panic in sprd_plane_atomic_update().<br>
> +        *<br>
Why do we disable all the planes on flip? This is the first time I see such<br>
driver decision.<br></blockquote>Our layers commit to HW on atomic_flush, not in atomic_update.</div><div class="gmail_quote"><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">We will wait for all layers to be ready</span></span>, then flip.</div><div class="gmail_quote">So we need to disable all the planes before flip.<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
> +static void sprd_crtc_atomic_enable(struct drm_crtc *crtc,<br>
> +                                  struct drm_crtc_state *old_state)<br>
> +{<br>
> +       struct sprd_dpu *dpu = crtc_to_dpu(crtc);<br>
> +       static bool is_enabled = true;<br>
> +<br>
More static variables - please remove.<br>
<br>
<br>
<br>
> +static int sprd_dpu_init(struct sprd_dpu *dpu)<br>
> +{<br>
> +       struct dpu_context *ctx = &dpu->ctx;<br>
> +<br>
> +       down(&ctx->refresh_lock);<br>
> +<br>
Why do we need the semaphore? From a quick look all the other drivers are<br>
semaphore/lock free in their atomic codepath.<br>
<br>
One notable exception is the event_lock.<br></blockquote><div>Because sysfs debug driver, <span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">not uploaded</span></span> yet.<br></div><div>We will run or stop our display controller on sysfs debug driver, so we need to add semaphore lock to</div><div>protect atomic codepath. I will be remove it later...</div><div><br></div><div><span class="gmail-tlid-translation gmail-translation" lang="en"><span title="" class="gmail-">Maybe the statemachine "is_inited" is also not needed now.<br></span></span></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
<br>
> +       if (dpu->ctx.is_inited) {<br>
> +               up(&ctx->refresh_lock);<br>
> +               return 0;<br>
> +       }<br>
> +<br>
How can did this trigger? IMHO we either have a serious bug or the check is dead<br>
code.<br></blockquote><div>Sorry, this will be trigger on our sysfs debug driver, i will remove it. <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
> +       if (dpu->core && dpu->core->init)<br>
<br>
Using if dpu->core && dpu->core->FOO is a recurring pattern, yet they are always<br>
set. Unless needed we can kill the abstraction layer all together can call FOO<br>
directly.<br>
<br>
> --- /dev/null<br>
> +++ b/drivers/gpu/drm/sprd/sprd_dpu.h<br>
<br>
> +struct dpu_context {<br>
> +       unsigned long base;<br>
> +       const char *version;<br>
> +       int irq;<br>
> +       u8 if_type;<br>
> +       bool is_inited;<br>
> +       bool is_stopped;<br>
Nit: more natural names for these are "initialized" and "stopped"<br>
<br>
<br>
> +       struct videomode vm;<br>
> +       struct semaphore refresh_lock;<br>
I've mentioned it earlier - not 100% sure that the semaphore is needed. If it is<br>
please add a comment just above it.<br>
<br>
<br>
<br>
> +int sprd_dpu_run(struct sprd_dpu *dpu);<br>
> +int sprd_dpu_stop(struct sprd_dpu *dpu);<br>
> +<br>
These two functions seem to be unused in this patch. Let's drop them for now.<br></blockquote><div>The encoder driver will call it, so commit those with encoder driver? <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
Thanks<br>
Emil<br>
</blockquote></div></div>