diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h index dba4d52cceebaeec609b95cdbcf27af495d5a545..4e90740c97497dd64fb509131d4f5a82859a3618 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h @@ -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); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index bfba236daaa665f506f5858fa2abf2cef6b9b5a9..15136f17f8cec1fc4d00e50197a11f497323f5d5 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -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); } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c index 151129032d165875477d870c8c6cca5b2245e1e6..a548113a8f68d0d6a3cd79fa2ce67d0bee741273 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c @@ -33,6 +33,16 @@ * 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_*() 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; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h index ad48788efeea85e049727a26f5ed4053d303f99f..271d5ac429be276e73ffc9fda6a7f7463b54b8f2 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h @@ -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); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c index af0e02fa4f4821ac7a71a4b641fde76db366a8cd..b18b381502a348bae94dd90310af20975ad0557f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c @@ -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); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 92b61db5754cbf71f9368011fda966cbb9cbabfa..390d9d2b688274872437b16c6c2a54d912b6eb6b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -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); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index f30a700d04bf28c435df6fd06b3352dd1d1edfda..1a6aa494d92f1195a19593293a8657ab08d0847a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -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__ */