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> 1259abba48SPhilipp Zabel #include <drm/drm_managed.h> 135b809074SNoralf Trønnes #include <drm/drm_plane_helper.h> 14fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 155b809074SNoralf Trønnes #include <drm/drm_simple_kms_helper.h> 165b809074SNoralf Trønnes 175b809074SNoralf Trønnes /** 185b809074SNoralf Trønnes * DOC: overview 195b809074SNoralf Trønnes * 205b809074SNoralf Trønnes * This helper library provides helpers for drivers for simple display 215b809074SNoralf Trønnes * hardware. 225b809074SNoralf Trønnes * 235b809074SNoralf Trønnes * drm_simple_display_pipe_init() initializes a simple display pipeline 245b809074SNoralf Trønnes * which has only one full-screen scanout buffer feeding one output. The 25ea0dd85aSDaniel Vetter * pipeline is represented by &struct drm_simple_display_pipe and binds 265b809074SNoralf Trønnes * together &drm_plane, &drm_crtc and &drm_encoder structures into one fixed 275b809074SNoralf Trønnes * entity. Some flexibility for code reuse is provided through a separately 285b809074SNoralf Trønnes * allocated &drm_connector object and supporting optional &drm_bridge 295b809074SNoralf Trønnes * encoder drivers. 3063170ac6SThomas Zimmermann * 3163170ac6SThomas Zimmermann * Many drivers require only a very simple encoder that fulfills the minimum 3263170ac6SThomas Zimmermann * requirements of the display pipeline and does not add additional 3363170ac6SThomas Zimmermann * functionality. The function drm_simple_encoder_init() provides an 3463170ac6SThomas Zimmermann * implementation of such an encoder. 355b809074SNoralf Trønnes */ 365b809074SNoralf Trønnes 3763170ac6SThomas Zimmermann static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = { 385b809074SNoralf Trønnes .destroy = drm_encoder_cleanup, 395b809074SNoralf Trønnes }; 405b809074SNoralf Trønnes 4163170ac6SThomas Zimmermann /** 422cb5974dSThomas Zimmermann * drm_simple_encoder_init - Initialize a preallocated encoder with 432cb5974dSThomas Zimmermann * basic functionality. 4463170ac6SThomas Zimmermann * @dev: drm device 452cb5974dSThomas Zimmermann * @encoder: the encoder to initialize 4663170ac6SThomas Zimmermann * @encoder_type: user visible type of the encoder 4763170ac6SThomas Zimmermann * 4863170ac6SThomas Zimmermann * Initialises a preallocated encoder that has no further functionality. 4963170ac6SThomas Zimmermann * Settings for possible CRTC and clones are left to their initial values. 5063170ac6SThomas Zimmermann * The encoder will be cleaned up automatically as part of the mode-setting 5163170ac6SThomas Zimmermann * cleanup. 5263170ac6SThomas Zimmermann * 532cb5974dSThomas Zimmermann * The caller of drm_simple_encoder_init() is responsible for freeing 542cb5974dSThomas Zimmermann * the encoder's memory after the encoder has been cleaned up. At the 552cb5974dSThomas Zimmermann * moment this only works reliably if the encoder data structure is 562cb5974dSThomas Zimmermann * stored in the device structure. Free the encoder's memory as part of 572cb5974dSThomas Zimmermann * the device release function. 582cb5974dSThomas Zimmermann * 5959abba48SPhilipp Zabel * Note: consider using drmm_simple_encoder_alloc() instead of 6059abba48SPhilipp Zabel * drm_simple_encoder_init() to let the DRM managed resource infrastructure 6159abba48SPhilipp Zabel * take care of cleanup and deallocation. 622cb5974dSThomas Zimmermann * 6363170ac6SThomas Zimmermann * Returns: 6463170ac6SThomas Zimmermann * Zero on success, error code on failure. 6563170ac6SThomas Zimmermann */ 6663170ac6SThomas Zimmermann int drm_simple_encoder_init(struct drm_device *dev, 6763170ac6SThomas Zimmermann struct drm_encoder *encoder, 6863170ac6SThomas Zimmermann int encoder_type) 6963170ac6SThomas Zimmermann { 7063170ac6SThomas Zimmermann return drm_encoder_init(dev, encoder, 7163170ac6SThomas Zimmermann &drm_simple_encoder_funcs_cleanup, 7263170ac6SThomas Zimmermann encoder_type, NULL); 7363170ac6SThomas Zimmermann } 7463170ac6SThomas Zimmermann EXPORT_SYMBOL(drm_simple_encoder_init); 7563170ac6SThomas Zimmermann 7659abba48SPhilipp Zabel void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size, 7759abba48SPhilipp Zabel size_t offset, int encoder_type) 7859abba48SPhilipp Zabel { 7959abba48SPhilipp Zabel return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type, 8059abba48SPhilipp Zabel NULL); 8159abba48SPhilipp Zabel } 8259abba48SPhilipp Zabel EXPORT_SYMBOL(__drmm_simple_encoder_alloc); 8359abba48SPhilipp Zabel 8440275dc4SLinus Walleij static enum drm_mode_status 8540275dc4SLinus Walleij drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc, 8640275dc4SLinus Walleij const struct drm_display_mode *mode) 8740275dc4SLinus Walleij { 8840275dc4SLinus Walleij struct drm_simple_display_pipe *pipe; 8940275dc4SLinus Walleij 9040275dc4SLinus Walleij pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 9140275dc4SLinus Walleij if (!pipe->funcs || !pipe->funcs->mode_valid) 9240275dc4SLinus Walleij /* Anything goes */ 9340275dc4SLinus Walleij return MODE_OK; 9440275dc4SLinus Walleij 9562db7d1eSDaniel Vetter return pipe->funcs->mode_valid(pipe, mode); 9640275dc4SLinus Walleij } 9740275dc4SLinus Walleij 986dcf0de7SDaniel Vetter static int drm_simple_kms_crtc_check(struct drm_crtc *crtc, 9929b77ad7SMaxime Ripard struct drm_atomic_state *state) 1006dcf0de7SDaniel Vetter { 10129b77ad7SMaxime Ripard struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, 10229b77ad7SMaxime Ripard crtc); 10329b77ad7SMaxime Ripard bool has_primary = crtc_state->plane_mask & 10462f77ad0SVille Syrjälä drm_plane_mask(crtc->primary); 105765831dcSMaarten Lankhorst 106765831dcSMaarten Lankhorst /* We always want to have an active plane with an active CRTC */ 10729b77ad7SMaxime Ripard if (has_primary != crtc_state->enable) 108765831dcSMaarten Lankhorst return -EINVAL; 109765831dcSMaarten Lankhorst 110d74252bbSMaxime Ripard return drm_atomic_add_affected_planes(state, crtc); 1116dcf0de7SDaniel Vetter } 1126dcf0de7SDaniel Vetter 1130b20a0f8SLaurent Pinchart static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc, 114351f950dSMaxime Ripard struct drm_atomic_state *state) 1155b809074SNoralf Trønnes { 1160c9c7fd0SVille Syrjälä struct drm_plane *plane; 1175b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 1185b809074SNoralf Trønnes 1195b809074SNoralf Trønnes pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 1205b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->enable) 1215b809074SNoralf Trønnes return; 1225b809074SNoralf Trønnes 1230c9c7fd0SVille Syrjälä plane = &pipe->plane; 1240c9c7fd0SVille Syrjälä pipe->funcs->enable(pipe, crtc->state, plane->state); 1255b809074SNoralf Trønnes } 1265b809074SNoralf Trønnes 12764581714SLaurent Pinchart static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc, 128351f950dSMaxime Ripard struct drm_atomic_state *state) 1295b809074SNoralf Trønnes { 1305b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 1315b809074SNoralf Trønnes 1325b809074SNoralf Trønnes pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 1335b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->disable) 1345b809074SNoralf Trønnes return; 1355b809074SNoralf Trønnes 1365b809074SNoralf Trønnes pipe->funcs->disable(pipe); 1375b809074SNoralf Trønnes } 1385b809074SNoralf Trønnes 1395b809074SNoralf Trønnes static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = { 14040275dc4SLinus Walleij .mode_valid = drm_simple_kms_crtc_mode_valid, 1416dcf0de7SDaniel Vetter .atomic_check = drm_simple_kms_crtc_check, 1420b20a0f8SLaurent Pinchart .atomic_enable = drm_simple_kms_crtc_enable, 14364581714SLaurent Pinchart .atomic_disable = drm_simple_kms_crtc_disable, 1445b809074SNoralf Trønnes }; 1455b809074SNoralf Trønnes 146ac86cba9SOleksandr Andrushchenko static int drm_simple_kms_crtc_enable_vblank(struct drm_crtc *crtc) 147ac86cba9SOleksandr Andrushchenko { 148ac86cba9SOleksandr Andrushchenko struct drm_simple_display_pipe *pipe; 149ac86cba9SOleksandr Andrushchenko 150ac86cba9SOleksandr Andrushchenko pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 151ac86cba9SOleksandr Andrushchenko if (!pipe->funcs || !pipe->funcs->enable_vblank) 152ac86cba9SOleksandr Andrushchenko return 0; 153ac86cba9SOleksandr Andrushchenko 154ac86cba9SOleksandr Andrushchenko return pipe->funcs->enable_vblank(pipe); 155ac86cba9SOleksandr Andrushchenko } 156ac86cba9SOleksandr Andrushchenko 157ac86cba9SOleksandr Andrushchenko static void drm_simple_kms_crtc_disable_vblank(struct drm_crtc *crtc) 158ac86cba9SOleksandr Andrushchenko { 159ac86cba9SOleksandr Andrushchenko struct drm_simple_display_pipe *pipe; 160ac86cba9SOleksandr Andrushchenko 161ac86cba9SOleksandr Andrushchenko pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 162ac86cba9SOleksandr Andrushchenko if (!pipe->funcs || !pipe->funcs->disable_vblank) 163ac86cba9SOleksandr Andrushchenko return; 164ac86cba9SOleksandr Andrushchenko 165ac86cba9SOleksandr Andrushchenko pipe->funcs->disable_vblank(pipe); 166ac86cba9SOleksandr Andrushchenko } 167ac86cba9SOleksandr Andrushchenko 1685b809074SNoralf Trønnes static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = { 1695b809074SNoralf Trønnes .reset = drm_atomic_helper_crtc_reset, 1705b809074SNoralf Trønnes .destroy = drm_crtc_cleanup, 1715b809074SNoralf Trønnes .set_config = drm_atomic_helper_set_config, 1725b809074SNoralf Trønnes .page_flip = drm_atomic_helper_page_flip, 1735b809074SNoralf Trønnes .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 1745b809074SNoralf Trønnes .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 175ac86cba9SOleksandr Andrushchenko .enable_vblank = drm_simple_kms_crtc_enable_vblank, 176ac86cba9SOleksandr Andrushchenko .disable_vblank = drm_simple_kms_crtc_disable_vblank, 1775b809074SNoralf Trønnes }; 1785b809074SNoralf Trønnes 1795b809074SNoralf Trønnes static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, 180*7c11b99aSMaxime Ripard struct drm_atomic_state *state) 1815b809074SNoralf Trønnes { 182*7c11b99aSMaxime Ripard struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, 183*7c11b99aSMaxime Ripard plane); 1845b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 1855b809074SNoralf Trønnes struct drm_crtc_state *crtc_state; 1865b809074SNoralf Trønnes int ret; 1875b809074SNoralf Trønnes 1885b809074SNoralf Trønnes pipe = container_of(plane, struct drm_simple_display_pipe, plane); 189b4d93679SMaarten Lankhorst crtc_state = drm_atomic_get_new_crtc_state(plane_state->state, 1905b809074SNoralf Trønnes &pipe->crtc); 1914be12cc2SVille Syrjälä 192a01cb8baSVille Syrjälä ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, 1935b809074SNoralf Trønnes DRM_PLANE_HELPER_NO_SCALING, 1945b809074SNoralf Trønnes DRM_PLANE_HELPER_NO_SCALING, 1954be12cc2SVille Syrjälä false, true); 1965b809074SNoralf Trønnes if (ret) 1975b809074SNoralf Trønnes return ret; 1985b809074SNoralf Trønnes 1994be12cc2SVille Syrjälä if (!plane_state->visible) 2004751cf73SOleksandr Andrushchenko return 0; 2014751cf73SOleksandr Andrushchenko 2025b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->check) 2035b809074SNoralf Trønnes return 0; 2045b809074SNoralf Trønnes 2055b809074SNoralf Trønnes return pipe->funcs->check(pipe, plane_state, crtc_state); 2065b809074SNoralf Trønnes } 2075b809074SNoralf Trønnes 2085b809074SNoralf Trønnes static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane, 209bcd2ba02SEric Anholt struct drm_plane_state *old_pstate) 2105b809074SNoralf Trønnes { 2115b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 2125b809074SNoralf Trønnes 2135b809074SNoralf Trønnes pipe = container_of(plane, struct drm_simple_display_pipe, plane); 2145b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->update) 2155b809074SNoralf Trønnes return; 2165b809074SNoralf Trønnes 217bcd2ba02SEric Anholt pipe->funcs->update(pipe, old_pstate); 2185b809074SNoralf Trønnes } 2195b809074SNoralf Trønnes 2207d83a155SMarek Vasut static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane, 2217d83a155SMarek Vasut struct drm_plane_state *state) 2227d83a155SMarek Vasut { 2237d83a155SMarek Vasut struct drm_simple_display_pipe *pipe; 2247d83a155SMarek Vasut 2257d83a155SMarek Vasut pipe = container_of(plane, struct drm_simple_display_pipe, plane); 2267d83a155SMarek Vasut if (!pipe->funcs || !pipe->funcs->prepare_fb) 2277d83a155SMarek Vasut return 0; 2287d83a155SMarek Vasut 2297d83a155SMarek Vasut return pipe->funcs->prepare_fb(pipe, state); 2307d83a155SMarek Vasut } 2317d83a155SMarek Vasut 2327d83a155SMarek Vasut static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane, 2337d83a155SMarek Vasut struct drm_plane_state *state) 2347d83a155SMarek Vasut { 2357d83a155SMarek Vasut struct drm_simple_display_pipe *pipe; 2367d83a155SMarek Vasut 2377d83a155SMarek Vasut pipe = container_of(plane, struct drm_simple_display_pipe, plane); 2387d83a155SMarek Vasut if (!pipe->funcs || !pipe->funcs->cleanup_fb) 2397d83a155SMarek Vasut return; 2407d83a155SMarek Vasut 2417d83a155SMarek Vasut pipe->funcs->cleanup_fb(pipe, state); 2427d83a155SMarek Vasut } 2437d83a155SMarek Vasut 244dff906c3SEric Anholt static bool drm_simple_kms_format_mod_supported(struct drm_plane *plane, 245dff906c3SEric Anholt uint32_t format, 246dff906c3SEric Anholt uint64_t modifier) 247dff906c3SEric Anholt { 248dff906c3SEric Anholt return modifier == DRM_FORMAT_MOD_LINEAR; 249dff906c3SEric Anholt } 250dff906c3SEric Anholt 2515b809074SNoralf Trønnes static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = { 2527d83a155SMarek Vasut .prepare_fb = drm_simple_kms_plane_prepare_fb, 2537d83a155SMarek Vasut .cleanup_fb = drm_simple_kms_plane_cleanup_fb, 2545b809074SNoralf Trønnes .atomic_check = drm_simple_kms_plane_atomic_check, 2555b809074SNoralf Trønnes .atomic_update = drm_simple_kms_plane_atomic_update, 2565b809074SNoralf Trønnes }; 2575b809074SNoralf Trønnes 25840f302adSThomas Zimmermann static void drm_simple_kms_plane_reset(struct drm_plane *plane) 25940f302adSThomas Zimmermann { 26040f302adSThomas Zimmermann struct drm_simple_display_pipe *pipe; 26140f302adSThomas Zimmermann 26240f302adSThomas Zimmermann pipe = container_of(plane, struct drm_simple_display_pipe, plane); 26340f302adSThomas Zimmermann if (!pipe->funcs || !pipe->funcs->reset_plane) 26440f302adSThomas Zimmermann return drm_atomic_helper_plane_reset(plane); 26540f302adSThomas Zimmermann 26640f302adSThomas Zimmermann return pipe->funcs->reset_plane(pipe); 26740f302adSThomas Zimmermann } 26840f302adSThomas Zimmermann 26940f302adSThomas Zimmermann static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane) 27040f302adSThomas Zimmermann { 27140f302adSThomas Zimmermann struct drm_simple_display_pipe *pipe; 27240f302adSThomas Zimmermann 27340f302adSThomas Zimmermann pipe = container_of(plane, struct drm_simple_display_pipe, plane); 27440f302adSThomas Zimmermann if (!pipe->funcs || !pipe->funcs->duplicate_plane_state) 27540f302adSThomas Zimmermann return drm_atomic_helper_plane_duplicate_state(plane); 27640f302adSThomas Zimmermann 27740f302adSThomas Zimmermann return pipe->funcs->duplicate_plane_state(pipe); 27840f302adSThomas Zimmermann } 27940f302adSThomas Zimmermann 28040f302adSThomas Zimmermann static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane, 28140f302adSThomas Zimmermann struct drm_plane_state *state) 28240f302adSThomas Zimmermann { 28340f302adSThomas Zimmermann struct drm_simple_display_pipe *pipe; 28440f302adSThomas Zimmermann 28540f302adSThomas Zimmermann pipe = container_of(plane, struct drm_simple_display_pipe, plane); 28640f302adSThomas Zimmermann if (!pipe->funcs || !pipe->funcs->destroy_plane_state) 28740f302adSThomas Zimmermann drm_atomic_helper_plane_destroy_state(plane, state); 28840f302adSThomas Zimmermann else 28940f302adSThomas Zimmermann pipe->funcs->destroy_plane_state(pipe, state); 29040f302adSThomas Zimmermann } 29140f302adSThomas Zimmermann 2925b809074SNoralf Trønnes static const struct drm_plane_funcs drm_simple_kms_plane_funcs = { 2935b809074SNoralf Trønnes .update_plane = drm_atomic_helper_update_plane, 2945b809074SNoralf Trønnes .disable_plane = drm_atomic_helper_disable_plane, 2955b809074SNoralf Trønnes .destroy = drm_plane_cleanup, 29640f302adSThomas Zimmermann .reset = drm_simple_kms_plane_reset, 29740f302adSThomas Zimmermann .atomic_duplicate_state = drm_simple_kms_plane_duplicate_state, 29840f302adSThomas Zimmermann .atomic_destroy_state = drm_simple_kms_plane_destroy_state, 299dff906c3SEric Anholt .format_mod_supported = drm_simple_kms_format_mod_supported, 3005b809074SNoralf Trønnes }; 3015b809074SNoralf Trønnes 3025b809074SNoralf Trønnes /** 303315486c6SAndrea Merello * drm_simple_display_pipe_attach_bridge - Attach a bridge to the display pipe 304315486c6SAndrea Merello * @pipe: simple display pipe object 305315486c6SAndrea Merello * @bridge: bridge to attach 306315486c6SAndrea Merello * 307315486c6SAndrea Merello * Makes it possible to still use the drm_simple_display_pipe helpers when 308315486c6SAndrea Merello * a DRM bridge has to be used. 309315486c6SAndrea Merello * 310315486c6SAndrea Merello * Note that you probably want to initialize the pipe by passing a NULL 311315486c6SAndrea Merello * connector to drm_simple_display_pipe_init(). 312315486c6SAndrea Merello * 313315486c6SAndrea Merello * Returns: 314315486c6SAndrea Merello * Zero on success, negative error code on failure. 315315486c6SAndrea Merello */ 316315486c6SAndrea Merello int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe, 317315486c6SAndrea Merello struct drm_bridge *bridge) 318315486c6SAndrea Merello { 319a25b988fSLaurent Pinchart return drm_bridge_attach(&pipe->encoder, bridge, NULL, 0); 320315486c6SAndrea Merello } 321315486c6SAndrea Merello EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge); 322315486c6SAndrea Merello 323315486c6SAndrea Merello /** 3245b809074SNoralf Trønnes * drm_simple_display_pipe_init - Initialize a simple display pipeline 3255b809074SNoralf Trønnes * @dev: DRM device 3265b809074SNoralf Trønnes * @pipe: simple display pipe object to initialize 3275b809074SNoralf Trønnes * @funcs: callbacks for the display pipe (optional) 32862cacc79SDaniel Vetter * @formats: array of supported formats (DRM_FORMAT\_\*) 3295b809074SNoralf Trønnes * @format_count: number of elements in @formats 330e6fc3b68SBen Widawsky * @format_modifiers: array of formats modifiers 3314f993973SAndrea Merello * @connector: connector to attach and register (optional) 3325b809074SNoralf Trønnes * 3335b809074SNoralf Trønnes * Sets up a display pipeline which consist of a really simple 3344f993973SAndrea Merello * plane-crtc-encoder pipe. 3354f993973SAndrea Merello * 3364f993973SAndrea Merello * If a connector is supplied, the pipe will be coupled with the provided 3374f993973SAndrea Merello * connector. You may supply a NULL connector when using drm bridges, that 3384f993973SAndrea Merello * handle connectors themselves (see drm_simple_display_pipe_attach_bridge()). 3394f993973SAndrea Merello * 3405b809074SNoralf Trønnes * Teardown of a simple display pipe is all handled automatically by the drm 3415b809074SNoralf Trønnes * core through calling drm_mode_config_cleanup(). Drivers afterwards need to 3425b809074SNoralf Trønnes * release the memory for the structure themselves. 3435b809074SNoralf Trønnes * 3445b809074SNoralf Trønnes * Returns: 3455b809074SNoralf Trønnes * Zero on success, negative error code on failure. 3465b809074SNoralf Trønnes */ 3475b809074SNoralf Trønnes int drm_simple_display_pipe_init(struct drm_device *dev, 3485b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe, 3495b809074SNoralf Trønnes const struct drm_simple_display_pipe_funcs *funcs, 3505b809074SNoralf Trønnes const uint32_t *formats, unsigned int format_count, 351e6fc3b68SBen Widawsky const uint64_t *format_modifiers, 3525b809074SNoralf Trønnes struct drm_connector *connector) 3535b809074SNoralf Trønnes { 3545b809074SNoralf Trønnes struct drm_encoder *encoder = &pipe->encoder; 3555b809074SNoralf Trønnes struct drm_plane *plane = &pipe->plane; 3565b809074SNoralf Trønnes struct drm_crtc *crtc = &pipe->crtc; 3575b809074SNoralf Trønnes int ret; 3585b809074SNoralf Trønnes 3595b809074SNoralf Trønnes pipe->connector = connector; 3605b809074SNoralf Trønnes pipe->funcs = funcs; 3615b809074SNoralf Trønnes 3625b809074SNoralf Trønnes drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs); 3635b809074SNoralf Trønnes ret = drm_universal_plane_init(dev, plane, 0, 3645b809074SNoralf Trønnes &drm_simple_kms_plane_funcs, 3655b809074SNoralf Trønnes formats, format_count, 366e6fc3b68SBen Widawsky format_modifiers, 3675b809074SNoralf Trønnes DRM_PLANE_TYPE_PRIMARY, NULL); 3685b809074SNoralf Trønnes if (ret) 3695b809074SNoralf Trønnes return ret; 3705b809074SNoralf Trønnes 3715b809074SNoralf Trønnes drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs); 3725b809074SNoralf Trønnes ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 3735b809074SNoralf Trønnes &drm_simple_kms_crtc_funcs, NULL); 3745b809074SNoralf Trønnes if (ret) 3755b809074SNoralf Trønnes return ret; 3765b809074SNoralf Trønnes 3776a52193bSVille Syrjälä encoder->possible_crtcs = drm_crtc_mask(crtc); 37863170ac6SThomas Zimmermann ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_NONE); 3794f993973SAndrea Merello if (ret || !connector) 3805b809074SNoralf Trønnes return ret; 3815b809074SNoralf Trønnes 382cde4c44dSDaniel Vetter return drm_connector_attach_encoder(connector, encoder); 3835b809074SNoralf Trønnes } 3845b809074SNoralf Trønnes EXPORT_SYMBOL(drm_simple_display_pipe_init); 3855b809074SNoralf Trønnes 3865b809074SNoralf Trønnes MODULE_LICENSE("GPL"); 387