12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 25b809074SNoralf Trønnes /* 35b809074SNoralf Trønnes * Copyright (C) 2016 Noralf Trønnes 45b809074SNoralf Trønnes */ 55b809074SNoralf Trønnes 60500c04eSSam Ravnborg #include <linux/module.h> 70500c04eSSam Ravnborg #include <linux/slab.h> 80500c04eSSam Ravnborg 95b809074SNoralf Trønnes #include <drm/drm_atomic.h> 105b809074SNoralf Trønnes #include <drm/drm_atomic_helper.h> 11ee68c743SBoris Brezillon #include <drm/drm_bridge.h> 1240cfc7fcSDaniel Vetter #include <drm/drm_drv.h> 1340cfc7fcSDaniel Vetter #include <drm/drm_gem_atomic_helper.h> 1459abba48SPhilipp Zabel #include <drm/drm_managed.h> 15fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 165b809074SNoralf Trønnes #include <drm/drm_simple_kms_helper.h> 175b809074SNoralf Trønnes 185b809074SNoralf Trønnes /** 195b809074SNoralf Trønnes * DOC: overview 205b809074SNoralf Trønnes * 215b809074SNoralf Trønnes * This helper library provides helpers for drivers for simple display 225b809074SNoralf Trønnes * hardware. 235b809074SNoralf Trønnes * 245b809074SNoralf Trønnes * drm_simple_display_pipe_init() initializes a simple display pipeline 255b809074SNoralf Trønnes * which has only one full-screen scanout buffer feeding one output. The 26ea0dd85aSDaniel Vetter * pipeline is represented by &struct drm_simple_display_pipe and binds 275b809074SNoralf Trønnes * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed 285b809074SNoralf Trønnes * entity. Some flexibility for code reuse is provided through a separately 295b809074SNoralf Trønnes * allocated &drm_connector object and supporting optional &drm_bridge 305b809074SNoralf Trønnes * encoder drivers. 3163170ac6SThomas Zimmermann * 3263170ac6SThomas Zimmermann * Many drivers require only a very simple encoder that fulfills the minimum 3363170ac6SThomas Zimmermann * requirements of the display pipeline and does not add additional 3463170ac6SThomas Zimmermann * functionality. The function drm_simple_encoder_init() provides an 3563170ac6SThomas Zimmermann * implementation of such an encoder. 365b809074SNoralf Trønnes */ 375b809074SNoralf Trønnes 3863170ac6SThomas Zimmermann static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = { 395b809074SNoralf Trønnes .destroy = drm_encoder_cleanup, 405b809074SNoralf Trønnes }; 415b809074SNoralf Trønnes 4263170ac6SThomas Zimmermann /** 432cb5974dSThomas Zimmermann * drm_simple_encoder_init - Initialize a preallocated encoder with 442cb5974dSThomas Zimmermann * basic functionality. 4563170ac6SThomas Zimmermann * @dev: drm device 462cb5974dSThomas Zimmermann * @encoder: the encoder to initialize 4763170ac6SThomas Zimmermann * @encoder_type: user visible type of the encoder 4863170ac6SThomas Zimmermann * 4963170ac6SThomas Zimmermann * Initialises a preallocated encoder that has no further functionality. 5063170ac6SThomas Zimmermann * Settings for possible CRTC and clones are left to their initial values. 5163170ac6SThomas Zimmermann * The encoder will be cleaned up automatically as part of the mode-setting 5263170ac6SThomas Zimmermann * cleanup. 5363170ac6SThomas Zimmermann * 542cb5974dSThomas Zimmermann * The caller of drm_simple_encoder_init() is responsible for freeing 552cb5974dSThomas Zimmermann * the encoder's memory after the encoder has been cleaned up. At the 562cb5974dSThomas Zimmermann * moment this only works reliably if the encoder data structure is 572cb5974dSThomas Zimmermann * stored in the device structure. Free the encoder's memory as part of 582cb5974dSThomas Zimmermann * the device release function. 592cb5974dSThomas Zimmermann * 6059abba48SPhilipp Zabel * Note: consider using drmm_simple_encoder_alloc() instead of 6159abba48SPhilipp Zabel * drm_simple_encoder_init() to let the DRM managed resource infrastructure 6259abba48SPhilipp Zabel * take care of cleanup and deallocation. 632cb5974dSThomas Zimmermann * 6463170ac6SThomas Zimmermann * Returns: 6563170ac6SThomas Zimmermann * Zero on success, error code on failure. 6663170ac6SThomas Zimmermann */ 6763170ac6SThomas Zimmermann int drm_simple_encoder_init(struct drm_device *dev, 6863170ac6SThomas Zimmermann struct drm_encoder *encoder, 6963170ac6SThomas Zimmermann int encoder_type) 7063170ac6SThomas Zimmermann { 7163170ac6SThomas Zimmermann return drm_encoder_init(dev, encoder, 7263170ac6SThomas Zimmermann &drm_simple_encoder_funcs_cleanup, 7363170ac6SThomas Zimmermann encoder_type, NULL); 7463170ac6SThomas Zimmermann } 7563170ac6SThomas Zimmermann EXPORT_SYMBOL(drm_simple_encoder_init); 7663170ac6SThomas Zimmermann 7759abba48SPhilipp Zabel void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size, 7859abba48SPhilipp Zabel size_t offset, int encoder_type) 7959abba48SPhilipp Zabel { 8059abba48SPhilipp Zabel return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type, 8159abba48SPhilipp Zabel NULL); 8259abba48SPhilipp Zabel } 8359abba48SPhilipp Zabel EXPORT_SYMBOL(__drmm_simple_encoder_alloc); 8459abba48SPhilipp Zabel 8540275dc4SLinus Walleij static enum drm_mode_status 8640275dc4SLinus Walleij drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc, 8740275dc4SLinus Walleij const struct drm_display_mode *mode) 8840275dc4SLinus Walleij { 8940275dc4SLinus Walleij struct drm_simple_display_pipe *pipe; 9040275dc4SLinus Walleij 9140275dc4SLinus Walleij pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 9240275dc4SLinus Walleij if (!pipe->funcs || !pipe->funcs->mode_valid) 9340275dc4SLinus Walleij /* Anything goes */ 9440275dc4SLinus Walleij return MODE_OK; 9540275dc4SLinus Walleij 9662db7d1eSDaniel Vetter return pipe->funcs->mode_valid(pipe, mode); 9740275dc4SLinus Walleij } 9840275dc4SLinus Walleij 996dcf0de7SDaniel Vetter static int drm_simple_kms_crtc_check(struct drm_crtc *crtc, 10029b77ad7SMaxime Ripard struct drm_atomic_state *state) 1016dcf0de7SDaniel Vetter { 102dc2cdd17SThomas Zimmermann struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 103dc2cdd17SThomas Zimmermann int ret; 104765831dcSMaarten Lankhorst 1058f2fd57dSThomas Zimmermann if (!crtc_state->enable) 1068f2fd57dSThomas Zimmermann goto out; 1078f2fd57dSThomas Zimmermann 1088f2fd57dSThomas Zimmermann ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); 109dc2cdd17SThomas Zimmermann if (ret) 110dc2cdd17SThomas Zimmermann return ret; 111765831dcSMaarten Lankhorst 1128f2fd57dSThomas Zimmermann out: 113d74252bbSMaxime Ripard return drm_atomic_add_affected_planes(state, crtc); 1146dcf0de7SDaniel Vetter } 1156dcf0de7SDaniel Vetter 1160b20a0f8SLaurent Pinchart static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc, 117351f950dSMaxime Ripard struct drm_atomic_state *state) 1185b809074SNoralf Trønnes { 1190c9c7fd0SVille Syrjälä struct drm_plane *plane; 1205b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 1215b809074SNoralf Trønnes 1225b809074SNoralf Trønnes pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 1235b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->enable) 1245b809074SNoralf Trønnes return; 1255b809074SNoralf Trønnes 1260c9c7fd0SVille Syrjälä plane = &pipe->plane; 1270c9c7fd0SVille Syrjälä pipe->funcs->enable(pipe, crtc->state, plane->state); 1285b809074SNoralf Trønnes } 1295b809074SNoralf Trønnes 13064581714SLaurent Pinchart static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc, 131351f950dSMaxime Ripard struct drm_atomic_state *state) 1325b809074SNoralf Trønnes { 1335b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 1345b809074SNoralf Trønnes 1355b809074SNoralf Trønnes pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 1365b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->disable) 1375b809074SNoralf Trønnes return; 1385b809074SNoralf Trønnes 1395b809074SNoralf Trønnes pipe->funcs->disable(pipe); 1405b809074SNoralf Trønnes } 1415b809074SNoralf Trønnes 1425b809074SNoralf Trønnes static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = { 14340275dc4SLinus Walleij .mode_valid = drm_simple_kms_crtc_mode_valid, 1446dcf0de7SDaniel Vetter .atomic_check = drm_simple_kms_crtc_check, 1450b20a0f8SLaurent Pinchart .atomic_enable = drm_simple_kms_crtc_enable, 14664581714SLaurent Pinchart .atomic_disable = drm_simple_kms_crtc_disable, 1475b809074SNoralf Trønnes }; 1485b809074SNoralf Trønnes 14938c5af44SThomas Zimmermann static void drm_simple_kms_crtc_reset(struct drm_crtc *crtc) 15038c5af44SThomas Zimmermann { 15138c5af44SThomas Zimmermann struct drm_simple_display_pipe *pipe; 15238c5af44SThomas Zimmermann 15338c5af44SThomas Zimmermann pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 15438c5af44SThomas Zimmermann if (!pipe->funcs || !pipe->funcs->reset_crtc) 15538c5af44SThomas Zimmermann return drm_atomic_helper_crtc_reset(crtc); 15638c5af44SThomas Zimmermann 15738c5af44SThomas Zimmermann return pipe->funcs->reset_crtc(pipe); 15838c5af44SThomas Zimmermann } 15938c5af44SThomas Zimmermann 16038c5af44SThomas Zimmermann static struct drm_crtc_state *drm_simple_kms_crtc_duplicate_state(struct drm_crtc *crtc) 16138c5af44SThomas Zimmermann { 16238c5af44SThomas Zimmermann struct drm_simple_display_pipe *pipe; 16338c5af44SThomas Zimmermann 16438c5af44SThomas Zimmermann pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 16538c5af44SThomas Zimmermann if (!pipe->funcs || !pipe->funcs->duplicate_crtc_state) 16638c5af44SThomas Zimmermann return drm_atomic_helper_crtc_duplicate_state(crtc); 16738c5af44SThomas Zimmermann 16838c5af44SThomas Zimmermann return pipe->funcs->duplicate_crtc_state(pipe); 16938c5af44SThomas Zimmermann } 17038c5af44SThomas Zimmermann 17138c5af44SThomas Zimmermann static void drm_simple_kms_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state) 17238c5af44SThomas Zimmermann { 17338c5af44SThomas Zimmermann struct drm_simple_display_pipe *pipe; 17438c5af44SThomas Zimmermann 17538c5af44SThomas Zimmermann pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 17638c5af44SThomas Zimmermann if (!pipe->funcs || !pipe->funcs->destroy_crtc_state) 17738c5af44SThomas Zimmermann drm_atomic_helper_crtc_destroy_state(crtc, state); 17838c5af44SThomas Zimmermann else 17938c5af44SThomas Zimmermann pipe->funcs->destroy_crtc_state(pipe, state); 18038c5af44SThomas Zimmermann } 18138c5af44SThomas Zimmermann 182ac86cba9SOleksandr Andrushchenko static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc) 183ac86cba9SOleksandr Andrushchenko { 184ac86cba9SOleksandr Andrushchenko struct drm_simple_display_pipe *pipe; 185ac86cba9SOleksandr Andrushchenko 186ac86cba9SOleksandr Andrushchenko pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 187ac86cba9SOleksandr Andrushchenko if (!pipe->funcs || !pipe->funcs->enable_vblank) 188ac86cba9SOleksandr Andrushchenko return 0; 189ac86cba9SOleksandr Andrushchenko 190ac86cba9SOleksandr Andrushchenko return pipe->funcs->enable_vblank(pipe); 191ac86cba9SOleksandr Andrushchenko } 192ac86cba9SOleksandr Andrushchenko 193ac86cba9SOleksandr Andrushchenko static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc) 194ac86cba9SOleksandr Andrushchenko { 195ac86cba9SOleksandr Andrushchenko struct drm_simple_display_pipe *pipe; 196ac86cba9SOleksandr Andrushchenko 197ac86cba9SOleksandr Andrushchenko pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 198ac86cba9SOleksandr Andrushchenko if (!pipe->funcs || !pipe->funcs->disable_vblank) 199ac86cba9SOleksandr Andrushchenko return; 200ac86cba9SOleksandr Andrushchenko 201ac86cba9SOleksandr Andrushchenko pipe->funcs->disable_vblank(pipe); 202ac86cba9SOleksandr Andrushchenko } 203ac86cba9SOleksandr Andrushchenko 2045b809074SNoralf Trønnes static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = { 20538c5af44SThomas Zimmermann .reset = drm_simple_kms_crtc_reset, 2065b809074SNoralf Trønnes .destroy = drm_crtc_cleanup, 2075b809074SNoralf Trønnes .set_config = drm_atomic_helper_set_config, 2085b809074SNoralf Trønnes .page_flip = drm_atomic_helper_page_flip, 20938c5af44SThomas Zimmermann .atomic_duplicate_state = drm_simple_kms_crtc_duplicate_state, 21038c5af44SThomas Zimmermann .atomic_destroy_state = drm_simple_kms_crtc_destroy_state, 211ac86cba9SOleksandr Andrushchenko .enable_vblank = drm_simple_kms_crtc_enable_vblank, 212ac86cba9SOleksandr Andrushchenko .disable_vblank = drm_simple_kms_crtc_disable_vblank, 2135b809074SNoralf Trønnes }; 2145b809074SNoralf Trønnes 2155b809074SNoralf Trønnes static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, 2167c11b99aSMaxime Ripard struct drm_atomic_state *state) 2175b809074SNoralf Trønnes { 2187c11b99aSMaxime Ripard struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, 2197c11b99aSMaxime Ripard plane); 2205b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 2215b809074SNoralf Trønnes struct drm_crtc_state *crtc_state; 2225b809074SNoralf Trønnes int ret; 2235b809074SNoralf Trønnes 2245b809074SNoralf Trønnes pipe = container_of(plane, struct drm_simple_display_pipe, plane); 225dec92020SMaxime Ripard crtc_state = drm_atomic_get_new_crtc_state(state, 2265b809074SNoralf Trønnes &pipe->crtc); 2274be12cc2SVille Syrjälä 228a01cb8baSVille Syrjälä ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, 229cce32e4eSThomas Zimmermann DRM_PLANE_NO_SCALING, 230cce32e4eSThomas Zimmermann DRM_PLANE_NO_SCALING, 231dc2cdd17SThomas Zimmermann false, false); 2325b809074SNoralf Trønnes if (ret) 2335b809074SNoralf Trønnes return ret; 2345b809074SNoralf Trønnes 2354be12cc2SVille Syrjälä if (!plane_state->visible) 2364751cf73SOleksandr Andrushchenko return 0; 2374751cf73SOleksandr Andrushchenko 2385b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->check) 2395b809074SNoralf Trønnes return 0; 2405b809074SNoralf Trønnes 2415b809074SNoralf Trønnes return pipe->funcs->check(pipe, plane_state, crtc_state); 2425b809074SNoralf Trønnes } 2435b809074SNoralf Trønnes 2445b809074SNoralf Trønnes static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane, 245977697e2SMaxime Ripard struct drm_atomic_state *state) 2465b809074SNoralf Trønnes { 247977697e2SMaxime Ripard struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state, 248977697e2SMaxime Ripard plane); 2495b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 2505b809074SNoralf Trønnes 2515b809074SNoralf Trønnes pipe = container_of(plane, struct drm_simple_display_pipe, plane); 2525b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->update) 2535b809074SNoralf Trønnes return; 2545b809074SNoralf Trønnes 255bcd2ba02SEric Anholt pipe->funcs->update(pipe, old_pstate); 2565b809074SNoralf Trønnes } 2575b809074SNoralf Trønnes 2587d83a155SMarek Vasut static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane, 2597d83a155SMarek Vasut struct drm_plane_state *state) 2607d83a155SMarek Vasut { 2617d83a155SMarek Vasut struct drm_simple_display_pipe *pipe; 2627d83a155SMarek Vasut 2637d83a155SMarek Vasut pipe = container_of(plane, struct drm_simple_display_pipe, plane); 26440cfc7fcSDaniel Vetter if (!pipe->funcs || !pipe->funcs->prepare_fb) { 26540cfc7fcSDaniel Vetter if (WARN_ON_ONCE(!drm_core_check_feature(plane->dev, DRIVER_GEM))) 2667d83a155SMarek Vasut return 0; 2677d83a155SMarek Vasut 26840cfc7fcSDaniel Vetter WARN_ON_ONCE(pipe->funcs && pipe->funcs->cleanup_fb); 26940cfc7fcSDaniel Vetter 270*00b5497dSThomas Zimmermann return drm_gem_plane_helper_prepare_fb(plane, state); 27140cfc7fcSDaniel Vetter } 27240cfc7fcSDaniel Vetter 2737d83a155SMarek Vasut return pipe->funcs->prepare_fb(pipe, state); 2747d83a155SMarek Vasut } 2757d83a155SMarek Vasut 2767d83a155SMarek Vasut static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane, 2777d83a155SMarek Vasut struct drm_plane_state *state) 2787d83a155SMarek Vasut { 2797d83a155SMarek Vasut struct drm_simple_display_pipe *pipe; 2807d83a155SMarek Vasut 2817d83a155SMarek Vasut pipe = container_of(plane, struct drm_simple_display_pipe, plane); 2827d83a155SMarek Vasut if (!pipe->funcs || !pipe->funcs->cleanup_fb) 2837d83a155SMarek Vasut return; 2847d83a155SMarek Vasut 2857d83a155SMarek Vasut pipe->funcs->cleanup_fb(pipe, state); 2867d83a155SMarek Vasut } 2877d83a155SMarek Vasut 28894d879eaSThomas Zimmermann static int drm_simple_kms_plane_begin_fb_access(struct drm_plane *plane, 28994d879eaSThomas Zimmermann struct drm_plane_state *new_plane_state) 29094d879eaSThomas Zimmermann { 29194d879eaSThomas Zimmermann struct drm_simple_display_pipe *pipe; 29294d879eaSThomas Zimmermann 29394d879eaSThomas Zimmermann pipe = container_of(plane, struct drm_simple_display_pipe, plane); 29494d879eaSThomas Zimmermann if (!pipe->funcs || !pipe->funcs->begin_fb_access) 29594d879eaSThomas Zimmermann return 0; 29694d879eaSThomas Zimmermann 29794d879eaSThomas Zimmermann return pipe->funcs->begin_fb_access(pipe, new_plane_state); 29894d879eaSThomas Zimmermann } 29994d879eaSThomas Zimmermann 30094d879eaSThomas Zimmermann static void drm_simple_kms_plane_end_fb_access(struct drm_plane *plane, 30194d879eaSThomas Zimmermann struct drm_plane_state *new_plane_state) 30294d879eaSThomas Zimmermann { 30394d879eaSThomas Zimmermann struct drm_simple_display_pipe *pipe; 30494d879eaSThomas Zimmermann 30594d879eaSThomas Zimmermann pipe = container_of(plane, struct drm_simple_display_pipe, plane); 30694d879eaSThomas Zimmermann if (!pipe->funcs || !pipe->funcs->end_fb_access) 30794d879eaSThomas Zimmermann return; 30894d879eaSThomas Zimmermann 30994d879eaSThomas Zimmermann pipe->funcs->end_fb_access(pipe, new_plane_state); 31094d879eaSThomas Zimmermann } 31194d879eaSThomas Zimmermann 312dff906c3SEric Anholt static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane, 313dff906c3SEric Anholt uint32_t format, 314dff906c3SEric Anholt uint64_t modifier) 315dff906c3SEric Anholt { 316dff906c3SEric Anholt return modifier == DRM_FORMAT_MOD_LINEAR; 317dff906c3SEric Anholt } 318dff906c3SEric Anholt 3195b809074SNoralf Trønnes static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = { 3207d83a155SMarek Vasut .prepare_fb = drm_simple_kms_plane_prepare_fb, 3217d83a155SMarek Vasut .cleanup_fb = drm_simple_kms_plane_cleanup_fb, 32294d879eaSThomas Zimmermann .begin_fb_access = drm_simple_kms_plane_begin_fb_access, 32394d879eaSThomas Zimmermann .end_fb_access = drm_simple_kms_plane_end_fb_access, 3245b809074SNoralf Trønnes .atomic_check = drm_simple_kms_plane_atomic_check, 3255b809074SNoralf Trønnes .atomic_update = drm_simple_kms_plane_atomic_update, 3265b809074SNoralf Trønnes }; 3275b809074SNoralf Trønnes 32840f302adSThomas Zimmermann static void drm_simple_kms_plane_reset(struct drm_plane *plane) 32940f302adSThomas Zimmermann { 33040f302adSThomas Zimmermann struct drm_simple_display_pipe *pipe; 33140f302adSThomas Zimmermann 33240f302adSThomas Zimmermann pipe = container_of(plane, struct drm_simple_display_pipe, plane); 33340f302adSThomas Zimmermann if (!pipe->funcs || !pipe->funcs->reset_plane) 33440f302adSThomas Zimmermann return drm_atomic_helper_plane_reset(plane); 33540f302adSThomas Zimmermann 33640f302adSThomas Zimmermann return pipe->funcs->reset_plane(pipe); 33740f302adSThomas Zimmermann } 33840f302adSThomas Zimmermann 33940f302adSThomas Zimmermann static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane) 34040f302adSThomas Zimmermann { 34140f302adSThomas Zimmermann struct drm_simple_display_pipe *pipe; 34240f302adSThomas Zimmermann 34340f302adSThomas Zimmermann pipe = container_of(plane, struct drm_simple_display_pipe, plane); 34440f302adSThomas Zimmermann if (!pipe->funcs || !pipe->funcs->duplicate_plane_state) 34540f302adSThomas Zimmermann return drm_atomic_helper_plane_duplicate_state(plane); 34640f302adSThomas Zimmermann 34740f302adSThomas Zimmermann return pipe->funcs->duplicate_plane_state(pipe); 34840f302adSThomas Zimmermann } 34940f302adSThomas Zimmermann 35040f302adSThomas Zimmermann static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane, 35140f302adSThomas Zimmermann struct drm_plane_state *state) 35240f302adSThomas Zimmermann { 35340f302adSThomas Zimmermann struct drm_simple_display_pipe *pipe; 35440f302adSThomas Zimmermann 35540f302adSThomas Zimmermann pipe = container_of(plane, struct drm_simple_display_pipe, plane); 35640f302adSThomas Zimmermann if (!pipe->funcs || !pipe->funcs->destroy_plane_state) 35740f302adSThomas Zimmermann drm_atomic_helper_plane_destroy_state(plane, state); 35840f302adSThomas Zimmermann else 35940f302adSThomas Zimmermann pipe->funcs->destroy_plane_state(pipe, state); 36040f302adSThomas Zimmermann } 36140f302adSThomas Zimmermann 3625b809074SNoralf Trønnes static const struct drm_plane_funcs drm_simple_kms_plane_funcs = { 3635b809074SNoralf Trønnes .update_plane = drm_atomic_helper_update_plane, 3645b809074SNoralf Trønnes .disable_plane = drm_atomic_helper_disable_plane, 3655b809074SNoralf Trønnes .destroy = drm_plane_cleanup, 36640f302adSThomas Zimmermann .reset = drm_simple_kms_plane_reset, 36740f302adSThomas Zimmermann .atomic_duplicate_state = drm_simple_kms_plane_duplicate_state, 36840f302adSThomas Zimmermann .atomic_destroy_state = drm_simple_kms_plane_destroy_state, 369dff906c3SEric Anholt .format_mod_supported = drm_simple_kms_format_mod_supported, 3705b809074SNoralf Trønnes }; 3715b809074SNoralf Trønnes 3725b809074SNoralf Trønnes /** 373315486c6SAndrea Merello * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe 374315486c6SAndrea Merello * @pipe: simple display pipe object 375315486c6SAndrea Merello * @bridge: bridge to attach 376315486c6SAndrea Merello * 377315486c6SAndrea Merello * Makes it possible to still use the drm_simple_display_pipe helpers when 378315486c6SAndrea Merello * a DRM bridge has to be used. 379315486c6SAndrea Merello * 380315486c6SAndrea Merello * Note that you probably want to initialize the pipe by passing a NULL 381315486c6SAndrea Merello * connector to drm_simple_display_pipe_init(). 382315486c6SAndrea Merello * 383315486c6SAndrea Merello * Returns: 384315486c6SAndrea Merello * Zero on success, negative error code on failure. 385315486c6SAndrea Merello */ 386315486c6SAndrea Merello int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe, 387315486c6SAndrea Merello struct drm_bridge *bridge) 388315486c6SAndrea Merello { 389a25b988fSLaurent Pinchart return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0); 390315486c6SAndrea Merello } 391315486c6SAndrea Merello EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge); 392315486c6SAndrea Merello 393315486c6SAndrea Merello /** 3945b809074SNoralf Trønnes * drm_simple_display_pipe_init - Initialize a simple display pipeline 3955b809074SNoralf Trønnes * @dev: DRM device 3965b809074SNoralf Trønnes * @pipe: simple display pipe object to initialize 3975b809074SNoralf Trønnes * @funcs: callbacks for the display pipe (optional) 39862cacc79SDaniel Vetter * @formats: array of supported formats (DRM_FORMAT\_\*) 3995b809074SNoralf Trønnes * @format_count: number of elements in @formats 400e6fc3b68SBen Widawsky * @format_modifiers: array of formats modifiers 4014f993973SAndrea Merello * @connector: connector to attach and register (optional) 4025b809074SNoralf Trønnes * 4035b809074SNoralf Trønnes * Sets up a display pipeline which consist of a really simple 4044f993973SAndrea Merello * plane-crtc-encoder pipe. 4054f993973SAndrea Merello * 4064f993973SAndrea Merello * If a connector is supplied, the pipe will be coupled with the provided 4074f993973SAndrea Merello * connector. You may supply a NULL connector when using drm bridges, that 4084f993973SAndrea Merello * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()). 4094f993973SAndrea Merello * 4105b809074SNoralf Trønnes * Teardown of a simple display pipe is all handled automatically by the drm 4115b809074SNoralf Trønnes * core through calling drm_mode_config_cleanup(). Drivers afterwards need to 4125b809074SNoralf Trønnes * release the memory for the structure themselves. 4135b809074SNoralf Trønnes * 4145b809074SNoralf Trønnes * Returns: 4155b809074SNoralf Trønnes * Zero on success, negative error code on failure. 4165b809074SNoralf Trønnes */ 4175b809074SNoralf Trønnes int drm_simple_display_pipe_init(struct drm_device *dev, 4185b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe, 4195b809074SNoralf Trønnes const struct drm_simple_display_pipe_funcs *funcs, 4205b809074SNoralf Trønnes const uint32_t *formats, unsigned int format_count, 421e6fc3b68SBen Widawsky const uint64_t *format_modifiers, 4225b809074SNoralf Trønnes struct drm_connector *connector) 4235b809074SNoralf Trønnes { 4245b809074SNoralf Trønnes struct drm_encoder *encoder = &pipe->encoder; 4255b809074SNoralf Trønnes struct drm_plane *plane = &pipe->plane; 4265b809074SNoralf Trønnes struct drm_crtc *crtc = &pipe->crtc; 4275b809074SNoralf Trønnes int ret; 4285b809074SNoralf Trønnes 4295b809074SNoralf Trønnes pipe->connector = connector; 4305b809074SNoralf Trønnes pipe->funcs = funcs; 4315b809074SNoralf Trønnes 4325b809074SNoralf Trønnes drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs); 4335b809074SNoralf Trønnes ret = drm_universal_plane_init(dev, plane, 0, 4345b809074SNoralf Trønnes &drm_simple_kms_plane_funcs, 4355b809074SNoralf Trønnes formats, format_count, 436e6fc3b68SBen Widawsky format_modifiers, 4375b809074SNoralf Trønnes DRM_PLANE_TYPE_PRIMARY, NULL); 4385b809074SNoralf Trønnes if (ret) 4395b809074SNoralf Trønnes return ret; 4405b809074SNoralf Trønnes 4415b809074SNoralf Trønnes drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs); 4425b809074SNoralf Trønnes ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 4435b809074SNoralf Trønnes &drm_simple_kms_crtc_funcs, NULL); 4445b809074SNoralf Trønnes if (ret) 4455b809074SNoralf Trønnes return ret; 4465b809074SNoralf Trønnes 4476a52193bSVille Syrjälä encoder->possible_crtcs = drm_crtc_mask(crtc); 44863170ac6SThomas Zimmermann ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE); 4494f993973SAndrea Merello if (ret || !connector) 4505b809074SNoralf Trønnes return ret; 4515b809074SNoralf Trønnes 452cde4c44dSDaniel Vetter return drm_connector_attach_encoder(connector, encoder); 4535b809074SNoralf Trønnes } 4545b809074SNoralf Trønnes EXPORT_SYMBOL(drm_simple_display_pipe_init); 4555b809074SNoralf Trønnes 4565b809074SNoralf Trønnes MODULE_LICENSE("GPL"); 457