Hi Robert,
On Wed, Jun 26, 2019 at 04:32:09PM +0300, Robert Chiras wrote:
> Currently, the MXSFB DRM driver only supports a panel. But, its output
> display signal can also be redirected to another encoder, like a DSI
> controller. In this case, that DSI controller may act like a drm_bridge.
> In order support this use-case too, this patch adds support for
> drm_bridge in mxsfb.
> 
> Signed-off-by: Robert Chiras <robert.chi...@nxp.com>
> ---
>  drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 46 
> +++++++++++++++++++++++++++++++++++---
>  drivers/gpu/drm/mxsfb/mxsfb_drv.c  | 46 
> +++++++++++++++++++++++++++++++++-----
>  drivers/gpu/drm/mxsfb/mxsfb_drv.h  |  4 +++-
>  drivers/gpu/drm/mxsfb/mxsfb_out.c  | 26 +++++++++++----------
>  drivers/gpu/drm/mxsfb/mxsfb_regs.h | 15 +++++++++++++
>  5 files changed, 116 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c 
> b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> index 93f4133..14bde024 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> @@ -93,8 +93,11 @@ static void mxsfb_set_bus_fmt(struct mxsfb_drm_private 
> *mxsfb)
>  
>       reg = readl(mxsfb->base + LCDC_CTRL);
>  
> -     if (mxsfb->connector.display_info.num_bus_formats)
> -             bus_format = mxsfb->connector.display_info.bus_formats[0];
> +     if (mxsfb->connector->display_info.num_bus_formats)
> +             bus_format = mxsfb->connector->display_info.bus_formats[0];
> +
> +     DRM_DEV_DEBUG_DRIVER(drm->dev, "Using bus_format: 0x%08X\n",
> +                          bus_format);
>  
>       reg &= ~CTRL_BUS_WIDTH_MASK;
>       switch (bus_format) {
> @@ -122,6 +125,9 @@ static void mxsfb_enable_controller(struct 
> mxsfb_drm_private *mxsfb)
>               clk_prepare_enable(mxsfb->clk_disp_axi);
>       clk_prepare_enable(mxsfb->clk);
>  
> +     writel(CTRL2_OUTSTANDING_REQS__REQ_16,
> +            mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
> +
>       /* If it was disabled, re-enable the mode again */
>       writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
>  
> @@ -131,12 +137,15 @@ static void mxsfb_enable_controller(struct 
> mxsfb_drm_private *mxsfb)
>       writel(reg, mxsfb->base + LCDC_VDCTRL4);
>  
>       writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
> +     writel(CTRL1_RECOVERY_ON_UNDERFLOW, mxsfb->base + LCDC_CTRL1 + REG_SET);
>  }
>  
>  static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
>  {
>       u32 reg;
>  
> +     writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_CLR);
> +
>       /*
>        * Even if we disable the controller here, it will still continue
>        * until its FIFOs are running out of data
> @@ -202,8 +211,9 @@ static dma_addr_t mxsfb_get_fb_paddr(struct 
> mxsfb_drm_private *mxsfb)
>  
>  static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
>  {
> +     struct drm_device *drm = mxsfb->pipe.crtc.dev;
>       struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
> -     const u32 bus_flags = mxsfb->connector.display_info.bus_flags;
> +     const u32 bus_flags = mxsfb->connector->display_info.bus_flags;
>       u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
>       int err;
>  
> @@ -227,6 +237,13 @@ static void mxsfb_crtc_mode_set_nofb(struct 
> mxsfb_drm_private *mxsfb)
>  
>       clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
>  
> +     DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
> +                          m->crtc_clock,
> +                          (int)(clk_get_rate(mxsfb->clk) / 1000));
> +     DRM_DEV_DEBUG_DRIVER(drm->dev, "Connector bus_flags: 0x%08X\n",
> +                          bus_flags);
> +     DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
> +
>       writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
>              TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
>              mxsfb->base + mxsfb->devdata->transfer_count);
> @@ -279,6 +296,7 @@ void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
>       dma_addr_t paddr;
>  
>       mxsfb_enable_axi_clk(mxsfb);
> +     writel(0, mxsfb->base + LCDC_CTRL);
>       mxsfb_crtc_mode_set_nofb(mxsfb);
>  
>       /* Write cur_buf as well to avoid an initial corrupt frame */
> @@ -302,6 +320,8 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private 
> *mxsfb,
>  {
>       struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
>       struct drm_crtc *crtc = &pipe->crtc;
> +     struct drm_framebuffer *fb = pipe->plane.state->fb;
> +     struct drm_framebuffer *old_fb = old_state->fb;
>       struct drm_pending_vblank_event *event;
>       dma_addr_t paddr;
>  
> @@ -324,4 +344,24 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private 
> *mxsfb,
>               writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
>               mxsfb_disable_axi_clk(mxsfb);
>       }
> +
> +     if (!fb || !old_fb)
> +             return;
> +
> +     /*
> +      * TODO: Currently, we only support pixel format change, but we need
> +      * also to care about size changes too
> +      */
> +     if (old_fb->format->format != fb->format->format) {
> +             struct drm_format_name_buf old_fmt_buf;
> +             struct drm_format_name_buf new_fmt_buf;
> +
> +             DRM_DEV_DEBUG_DRIVER(crtc->dev->dev,
> +                                  "Switching pixel format: %s -> %s\n",
> +                                  drm_get_format_name(old_fb->format->format,
> +                                                      &old_fmt_buf),
> +                                  drm_get_format_name(fb->format->format,
> +                                                      &new_fmt_buf));
> +             mxsfb_set_pixel_fmt(mxsfb, true);

This assumes mxsfb_set_pixel_fmt has two arguments which is being introduced
in the following commit. With that fixed:

Tested-by: Guido Günther <a...@sigxcpu.org> 

Cheers,
 -- Guido

> +     }
>  }
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c 
> b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
> index 6fafc90..0d171e9 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
> @@ -98,9 +98,25 @@ static void mxsfb_pipe_enable(struct 
> drm_simple_display_pipe *pipe,
>                             struct drm_crtc_state *crtc_state,
>                             struct drm_plane_state *plane_state)
>  {
> +     struct drm_connector *connector;
>       struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
>       struct drm_device *drm = pipe->plane.dev;
>  
> +     if (!mxsfb->connector) {
> +             list_for_each_entry(connector,
> +                                 &drm->mode_config.connector_list,
> +                                 head)
> +                     if (connector->encoder == &mxsfb->pipe.encoder) {
> +                             mxsfb->connector = connector;
> +                             break;
> +                     }
> +     }
> +
> +     if (!mxsfb->connector) {
> +             dev_warn(drm->dev, "No connector attached, using default\n");
> +             mxsfb->connector = &mxsfb->panel_connector;
> +     }
> +
>       pm_runtime_get_sync(drm->dev);
>       drm_panel_prepare(mxsfb->panel);
>       mxsfb_crtc_enable(mxsfb);
> @@ -126,6 +142,9 @@ static void mxsfb_pipe_disable(struct 
> drm_simple_display_pipe *pipe)
>               drm_crtc_send_vblank_event(crtc, event);
>       }
>       spin_unlock_irq(&drm->event_lock);
> +
> +     if (mxsfb->connector != &mxsfb->panel_connector)
> +             mxsfb->connector = NULL;
>  }
>  
>  static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
> @@ -223,16 +242,33 @@ static int mxsfb_load(struct drm_device *drm, unsigned 
> long flags)
>  
>       ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
>                       mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL,
> -                     &mxsfb->connector);
> +                     mxsfb->connector);
>       if (ret < 0) {
>               dev_err(drm->dev, "Cannot setup simple display pipe\n");
>               goto err_vblank;
>       }
>  
> -     ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector);
> -     if (ret) {
> -             dev_err(drm->dev, "Cannot connect panel\n");
> -             goto err_vblank;
> +     /*
> +      * Attach panel only if there is one.
> +      * If there is no panel attach, it must be a bridge. In this case, we
> +      * need a reference to its connector for a proper initialization.
> +      * We will do this check in pipe->enable(), since the connector won't
> +      * be attached to an encoder until then.
> +      */
> +
> +     if (mxsfb->panel) {
> +             ret = drm_panel_attach(mxsfb->panel, mxsfb->connector);
> +             if (ret) {
> +                     dev_err(drm->dev, "Cannot connect panel\n");
> +                     goto err_vblank;
> +             }
> +     } else if (mxsfb->bridge) {
> +             ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe,
> +                                                         mxsfb->bridge);
> +             if (ret) {
> +                     dev_err(drm->dev, "Cannot connect bridge\n");
> +                     goto err_vblank;
> +             }
>       }
>  
>       drm->mode_config.min_width      = MXSFB_MIN_XRES;
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h 
> b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
> index d975300..0b65b51 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.h
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
> @@ -27,8 +27,10 @@ struct mxsfb_drm_private {
>       struct clk                      *clk_disp_axi;
>  
>       struct drm_simple_display_pipe  pipe;
> -     struct drm_connector            connector;
> +     struct drm_connector            panel_connector;
> +     struct drm_connector            *connector;
>       struct drm_panel                *panel;
> +     struct drm_bridge               *bridge;
>  };
>  
>  int mxsfb_setup_crtc(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c 
> b/drivers/gpu/drm/mxsfb/mxsfb_out.c
> index 91e76f9..b9acf2b 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_out.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c
> @@ -22,7 +22,8 @@
>  static struct mxsfb_drm_private *
>  drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
>  {
> -     return container_of(connector, struct mxsfb_drm_private, connector);
> +     return container_of(connector, struct mxsfb_drm_private,
> +                         panel_connector);
>  }
>  
>  static int mxsfb_panel_get_modes(struct drm_connector *connector)
> @@ -77,22 +78,23 @@ static const struct drm_connector_funcs 
> mxsfb_panel_connector_funcs = {
>  int mxsfb_create_output(struct drm_device *drm)
>  {
>       struct mxsfb_drm_private *mxsfb = drm->dev_private;
> -     struct drm_panel *panel;
>       int ret;
>  
> -     ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel, 
> NULL);
> +     ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0,
> +                                       &mxsfb->panel, &mxsfb->bridge);
>       if (ret)
>               return ret;
>  
> -     mxsfb->connector.dpms = DRM_MODE_DPMS_OFF;
> -     mxsfb->connector.polled = 0;
> -     drm_connector_helper_add(&mxsfb->connector,
> -                     &mxsfb_panel_connector_helper_funcs);
> -     ret = drm_connector_init(drm, &mxsfb->connector,
> -                              &mxsfb_panel_connector_funcs,
> -                              DRM_MODE_CONNECTOR_Unknown);
> -     if (!ret)
> -             mxsfb->panel = panel;
> +     if (mxsfb->panel) {
> +             mxsfb->connector = &mxsfb->panel_connector;
> +             mxsfb->connector->dpms = DRM_MODE_DPMS_OFF;
> +             mxsfb->connector->polled = 0;
> +             drm_connector_helper_add(mxsfb->connector,
> +                                      &mxsfb_panel_connector_helper_funcs);
> +             ret = drm_connector_init(drm, mxsfb->connector,
> +                                      &mxsfb_panel_connector_funcs,
> +                                      DRM_MODE_CONNECTOR_Unknown);
> +     }
>  
>       return ret;
>  }
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_regs.h 
> b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
> index 932d7ea..71426aa 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_regs.h
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
> @@ -14,19 +14,31 @@
>  
>  #define LCDC_CTRL                    0x00
>  #define LCDC_CTRL1                   0x10
> +#define LCDC_V4_CTRL2                        0x20
>  #define LCDC_V3_TRANSFER_COUNT               0x20
>  #define LCDC_V4_TRANSFER_COUNT               0x30
>  #define LCDC_V4_CUR_BUF                      0x40
>  #define LCDC_V4_NEXT_BUF             0x50
>  #define LCDC_V3_CUR_BUF                      0x30
>  #define LCDC_V3_NEXT_BUF             0x40
> +#define LCDC_TIMING                  0x60
>  #define LCDC_VDCTRL0                 0x70
>  #define LCDC_VDCTRL1                 0x80
>  #define LCDC_VDCTRL2                 0x90
>  #define LCDC_VDCTRL3                 0xa0
>  #define LCDC_VDCTRL4                 0xb0
> +#define LCDC_DVICTRL0                        0xc0
> +#define LCDC_DVICTRL1                        0xd0
> +#define LCDC_DVICTRL2                        0xe0
> +#define LCDC_DVICTRL3                        0xf0
> +#define LCDC_DVICTRL4                        0x100
> +#define LCDC_V4_DATA                 0x180
> +#define LCDC_V3_DATA                 0x1b0
>  #define LCDC_V4_DEBUG0                       0x1d0
>  #define LCDC_V3_DEBUG0                       0x1f0
> +#define LCDC_AS_CTRL                 0x210
> +#define LCDC_AS_BUF                  0x220
> +#define LCDC_AS_NEXT_BUF             0x230
>  
>  #define CTRL_SFTRST                  (1 << 31)
>  #define CTRL_CLKGATE                 (1 << 30)
> @@ -45,12 +57,15 @@
>  #define CTRL_DF24                    (1 << 1)
>  #define CTRL_RUN                     (1 << 0)
>  
> +#define CTRL1_RECOVERY_ON_UNDERFLOW  (1 << 24)
>  #define CTRL1_FIFO_CLEAR             (1 << 21)
>  #define CTRL1_SET_BYTE_PACKAGING(x)  (((x) & 0xf) << 16)
>  #define CTRL1_GET_BYTE_PACKAGING(x)  (((x) >> 16) & 0xf)
>  #define CTRL1_CUR_FRAME_DONE_IRQ_EN  (1 << 13)
>  #define CTRL1_CUR_FRAME_DONE_IRQ     (1 << 9)
>  
> +#define CTRL2_OUTSTANDING_REQS__REQ_16               (4 << 21)
> +
>  #define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
>  #define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
>  #define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff)
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-ker...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to