1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2016 Noralf Trønnes 4 */ 5 6 #include <drm/drmP.h> 7 #include <drm/drm_atomic.h> 8 #include <drm/drm_atomic_helper.h> 9 #include <drm/drm_plane_helper.h> 10 #include <drm/drm_probe_helper.h> 11 #include <drm/drm_simple_kms_helper.h> 12 #include <linux/slab.h> 13 14 /** 15 * DOC: overview 16 * 17 * This helper library provides helpers for drivers for simple display 18 * hardware. 19 * 20 * drm_simple_display_pipe_init() initializes a simple display pipeline 21 * which has only one full-screen scanout buffer feeding one output. The 22 * pipeline is represented by &struct drm_simple_display_pipe and binds 23 * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed 24 * entity. Some flexibility for code reuse is provided through a separately 25 * allocated &drm_connector object and supporting optional &drm_bridge 26 * encoder drivers. 27 */ 28 29 static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = { 30 .destroy = drm_encoder_cleanup, 31 }; 32 33 static enum drm_mode_status 34 drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc, 35 const struct drm_display_mode *mode) 36 { 37 struct drm_simple_display_pipe *pipe; 38 39 pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 40 if (!pipe->funcs || !pipe->funcs->mode_valid) 41 /* Anything goes */ 42 return MODE_OK; 43 44 return pipe->funcs->mode_valid(crtc, mode); 45 } 46 47 static int drm_simple_kms_crtc_check(struct drm_crtc *crtc, 48 struct drm_crtc_state *state) 49 { 50 bool has_primary = state->plane_mask & 51 drm_plane_mask(crtc->primary); 52 53 /* We always want to have an active plane with an active CRTC */ 54 if (has_primary != state->enable) 55 return -EINVAL; 56 57 return drm_atomic_add_affected_planes(state->state, crtc); 58 } 59 60 static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc, 61 struct drm_crtc_state *old_state) 62 { 63 struct drm_plane *plane; 64 struct drm_simple_display_pipe *pipe; 65 66 pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 67 if (!pipe->funcs || !pipe->funcs->enable) 68 return; 69 70 plane = &pipe->plane; 71 pipe->funcs->enable(pipe, crtc->state, plane->state); 72 } 73 74 static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc, 75 struct drm_crtc_state *old_state) 76 { 77 struct drm_simple_display_pipe *pipe; 78 79 pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 80 if (!pipe->funcs || !pipe->funcs->disable) 81 return; 82 83 pipe->funcs->disable(pipe); 84 } 85 86 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = { 87 .mode_valid = drm_simple_kms_crtc_mode_valid, 88 .atomic_check = drm_simple_kms_crtc_check, 89 .atomic_enable = drm_simple_kms_crtc_enable, 90 .atomic_disable = drm_simple_kms_crtc_disable, 91 }; 92 93 static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc) 94 { 95 struct drm_simple_display_pipe *pipe; 96 97 pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 98 if (!pipe->funcs || !pipe->funcs->enable_vblank) 99 return 0; 100 101 return pipe->funcs->enable_vblank(pipe); 102 } 103 104 static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc) 105 { 106 struct drm_simple_display_pipe *pipe; 107 108 pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 109 if (!pipe->funcs || !pipe->funcs->disable_vblank) 110 return; 111 112 pipe->funcs->disable_vblank(pipe); 113 } 114 115 static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = { 116 .reset = drm_atomic_helper_crtc_reset, 117 .destroy = drm_crtc_cleanup, 118 .set_config = drm_atomic_helper_set_config, 119 .page_flip = drm_atomic_helper_page_flip, 120 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 121 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 122 .enable_vblank = drm_simple_kms_crtc_enable_vblank, 123 .disable_vblank = drm_simple_kms_crtc_disable_vblank, 124 }; 125 126 static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, 127 struct drm_plane_state *plane_state) 128 { 129 struct drm_simple_display_pipe *pipe; 130 struct drm_crtc_state *crtc_state; 131 int ret; 132 133 pipe = container_of(plane, struct drm_simple_display_pipe, plane); 134 crtc_state = drm_atomic_get_new_crtc_state(plane_state->state, 135 &pipe->crtc); 136 137 ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, 138 DRM_PLANE_HELPER_NO_SCALING, 139 DRM_PLANE_HELPER_NO_SCALING, 140 false, true); 141 if (ret) 142 return ret; 143 144 if (!plane_state->visible) 145 return 0; 146 147 if (!pipe->funcs || !pipe->funcs->check) 148 return 0; 149 150 return pipe->funcs->check(pipe, plane_state, crtc_state); 151 } 152 153 static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane, 154 struct drm_plane_state *old_pstate) 155 { 156 struct drm_simple_display_pipe *pipe; 157 158 pipe = container_of(plane, struct drm_simple_display_pipe, plane); 159 if (!pipe->funcs || !pipe->funcs->update) 160 return; 161 162 pipe->funcs->update(pipe, old_pstate); 163 } 164 165 static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane, 166 struct drm_plane_state *state) 167 { 168 struct drm_simple_display_pipe *pipe; 169 170 pipe = container_of(plane, struct drm_simple_display_pipe, plane); 171 if (!pipe->funcs || !pipe->funcs->prepare_fb) 172 return 0; 173 174 return pipe->funcs->prepare_fb(pipe, state); 175 } 176 177 static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane, 178 struct drm_plane_state *state) 179 { 180 struct drm_simple_display_pipe *pipe; 181 182 pipe = container_of(plane, struct drm_simple_display_pipe, plane); 183 if (!pipe->funcs || !pipe->funcs->cleanup_fb) 184 return; 185 186 pipe->funcs->cleanup_fb(pipe, state); 187 } 188 189 static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane, 190 uint32_t format, 191 uint64_t modifier) 192 { 193 return modifier == DRM_FORMAT_MOD_LINEAR; 194 } 195 196 static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = { 197 .prepare_fb = drm_simple_kms_plane_prepare_fb, 198 .cleanup_fb = drm_simple_kms_plane_cleanup_fb, 199 .atomic_check = drm_simple_kms_plane_atomic_check, 200 .atomic_update = drm_simple_kms_plane_atomic_update, 201 }; 202 203 static const struct drm_plane_funcs drm_simple_kms_plane_funcs = { 204 .update_plane = drm_atomic_helper_update_plane, 205 .disable_plane = drm_atomic_helper_disable_plane, 206 .destroy = drm_plane_cleanup, 207 .reset = drm_atomic_helper_plane_reset, 208 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 209 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 210 .format_mod_supported = drm_simple_kms_format_mod_supported, 211 }; 212 213 /** 214 * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe 215 * @pipe: simple display pipe object 216 * @bridge: bridge to attach 217 * 218 * Makes it possible to still use the drm_simple_display_pipe helpers when 219 * a DRM bridge has to be used. 220 * 221 * Note that you probably want to initialize the pipe by passing a NULL 222 * connector to drm_simple_display_pipe_init(). 223 * 224 * Returns: 225 * Zero on success, negative error code on failure. 226 */ 227 int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe, 228 struct drm_bridge *bridge) 229 { 230 return drm_bridge_attach(&pipe->encoder, bridge, NULL); 231 } 232 EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge); 233 234 /** 235 * drm_simple_display_pipe_init - Initialize a simple display pipeline 236 * @dev: DRM device 237 * @pipe: simple display pipe object to initialize 238 * @funcs: callbacks for the display pipe (optional) 239 * @formats: array of supported formats (DRM_FORMAT\_\*) 240 * @format_count: number of elements in @formats 241 * @format_modifiers: array of formats modifiers 242 * @connector: connector to attach and register (optional) 243 * 244 * Sets up a display pipeline which consist of a really simple 245 * plane-crtc-encoder pipe. 246 * 247 * If a connector is supplied, the pipe will be coupled with the provided 248 * connector. You may supply a NULL connector when using drm bridges, that 249 * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()). 250 * 251 * Teardown of a simple display pipe is all handled automatically by the drm 252 * core through calling drm_mode_config_cleanup(). Drivers afterwards need to 253 * release the memory for the structure themselves. 254 * 255 * Returns: 256 * Zero on success, negative error code on failure. 257 */ 258 int drm_simple_display_pipe_init(struct drm_device *dev, 259 struct drm_simple_display_pipe *pipe, 260 const struct drm_simple_display_pipe_funcs *funcs, 261 const uint32_t *formats, unsigned int format_count, 262 const uint64_t *format_modifiers, 263 struct drm_connector *connector) 264 { 265 struct drm_encoder *encoder = &pipe->encoder; 266 struct drm_plane *plane = &pipe->plane; 267 struct drm_crtc *crtc = &pipe->crtc; 268 int ret; 269 270 pipe->connector = connector; 271 pipe->funcs = funcs; 272 273 drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs); 274 ret = drm_universal_plane_init(dev, plane, 0, 275 &drm_simple_kms_plane_funcs, 276 formats, format_count, 277 format_modifiers, 278 DRM_PLANE_TYPE_PRIMARY, NULL); 279 if (ret) 280 return ret; 281 282 drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs); 283 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 284 &drm_simple_kms_crtc_funcs, NULL); 285 if (ret) 286 return ret; 287 288 encoder->possible_crtcs = drm_crtc_mask(crtc); 289 ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs, 290 DRM_MODE_ENCODER_NONE, NULL); 291 if (ret || !connector) 292 return ret; 293 294 return drm_connector_attach_encoder(connector, encoder); 295 } 296 EXPORT_SYMBOL(drm_simple_display_pipe_init); 297 298 MODULE_LICENSE("GPL"); 299