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 .set_property = drm_atomic_helper_plane_set_property, 32 .reset = drm_atomic_helper_plane_reset, 33 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 34 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 35 }; 36 37 static int tilcdc_plane_atomic_check(struct drm_plane *plane, 38 struct drm_plane_state *state) 39 { 40 struct drm_crtc_state *crtc_state; 41 struct drm_plane_state *old_state = plane->state; 42 unsigned int pitch; 43 44 if (!state->crtc) 45 return 0; 46 47 if (WARN_ON(!state->fb)) 48 return -EINVAL; 49 50 if (state->crtc_x || state->crtc_y) { 51 dev_err(plane->dev->dev, "%s: crtc position must be zero.", 52 __func__); 53 return -EINVAL; 54 } 55 56 crtc_state = drm_atomic_get_existing_crtc_state(state->state, 57 state->crtc); 58 /* we should have a crtc state if the plane is attached to a crtc */ 59 if (WARN_ON(!crtc_state)) 60 return 0; 61 62 if (crtc_state->mode.hdisplay != state->crtc_w || 63 crtc_state->mode.vdisplay != state->crtc_h) { 64 dev_err(plane->dev->dev, 65 "%s: Size must match mode (%dx%d == %dx%d)", __func__, 66 crtc_state->mode.hdisplay, crtc_state->mode.vdisplay, 67 state->crtc_w, state->crtc_h); 68 return -EINVAL; 69 } 70 71 pitch = crtc_state->mode.hdisplay * 72 state->fb->format->cpp[0]; 73 if (state->fb->pitches[0] != pitch) { 74 dev_err(plane->dev->dev, 75 "Invalid pitch: fb and crtc widths must be the same"); 76 return -EINVAL; 77 } 78 79 if (state->fb && old_state->fb && 80 state->fb->format != old_state->fb->format) { 81 dev_dbg(plane->dev->dev, 82 "%s(): pixel format change requires mode_change\n", 83 __func__); 84 crtc_state->mode_changed = true; 85 } 86 87 return 0; 88 } 89 90 static void tilcdc_plane_atomic_update(struct drm_plane *plane, 91 struct drm_plane_state *old_state) 92 { 93 struct drm_plane_state *state = plane->state; 94 95 if (!state->crtc) 96 return; 97 98 if (WARN_ON(!state->fb || !state->crtc->state)) 99 return; 100 101 tilcdc_crtc_update_fb(state->crtc, 102 state->fb, 103 state->crtc->state->event); 104 } 105 106 static const struct drm_plane_helper_funcs plane_helper_funcs = { 107 .atomic_check = tilcdc_plane_atomic_check, 108 .atomic_update = tilcdc_plane_atomic_update, 109 }; 110 111 int tilcdc_plane_init(struct drm_device *dev, 112 struct drm_plane *plane) 113 { 114 struct tilcdc_drm_private *priv = dev->dev_private; 115 int ret; 116 117 ret = drm_plane_init(dev, plane, 1, 118 &tilcdc_plane_funcs, 119 priv->pixelformats, 120 priv->num_pixelformats, 121 true); 122 if (ret) { 123 dev_err(dev->dev, "Failed to initialize plane: %d\n", ret); 124 return ret; 125 } 126 127 drm_plane_helper_add(plane, &plane_helper_funcs); 128 129 return 0; 130 } 131