drm/msm/mdp5: Enhance operation mode for pipeline configuration
authorStephane Viau <sviau@codeaurora.org>
Fri, 13 Mar 2015 19:49:32 +0000 (15:49 -0400)
committerRob Clark <robdclark@gmail.com>
Wed, 1 Apr 2015 23:29:34 +0000 (19:29 -0400)
DSI and WB interfaces need a more complex pipeline configuration
than the current mdp5_ctl_set_intf().

For example, memory output connections need to be selected for
WB. Interface mode (Video vs. Command modes) also need to be
configured for DSI.

This change takes care of configuring the whole pipeline as far
as operation mode goes. DSI and WB interfaces will be added
later.

v2: rename macro to mdp5_cfg_intf_is_virtual() [pointed by Archit]

Signed-off-by: Stephane Viau <sviau@codeaurora.org>
[Remove temp bisectability hack -Rob]
Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h

index dba4d52cceebaeec609b95cdbcf27af495d5a545..4e90740c97497dd64fb509131d4f5a82859a3618 100644 (file)
@@ -84,6 +84,10 @@ const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_hn
 struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_hnd);
 int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_hnd);
 
+#define mdp5_cfg_intf_is_virtual(intf_type) ({ \
+       typeof(intf_type) __val = (intf_type);  \
+       (__val) >= INTF_VIRTUAL ? true : false; })
+
 struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
                uint32_t major, uint32_t minor);
 void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_hnd);
index bfba236daaa665f506f5858fa2abf2cef6b9b5a9..15136f17f8cec1fc4d00e50197a11f497323f5d5 100644 (file)
@@ -611,48 +611,17 @@ void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
 }
 
 /* set interface for routing crtc->encoder: */
-void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
-               enum mdp5_intf intf_id)
+void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
 {
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
-       uint32_t intf_sel;
-       unsigned long flags;
+       int lm = mdp5_crtc_get_lm(crtc);
 
        /* now that we know what irq's we want: */
-       mdp5_crtc->err.irqmask = intf2err(intf);
-       mdp5_crtc->vblank.irqmask = intf2vblank(intf);
+       mdp5_crtc->err.irqmask = intf2err(intf->num);
+       mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf);
        mdp_irq_update(&mdp5_kms->base);
 
-       spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
-       intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
-
-       switch (intf) {
-       case 0:
-               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK;
-               intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf_id);
-               break;
-       case 1:
-               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK;
-               intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf_id);
-               break;
-       case 2:
-               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK;
-               intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf_id);
-               break;
-       case 3:
-               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK;
-               intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf_id);
-               break;
-       default:
-               BUG();
-               break;
-       }
-
-       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
-       spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
-
-       DBG("%s: intf_sel=%08x", mdp5_crtc->name, intf_sel);
        mdp5_ctl_set_intf(mdp5_crtc->ctl, intf);
 }
 
index 151129032d165875477d870c8c6cca5b2245e1e6..a548113a8f68d0d6a3cd79fa2ce67d0bee741273 100644 (file)
  * requested by the client (in mdp5_crtc_mode_set()).
  */
 
+struct op_mode {
+       struct mdp5_interface intf;
+       /*
+        * TODO: add a state variable to control the pipeline
+        *
+        * eg: WB interface needs both buffer addresses to be committed +
+        * output buffers ready to be written into, before we can START.
+        */
+};
+
 struct mdp5_ctl {
        struct mdp5_ctl_manager *ctlm;
 
@@ -41,8 +51,8 @@ struct mdp5_ctl {
        /* whether this CTL has been allocated or not: */
        bool busy;
 
-       /* memory output connection (@see mdp5_ctl_mode): */
-       u32 mode;
+       /* Operation Mode Configuration for the Pipeline */
+       struct op_mode pipeline;
 
        /* REG_MDP5_CTL_*(<id>) registers access info + lock: */
        spinlock_t hw_lock;
@@ -94,19 +104,81 @@ u32 ctl_read(struct mdp5_ctl *ctl, u32 reg)
        return mdp5_read(mdp5_kms, reg);
 }
 
+static void set_display_intf(struct mdp5_kms *mdp5_kms,
+               struct mdp5_interface *intf)
+{
+       unsigned long flags;
+       u32 intf_sel;
+
+       spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
+       intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
+
+       switch (intf->num) {
+       case 0:
+               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK;
+               intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf->type);
+               break;
+       case 1:
+               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK;
+               intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf->type);
+               break;
+       case 2:
+               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK;
+               intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf->type);
+               break;
+       case 3:
+               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK;
+               intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf->type);
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
+       spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
+}
 
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf)
+static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
 {
        unsigned long flags;
-       static const enum mdp5_intfnum intfnum[] = {
-                       INTF0, INTF1, INTF2, INTF3,
-       };
+       u32 ctl_op = 0;
+
+       if (!mdp5_cfg_intf_is_virtual(intf->type))
+               ctl_op |= MDP5_CTL_OP_INTF_NUM(INTF0 + intf->num);
+
+       switch (intf->type) {
+       case INTF_DSI:
+               if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+                       ctl_op |= MDP5_CTL_OP_CMD_MODE;
+               break;
+
+       case INTF_WB:
+               if (intf->mode == MDP5_INTF_WB_MODE_LINE)
+                       ctl_op |= MDP5_CTL_OP_MODE(MODE_WB_2_LINE);
+               break;
+
+       default:
+               break;
+       }
 
        spin_lock_irqsave(&ctl->hw_lock, flags);
-       ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id),
-                       MDP5_CTL_OP_MODE(ctl->mode) |
-                       MDP5_CTL_OP_INTF_NUM(intfnum[intf]));
+       ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), ctl_op);
        spin_unlock_irqrestore(&ctl->hw_lock, flags);
