Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2016 Noralf Trønnes
0004  */
0005 
0006 #include <linux/module.h>
0007 #include <linux/slab.h>
0008 
0009 #include <drm/drm_atomic.h>
0010 #include <drm/drm_atomic_helper.h>
0011 #include <drm/drm_bridge.h>
0012 #include <drm/drm_drv.h>
0013 #include <drm/drm_gem_atomic_helper.h>
0014 #include <drm/drm_managed.h>
0015 #include <drm/drm_plane_helper.h>
0016 #include <drm/drm_probe_helper.h>
0017 #include <drm/drm_simple_kms_helper.h>
0018 
0019 /**
0020  * DOC: overview
0021  *
0022  * This helper library provides helpers for drivers for simple display
0023  * hardware.
0024  *
0025  * drm_simple_display_pipe_init() initializes a simple display pipeline
0026  * which has only one full-screen scanout buffer feeding one output. The
0027  * pipeline is represented by &struct drm_simple_display_pipe and binds
0028  * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed
0029  * entity. Some flexibility for code reuse is provided through a separately
0030  * allocated &drm_connector object and supporting optional &drm_bridge
0031  * encoder drivers.
0032  *
0033  * Many drivers require only a very simple encoder that fulfills the minimum
0034  * requirements of the display pipeline and does not add additional
0035  * functionality. The function drm_simple_encoder_init() provides an
0036  * implementation of such an encoder.
0037  */
0038 
0039 static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
0040     .destroy = drm_encoder_cleanup,
0041 };
0042 
0043 /**
0044  * drm_simple_encoder_init - Initialize a preallocated encoder with
0045  *                           basic functionality.
0046  * @dev: drm device
0047  * @encoder: the encoder to initialize
0048  * @encoder_type: user visible type of the encoder
0049  *
0050  * Initialises a preallocated encoder that has no further functionality.
0051  * Settings for possible CRTC and clones are left to their initial values.
0052  * The encoder will be cleaned up automatically as part of the mode-setting
0053  * cleanup.
0054  *
0055  * The caller of drm_simple_encoder_init() is responsible for freeing
0056  * the encoder's memory after the encoder has been cleaned up. At the
0057  * moment this only works reliably if the encoder data structure is
0058  * stored in the device structure. Free the encoder's memory as part of
0059  * the device release function.
0060  *
0061  * Note: consider using drmm_simple_encoder_alloc() instead of
0062  * drm_simple_encoder_init() to let the DRM managed resource infrastructure
0063  * take care of cleanup and deallocation.
0064  *
0065  * Returns:
0066  * Zero on success, error code on failure.
0067  */
0068 int drm_simple_encoder_init(struct drm_device *dev,
0069                 struct drm_encoder *encoder,
0070                 int encoder_type)
0071 {
0072     return drm_encoder_init(dev, encoder,
0073                 &drm_simple_encoder_funcs_cleanup,
0074                 encoder_type, NULL);
0075 }
0076 EXPORT_SYMBOL(drm_simple_encoder_init);
0077 
0078 void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
0079                   size_t offset, int encoder_type)
0080 {
0081     return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type,
0082                     NULL);
0083 }
0084 EXPORT_SYMBOL(__drmm_simple_encoder_alloc);
0085 
0086 static enum drm_mode_status
0087 drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
0088                    const struct drm_display_mode *mode)
0089 {
0090     struct drm_simple_display_pipe *pipe;
0091 
0092     pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
0093     if (!pipe->funcs || !pipe->funcs->mode_valid)
0094         /* Anything goes */
0095         return MODE_OK;
0096 
0097     return pipe->funcs->mode_valid(pipe, mode);
0098 }
0099 
0100 static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
0101                      struct drm_atomic_state *state)
0102 {
0103     struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
0104     int ret;
0105 
0106     ret = drm_atomic_helper_check_crtc_state(crtc_state, false);
0107     if (ret)
0108         return ret;
0109 
0110     return drm_atomic_add_affected_planes(state, crtc);
0111 }
0112 
0113 static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc,
0114                        struct drm_atomic_state *state)
0115 {
0116     struct drm_plane *plane;
0117     struct drm_simple_display_pipe *pipe;
0118 
0119     pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
0120     if (!pipe->funcs || !pipe->funcs->enable)
0121         return;
0122 
0123     plane = &pipe->plane;
0124     pipe->funcs->enable(pipe, crtc->state, plane->state);
0125 }
0126 
0127 static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
0128                     struct drm_atomic_state *state)
0129 {
0130     struct drm_simple_display_pipe *pipe;
0131 
0132     pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
0133     if (!pipe->funcs || !pipe->funcs->disable)
0134         return;
0135 
0136     pipe->funcs->disable(pipe);
0137 }
0138 
0139 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
0140     .mode_valid = drm_simple_kms_crtc_mode_valid,
0141     .atomic_check = drm_simple_kms_crtc_check,
0142     .atomic_enable = drm_simple_kms_crtc_enable,
0143     .atomic_disable = drm_simple_kms_crtc_disable,
0144 };
0145 
0146 static void drm_simple_kms_crtc_reset(struct drm_crtc *crtc)
0147 {
0148     struct drm_simple_display_pipe *pipe;
0149 
0150     pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
0151     if (!pipe->funcs || !pipe->funcs->reset_crtc)
0152         return drm_atomic_helper_crtc_reset(crtc);
0153 
0154     return pipe->funcs->reset_crtc(pipe);
0155 }
0156 
0157 static struct drm_crtc_state *drm_simple_kms_crtc_duplicate_state(struct drm_crtc *crtc)
0158 {
0159     struct drm_simple_display_pipe *pipe;
0160 
0161     pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
0162     if (!pipe->funcs || !pipe->funcs->duplicate_crtc_state)
0163         return drm_atomic_helper_crtc_duplicate_state(crtc);
0164 
0165     return pipe->funcs->duplicate_crtc_state(pipe);
0166 }
0167 
0168 static void drm_simple_kms_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state)
0169 {
0170     struct drm_simple_display_pipe *pipe;
0171 
0172     pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
0173     if (!pipe->funcs || !pipe->funcs->destroy_crtc_state)
0174         drm_atomic_helper_crtc_destroy_state(crtc, state);
0175     else
0176         pipe->funcs->destroy_crtc_state(pipe, state);
0177 }
0178 
0179 static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc)
0180 {
0181     struct drm_simple_display_pipe *pipe;
0182 
0183     pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
0184     if (!pipe->funcs || !pipe->funcs->enable_vblank)
0185         return 0;
0186 
0187     return pipe->funcs->enable_vblank(pipe);
0188 }
0189 
0190 static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc)
0191 {
0192     struct drm_simple_display_pipe *pipe;
0193 
0194     pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
0195     if (!pipe->funcs || !pipe->funcs->disable_vblank)
0196         return;
0197 
0198     pipe->funcs->disable_vblank(pipe);
0199 }
0200 
0201 static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = {
0202     .reset = drm_simple_kms_crtc_reset,
0203     .destroy = drm_crtc_cleanup,
0204     .set_config = drm_atomic_helper_set_config,
0205     .page_flip = drm_atomic_helper_page_flip,
0206     .atomic_duplicate_state = drm_simple_kms_crtc_duplicate_state,
0207     .atomic_destroy_state = drm_simple_kms_crtc_destroy_state,
0208     .enable_vblank = drm_simple_kms_crtc_enable_vblank,
0209     .disable_vblank = drm_simple_kms_crtc_disable_vblank,
0210 };
0211 
0212 static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
0213                     struct drm_atomic_state *state)
0214 {
0215     struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
0216                                          plane);
0217     struct drm_simple_display_pipe *pipe;
0218     struct drm_crtc_state *crtc_state;
0219     int ret;
0220 
0221     pipe = container_of(plane, struct drm_simple_display_pipe, plane);
0222     crtc_state = drm_atomic_get_new_crtc_state(state,
0223                            &pipe->crtc);
0224 
0225     ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
0226                           DRM_PLANE_HELPER_NO_SCALING,
0227                           DRM_PLANE_HELPER_NO_SCALING,
0228                           false, false);
0229     if (ret)
0230         return ret;
0231 
0232     if (!plane_state->visible)
0233         return 0;
0234 
0235     if (!pipe->funcs || !pipe->funcs->check)
0236         return 0;
0237 
0238     return pipe->funcs->check(pipe, plane_state, crtc_state);
0239 }
0240 
0241 static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
0242                     struct drm_atomic_state *state)
0243 {
0244     struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state,
0245                                         plane);
0246     struct drm_simple_display_pipe *pipe;
0247 
0248     pipe = container_of(plane, struct drm_simple_display_pipe, plane);
0249     if (!pipe->funcs || !pipe->funcs->update)
0250         return;
0251 
0252     pipe->funcs->update(pipe, old_pstate);
0253 }
0254 
0255 static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane,
0256                        struct drm_plane_state *state)
0257 {
0258     struct drm_simple_display_pipe *pipe;
0259 
0260     pipe = container_of(plane, struct drm_simple_display_pipe, plane);
0261     if (!pipe->funcs || !pipe->funcs->prepare_fb) {
0262         if (WARN_ON_ONCE(!drm_core_check_feature(plane->dev, DRIVER_GEM)))
0263             return 0;
0264 
0265         WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb);
0266 
0267         return drm_gem_simple_display_pipe_prepare_fb(pipe, state);
0268     }
0269 
0270     return pipe->funcs->prepare_fb(pipe, state);
0271 }
0272 
0273 static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
0274                         struct drm_plane_state *state)
0275 {
0276     struct drm_simple_display_pipe *pipe;
0277 
0278     pipe = container_of(plane, struct drm_simple_display_pipe, plane);
0279     if (!pipe->funcs || !pipe->funcs->cleanup_fb)
0280         return;
0281 
0282     pipe->funcs->cleanup_fb(pipe, state);
0283 }
0284 
0285 static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane,
0286                         uint32_t format,
0287                         uint64_t modifier)
0288 {
0289     return modifier == DRM_FORMAT_MOD_LINEAR;
0290 }
0291 
0292 static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
0293     .prepare_fb = drm_simple_kms_plane_prepare_fb,
0294     .cleanup_fb = drm_simple_kms_plane_cleanup_fb,
0295     .atomic_check = drm_simple_kms_plane_atomic_check,
0296     .atomic_update = drm_simple_kms_plane_atomic_update,
0297 };
0298 
0299 static void drm_simple_kms_plane_reset(struct drm_plane *plane)
0300 {
0301     struct drm_simple_display_pipe *pipe;
0302 
0303     pipe = container_of(plane, struct drm_simple_display_pipe, plane);
0304     if (!pipe->funcs || !pipe->funcs->reset_plane)
0305         return drm_atomic_helper_plane_reset(plane);
0306 
0307     return pipe->funcs->reset_plane(pipe);
0308 }
0309 
0310 static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane)
0311 {
0312     struct drm_simple_display_pipe *pipe;
0313 
0314     pipe = container_of(plane, struct drm_simple_display_pipe, plane);
0315     if (!pipe->funcs || !pipe->funcs->duplicate_plane_state)
0316         return drm_atomic_helper_plane_duplicate_state(plane);
0317 
0318     return pipe->funcs->duplicate_plane_state(pipe);
0319 }
0320 
0321 static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane,
0322                            struct drm_plane_state *state)
0323 {
0324     struct drm_simple_display_pipe *pipe;
0325 
0326     pipe = container_of(plane, struct drm_simple_display_pipe, plane);
0327     if (!pipe->funcs || !pipe->funcs->destroy_plane_state)
0328         drm_atomic_helper_plane_destroy_state(plane, state);
0329     else
0330         pipe->funcs->destroy_plane_state(pipe, state);
0331 }
0332 
0333 static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
0334     .update_plane       = drm_atomic_helper_update_plane,
0335     .disable_plane      = drm_atomic_helper_disable_plane,
0336     .destroy        = drm_plane_cleanup,
0337     .reset          = drm_simple_kms_plane_reset,
0338     .atomic_duplicate_state = drm_simple_kms_plane_duplicate_state,
0339     .atomic_destroy_state   = drm_simple_kms_plane_destroy_state,
0340     .format_mod_supported   = drm_simple_kms_format_mod_supported,
0341 };
0342 
0343 /**
0344  * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe
0345  * @pipe: simple display pipe object
0346  * @bridge: bridge to attach
0347  *
0348  * Makes it possible to still use the drm_simple_display_pipe helpers when
0349  * a DRM bridge has to be used.
0350  *
0351  * Note that you probably want to initialize the pipe by passing a NULL
0352  * connector to drm_simple_display_pipe_init().
0353  *
0354  * Returns:
0355  * Zero on success, negative error code on failure.
0356  */
0357 int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
0358                       struct drm_bridge *bridge)
0359 {
0360     return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0);
0361 }
0362 EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
0363 
0364 /**
0365  * drm_simple_display_pipe_init - Initialize a simple display pipeline
0366  * @dev: DRM device
0367  * @pipe: simple display pipe object to initialize
0368  * @funcs: callbacks for the display pipe (optional)
0369  * @formats: array of supported formats (DRM_FORMAT\_\*)
0370  * @format_count: number of elements in @formats
0371  * @format_modifiers: array of formats modifiers
0372  * @connector: connector to attach and register (optional)
0373  *
0374  * Sets up a display pipeline which consist of a really simple
0375  * plane-crtc-encoder pipe.
0376  *
0377  * If a connector is supplied, the pipe will be coupled with the provided
0378  * connector. You may supply a NULL connector when using drm bridges, that
0379  * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()).
0380  *
0381  * Teardown of a simple display pipe is all handled automatically by the drm
0382  * core through calling drm_mode_config_cleanup(). Drivers afterwards need to
0383  * release the memory for the structure themselves.
0384  *
0385  * Returns:
0386  * Zero on success, negative error code on failure.
0387  */
0388 int drm_simple_display_pipe_init(struct drm_device *dev,
0389             struct drm_simple_display_pipe *pipe,
0390             const struct drm_simple_display_pipe_funcs *funcs,
0391             const uint32_t *formats, unsigned int format_count,
0392             const uint64_t *format_modifiers,
0393             struct drm_connector *connector)
0394 {
0395     struct drm_encoder *encoder = &pipe->encoder;
0396     struct drm_plane *plane = &pipe->plane;
0397     struct drm_crtc *crtc = &pipe->crtc;
0398     int ret;
0399 
0400     pipe->connector = connector;
0401     pipe->funcs = funcs;
0402 
0403     drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
0404     ret = drm_universal_plane_init(dev, plane, 0,
0405                        &drm_simple_kms_plane_funcs,
0406                        formats, format_count,
0407                        format_modifiers,
0408                        DRM_PLANE_TYPE_PRIMARY, NULL);
0409     if (ret)
0410         return ret;
0411 
0412     drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
0413     ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
0414                     &drm_simple_kms_crtc_funcs, NULL);
0415     if (ret)
0416         return ret;
0417 
0418     encoder->possible_crtcs = drm_crtc_mask(crtc);
0419     ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE);
0420     if (ret || !connector)
0421         return ret;
0422 
0423     return drm_connector_attach_encoder(connector, encoder);
0424 }
0425 EXPORT_SYMBOL(drm_simple_display_pipe_init);
0426 
0427 MODULE_LICENSE("GPL");