1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   * Copyright (C) 2016 Noralf Trønnes
4   */
5  
6  #include <linux/module.h>
7  #include <linux/slab.h>
8  
9  #include <drm/drm_atomic.h>
10  #include <drm/drm_atomic_helper.h>
11  #include <drm/drm_bridge.h>
12  #include <drm/drm_drv.h>
13  #include <drm/drm_gem_atomic_helper.h>
14  #include <drm/drm_managed.h>
15  #include <drm/drm_probe_helper.h>
16  #include <drm/drm_simple_kms_helper.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   * Many drivers require only a very simple encoder that fulfills the minimum
33   * requirements of the display pipeline and does not add additional
34   * functionality. The function drm_simple_encoder_init() provides an
35   * implementation of such an encoder.
36   */
37  
38  static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
39  	.destroy = drm_encoder_cleanup,
40  };
41  
42  /**
43   * drm_simple_encoder_init - Initialize a preallocated encoder with
44   *                           basic functionality.
45   * @dev: drm device
46   * @encoder: the encoder to initialize
47   * @encoder_type: user visible type of the encoder
48   *
49   * Initialises a preallocated encoder that has no further functionality.
50   * Settings for possible CRTC and clones are left to their initial values.
51   * The encoder will be cleaned up automatically as part of the mode-setting
52   * cleanup.
53   *
54   * The caller of drm_simple_encoder_init() is responsible for freeing
55   * the encoder's memory after the encoder has been cleaned up. At the
56   * moment this only works reliably if the encoder data structure is
57   * stored in the device structure. Free the encoder's memory as part of
58   * the device release function.
59   *
60   * Note: consider using drmm_simple_encoder_alloc() instead of
61   * drm_simple_encoder_init() to let the DRM managed resource infrastructure
62   * take care of cleanup and deallocation.
63   *
64   * Returns:
65   * Zero on success, error code on failure.
66   */
drm_simple_encoder_init(struct drm_device * dev,struct drm_encoder * encoder,int encoder_type)67  int drm_simple_encoder_init(struct drm_device *dev,
68  			    struct drm_encoder *encoder,
69  			    int encoder_type)
70  {
71  	return drm_encoder_init(dev, encoder,
72  				&drm_simple_encoder_funcs_cleanup,
73  				encoder_type, NULL);
74  }
75  EXPORT_SYMBOL(drm_simple_encoder_init);
76  
__drmm_simple_encoder_alloc(struct drm_device * dev,size_t size,size_t offset,int encoder_type)77  void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
78  				  size_t offset, int encoder_type)
79  {
80  	return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type,
81  				    NULL);
82  }
83  EXPORT_SYMBOL(__drmm_simple_encoder_alloc);
84  
85  static enum drm_mode_status
drm_simple_kms_crtc_mode_valid(struct drm_crtc * crtc,const struct drm_display_mode * mode)86  drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
87  			       const struct drm_display_mode *mode)
88  {
89  	struct drm_simple_display_pipe *pipe;
90  
91  	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
92  	if (!pipe->funcs || !pipe->funcs->mode_valid)
93  		/* Anything goes */
94  		return MODE_OK;
95  
96  	return pipe->funcs->mode_valid(pipe, mode);
97  }
98  
drm_simple_kms_crtc_check(struct drm_crtc * crtc,struct drm_atomic_state * state)99  static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
100  				     struct drm_atomic_state *state)
101  {
102  	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
103  	int ret;
104  
105  	if (!crtc_state->enable)
106  		goto out;
107  
108  	ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
109  	if (ret)
110  		return ret;
111  
112  out:
113  	return drm_atomic_add_affected_planes(state, crtc);
114  }
115  
drm_simple_kms_crtc_enable(struct drm_crtc * crtc,struct drm_atomic_state * state)116  static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
117  				       struct drm_atomic_state *state)
118  {
119  	struct drm_plane *plane;
120  	struct drm_simple_display_pipe *pipe;
121  
122  	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
123  	if (!pipe->funcs || !pipe->funcs->enable)
124  		return;
125  
126  	plane = &pipe->plane;
127  	pipe->funcs->enable(pipe, crtc->state, plane->state);
128  }
129  
drm_simple_kms_crtc_disable(struct drm_crtc * crtc,struct drm_atomic_state * state)130  static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
131  					struct drm_atomic_state *state)
132  {
133  	struct drm_simple_display_pipe *pipe;
134  
135  	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
136  	if (!pipe->funcs || !pipe->funcs->disable)
137  		return;
138  
139  	pipe->funcs->disable(pipe);
140  }
141  
142  static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
143  	.mode_valid = drm_simple_kms_crtc_mode_valid,
144  	.atomic_check = drm_simple_kms_crtc_check,
145  	.atomic_enable = drm_simple_kms_crtc_enable,
146  	.atomic_disable = drm_simple_kms_crtc_disable,
147  };
148  
drm_simple_kms_crtc_reset(struct drm_crtc * crtc)149  static void drm_simple_kms_crtc_reset(struct drm_crtc *crtc)
150  {
151  	struct drm_simple_display_pipe *pipe;
152  
153  	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
154  	if (!pipe->funcs || !pipe->funcs->reset_crtc)
155  		return drm_atomic_helper_crtc_reset(crtc);
156  
157  	return pipe->funcs->reset_crtc(pipe);
158  }
159  
drm_simple_kms_crtc_duplicate_state(struct drm_crtc * crtc)160  static struct drm_crtc_state *drm_simple_kms_crtc_duplicate_state(struct drm_crtc *crtc)
161  {
162  	struct drm_simple_display_pipe *pipe;
163  
164  	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
165  	if (!pipe->funcs || !pipe->funcs->duplicate_crtc_state)
166  		return drm_atomic_helper_crtc_duplicate_state(crtc);
167  
168  	return pipe->funcs->duplicate_crtc_state(pipe);
169  }
170  
drm_simple_kms_crtc_destroy_state(struct drm_crtc * crtc,struct drm_crtc_state * state)171  static void drm_simple_kms_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state)
172  {
173  	struct drm_simple_display_pipe *pipe;
174  
175  	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
176  	if (!pipe->funcs || !pipe->funcs->destroy_crtc_state)
177  		drm_atomic_helper_crtc_destroy_state(crtc, state);
178  	else
179  		pipe->funcs->destroy_crtc_state(pipe, state);
180  }
181  
drm_simple_kms_crtc_enable_vblank(struct drm_crtc * crtc)182  static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
183  {
184  	struct drm_simple_display_pipe *pipe;
185  
186  	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
187  	if (!pipe->funcs || !pipe->funcs->enable_vblank)
188  		return 0;
189  
190  	return pipe->funcs->enable_vblank(pipe);
191  }
192  
drm_simple_kms_crtc_disable_vblank(struct drm_crtc * crtc)193  static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
194  {
195  	struct drm_simple_display_pipe *pipe;
196  
197  	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
198  	if (!pipe->funcs || !pipe->funcs->disable_vblank)
199  		return;
200  
201  	pipe->funcs->disable_vblank(pipe);
202  }
203  
204  static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
205  	.reset = drm_simple_kms_crtc_reset,
206  	.destroy = drm_crtc_cleanup,
207  	.set_config = drm_atomic_helper_set_config,
208  	.page_flip = drm_atomic_helper_page_flip,
209  	.atomic_duplicate_state = drm_simple_kms_crtc_duplicate_state,
210  	.atomic_destroy_state = drm_simple_kms_crtc_destroy_state,
211  	.enable_vblank = drm_simple_kms_crtc_enable_vblank,
212  	.disable_vblank = drm_simple_kms_crtc_disable_vblank,
213  };
214  
drm_simple_kms_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)215  static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
216  					struct drm_atomic_state *state)
217  {
218  	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
219  									     plane);
220  	struct drm_simple_display_pipe *pipe;
221  	struct drm_crtc_state *crtc_state;
222  	int ret;
223  
224  	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
225  	crtc_state = drm_atomic_get_new_crtc_state(state,
226  						   &pipe->crtc);
227  
228  	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
229  						  DRM_PLANE_NO_SCALING,
230  						  DRM_PLANE_NO_SCALING,
231  						  false, false);
232  	if (ret)
233  		return ret;
234  
235  	if (!plane_state->visible)
236  		return 0;
237  
238  	if (!pipe->funcs || !pipe->funcs->check)
239  		return 0;
240  
241  	return pipe->funcs->check(pipe, plane_state, crtc_state);
242  }
243  
drm_simple_kms_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)244  static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
245  					struct drm_atomic_state *state)
246  {
247  	struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
248  									    plane);
249  	struct drm_simple_display_pipe *pipe;
250  
251  	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
252  	if (!pipe->funcs || !pipe->funcs->update)
253  		return;
254  
255  	pipe->funcs->update(pipe, old_pstate);
256  }
257  
drm_simple_kms_plane_prepare_fb(struct drm_plane * plane,struct drm_plane_state * state)258  static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
259  					   struct drm_plane_state *state)
260  {
261  	struct drm_simple_display_pipe *pipe;
262  
263  	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
264  	if (!pipe->funcs || !pipe->funcs->prepare_fb) {
265  		if (WARN_ON_ONCE(!drm_core_check_feature(plane->dev, DRIVER_GEM)))
266  			return 0;
267  
268  		WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb);
269  
270  		return drm_gem_plane_helper_prepare_fb(plane, state);
271  	}
272  
273  	return pipe->funcs->prepare_fb(pipe, state);
274  }
275  
drm_simple_kms_plane_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * state)276  static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
277  					    struct drm_plane_state *state)
278  {
279  	struct drm_simple_display_pipe *pipe;
280  
281  	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
282  	if (!pipe->funcs || !pipe->funcs->cleanup_fb)
283  		return;
284  
285  	pipe->funcs->cleanup_fb(pipe, state);
286  }
287  
drm_simple_kms_plane_begin_fb_access(struct drm_plane * plane,struct drm_plane_state * new_plane_state)288  static int drm_simple_kms_plane_begin_fb_access(struct drm_plane *plane,
289  						struct drm_plane_state *new_plane_state)
290  {
291  	struct drm_simple_display_pipe *pipe;
292  
293  	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
294  	if (!pipe->funcs || !pipe->funcs->begin_fb_access)
295  		return 0;
296  
297  	return pipe->funcs->begin_fb_access(pipe, new_plane_state);
298  }
299  
drm_simple_kms_plane_end_fb_access(struct drm_plane * plane,struct drm_plane_state * new_plane_state)300  static void drm_simple_kms_plane_end_fb_access(struct drm_plane *plane,
301  					       struct drm_plane_state *new_plane_state)
302  {
303  	struct drm_simple_display_pipe *pipe;
304  
305  	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
306  	if (!pipe->funcs || !pipe->funcs->end_fb_access)
307  		return;
308  
309  	pipe->funcs->end_fb_access(pipe, new_plane_state);
310  }
311  
drm_simple_kms_format_mod_supported(struct drm_plane * plane,uint32_t format,uint64_t modifier)312  static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
313  						uint32_t format,
314  						uint64_t modifier)
315  {
316  	return modifier == DRM_FORMAT_MOD_LINEAR;
317  }
318  
319  static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
320  	.prepare_fb = drm_simple_kms_plane_prepare_fb,
321  	.cleanup_fb = drm_simple_kms_plane_cleanup_fb,
322  	.begin_fb_access = drm_simple_kms_plane_begin_fb_access,
323  	.end_fb_access = drm_simple_kms_plane_end_fb_access,
324  	.atomic_check = drm_simple_kms_plane_atomic_check,
325  	.atomic_update = drm_simple_kms_plane_atomic_update,
326  };
327  
drm_simple_kms_plane_reset(struct drm_plane * plane)328  static void drm_simple_kms_plane_reset(struct drm_plane *plane)
329  {
330  	struct drm_simple_display_pipe *pipe;
331  
332  	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
333  	if (!pipe->funcs || !pipe->funcs->reset_plane)
334  		return drm_atomic_helper_plane_reset(plane);
335  
336  	return pipe->funcs->reset_plane(pipe);
337  }
338  
drm_simple_kms_plane_duplicate_state(struct drm_plane * plane)339  static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane)
340  {
341  	struct drm_simple_display_pipe *pipe;
342  
343  	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
344  	if (!pipe->funcs || !pipe->funcs->duplicate_plane_state)
345  		return drm_atomic_helper_plane_duplicate_state(plane);
346  
347  	return pipe->funcs->duplicate_plane_state(pipe);
348  }
349  
drm_simple_kms_plane_destroy_state(struct drm_plane * plane,struct drm_plane_state * state)350  static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane,
351  					       struct drm_plane_state *state)
352  {
353  	struct drm_simple_display_pipe *pipe;
354  
355  	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
356  	if (!pipe->funcs || !pipe->funcs->destroy_plane_state)
357  		drm_atomic_helper_plane_destroy_state(plane, state);
358  	else
359  		pipe->funcs->destroy_plane_state(pipe, state);
360  }
361  
362  static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
363  	.update_plane		= drm_atomic_helper_update_plane,
364  	.disable_plane		= drm_atomic_helper_disable_plane,
365  	.destroy		= drm_plane_cleanup,
366  	.reset			= drm_simple_kms_plane_reset,
367  	.atomic_duplicate_state	= drm_simple_kms_plane_duplicate_state,
368  	.atomic_destroy_state	= drm_simple_kms_plane_destroy_state,
369  	.format_mod_supported   = drm_simple_kms_format_mod_supported,
370  };
371  
372  /**
373   * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
374   * @pipe: simple display pipe object
375   * @bridge: bridge to attach
376   *
377   * Makes it possible to still use the drm_simple_display_pipe helpers when
378   * a DRM bridge has to be used.
379   *
380   * Note that you probably want to initialize the pipe by passing a NULL
381   * connector to drm_simple_display_pipe_init().
382   *
383   * Returns:
384   * Zero on success, negative error code on failure.
385   */
drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe * pipe,struct drm_bridge * bridge)386  int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
387  					  struct drm_bridge *bridge)
388  {
389  	return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0);
390  }
391  EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
392  
393  /**
394   * drm_simple_display_pipe_init - Initialize a simple display pipeline
395   * @dev: DRM device
396   * @pipe: simple display pipe object to initialize
397   * @funcs: callbacks for the display pipe (optional)
398   * @formats: array of supported formats (DRM_FORMAT\_\*)
399   * @format_count: number of elements in @formats
400   * @format_modifiers: array of formats modifiers
401   * @connector: connector to attach and register (optional)
402   *
403   * Sets up a display pipeline which consist of a really simple
404   * plane-crtc-encoder pipe.
405   *
406   * If a connector is supplied, the pipe will be coupled with the provided
407   * connector. You may supply a NULL connector when using drm bridges, that
408   * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
409   *
410   * Teardown of a simple display pipe is all handled automatically by the drm
411   * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
412   * release the memory for the structure themselves.
413   *
414   * Returns:
415   * Zero on success, negative error code on failure.
416   */
drm_simple_display_pipe_init(struct drm_device * dev,struct drm_simple_display_pipe * pipe,const struct drm_simple_display_pipe_funcs * funcs,const uint32_t * formats,unsigned int format_count,const uint64_t * format_modifiers,struct drm_connector * connector)417  int drm_simple_display_pipe_init(struct drm_device *dev,
418  			struct drm_simple_display_pipe *pipe,
419  			const struct drm_simple_display_pipe_funcs *funcs,
420  			const uint32_t *formats, unsigned int format_count,
421  			const uint64_t *format_modifiers,
422  			struct drm_connector *connector)
423  {
424  	struct drm_encoder *encoder = &pipe->encoder;
425  	struct drm_plane *plane = &pipe->plane;
426  	struct drm_crtc *crtc = &pipe->crtc;
427  	int ret;
428  
429  	pipe->connector = connector;
430  	pipe->funcs = funcs;
431  
432  	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
433  	ret = drm_universal_plane_init(dev, plane, 0,
434  				       &drm_simple_kms_plane_funcs,
435  				       formats, format_count,
436  				       format_modifiers,
437  				       DRM_PLANE_TYPE_PRIMARY, NULL);
438  	if (ret)
439  		return ret;
440  
441  	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
442  	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
443  					&drm_simple_kms_crtc_funcs, NULL);
444  	if (ret)
445  		return ret;
446  
447  	encoder->possible_crtcs = drm_crtc_mask(crtc);
448  	ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
449  	if (ret || !connector)
450  		return ret;
451  
452  	return drm_connector_attach_encoder(connector, encoder);
453  }
454  EXPORT_SYMBOL(drm_simple_display_pipe_init);
455  
456  MODULE_DESCRIPTION("Helpers for drivers for simple display hardware");
457  MODULE_LICENSE("GPL");
458