+}
+
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
+{
+       struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
+       struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
+
+       memcpy(&ctl->pipeline.intf, intf, sizeof(*intf));
+
+       /* Virtual interfaces need not set a display intf (e.g.: Writeback) */
+       if (!mdp5_cfg_intf_is_virtual(intf->type))
+               set_display_intf(mdp5_kms, intf);
+
+       set_ctl_op(ctl, intf);
 
        return 0;
 }
@@ -303,7 +375,6 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
                }
                ctl->ctlm = ctl_mgr;
                ctl->id = c;
-               ctl->mode = MODE_NONE;
                ctl->reg_offset = ctl_cfg->base[c];
                ctl->flush_mask = MDP5_CTL_FLUSH_CTL;
                ctl->busy = false;
index ad48788efeea85e049727a26f5ed4053d303f99f..271d5ac429be276e73ffc9fda6a7f7463b54b8f2 100644 (file)
@@ -34,7 +34,8 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
  */
 struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc);
 
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf);
+struct mdp5_interface;
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf);
 
 int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable);
 
index af0e02fa4f4821ac7a71a4b641fde76db366a8cd..b18b381502a348bae94dd90310af20975ad0557f 100644 (file)
@@ -23,8 +23,7 @@
 
 struct mdp5_encoder {
        struct drm_encoder base;
-       int intf;
-       enum mdp5_intf intf_id;
+       struct mdp5_interface intf;
        spinlock_t intf_lock;   /* protect REG_MDP5_INTF_* registers */
        bool enabled;
        uint32_t bsc;
@@ -126,7 +125,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
        struct drm_device *dev = encoder->dev;
        struct drm_connector *connector;
-       int intf = mdp5_encoder->intf;
+       int intf = mdp5_encoder->intf.num;
        uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
        uint32_t display_v_start, display_v_end;
        uint32_t hsync_start_x, hsync_end_x;
@@ -188,7 +187,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
         * DISPLAY_V_START = (VBP * HCYCLE) + HBP
         * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
         */
-       if (mdp5_encoder->intf_id == INTF_eDP) {
+       if (mdp5_encoder->intf.type == INTF_eDP) {
                display_v_start += mode->htotal - mode->hsync_start;
                display_v_end -= mode->hsync_start - mode->hdisplay;
        }
@@ -224,14 +223,16 @@ static void mdp5_encoder_disable(struct drm_encoder *encoder)
 {
        struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
-       int intf = mdp5_encoder->intf;
+       int lm = mdp5_crtc_get_lm(encoder->crtc);
+       struct mdp5_interface *intf = &mdp5_encoder->intf;
+       int intfn = mdp5_encoder->intf.num;
        unsigned long flags;
 
        if (WARN_ON(!mdp5_encoder->enabled))
                return;
 
        spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0);
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
 
        /*
@@ -242,7 +243,7 @@ static void mdp5_encoder_disable(struct drm_encoder *encoder)
         * the settings changes for the new modeset (like new
         * scanout buffer) don't latch properly..
         */
-       mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf));
+       mdp_irq_wait(&mdp5_kms->base, intf2vblank(lm, intf));
 
        bs_set(mdp5_encoder, 0);
 
@@ -253,18 +254,17 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
 {
        struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
        struct mdp5_kms *mdp5_kms = get_kms(encoder);
-       int intf = mdp5_encoder->intf;
+       int intfn = mdp5_encoder->intf.num;
        unsigned long flags;
 
        if (WARN_ON(mdp5_encoder->enabled))
                return;
 
-       mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf,
-                       mdp5_encoder->intf_id);
+       mdp5_crtc_set_intf(encoder->crtc, &mdp5_encoder->intf);
 
        bs_set(mdp5_encoder, 1);
        spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
-       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1);
        spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
 
        mdp5_encoder->enabled = true;
@@ -278,8 +278,8 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
 };
 
 /* initialize encoder */
-struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
-               enum mdp5_intf intf_id)
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
+                               struct mdp5_interface *intf)
 {
        struct drm_encoder *encoder = NULL;
        struct mdp5_encoder *mdp5_encoder;
@@ -291,8 +291,7 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
                goto fail;
        }
 
-       mdp5_encoder->intf = intf;
-       mdp5_encoder->intf_id = intf_id;
+       memcpy(&mdp5_encoder->intf, intf, sizeof(mdp5_encoder->intf));
        encoder = &mdp5_encoder->base;
 
        spin_lock_init(&mdp5_encoder->intf_lock);
