linux/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 Red Hat
   3 * Author: Rob Clark <robdclark@gmail.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License version 2 as published by
   7 * the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program.  If not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18#include "mdp5_kms.h"
  19
  20struct mdp5_hw_pipe *mdp5_pipe_assign(struct drm_atomic_state *s,
  21                struct drm_plane *plane, uint32_t caps, uint32_t blkcfg)
  22{
  23        struct msm_drm_private *priv = s->dev->dev_private;
  24        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
  25        struct mdp5_state *state;
  26        struct mdp5_hw_pipe_state *old_state, *new_state;
  27        struct mdp5_hw_pipe *hwpipe = NULL;
  28        int i;
  29
  30        state = mdp5_get_state(s);
  31        if (IS_ERR(state))
  32                return ERR_CAST(state);
  33
  34        /* grab old_state after mdp5_get_state(), since now we hold lock: */
  35        old_state = &mdp5_kms->state->hwpipe;
  36        new_state = &state->hwpipe;
  37
  38        for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
  39                struct mdp5_hw_pipe *cur = mdp5_kms->hwpipes[i];
  40
  41                /* skip if already in-use.. check both new and old state,
  42                 * since we cannot immediately re-use a pipe that is
  43                 * released in the current update in some cases:
  44                 *  (1) mdp5 can have SMP (non-double-buffered)
  45                 *  (2) hw pipe previously assigned to different CRTC
  46                 *      (vblanks might not be aligned)
  47                 */
  48                if (new_state->hwpipe_to_plane[cur->idx] ||
  49                                old_state->hwpipe_to_plane[cur->idx])
  50                        continue;
  51
  52                /* skip if doesn't support some required caps: */
  53                if (caps & ~cur->caps)
  54                        continue;
  55
  56                /*
  57                 * don't assign a cursor pipe to a plane that isn't going to
  58                 * be used as a cursor
  59                 */
  60                if (cur->caps & MDP_PIPE_CAP_CURSOR &&
  61                                plane->type != DRM_PLANE_TYPE_CURSOR)
  62                        continue;
  63
  64                /* possible candidate, take the one with the
  65                 * fewest unneeded caps bits set:
  66                 */
  67                if (!hwpipe || (hweight_long(cur->caps & ~caps) <
  68                                hweight_long(hwpipe->caps & ~caps)))
  69                        hwpipe = cur;
  70        }
  71
  72        if (!hwpipe)
  73                return ERR_PTR(-ENOMEM);
  74
  75        if (mdp5_kms->smp) {
  76                int ret;
  77
  78                DBG("%s: alloc SMP blocks", hwpipe->name);
  79                ret = mdp5_smp_assign(mdp5_kms->smp, &state->smp,
  80                                hwpipe->pipe, blkcfg);
  81                if (ret)
  82                        return ERR_PTR(-ENOMEM);
  83
  84                hwpipe->blkcfg = blkcfg;
  85        }
  86
  87        DBG("%s: assign to plane %s for caps %x",
  88                        hwpipe->name, plane->name, caps);
  89        new_state->hwpipe_to_plane[hwpipe->idx] = plane;
  90
  91        return hwpipe;
  92}
  93
  94void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe)
  95{
  96        struct msm_drm_private *priv = s->dev->dev_private;
  97        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
  98        struct mdp5_state *state = mdp5_get_state(s);
  99        struct mdp5_hw_pipe_state *new_state = &state->hwpipe;
 100
 101        if (!hwpipe)
 102                return;
 103
 104        if (WARN_ON(!new_state->hwpipe_to_plane[hwpipe->idx]))
 105                return;
 106
 107        DBG("%s: release from plane %s", hwpipe->name,
 108                new_state->hwpipe_to_plane[hwpipe->idx]->name);
 109
 110        if (mdp5_kms->smp) {
 111                DBG("%s: free SMP blocks", hwpipe->name);
 112                mdp5_smp_release(mdp5_kms->smp, &state->smp, hwpipe->pipe);
 113        }
 114
 115        new_state->hwpipe_to_plane[hwpipe->idx] = NULL;
 116}
 117
 118void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe)
 119{
 120        kfree(hwpipe);
 121}
 122
 123struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
 124                uint32_t reg_offset, uint32_t caps)
 125{
 126        struct mdp5_hw_pipe *hwpipe;
 127
 128        hwpipe = kzalloc(sizeof(*hwpipe), GFP_KERNEL);
 129        if (!hwpipe)
 130                return ERR_PTR(-ENOMEM);
 131
 132        hwpipe->name = pipe2name(pipe);
 133        hwpipe->pipe = pipe;
 134        hwpipe->reg_offset = reg_offset;
 135        hwpipe->caps = caps;
 136        hwpipe->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
 137
 138        return hwpipe;
 139}
 140