1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2016 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
9 int mdp5_pipe_assign(struct drm_atomic_state
*s
, struct drm_plane
*plane
,
10 uint32_t caps
, uint32_t blkcfg
,
11 struct mdp5_hw_pipe
**hwpipe
,
12 struct mdp5_hw_pipe
**r_hwpipe
)
14 struct msm_drm_private
*priv
= s
->dev
->dev_private
;
15 struct mdp5_kms
*mdp5_kms
= to_mdp5_kms(to_mdp_kms(priv
->kms
));
16 struct mdp5_global_state
*new_global_state
, *old_global_state
;
17 struct mdp5_hw_pipe_state
*old_state
, *new_state
;
20 new_global_state
= mdp5_get_global_state(s
);
21 if (IS_ERR(new_global_state
))
22 return PTR_ERR(new_global_state
);
24 /* grab old_state after mdp5_get_global_state(), since now we hold lock: */
25 old_global_state
= mdp5_get_existing_global_state(mdp5_kms
);
27 old_state
= &old_global_state
->hwpipe
;
28 new_state
= &new_global_state
->hwpipe
;
30 for (i
= 0; i
< mdp5_kms
->num_hwpipes
; i
++) {
31 struct mdp5_hw_pipe
*cur
= mdp5_kms
->hwpipes
[i
];
33 /* skip if already in-use.. check both new and old state,
34 * since we cannot immediately re-use a pipe that is
35 * released in the current update in some cases:
36 * (1) mdp5 can have SMP (non-double-buffered)
37 * (2) hw pipe previously assigned to different CRTC
38 * (vblanks might not be aligned)
40 if (new_state
->hwpipe_to_plane
[cur
->idx
] ||
41 old_state
->hwpipe_to_plane
[cur
->idx
])
44 /* skip if doesn't support some required caps: */
45 if (caps
& ~cur
->caps
)
49 * don't assign a cursor pipe to a plane that isn't going to
52 if (cur
->caps
& MDP_PIPE_CAP_CURSOR
&&
53 plane
->type
!= DRM_PLANE_TYPE_CURSOR
)
56 /* possible candidate, take the one with the
57 * fewest unneeded caps bits set:
59 if (!(*hwpipe
) || (hweight_long(cur
->caps
& ~caps
) <
60 hweight_long((*hwpipe
)->caps
& ~caps
))) {
64 for (j
= i
+ 1; j
< mdp5_kms
->num_hwpipes
;
66 struct mdp5_hw_pipe
*r_cur
=
69 /* reject different types of hwpipes */
70 if (r_cur
->caps
!= cur
->caps
)
73 /* respect priority, eg. VIG0 > VIG1 */
74 if (cur
->pipe
> r_cur
->pipe
)
83 if (!r_hwpipe
|| r_found
)
91 if (r_hwpipe
&& !(*r_hwpipe
))
97 /* We don't support SMP and 2 hwpipes/plane together */
100 DBG("%s: alloc SMP blocks", (*hwpipe
)->name
);
101 ret
= mdp5_smp_assign(mdp5_kms
->smp
, &new_global_state
->smp
,
102 (*hwpipe
)->pipe
, blkcfg
);
106 (*hwpipe
)->blkcfg
= blkcfg
;
109 DBG("%s: assign to plane %s for caps %x",
110 (*hwpipe
)->name
, plane
->name
, caps
);
111 new_state
->hwpipe_to_plane
[(*hwpipe
)->idx
] = plane
;
114 DBG("%s: assign to right of plane %s for caps %x",
115 (*r_hwpipe
)->name
, plane
->name
, caps
);
116 new_state
->hwpipe_to_plane
[(*r_hwpipe
)->idx
] = plane
;
122 void mdp5_pipe_release(struct drm_atomic_state
*s
, struct mdp5_hw_pipe
*hwpipe
)
124 struct msm_drm_private
*priv
= s
->dev
->dev_private
;
125 struct mdp5_kms
*mdp5_kms
= to_mdp5_kms(to_mdp_kms(priv
->kms
));
126 struct mdp5_global_state
*state
= mdp5_get_global_state(s
);
127 struct mdp5_hw_pipe_state
*new_state
= &state
->hwpipe
;
132 if (WARN_ON(!new_state
->hwpipe_to_plane
[hwpipe
->idx
]))
135 DBG("%s: release from plane %s", hwpipe
->name
,
136 new_state
->hwpipe_to_plane
[hwpipe
->idx
]->name
);
139 DBG("%s: free SMP blocks", hwpipe
->name
);
140 mdp5_smp_release(mdp5_kms
->smp
, &state
->smp
, hwpipe
->pipe
);
143 new_state
->hwpipe_to_plane
[hwpipe
->idx
] = NULL
;
146 void mdp5_pipe_destroy(struct mdp5_hw_pipe
*hwpipe
)
151 struct mdp5_hw_pipe
*mdp5_pipe_init(enum mdp5_pipe pipe
,
152 uint32_t reg_offset
, uint32_t caps
)
154 struct mdp5_hw_pipe
*hwpipe
;
156 hwpipe
= kzalloc(sizeof(*hwpipe
), GFP_KERNEL
);
158 return ERR_PTR(-ENOMEM
);
160 hwpipe
->name
= pipe2name(pipe
);
162 hwpipe
->reg_offset
= reg_offset
;
164 hwpipe
->flush_mask
= mdp_ctl_flush_mask_pipe(pipe
);