15b809074SNoralf Trønnes /* 25b809074SNoralf Trønnes * Copyright (C) 2016 Noralf Trønnes 35b809074SNoralf Trønnes * 45b809074SNoralf Trønnes * This program is free software; you can redistribute it and/or modify 55b809074SNoralf Trønnes * it under the terms of the GNU General Public License as published by 65b809074SNoralf Trønnes * the Free Software Foundation; either version 2 of the License, or 75b809074SNoralf Trønnes * (at your option) any later version. 85b809074SNoralf Trønnes */ 95b809074SNoralf Trønnes 105b809074SNoralf Trønnes #include <drm/drmP.h> 115b809074SNoralf Trønnes #include <drm/drm_atomic.h> 125b809074SNoralf Trønnes #include <drm/drm_atomic_helper.h> 135b809074SNoralf Trønnes #include <drm/drm_crtc_helper.h> 145b809074SNoralf Trønnes #include <drm/drm_plane_helper.h> 155b809074SNoralf Trønnes #include <drm/drm_simple_kms_helper.h> 165b809074SNoralf Trønnes #include <linux/slab.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 265b809074SNoralf Trønnes * 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. 315b809074SNoralf Trønnes */ 325b809074SNoralf Trønnes 335b809074SNoralf Trønnes static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = { 345b809074SNoralf Trønnes .destroy = drm_encoder_cleanup, 355b809074SNoralf Trønnes }; 365b809074SNoralf Trønnes 37*6dcf0de7SDaniel Vetter static int drm_simple_kms_crtc_check(struct drm_crtc *crtc, 38*6dcf0de7SDaniel Vetter struct drm_crtc_state *state) 39*6dcf0de7SDaniel Vetter { 40*6dcf0de7SDaniel Vetter return drm_atomic_add_affected_planes(state->state, crtc); 41*6dcf0de7SDaniel Vetter } 42*6dcf0de7SDaniel Vetter 435b809074SNoralf Trønnes static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc) 445b809074SNoralf Trønnes { 455b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 465b809074SNoralf Trønnes 475b809074SNoralf Trønnes pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 485b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->enable) 495b809074SNoralf Trønnes return; 505b809074SNoralf Trønnes 515b809074SNoralf Trønnes pipe->funcs->enable(pipe, crtc->state); 525b809074SNoralf Trønnes } 535b809074SNoralf Trønnes 545b809074SNoralf Trønnes static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc) 555b809074SNoralf Trønnes { 565b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 575b809074SNoralf Trønnes 585b809074SNoralf Trønnes pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); 595b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->disable) 605b809074SNoralf Trønnes return; 615b809074SNoralf Trønnes 625b809074SNoralf Trønnes pipe->funcs->disable(pipe); 635b809074SNoralf Trønnes } 645b809074SNoralf Trønnes 655b809074SNoralf Trønnes static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = { 66*6dcf0de7SDaniel Vetter .atomic_check = drm_simple_kms_crtc_check, 675b809074SNoralf Trønnes .disable = drm_simple_kms_crtc_disable, 685b809074SNoralf Trønnes .enable = drm_simple_kms_crtc_enable, 695b809074SNoralf Trønnes }; 705b809074SNoralf Trønnes 715b809074SNoralf Trønnes static const struct drm_crtc_funcs drm_simple_kms_crtc_funcs = { 725b809074SNoralf Trønnes .reset = drm_atomic_helper_crtc_reset, 735b809074SNoralf Trønnes .destroy = drm_crtc_cleanup, 745b809074SNoralf Trønnes .set_config = drm_atomic_helper_set_config, 755b809074SNoralf Trønnes .page_flip = drm_atomic_helper_page_flip, 765b809074SNoralf Trønnes .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 775b809074SNoralf Trønnes .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 785b809074SNoralf Trønnes }; 795b809074SNoralf Trønnes 805b809074SNoralf Trønnes static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, 815b809074SNoralf Trønnes struct drm_plane_state *plane_state) 825b809074SNoralf Trønnes { 835b809074SNoralf Trønnes struct drm_rect clip = { 0 }; 845b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 855b809074SNoralf Trønnes struct drm_crtc_state *crtc_state; 865b809074SNoralf Trønnes int ret; 875b809074SNoralf Trønnes 885b809074SNoralf Trønnes pipe = container_of(plane, struct drm_simple_display_pipe, plane); 895b809074SNoralf Trønnes crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state, 905b809074SNoralf Trønnes &pipe->crtc); 915b809074SNoralf Trønnes if (crtc_state->enable != !!plane_state->crtc) 925b809074SNoralf Trønnes return -EINVAL; /* plane must match crtc enable state */ 935b809074SNoralf Trønnes 945b809074SNoralf Trønnes if (!crtc_state->enable) 955b809074SNoralf Trønnes return 0; /* nothing to check when disabling or disabled */ 965b809074SNoralf Trønnes 975b809074SNoralf Trønnes clip.x2 = crtc_state->adjusted_mode.hdisplay; 985b809074SNoralf Trønnes clip.y2 = crtc_state->adjusted_mode.vdisplay; 994be12cc2SVille Syrjälä 1004be12cc2SVille Syrjälä ret = drm_plane_helper_check_state(plane_state, &clip, 1015b809074SNoralf Trønnes DRM_PLANE_HELPER_NO_SCALING, 1025b809074SNoralf Trønnes DRM_PLANE_HELPER_NO_SCALING, 1034be12cc2SVille Syrjälä false, true); 1045b809074SNoralf Trønnes if (ret) 1055b809074SNoralf Trønnes return ret; 1065b809074SNoralf Trønnes 1074be12cc2SVille Syrjälä if (!plane_state->visible) 1085b809074SNoralf Trønnes return -EINVAL; 1095b809074SNoralf Trønnes 1105b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->check) 1115b809074SNoralf Trønnes return 0; 1125b809074SNoralf Trønnes 1135b809074SNoralf Trønnes return pipe->funcs->check(pipe, plane_state, crtc_state); 1145b809074SNoralf Trønnes } 1155b809074SNoralf Trønnes 1165b809074SNoralf Trønnes static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane, 1175b809074SNoralf Trønnes struct drm_plane_state *pstate) 1185b809074SNoralf Trønnes { 1195b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe; 1205b809074SNoralf Trønnes 1215b809074SNoralf Trønnes pipe = container_of(plane, struct drm_simple_display_pipe, plane); 1225b809074SNoralf Trønnes if (!pipe->funcs || !pipe->funcs->update) 1235b809074SNoralf Trønnes return; 1245b809074SNoralf Trønnes 1255b809074SNoralf Trønnes pipe->funcs->update(pipe, pstate); 1265b809074SNoralf Trønnes } 1275b809074SNoralf Trønnes 1285b809074SNoralf Trønnes static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = { 1295b809074SNoralf Trønnes .atomic_check = drm_simple_kms_plane_atomic_check, 1305b809074SNoralf Trønnes .atomic_update = drm_simple_kms_plane_atomic_update, 1315b809074SNoralf Trønnes }; 1325b809074SNoralf Trønnes 1335b809074SNoralf Trønnes static const struct drm_plane_funcs drm_simple_kms_plane_funcs = { 1345b809074SNoralf Trønnes .update_plane = drm_atomic_helper_update_plane, 1355b809074SNoralf Trønnes .disable_plane = drm_atomic_helper_disable_plane, 1365b809074SNoralf Trønnes .destroy = drm_plane_cleanup, 1375b809074SNoralf Trønnes .reset = drm_atomic_helper_plane_reset, 1385b809074SNoralf Trønnes .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 1395b809074SNoralf Trønnes .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 1405b809074SNoralf Trønnes }; 1415b809074SNoralf Trønnes 1425b809074SNoralf Trønnes /** 1435b809074SNoralf Trønnes * drm_simple_display_pipe_init - Initialize a simple display pipeline 1445b809074SNoralf Trønnes * @dev: DRM device 1455b809074SNoralf Trønnes * @pipe: simple display pipe object to initialize 1465b809074SNoralf Trønnes * @funcs: callbacks for the display pipe (optional) 14762cacc79SDaniel Vetter * @formats: array of supported formats (DRM_FORMAT\_\*) 1485b809074SNoralf Trønnes * @format_count: number of elements in @formats 1495b809074SNoralf Trønnes * @connector: connector to attach and register 1505b809074SNoralf Trønnes * 1515b809074SNoralf Trønnes * Sets up a display pipeline which consist of a really simple 1525b809074SNoralf Trønnes * plane-crtc-encoder pipe coupled with the provided connector. 1535b809074SNoralf Trønnes * Teardown of a simple display pipe is all handled automatically by the drm 1545b809074SNoralf Trønnes * core through calling drm_mode_config_cleanup(). Drivers afterwards need to 1555b809074SNoralf Trønnes * release the memory for the structure themselves. 1565b809074SNoralf Trønnes * 1575b809074SNoralf Trønnes * Returns: 1585b809074SNoralf Trønnes * Zero on success, negative error code on failure. 1595b809074SNoralf Trønnes */ 1605b809074SNoralf Trønnes int drm_simple_display_pipe_init(struct drm_device *dev, 1615b809074SNoralf Trønnes struct drm_simple_display_pipe *pipe, 1625b809074SNoralf Trønnes const struct drm_simple_display_pipe_funcs *funcs, 1635b809074SNoralf Trønnes const uint32_t *formats, unsigned int format_count, 1645b809074SNoralf Trønnes struct drm_connector *connector) 1655b809074SNoralf Trønnes { 1665b809074SNoralf Trønnes struct drm_encoder *encoder = &pipe->encoder; 1675b809074SNoralf Trønnes struct drm_plane *plane = &pipe->plane; 1685b809074SNoralf Trønnes struct drm_crtc *crtc = &pipe->crtc; 1695b809074SNoralf Trønnes int ret; 1705b809074SNoralf Trønnes 1715b809074SNoralf Trønnes pipe->connector = connector; 1725b809074SNoralf Trønnes pipe->funcs = funcs; 1735b809074SNoralf Trønnes 1745b809074SNoralf Trønnes drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs); 1755b809074SNoralf Trønnes ret = drm_universal_plane_init(dev, plane, 0, 1765b809074SNoralf Trønnes &drm_simple_kms_plane_funcs, 1775b809074SNoralf Trønnes formats, format_count, 1785b809074SNoralf Trønnes DRM_PLANE_TYPE_PRIMARY, NULL); 1795b809074SNoralf Trønnes if (ret) 1805b809074SNoralf Trønnes return ret; 1815b809074SNoralf Trønnes 1825b809074SNoralf Trønnes drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs); 1835b809074SNoralf Trønnes ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 1845b809074SNoralf Trønnes &drm_simple_kms_crtc_funcs, NULL); 1855b809074SNoralf Trønnes if (ret) 1865b809074SNoralf Trønnes return ret; 1875b809074SNoralf Trønnes 1885b809074SNoralf Trønnes encoder->possible_crtcs = 1 << drm_crtc_index(crtc); 1895b809074SNoralf Trønnes ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs, 1905b809074SNoralf Trønnes DRM_MODE_ENCODER_NONE, NULL); 1915b809074SNoralf Trønnes if (ret) 1925b809074SNoralf Trønnes return ret; 1935b809074SNoralf Trønnes 1945b809074SNoralf Trønnes return drm_mode_connector_attach_encoder(connector, encoder); 1955b809074SNoralf Trønnes } 1965b809074SNoralf Trønnes EXPORT_SYMBOL(drm_simple_display_pipe_init); 1975b809074SNoralf Trønnes 1985b809074SNoralf Trønnes MODULE_LICENSE("GPL"); 199