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