LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_simple_kms_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 116 0.0 %
Date: 2023-07-19 18:55:55 Functions: 0 23 0.0 %

          Line data    Source code
       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             :  */
      67           0 : int drm_simple_encoder_init(struct drm_device *dev,
      68             :                             struct drm_encoder *encoder,
      69             :                             int encoder_type)
      70             : {
      71           0 :         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             : 
      77           0 : void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
      78             :                                   size_t offset, int encoder_type)
      79             : {
      80           0 :         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
      86           0 : 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           0 :         pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
      92           0 :         if (!pipe->funcs || !pipe->funcs->mode_valid)
      93             :                 /* Anything goes */
      94             :                 return MODE_OK;
      95             : 
      96           0 :         return pipe->funcs->mode_valid(pipe, mode);
      97             : }
      98             : 
      99           0 : static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
     100             :                                      struct drm_atomic_state *state)
     101             : {
     102           0 :         struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
     103             :         int ret;
     104             : 
     105           0 :         if (!crtc_state->enable)
     106             :                 goto out;
     107             : 
     108           0 :         ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
     109           0 :         if (ret)
     110             :                 return ret;
     111             : 
     112             : out:
     113           0 :         return drm_atomic_add_affected_planes(state, crtc);
     114             : }
     115             : 
     116           0 : 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           0 :         pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
     123           0 :         if (!pipe->funcs || !pipe->funcs->enable)
     124             :                 return;
     125             : 
     126           0 :         plane = &pipe->plane;
     127           0 :         pipe->funcs->enable(pipe, crtc->state, plane->state);
     128             : }
     129             : 
     130           0 : 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           0 :         pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
     136           0 :         if (!pipe->funcs || !pipe->funcs->disable)
     137             :                 return;
     138             : 
     139           0 :         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             : 
     149           0 : static void drm_simple_kms_crtc_reset(struct drm_crtc *crtc)
     150             : {
     151             :         struct drm_simple_display_pipe *pipe;
     152             : 
     153           0 :         pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
     154           0 :         if (!pipe->funcs || !pipe->funcs->reset_crtc)
     155           0 :                 return drm_atomic_helper_crtc_reset(crtc);
     156             : 
     157           0 :         return pipe->funcs->reset_crtc(pipe);
     158             : }
     159             : 
     160           0 : 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           0 :         pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
     165           0 :         if (!pipe->funcs || !pipe->funcs->duplicate_crtc_state)
     166           0 :                 return drm_atomic_helper_crtc_duplicate_state(crtc);
     167             : 
     168           0 :         return pipe->funcs->duplicate_crtc_state(pipe);
     169             : }
     170             : 
     171           0 : 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           0 :         pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
     176           0 :         if (!pipe->funcs || !pipe->funcs->destroy_crtc_state)
     177           0 :                 drm_atomic_helper_crtc_destroy_state(crtc, state);
     178             :         else
     179           0 :                 pipe->funcs->destroy_crtc_state(pipe, state);
     180           0 : }
     181             : 
     182           0 : static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
     183             : {
     184             :         struct drm_simple_display_pipe *pipe;
     185             : 
     186           0 :         pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
     187           0 :         if (!pipe->funcs || !pipe->funcs->enable_vblank)
     188             :                 return 0;
     189             : 
     190           0 :         return pipe->funcs->enable_vblank(pipe);
     191             : }
     192             : 
     193           0 : static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
     194             : {
     195             :         struct drm_simple_display_pipe *pipe;
     196             : 
     197           0 :         pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
     198           0 :         if (!pipe->funcs || !pipe->funcs->disable_vblank)
     199             :                 return;
     200             : 
     201           0 :         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             : 
     215           0 : static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
     216             :                                         struct drm_atomic_state *state)
     217             : {
     218           0 :         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           0 :         pipe = container_of(plane, struct drm_simple_display_pipe, plane);
     225           0 :         crtc_state = drm_atomic_get_new_crtc_state(state,
     226             :                                                    &pipe->crtc);
     227             : 
     228           0 :         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           0 :         if (ret)
     233             :                 return ret;
     234             : 
     235           0 :         if (!plane_state->visible)
     236             :                 return 0;
     237             : 
     238           0 :         if (!pipe->funcs || !pipe->funcs->check)
     239             :                 return 0;
     240             : 
     241           0 :         return pipe->funcs->check(pipe, plane_state, crtc_state);
     242             : }
     243             : 
     244           0 : static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
     245             :                                         struct drm_atomic_state *state)
     246             : {
     247           0 :         struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
     248             :                                                                             plane);
     249             :         struct drm_simple_display_pipe *pipe;
     250             : 
     251           0 :         pipe = container_of(plane, struct drm_simple_display_pipe, plane);
     252           0 :         if (!pipe->funcs || !pipe->funcs->update)
     253             :                 return;
     254             : 
     255           0 :         pipe->funcs->update(pipe, old_pstate);
     256             : }
     257             : 
     258           0 : 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           0 :         pipe = container_of(plane, struct drm_simple_display_pipe, plane);
     264           0 :         if (!pipe->funcs || !pipe->funcs->prepare_fb) {
     265           0 :                 if (WARN_ON_ONCE(!drm_core_check_feature(plane->dev, DRIVER_GEM)))
     266             :                         return 0;
     267             : 
     268           0 :                 WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb);
     269             : 
     270           0 :                 return drm_gem_plane_helper_prepare_fb(plane, state);
     271             :         }
     272             : 
     273           0 :         return pipe->funcs->prepare_fb(pipe, state);
     274             : }
     275             : 
     276           0 : 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           0 :         pipe = container_of(plane, struct drm_simple_display_pipe, plane);
     282           0 :         if (!pipe->funcs || !pipe->funcs->cleanup_fb)
     283             :                 return;
     284             : 
     285           0 :         pipe->funcs->cleanup_fb(pipe, state);
     286             : }
     287             : 
     288           0 : 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           0 :         pipe = container_of(plane, struct drm_simple_display_pipe, plane);
     294           0 :         if (!pipe->funcs || !pipe->funcs->begin_fb_access)
     295             :                 return 0;
     296             : 
     297           0 :         return pipe->funcs->begin_fb_access(pipe, new_plane_state);
     298             : }
     299             : 
     300           0 : 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           0 :         pipe = container_of(plane, struct drm_simple_display_pipe, plane);
     306           0 :         if (!pipe->funcs || !pipe->funcs->end_fb_access)
     307             :                 return;
     308             : 
     309           0 :         pipe->funcs->end_fb_access(pipe, new_plane_state);
     310             : }
     311             : 
     312           0 : static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
     313             :                                                 uint32_t format,
     314             :                                                 uint64_t modifier)
     315             : {
     316           0 :         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             : 
     328           0 : static void drm_simple_kms_plane_reset(struct drm_plane *plane)
     329             : {
     330             :         struct drm_simple_display_pipe *pipe;
     331             : 
     332           0 :         pipe = container_of(plane, struct drm_simple_display_pipe, plane);
     333           0 :         if (!pipe->funcs || !pipe->funcs->reset_plane)
     334           0 :                 return drm_atomic_helper_plane_reset(plane);
     335             : 
     336           0 :         return pipe->funcs->reset_plane(pipe);
     337             : }
     338             : 
     339           0 : 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           0 :         pipe = container_of(plane, struct drm_simple_display_pipe, plane);
     344           0 :         if (!pipe->funcs || !pipe->funcs->duplicate_plane_state)
     345           0 :                 return drm_atomic_helper_plane_duplicate_state(plane);
     346             : 
     347           0 :         return pipe->funcs->duplicate_plane_state(pipe);
     348             : }
     349             : 
     350           0 : 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           0 :         pipe = container_of(plane, struct drm_simple_display_pipe, plane);
     356           0 :         if (!pipe->funcs || !pipe->funcs->destroy_plane_state)
     357           0 :                 drm_atomic_helper_plane_destroy_state(plane, state);
     358             :         else
     359           0 :                 pipe->funcs->destroy_plane_state(pipe, state);
     360           0 : }
     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             :  */
     386           0 : int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
     387             :                                           struct drm_bridge *bridge)
     388             : {
     389           0 :         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             :  */
     417           0 : 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           0 :         struct drm_encoder *encoder = &pipe->encoder;
     425           0 :         struct drm_plane *plane = &pipe->plane;
     426           0 :         struct drm_crtc *crtc = &pipe->crtc;
     427             :         int ret;
     428             : 
     429           0 :         pipe->connector = connector;
     430           0 :         pipe->funcs = funcs;
     431             : 
     432           0 :         drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
     433           0 :         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           0 :         if (ret)
     439             :                 return ret;
     440             : 
     441           0 :         drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
     442           0 :         ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
     443             :                                         &drm_simple_kms_crtc_funcs, NULL);
     444           0 :         if (ret)
     445             :                 return ret;
     446             : 
     447           0 :         encoder->possible_crtcs = drm_crtc_mask(crtc);
     448           0 :         ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
     449           0 :         if (ret || !connector)
     450             :                 return ret;
     451             : 
     452           0 :         return drm_connector_attach_encoder(connector, encoder);
     453             : }
     454             : EXPORT_SYMBOL(drm_simple_display_pipe_init);
     455             : 
     456             : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14