index 92b61db5754cbf71f9368011fda966cbb9cbabfa..390d9d2b688274872437b16c6c2a54d912b6eb6b 100644 (file)
@@ -223,8 +223,14 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
        }
 
        if (priv->hdmi) {
+               struct mdp5_interface intf = {
+                               .num    = 3,
+                               .type   = INTF_HDMI,
+                               .mode   = MDP5_INTF_MODE_NONE,
+               };
+
                /* Construct encoder for HDMI: */
-               encoder = mdp5_encoder_init(dev, 3, INTF_HDMI);
+               encoder = mdp5_encoder_init(dev, &intf);
                if (IS_ERR(encoder)) {
                        dev_err(dev->dev, "failed to construct encoder\n");
                        ret = PTR_ERR(encoder);
@@ -242,8 +248,14 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
        }
 
        if (priv->edp) {
+               struct mdp5_interface intf = {
+                               .num    = 0,
+                               .type   = INTF_eDP,
+                               .mode   = MDP5_INTF_MODE_NONE,
+               };
+
                /* Construct encoder for eDP: */
-               encoder = mdp5_encoder_init(dev, 0, INTF_eDP);
+               encoder = mdp5_encoder_init(dev, &intf);
                if (IS_ERR(encoder)) {
                        dev_err(dev->dev, "failed to construct eDP encoder\n");
                        ret = PTR_ERR(encoder);
index f30a700d04bf28c435df6fd06b3352dd1d1edfda..1a6aa494d92f1195a19593293a8657ab08d0847a 100644 (file)
@@ -26,9 +26,6 @@
 #include "mdp5_ctl.h"
 #include "mdp5_smp.h"
 
-/* temporary compat for enum name change: */
-#define mdp5_intf mdp5_intf_type
-
 struct mdp5_kms {
        struct mdp_kms base;
 
@@ -97,6 +94,24 @@ struct mdp5_plane_state {
 #define to_mdp5_plane_state(x) \
                container_of(x, struct mdp5_plane_state, base)
 
+enum mdp5_intf_mode {
+       MDP5_INTF_MODE_NONE = 0,
+
+       /* Modes used for DSI interface (INTF_DSI type): */
+       MDP5_INTF_DSI_MODE_VIDEO,
+       MDP5_INTF_DSI_MODE_COMMAND,
+
+       /* Modes used for WB interface (INTF_WB type):  */
+       MDP5_INTF_WB_MODE_BLOCK,
+       MDP5_INTF_WB_MODE_LINE,
+};
+
+struct mdp5_interface {
+       int num; /* display interface number */
+       enum mdp5_intf_type type;
+       enum mdp5_intf_mode mode;
+};
+
 static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
 {
        msm_writel(data, mdp5_kms->mmio + reg);
@@ -133,9 +148,9 @@ static inline int pipe2nclients(enum mdp5_pipe pipe)
        }
 }
 
-static inline uint32_t intf2err(int intf)
+static inline uint32_t intf2err(int intf_num)
 {
-       switch (intf) {
+       switch (intf_num) {
        case 0:  return MDP5_IRQ_INTF0_UNDER_RUN;
        case 1:  return MDP5_IRQ_INTF1_UNDER_RUN;
        case 2:  return MDP5_IRQ_INTF2_UNDER_RUN;
@@ -144,9 +159,24 @@ static inline uint32_t intf2err(int intf)
        }
 }
 
-static inline uint32_t intf2vblank(int intf)
+static inline uint32_t intf2vblank(int lm, struct mdp5_interface *intf)
 {
-       switch (intf) {
+#define GET_PING_PONG_ID(layer_mixer)  ((layer_mixer == 5) ? 3 : layer_mixer)
+
+       /*
+        * In case of DSI Command Mode, the Ping Pong's read pointer IRQ
+        * acts as a Vblank signal. The Ping Pong buffer used is bound to
+        * layer mixer.
+        */
+
+       if ((intf->type == INTF_DSI) &&
+                       (intf->mode == MDP5_INTF_DSI_MODE_COMMAND))
+               return MDP5_IRQ_PING_PONG_0_RD_PTR << GET_PING_PONG_ID(lm);
+
+       if (intf->type == INTF_WB)
+               return MDP5_IRQ_WB_2_DONE;
+
+       switch (intf->num) {
        case 0:  return MDP5_IRQ_INTF0_VSYNC;
        case 1:  return MDP5_IRQ_INTF1_VSYNC;
        case 2:  return MDP5_IRQ_INTF2_VSYNC;
@@ -201,12 +231,11 @@ uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
 
 int mdp5_crtc_get_lm(struct drm_crtc *crtc);
 void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
-void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
-               enum mdp5_intf intf_id);
+void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf);
 struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
                struct drm_plane *plane, int id);
 
-struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
-               enum mdp5_intf intf_id);
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
+               struct mdp5_interface *intf);
 
 #endif /* __MDP5_KMS_H__ */