1 /* 2 * Copyright (C) 2015 Texas Instruments 3 * Author: Jyri Sarha <jsarha@ti.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <drm/drmP.h> 19 20 #include <drm/drm_atomic.h> 21 #include <drm/drm_plane_helper.h> 22 #include <drm/drm_atomic_helper.h> 23 #include <uapi/drm/drm_fourcc.h> 24 25 #include "tilcdc_drv.h" 26 27 static struct drm_plane_funcs tilcdc_plane_funcs = { 28 .update_plane = drm_atomic_helper_update_plane, 29 .disable_plane = drm_atomic_helper_disable_plane, 30 .destroy = drm_plane_cleanup, 31 .reset = drm_atomic_helper_plane_reset, 32 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 33 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 34 }; 35 36 static int tilcdc_plane_atomic_check(struct drm_plane *plane, 37 struct drm_plane_state *state) 38 { 39 struct drm_crtc_state *crtc_state; 40 struct drm_plane_state *old_state = plane->state; 41 unsigned int pitch; 42 43 if (!state->crtc) 44 return 0; 45 46 if (WARN_ON(!state->fb)) 47 return -EINVAL; 48 49 if (state->crtc_x || state->crtc_y) { 50 dev_err(plane->dev->dev, "%s: crtc position must be zero.", 51 __func__); 52 return -EINVAL; 53 } 54 55 crtc_state = drm_atomic_get_existing_crtc_state(state->state, 56 state->crtc); 57 /* we should have a crtc state if the plane is attached to a crtc */ 58 if (WARN_ON(!crtc_state)) 59 return 0; 60 61 if (crtc_state->mode.hdisplay != state->crtc_w || 62 crtc_state->mode.vdisplay != state->crtc_h) { 63 dev_err(plane->dev->dev, 64 "%s: Size must match mode (%dx%d == %dx%d)", __func__, 65 crtc_state->mode.hdisplay, crtc_state->mode.vdisplay, 66 state->crtc_w, state->crtc_h); 67 return -EINVAL; 68 } 69 70 pitch = crtc_state->mode.hdisplay * 71 state->fb->format->cpp[0]; 72 if (state->fb->pitches[0] != pitch) { 73 dev_err(plane->dev->dev, 74 "Invalid pitch: fb and crtc widths must be the same"); 75 return -EINVAL; 76 } 77 78 if (state->fb && old_state->fb && 79 state->fb->format != old_state->fb->format) { 80 dev_dbg(plane->dev->dev, 81 "%s(): pixel format change requires mode_change\n", 82 __func__); 83 crtc_state->mode_changed = true; 84 } 85 86 return 0; 87 } 88 89 static void tilcdc_plane_atomic_update(struct drm_plane *plane, 90 struct drm_plane_state *old_state) 91 { 92 struct drm_plane_state *state = plane->state; 93 94 if (!state->crtc) 95 return; 96 97 if (WARN_ON(!state->fb || !state->crtc->state)) 98 return; 99 100 tilcdc_crtc_update_fb(state->crtc, 101 state->fb, 102 state->crtc->state->event); 103 } 104 105 static const struct drm_plane_helper_funcs plane_helper_funcs = { 106 .atomic_check = tilcdc_plane_atomic_check, 107 .atomic_update = tilcdc_plane_atomic_update, 108 }; 109 110 int tilcdc_plane_init(struct drm_device *dev, 111 struct drm_plane *plane) 112 { 113 struct tilcdc_drm_private *priv = dev->dev_private; 114 int ret; 115 116 ret = drm_plane_init(dev, plane, 1, 117 &tilcdc_plane_funcs, 118 priv->pixelformats, 119 priv->num_pixelformats, 120 true); 121 if (ret) { 122 dev_err(dev->dev, "Failed to initialize plane: %d\n", ret); 123 return ret; 124 } 125 126 drm_plane_helper_add(plane, &plane_helper_funcs); 127 128 return 0; 129 } 130