From patchwork Thu Mar 23 10:28:15 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Archit Taneja X-Patchwork-Id: 9640777 X-Patchwork-Delegate: agross@codeaurora.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 03428602D6 for ; Thu, 23 Mar 2017 10:30:22 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 04D6E28438 for ; Thu, 23 Mar 2017 10:30:22 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EDDB9284A5; Thu, 23 Mar 2017 10:30:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3D3BF28438 for ; Thu, 23 Mar 2017 10:30:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933261AbdCWKaP (ORCPT ); Thu, 23 Mar 2017 06:30:15 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:58698 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933242AbdCWKaP (ORCPT ); Thu, 23 Mar 2017 06:30:15 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 5362260CE0; Thu, 23 Mar 2017 10:30:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1490265013; bh=A0F2REZh0tdWbFeJt41/bJk05UB21IiWIUEP7YQv2Z4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=K6T9vwIA+ZXsDLxNDpPNmAKuQVewsBGcqDWF4m0xoByi5UohajflIAVfyYnpf5gBM V6EzxjeqcRwHSS+a6wUbcTiltl0rwDrdLabXMFgpyU1q5OLJVWxLuugl4830Ey7b0X 6J5sMdvFia36I9PO1Ya3jhKr+th0A4VkK1iZ51Sc= Received: from localhost (unknown [202.46.23.61]) (using TLSv1.2 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) (Authenticated sender: architt@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id D46656110B; Thu, 23 Mar 2017 10:29:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1490265001; bh=A0F2REZh0tdWbFeJt41/bJk05UB21IiWIUEP7YQv2Z4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DW8e2wTSiDWgq4puxk3Wx9WZ+EVOvZZ2Ft16Bi5vFujMC/rwYH5k1fjv6q1Siyk+i mPQ9J6RIuxHABE5gCN5Yiu/oVrdlbflWeqyUuUYA2yRIkt455bDPiYsr2o0Gwhmf86 FGblKIZIPdTn/gLEf7XfGSDWALNozaHgCDwF0vys= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org D46656110B Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=architt@codeaurora.org From: Archit Taneja To: robdclark@gmail.com Cc: dri-devel@lists.freedesktop.org, linux-arm-msm@vger.kernel.org, Archit Taneja Subject: [PATCH 22/24] drm/msm/mdp5: Assign 'right' mixer to CRTC state Date: Thu, 23 Mar 2017 15:58:15 +0530 Message-Id: <20170323102817.15017-23-architt@codeaurora.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170323102817.15017-1-architt@codeaurora.org> References: <20170323102817.15017-1-architt@codeaurora.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Dynamically assign a right mixer to mdp5_crtc_state in the CRTC's atomic_check path. Assigning the right mixer has some constraints, i.e, only a few LMs can be paired together. Update mdp5_mixer_assign to handle these constraints. Firstly, we need to identify whether we need a right mixer or not. At the moment, there are 2 scenarios where a right mixer might be needed: - If any of the planes connected to this CRTC is too wide (i.e, is comprised of 2 hwpipes). - If the CRTC's mode itself is too wide (i.e, a 4K mode on HDMI). We implement both these checks in the mdp5_crtc_atomic_check(), and pass 'need_right_mixer' to mdp5_setup_pipeline. If a CRTC is already assigned a single mixer, and a new atomic commit brings in a drm_plane that needs 2 hwpipes, we can successfully commit this mode without requiring a full modeset, provided that we still use the previously assigned mixer as the left mixer. If such an assignment isn't possible, we'd need to do a full modeset. This scenario has been ignored for now. The mixer assignment code is a bit messy, considering we have at most 4 LM instances in hardware. This can probably be re-visited later with simplified logic. Signed-off-by: Archit Taneja --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 49 +++++++++++++--- drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c | 97 +++++++++++++++++++++++++++---- drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h | 5 +- 3 files changed, 129 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index d0559962f85b..42fef018c04e 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -455,7 +455,8 @@ static void mdp5_crtc_enable(struct drm_crtc *crtc) } int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc, - struct drm_crtc_state *new_crtc_state) + struct drm_crtc_state *new_crtc_state, + bool need_right_mixer) { struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(new_crtc_state); @@ -465,15 +466,32 @@ int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc, new_mixer = !pipeline->mixer; + if ((need_right_mixer && !pipeline->r_mixer) || + (!need_right_mixer && pipeline->r_mixer)) + new_mixer = true; + if (new_mixer) { struct mdp5_hw_mixer *old_mixer = pipeline->mixer; + struct mdp5_hw_mixer *old_r_mixer = pipeline->r_mixer; + u32 caps; + int ret; + + caps = MDP_LM_CAP_DISPLAY; + if (need_right_mixer) + caps |= MDP_LM_CAP_PAIR; - pipeline->mixer = mdp5_mixer_assign(new_crtc_state->state, crtc, - MDP_LM_CAP_DISPLAY); - if (IS_ERR(pipeline->mixer)) - return PTR_ERR(pipeline->mixer); + ret = mdp5_mixer_assign(new_crtc_state->state, crtc, caps, + &pipeline->mixer, need_right_mixer ? + &pipeline->r_mixer : NULL); + if (ret) + return ret; mdp5_mixer_release(new_crtc_state->state, old_mixer); + if (old_r_mixer) { + mdp5_mixer_release(new_crtc_state->state, old_r_mixer); + if (!need_right_mixer) + pipeline->r_mixer = NULL; + } } /* @@ -550,7 +568,9 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, struct plane_state pstates[STAGE_MAX + 1]; const struct mdp5_cfg_hw *hw_cfg; const struct drm_plane_state *pstate; + const struct drm_display_mode *mode = &state->adjusted_mode; bool cursor_plane = false; + bool need_right_mixer = false; int cnt = 0, i; int ret; enum mdp_mixer_stage_id start; @@ -561,6 +581,12 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, pstates[cnt].plane = plane; pstates[cnt].state = to_mdp5_plane_state(pstate); + /* + * if any plane on this crtc uses 2 hwpipes, then we need + * the crtc to have a right hwmixer. + */ + if (pstates[cnt].state->r_hwpipe) + need_right_mixer = true; cnt++; if (plane->type == DRM_PLANE_TYPE_CURSOR) @@ -571,7 +597,16 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, if (!cnt) return 0; - ret = mdp5_crtc_setup_pipeline(crtc, state); + hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); + + /* + * we need a right hwmixer if the mode's width is greater than a single + * LM's max width + */ + if (mode->hdisplay > hw_cfg->lm.max_width) + need_right_mixer = true; + + ret = mdp5_crtc_setup_pipeline(crtc, state, need_right_mixer); if (ret) { dev_err(dev->dev, "couldn't assign mixers %d\n", ret); return ret; @@ -589,8 +624,6 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, /* verify that there are not too many planes attached to crtc * and that we don't have conflicting mixer stages: */ - hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); - if ((cnt + start - 1) >= hw_cfg->lm.nb_stages) { dev_err(dev->dev, "too many planes! cnt=%d, start stage=%d\n", cnt, start); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c index 9bb1f824b2a9..8a00991f03c7 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.c @@ -16,42 +16,115 @@ #include "mdp5_kms.h" -struct mdp5_hw_mixer *mdp5_mixer_assign(struct drm_atomic_state *s, - struct drm_crtc *crtc, uint32_t caps) +/* + * As of now, there are only 2 combinations possible for source split: + * + * Left | Right + * -----|------ + * LM0 | LM1 + * LM2 | LM5 + * + */ +static int lm_right_pair[] = { 1, -1, 5, -1, -1, -1 }; + +static int get_right_pair_idx(struct mdp5_kms *mdp5_kms, int lm) +{ + int i; + int pair_lm; + + pair_lm = lm_right_pair[lm]; + if (pair_lm < 0) + return -EINVAL; + + for (i = 0; i < mdp5_kms->num_hwmixers; i++) { + struct mdp5_hw_mixer *mixer = mdp5_kms->hwmixers[i]; + + if (mixer->lm == pair_lm) + return mixer->idx; + } + + return -1; +} + +int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc, + uint32_t caps, struct mdp5_hw_mixer **mixer, + struct mdp5_hw_mixer **r_mixer) { struct msm_drm_private *priv = s->dev->dev_private; struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms)); struct mdp5_state *state = mdp5_get_state(s); struct mdp5_hw_mixer_state *new_state; - struct mdp5_hw_mixer *mixer = NULL; int i; if (IS_ERR(state)) - return ERR_CAST(state); + return PTR_ERR(state); new_state = &state->hwmixer; for (i = 0; i < mdp5_kms->num_hwmixers; i++) { struct mdp5_hw_mixer *cur = mdp5_kms->hwmixers[i]; - /* skip if already in-use */ - if (new_state->hwmixer_to_crtc[cur->idx]) + /* + * skip if already in-use by a different CRTC. If there is a + * mixer already assigned to this CRTC, it means this call is + * a request to get an additional right mixer. Assume that the + * existing mixer is the 'left' one, and try to see if we can + * get its corresponding 'right' pair. + */ + if (new_state->hwmixer_to_crtc[cur->idx] && + new_state->hwmixer_to_crtc[cur->idx] != crtc) continue; /* skip if doesn't support some required caps: */ if (caps & ~cur->caps) continue; - if (!mixer) - mixer = cur; + if (r_mixer) { + int pair_idx; + + pair_idx = get_right_pair_idx(mdp5_kms, cur->lm); + if (pair_idx < 0) + return -EINVAL; + + if (new_state->hwmixer_to_crtc[pair_idx]) + continue; + + *r_mixer = mdp5_kms->hwmixers[pair_idx]; + } + + /* + * prefer a pair-able LM over an unpairable one. We can + * switch the CRTC from Normal mode to Source Split mode + * without requiring a full modeset if we had already + * assigned this CRTC a pair-able LM. + * + * TODO: There will be assignment sequences which would + * result in the CRTC requiring a full modeset, even + * if we have the LM resources to prevent it. For a platform + * with a few displays, we don't run out of pair-able LMs + * so easily. For now, ignore the possibility of requiring + * a full modeset. + */ + if (!(*mixer) || cur->caps & MDP_LM_CAP_PAIR) + *mixer = cur; } - if (!mixer) - return ERR_PTR(-ENOMEM); + if (!(*mixer)) + return -ENOMEM; - new_state->hwmixer_to_crtc[mixer->idx] = crtc; + if (r_mixer && !(*r_mixer)) + return -ENOMEM; - return mixer; + DBG("assigning Layer Mixer %d to crtc %s", (*mixer)->lm, crtc->name); + + new_state->hwmixer_to_crtc[(*mixer)->idx] = crtc; + if (r_mixer) { + DBG("assigning Right Layer Mixer %d to crtc %s", (*r_mixer)->lm, + crtc->name); + new_state->hwmixer_to_crtc[(*r_mixer)->idx] = crtc; + } + + return 0; } void mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h index 18ed933ae574..9be94f567fbd 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mixer.h @@ -38,8 +38,9 @@ struct mdp5_hw_mixer_state { struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm); void mdp5_mixer_destroy(struct mdp5_hw_mixer *lm); -struct mdp5_hw_mixer *mdp5_mixer_assign(struct drm_atomic_state *s, - struct drm_crtc *crtc, uint32_t caps); +int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc, + uint32_t caps, struct mdp5_hw_mixer **mixer, + struct mdp5_hw_mixer **r_mixer); void mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer);