mode->vsync_end, mode->vtotal,
mode->type, mode->flags);
pingpong_tearcheck_setup(encoder, mode);
- mdp5_crtc_set_pipeline(encoder->crtc, &mdp5_cmd_enc->intf,
+ mdp5_crtc_set_pipeline(encoder->crtc, mdp5_cmd_enc->intf,
mdp5_cmd_enc->ctl);
}
{
struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
- struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
+ struct mdp5_interface *intf = mdp5_cmd_enc->intf;
if (WARN_ON(!mdp5_cmd_enc->enabled))
return;
{
struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
- struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
+ struct mdp5_interface *intf = mdp5_cmd_enc->intf;
if (WARN_ON(mdp5_cmd_enc->enabled))
return;
return -EINVAL;
mdp5_kms = get_kms(encoder);
- intf_num = mdp5_cmd_enc->intf.num;
+ intf_num = mdp5_cmd_enc->intf->num;
/* Switch slave encoder's trigger MUX, to use the master's
* start signal for the slave encoder
#define CTL_STAT_BOOKED 0x2
struct op_mode {
- struct mdp5_interface intf;
+ struct mdp5_interface *intf;
bool encoder_enabled;
uint32_t start_mask;
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
- if (unlikely(WARN_ON(intf->num != ctl->pipeline.intf.num))) {
- dev_err(mdp5_kms->dev->dev,
- "CTL %d is allocated by INTF %d, but used by INTF %d\n",
- ctl->id, ctl->pipeline.intf.num, intf->num);
- return -EINVAL;
- }
-
ctl->mixer = mixer;
-
- memcpy(&ctl->pipeline.intf, intf, sizeof(*intf));
+ ctl->pipeline.intf = intf;
ctl->pipeline.start_mask = mdp_ctl_flush_mask_lm(mixer->lm) |
mdp_ctl_flush_mask_encoder(intf);
if (!pipeline->encoder_enabled || pipeline->start_mask != 0)
return false;
- switch (pipeline->intf.type) {
+ switch (pipeline->intf->type) {
case INTF_WB:
return true;
case INTF_DSI:
- return pipeline->intf.mode == MDP5_INTF_DSI_MODE_COMMAND;
+ return pipeline->intf->mode == MDP5_INTF_DSI_MODE_COMMAND;
default:
return false;
}
static void refill_start_mask(struct mdp5_ctl *ctl)
{
struct op_mode *pipeline = &ctl->pipeline;
- struct mdp5_interface *intf = &ctl->pipeline.intf;
+ struct mdp5_interface *intf = pipeline->intf;
pipeline->start_mask = mdp_ctl_flush_mask_lm(ctl->mixer->lm);
return -EINVAL;
ctl->pipeline.encoder_enabled = enabled;
- DBG("intf_%d: %s", ctl->pipeline.intf.num, enabled ? "on" : "off");
+ DBG("intf_%d: %s", ctl->pipeline.intf->num, enabled ? "on" : "off");
if (start_signal_needed(ctl)) {
send_start_signal(ctl);
found:
ctl = &ctl_mgr->ctls[c];
- ctl->pipeline.intf.num = intf_num;
ctl->mixer = NULL;
ctl->status |= CTL_STAT_BUSY;
ctl->pending_ctl_trigger = 0;
struct mdp5_kms *mdp5_kms = get_kms(encoder);
struct drm_device *dev = encoder->dev;
struct drm_connector *connector;
- int intf = mdp5_encoder->intf.num;
+ 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;
ctrl_pol = 0;
/* DSI controller cannot handle active-low sync signals. */
- if (mdp5_encoder->intf.type != INTF_DSI) {
+ if (mdp5_encoder->intf->type != INTF_DSI) {
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
ctrl_pol |= MDP5_INTF_POLARITY_CTL_HSYNC_LOW;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
* DISPLAY_V_START = (VBP * HCYCLE) + HBP
* DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
*/
- if (mdp5_encoder->intf.type == 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;
}
spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
- mdp5_crtc_set_pipeline(encoder->crtc, &mdp5_encoder->intf,
- mdp5_encoder->ctl);
+ mdp5_crtc_set_pipeline(encoder->crtc, mdp5_encoder->intf,
+ mdp5_encoder->ctl);
}
static void mdp5_vid_encoder_disable(struct drm_encoder *encoder)
struct mdp5_kms *mdp5_kms = get_kms(encoder);
struct mdp5_ctl *ctl = mdp5_encoder->ctl;
struct mdp5_hw_mixer *mixer = mdp5_crtc_get_mixer(encoder->crtc);
- struct mdp5_interface *intf = &mdp5_encoder->intf;
- int intfn = mdp5_encoder->intf.num;
+ struct mdp5_interface *intf = mdp5_encoder->intf;
+ int intfn = mdp5_encoder->intf->num;
unsigned long flags;
if (WARN_ON(!mdp5_encoder->enabled))
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms = get_kms(encoder);
struct mdp5_ctl *ctl = mdp5_encoder->ctl;
- struct mdp5_interface *intf = &mdp5_encoder->intf;
- int intfn = mdp5_encoder->intf.num;
+ struct mdp5_interface *intf = mdp5_encoder->intf;
+ int intfn = intf->num;
unsigned long flags;
if (WARN_ON(mdp5_encoder->enabled))
struct drm_display_mode *adjusted_mode)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
- struct mdp5_interface *intf = &mdp5_encoder->intf;
+ struct mdp5_interface *intf = mdp5_encoder->intf;
if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
mdp5_cmd_encoder_mode_set(encoder, mode, adjusted_mode);
static void mdp5_encoder_disable(struct drm_encoder *encoder)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
- struct mdp5_interface *intf = &mdp5_encoder->intf;
+ struct mdp5_interface *intf = mdp5_encoder->intf;
if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
mdp5_cmd_encoder_disable(encoder);
static void mdp5_encoder_enable(struct drm_encoder *encoder)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
- struct mdp5_interface *intf = &mdp5_encoder->intf;
+ struct mdp5_interface *intf = mdp5_encoder->intf;
if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
mdp5_cmd_encoder_disable(encoder);
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms = get_kms(encoder);
- int intf = mdp5_encoder->intf.num;
+ int intf = mdp5_encoder->intf->num;
return mdp5_read(mdp5_kms, REG_MDP5_INTF_LINE_COUNT(intf));
}
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms = get_kms(encoder);
- int intf = mdp5_encoder->intf.num;
+ int intf = mdp5_encoder->intf->num;
return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
}
return -EINVAL;
mdp5_kms = get_kms(encoder);
- intf_num = mdp5_encoder->intf.num;
+ intf_num = mdp5_encoder->intf->num;
/* Switch slave encoder's TimingGen Sync mode,
* to use the master's enable signal for the slave encoder.
void mdp5_encoder_set_intf_mode(struct drm_encoder *encoder, bool cmd_mode)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
- struct mdp5_interface *intf = &mdp5_encoder->intf;
+ struct mdp5_interface *intf = mdp5_encoder->intf;
/* TODO: Expand this to set writeback modes too */
if (cmd_mode) {
/* initialize encoder */
struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
- struct mdp5_interface *intf, struct mdp5_ctl *ctl)
+ struct mdp5_interface *intf,
+ struct mdp5_ctl *ctl)
{
struct drm_encoder *encoder = NULL;
struct mdp5_encoder *mdp5_encoder;
goto fail;
}
- memcpy(&mdp5_encoder->intf, intf, sizeof(mdp5_encoder->intf));
encoder = &mdp5_encoder->base;
mdp5_encoder->ctl = ctl;
+ mdp5_encoder->intf = intf;
spin_lock_init(&mdp5_encoder->intf_lock);
}
static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
- enum mdp5_intf_type intf_type, int intf_num,
- struct mdp5_ctl *ctl)
+ struct mdp5_interface *intf,
+ struct mdp5_ctl *ctl)
{
struct drm_device *dev = mdp5_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
struct drm_encoder *encoder;
- struct mdp5_interface intf = {
- .num = intf_num,
- .type = intf_type,
- .mode = MDP5_INTF_MODE_NONE,
- };
- encoder = mdp5_encoder_init(dev, &intf, ctl);
+ encoder = mdp5_encoder_init(dev, intf, ctl);
if (IS_ERR(encoder)) {
dev_err(dev->dev, "failed to construct encoder\n");
return encoder;
return -EINVAL;
}
-static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
+static int modeset_init_intf(struct mdp5_kms *mdp5_kms,
+ struct mdp5_interface *intf)
{
struct drm_device *dev = mdp5_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
- const struct mdp5_cfg_hw *hw_cfg =
- mdp5_cfg_get_hw_config(mdp5_kms->cfg);
- enum mdp5_intf_type intf_type = hw_cfg->intf.connect[intf_num];
struct mdp5_ctl_manager *ctlm = mdp5_kms->ctlm;
struct mdp5_ctl *ctl;
struct drm_encoder *encoder;
int ret = 0;
- switch (intf_type) {
- case INTF_DISABLED:
- break;
+ switch (intf->type) {
case INTF_eDP:
if (!priv->edp)
break;
- ctl = mdp5_ctlm_request(ctlm, intf_num);
+ ctl = mdp5_ctlm_request(ctlm, intf->num);
if (!ctl) {
ret = -EINVAL;
break;
}
- encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num, ctl);
+ encoder = construct_encoder(mdp5_kms, intf, ctl);
if (IS_ERR(encoder)) {
ret = PTR_ERR(encoder);
break;
if (!priv->hdmi)
break;
- ctl = mdp5_ctlm_request(ctlm, intf_num);
+ ctl = mdp5_ctlm_request(ctlm, intf->num);
if (!ctl) {
ret = -EINVAL;
break;
}
- encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num, ctl);
+ encoder = construct_encoder(mdp5_kms, intf, ctl);
if (IS_ERR(encoder)) {
ret = PTR_ERR(encoder);
break;
break;
case INTF_DSI:
{
- int dsi_id = get_dsi_id_from_intf(hw_cfg, intf_num);
+ const struct mdp5_cfg_hw *hw_cfg =
+ mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+ int dsi_id = get_dsi_id_from_intf(hw_cfg, intf->num);
if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
dev_err(dev->dev, "failed to find dsi from intf %d\n",
- intf_num);
+ intf->num);
ret = -EINVAL;
break;
}
if (!priv->dsi[dsi_id])
break;
- ctl = mdp5_ctlm_request(ctlm, intf_num);
+ ctl = mdp5_ctlm_request(ctlm, intf->num);
if (!ctl) {
ret = -EINVAL;
break;
}
- encoder = construct_encoder(mdp5_kms, INTF_DSI, intf_num, ctl);
+ encoder = construct_encoder(mdp5_kms, intf, ctl);
if (IS_ERR(encoder)) {
ret = PTR_ERR(encoder);
break;
break;
}
default:
- dev_err(dev->dev, "unknown intf: %d\n", intf_type);
+ dev_err(dev->dev, "unknown intf: %d\n", intf->type);
ret = -EINVAL;
break;
}
* Construct encoders and modeset initialize connector devices
* for each external display interface.
*/
- for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {
- ret = modeset_init_intf(mdp5_kms, i);
+ for (i = 0; i < mdp5_kms->num_intfs; i++) {
+ ret = modeset_init_intf(mdp5_kms, mdp5_kms->intfs[i]);
if (ret)
goto fail;
}
static void mdp5_destroy(struct platform_device *pdev)
{
struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
+ int i;
if (mdp5_kms->ctlm)
mdp5_ctlm_destroy(mdp5_kms->ctlm);
if (mdp5_kms->cfg)
mdp5_cfg_destroy(mdp5_kms->cfg);
+ for (i = 0; i < mdp5_kms->num_intfs; i++)
+ kfree(mdp5_kms->intfs[i]);
+
if (mdp5_kms->rpm_enabled)
pm_runtime_disable(&pdev->dev);
return 0;
}
+static int interface_init(struct mdp5_kms *mdp5_kms)
+{
+ struct drm_device *dev = mdp5_kms->dev;
+ const struct mdp5_cfg_hw *hw_cfg;
+ const enum mdp5_intf_type *intf_types;
+ int i;
+
+ hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+ intf_types = hw_cfg->intf.connect;
+
+ for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {
+ struct mdp5_interface *intf;
+
+ if (intf_types[i] == INTF_DISABLED)
+ continue;
+
+ intf = kzalloc(sizeof(*intf), GFP_KERNEL);
+ if (!intf) {
+ dev_err(dev->dev, "failed to construct INTF%d\n", i);
+ return -ENOMEM;
+ }
+
+ intf->num = i;
+ intf->type = intf_types[i];
+ intf->mode = MDP5_INTF_MODE_NONE;
+ intf->idx = mdp5_kms->num_intfs;
+ mdp5_kms->intfs[mdp5_kms->num_intfs++] = intf;
+ }
+
+ return 0;
+}
+
static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
{
struct msm_drm_private *priv = dev->dev_private;
if (ret)
goto fail;
+ ret = interface_init(mdp5_kms);
+ if (ret)
+ goto fail;
+
/* set uninit-ed kms */
priv->kms = &mdp5_kms->base.base;
unsigned num_hwmixers;
struct mdp5_hw_mixer *hwmixers[8];
+ unsigned num_intfs;
+ struct mdp5_interface *intfs[5];
+
struct mdp5_cfg_handler *cfg;
uint32_t caps; /* MDP capabilities (MDP_CAP_XXX bits) */
};
struct mdp5_interface {
+ int idx;
int num; /* display interface number */
enum mdp5_intf_type type;
enum mdp5_intf_mode mode;
struct mdp5_encoder {
struct drm_encoder base;
- struct mdp5_interface intf;
spinlock_t intf_lock; /* protect REG_MDP5_INTF_* registers */
bool enabled;
uint32_t bsc;
+ struct mdp5_interface *intf;
struct mdp5_ctl *ctl;
};
#define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base)