1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved. 4 * Author: James.Qian.Wang <james.qian.wang@arm.com> 5 * 6 */ 7 #include <drm/drm_atomic.h> 8 #include <drm/drm_atomic_helper.h> 9 #include <drm/drm_plane_helper.h> 10 #include <drm/drm_print.h> 11 #include "komeda_dev.h" 12 #include "komeda_kms.h" 13 14 static int 15 komeda_plane_init_data_flow(struct drm_plane_state *st, 16 struct komeda_data_flow_cfg *dflow) 17 { 18 struct drm_framebuffer *fb = st->fb; 19 20 memset(dflow, 0, sizeof(*dflow)); 21 22 dflow->blending_zorder = st->zpos; 23 24 /* if format doesn't have alpha, fix blend mode to PIXEL_NONE */ 25 dflow->pixel_blend_mode = fb->format->has_alpha ? 26 st->pixel_blend_mode : DRM_MODE_BLEND_PIXEL_NONE; 27 dflow->layer_alpha = st->alpha >> 8; 28 29 dflow->out_x = st->crtc_x; 30 dflow->out_y = st->crtc_y; 31 dflow->out_w = st->crtc_w; 32 dflow->out_h = st->crtc_h; 33 34 dflow->in_x = st->src_x >> 16; 35 dflow->in_y = st->src_y >> 16; 36 dflow->in_w = st->src_w >> 16; 37 dflow->in_h = st->src_h >> 16; 38 39 return 0; 40 } 41 42 /** 43 * komeda_plane_atomic_check - build input data flow 44 * @plane: DRM plane 45 * @state: the plane state object 46 * 47 * RETURNS: 48 * Zero for success or -errno 49 */ 50 static int 51 komeda_plane_atomic_check(struct drm_plane *plane, 52 struct drm_plane_state *state) 53 { 54 struct komeda_plane *kplane = to_kplane(plane); 55 struct komeda_plane_state *kplane_st = to_kplane_st(state); 56 struct komeda_layer *layer = kplane->layer; 57 struct drm_crtc_state *crtc_st; 58 struct komeda_crtc *kcrtc; 59 struct komeda_crtc_state *kcrtc_st; 60 struct komeda_data_flow_cfg dflow; 61 int err; 62 63 if (!state->crtc || !state->fb) 64 return 0; 65 66 crtc_st = drm_atomic_get_crtc_state(state->state, state->crtc); 67 if (!crtc_st->enable) { 68 DRM_DEBUG_ATOMIC("Cannot update plane on a disabled CRTC.\n"); 69 return -EINVAL; 70 } 71 72 /* crtc is inactive, skip the resource assignment */ 73 if (!crtc_st->active) 74 return 0; 75 76 kcrtc = to_kcrtc(state->crtc); 77 kcrtc_st = to_kcrtc_st(crtc_st); 78 79 err = komeda_plane_init_data_flow(state, &dflow); 80 if (err) 81 return err; 82 83 err = komeda_build_layer_data_flow(layer, kplane_st, kcrtc_st, &dflow); 84 85 return err; 86 } 87 88 /* plane doesn't represent a real HW, so there is no HW update for plane. 89 * komeda handles all the HW update in crtc->atomic_flush 90 */ 91 static void 92 komeda_plane_atomic_update(struct drm_plane *plane, 93 struct drm_plane_state *old_state) 94 { 95 } 96 97 static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = { 98 .atomic_check = komeda_plane_atomic_check, 99 .atomic_update = komeda_plane_atomic_update, 100 }; 101 102 static void komeda_plane_destroy(struct drm_plane *plane) 103 { 104 drm_plane_cleanup(plane); 105 106 kfree(to_kplane(plane)); 107 } 108 109 static void komeda_plane_reset(struct drm_plane *plane) 110 { 111 struct komeda_plane_state *state; 112 struct komeda_plane *kplane = to_kplane(plane); 113 114 if (plane->state) 115 __drm_atomic_helper_plane_destroy_state(plane->state); 116 117 kfree(plane->state); 118 plane->state = NULL; 119 120 state = kzalloc(sizeof(*state), GFP_KERNEL); 121 if (state) { 122 state->base.rotation = DRM_MODE_ROTATE_0; 123 state->base.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; 124 state->base.alpha = DRM_BLEND_ALPHA_OPAQUE; 125 state->base.zpos = kplane->layer->base.id; 126 plane->state = &state->base; 127 plane->state->plane = plane; 128 } 129 } 130 131 static struct drm_plane_state * 132 komeda_plane_atomic_duplicate_state(struct drm_plane *plane) 133 { 134 struct komeda_plane_state *new; 135 136 if (WARN_ON(!plane->state)) 137 return NULL; 138 139 new = kzalloc(sizeof(*new), GFP_KERNEL); 140 if (!new) 141 return NULL; 142 143 __drm_atomic_helper_plane_duplicate_state(plane, &new->base); 144 145 return &new->base; 146 } 147 148 static void 149 komeda_plane_atomic_destroy_state(struct drm_plane *plane, 150 struct drm_plane_state *state) 151 { 152 __drm_atomic_helper_plane_destroy_state(state); 153 kfree(to_kplane_st(state)); 154 } 155 156 static const struct drm_plane_funcs komeda_plane_funcs = { 157 .update_plane = drm_atomic_helper_update_plane, 158 .disable_plane = drm_atomic_helper_disable_plane, 159 .destroy = komeda_plane_destroy, 160 .reset = komeda_plane_reset, 161 .atomic_duplicate_state = komeda_plane_atomic_duplicate_state, 162 .atomic_destroy_state = komeda_plane_atomic_destroy_state, 163 }; 164 165 /* for komeda, which is pipeline can be share between crtcs */ 166 static u32 get_possible_crtcs(struct komeda_kms_dev *kms, 167 struct komeda_pipeline *pipe) 168 { 169 struct komeda_crtc *crtc; 170 u32 possible_crtcs = 0; 171 int i; 172 173 for (i = 0; i < kms->n_crtcs; i++) { 174 crtc = &kms->crtcs[i]; 175 176 if ((pipe == crtc->master) || (pipe == crtc->slave)) 177 possible_crtcs |= BIT(i); 178 } 179 180 return possible_crtcs; 181 } 182 183 /* use Layer0 as primary */ 184 static u32 get_plane_type(struct komeda_kms_dev *kms, 185 struct komeda_component *c) 186 { 187 bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0); 188 189 return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; 190 } 191 192 static int komeda_plane_add(struct komeda_kms_dev *kms, 193 struct komeda_layer *layer) 194 { 195 struct komeda_dev *mdev = kms->base.dev_private; 196 struct komeda_component *c = &layer->base; 197 struct komeda_plane *kplane; 198 struct drm_plane *plane; 199 u32 *formats, n_formats = 0; 200 int err; 201 202 kplane = kzalloc(sizeof(*kplane), GFP_KERNEL); 203 if (!kplane) 204 return -ENOMEM; 205 206 plane = &kplane->base; 207 kplane->layer = layer; 208 209 formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl, 210 layer->layer_type, &n_formats); 211 212 err = drm_universal_plane_init(&kms->base, plane, 213 get_possible_crtcs(kms, c->pipeline), 214 &komeda_plane_funcs, 215 formats, n_formats, NULL, 216 get_plane_type(kms, c), 217 "%s", c->name); 218 219 komeda_put_fourcc_list(formats); 220 221 if (err) 222 goto cleanup; 223 224 drm_plane_helper_add(plane, &komeda_plane_helper_funcs); 225 226 return 0; 227 cleanup: 228 komeda_plane_destroy(plane); 229 return err; 230 } 231 232 int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev) 233 { 234 struct komeda_pipeline *pipe; 235 int i, j, err; 236 237 for (i = 0; i < mdev->n_pipelines; i++) { 238 pipe = mdev->pipelines[i]; 239 240 for (j = 0; j < pipe->n_layers; j++) { 241 err = komeda_plane_add(kms, pipe->layers[j]); 242 if (err) 243 return err; 244 } 245 } 246 247 return 0; 248 } 249