Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2016 Red Hat
0004  * Author: Rob Clark <robdclark@gmail.com>
0005  */
0006 
0007 #include "mdp5_kms.h"
0008 
0009 int mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane,
0010              uint32_t caps, uint32_t blkcfg,
0011              struct mdp5_hw_pipe **hwpipe,
0012              struct mdp5_hw_pipe **r_hwpipe)
0013 {
0014     struct msm_drm_private *priv = s->dev->dev_private;
0015     struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
0016     struct mdp5_global_state *new_global_state, *old_global_state;
0017     struct mdp5_hw_pipe_state *old_state, *new_state;
0018     int i, j;
0019 
0020     new_global_state = mdp5_get_global_state(s);
0021     if (IS_ERR(new_global_state))
0022         return PTR_ERR(new_global_state);
0023 
0024     /* grab old_state after mdp5_get_global_state(), since now we hold lock: */
0025     old_global_state = mdp5_get_existing_global_state(mdp5_kms);
0026 
0027     old_state = &old_global_state->hwpipe;
0028     new_state = &new_global_state->hwpipe;
0029 
0030     for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
0031         struct mdp5_hw_pipe *cur = mdp5_kms->hwpipes[i];
0032 
0033         /* skip if already in-use.. check both new and old state,
0034          * since we cannot immediately re-use a pipe that is
0035          * released in the current update in some cases:
0036          *  (1) mdp5 can have SMP (non-double-buffered)
0037          *  (2) hw pipe previously assigned to different CRTC
0038          *      (vblanks might not be aligned)
0039          */
0040         if (new_state->hwpipe_to_plane[cur->idx] ||
0041                 old_state->hwpipe_to_plane[cur->idx])
0042             continue;
0043 
0044         /* skip if doesn't support some required caps: */
0045         if (caps & ~cur->caps)
0046             continue;
0047 
0048         /*
0049          * don't assign a cursor pipe to a plane that isn't going to
0050          * be used as a cursor
0051          */
0052         if (cur->caps & MDP_PIPE_CAP_CURSOR &&
0053                 plane->type != DRM_PLANE_TYPE_CURSOR)
0054             continue;
0055 
0056         /* possible candidate, take the one with the
0057          * fewest unneeded caps bits set:
0058          */
0059         if (!(*hwpipe) || (hweight_long(cur->caps & ~caps) <
0060                    hweight_long((*hwpipe)->caps & ~caps))) {
0061             bool r_found = false;
0062 
0063             if (r_hwpipe) {
0064                 for (j = i + 1; j < mdp5_kms->num_hwpipes;
0065                      j++) {
0066                     struct mdp5_hw_pipe *r_cur =
0067                             mdp5_kms->hwpipes[j];
0068 
0069                     /* reject different types of hwpipes */
0070                     if (r_cur->caps != cur->caps)
0071                         continue;
0072 
0073                     /* respect priority, eg. VIG0 > VIG1 */
0074                     if (cur->pipe > r_cur->pipe)
0075                         continue;
0076 
0077                     *r_hwpipe = r_cur;
0078                     r_found = true;
0079                     break;
0080                 }
0081             }
0082 
0083             if (!r_hwpipe || r_found)
0084                 *hwpipe = cur;
0085         }
0086     }
0087 
0088     if (!(*hwpipe))
0089         return -ENOMEM;
0090 
0091     if (r_hwpipe && !(*r_hwpipe))
0092         return -ENOMEM;
0093 
0094     if (mdp5_kms->smp) {
0095         int ret;
0096 
0097         /* We don't support SMP and 2 hwpipes/plane together */
0098         WARN_ON(r_hwpipe);
0099 
0100         DBG("%s: alloc SMP blocks", (*hwpipe)->name);
0101         ret = mdp5_smp_assign(mdp5_kms->smp, &new_global_state->smp,
0102                 (*hwpipe)->pipe, blkcfg);
0103         if (ret)
0104             return -ENOMEM;
0105 
0106         (*hwpipe)->blkcfg = blkcfg;
0107     }
0108 
0109     DBG("%s: assign to plane %s for caps %x",
0110             (*hwpipe)->name, plane->name, caps);
0111     new_state->hwpipe_to_plane[(*hwpipe)->idx] = plane;
0112 
0113     if (r_hwpipe) {
0114         DBG("%s: assign to right of plane %s for caps %x",
0115             (*r_hwpipe)->name, plane->name, caps);
0116         new_state->hwpipe_to_plane[(*r_hwpipe)->idx] = plane;
0117     }
0118 
0119     return 0;
0120 }
0121 
0122 int mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe)
0123 {
0124     struct msm_drm_private *priv = s->dev->dev_private;
0125     struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
0126     struct mdp5_global_state *state;
0127     struct mdp5_hw_pipe_state *new_state;
0128 
0129     if (!hwpipe)
0130         return 0;
0131 
0132     state = mdp5_get_global_state(s);
0133     if (IS_ERR(state))
0134         return PTR_ERR(state);
0135 
0136     new_state = &state->hwpipe;
0137 
0138     if (WARN_ON(!new_state->hwpipe_to_plane[hwpipe->idx]))
0139         return -EINVAL;
0140 
0141     DBG("%s: release from plane %s", hwpipe->name,
0142         new_state->hwpipe_to_plane[hwpipe->idx]->name);
0143 
0144     if (mdp5_kms->smp) {
0145         DBG("%s: free SMP blocks", hwpipe->name);
0146         mdp5_smp_release(mdp5_kms->smp, &state->smp, hwpipe->pipe);
0147     }
0148 
0149     new_state->hwpipe_to_plane[hwpipe->idx] = NULL;
0150 
0151     return 0;
0152 }
0153 
0154 void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe)
0155 {
0156     kfree(hwpipe);
0157 }
0158 
0159 struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
0160         uint32_t reg_offset, uint32_t caps)
0161 {
0162     struct mdp5_hw_pipe *hwpipe;
0163 
0164     hwpipe = kzalloc(sizeof(*hwpipe), GFP_KERNEL);
0165     if (!hwpipe)
0166         return ERR_PTR(-ENOMEM);
0167 
0168     hwpipe->name = pipe2name(pipe);
0169     hwpipe->pipe = pipe;
0170     hwpipe->reg_offset = reg_offset;
0171     hwpipe->caps = caps;
0172     hwpipe->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
0173 
0174     return hwpipe;
0175 }