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