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

Generated by: LCOV version 1.14