1 /* 2 * Copyright (C) 2011 Samsung Electronics Co.Ltd 3 * Authors: Joonyoung Shim <jy0922.shim@samsung.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 as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 * 10 */ 11 12 #include "drmP.h" 13 14 #include "exynos_drm.h" 15 #include "exynos_drm_crtc.h" 16 #include "exynos_drm_drv.h" 17 #include "exynos_drm_encoder.h" 18 19 struct exynos_plane { 20 struct drm_plane base; 21 struct exynos_drm_overlay overlay; 22 bool enabled; 23 }; 24 25 static const uint32_t formats[] = { 26 DRM_FORMAT_XRGB8888, 27 DRM_FORMAT_ARGB8888, 28 DRM_FORMAT_NV12, 29 DRM_FORMAT_NV12M, 30 DRM_FORMAT_NV12MT, 31 }; 32 33 static int 34 exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 35 struct drm_framebuffer *fb, int crtc_x, int crtc_y, 36 unsigned int crtc_w, unsigned int crtc_h, 37 uint32_t src_x, uint32_t src_y, 38 uint32_t src_w, uint32_t src_h) 39 { 40 struct exynos_plane *exynos_plane = 41 container_of(plane, struct exynos_plane, base); 42 struct exynos_drm_overlay *overlay = &exynos_plane->overlay; 43 struct exynos_drm_crtc_pos pos; 44 int ret; 45 46 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 47 48 memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos)); 49 pos.crtc_x = crtc_x; 50 pos.crtc_y = crtc_y; 51 pos.crtc_w = crtc_w; 52 pos.crtc_h = crtc_h; 53 54 /* considering 16.16 fixed point of source values */ 55 pos.fb_x = src_x >> 16; 56 pos.fb_y = src_y >> 16; 57 pos.src_w = src_w >> 16; 58 pos.src_h = src_h >> 16; 59 60 ret = exynos_drm_overlay_update(overlay, fb, &crtc->mode, &pos); 61 if (ret < 0) 62 return ret; 63 64 exynos_drm_fn_encoder(crtc, overlay, 65 exynos_drm_encoder_crtc_mode_set); 66 exynos_drm_fn_encoder(crtc, &overlay->zpos, 67 exynos_drm_encoder_crtc_plane_commit); 68 69 exynos_plane->enabled = true; 70 71 return 0; 72 } 73 74 static int exynos_disable_plane(struct drm_plane *plane) 75 { 76 struct exynos_plane *exynos_plane = 77 container_of(plane, struct exynos_plane, base); 78 struct exynos_drm_overlay *overlay = &exynos_plane->overlay; 79 80 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 81 82 if (!exynos_plane->enabled) 83 return 0; 84 85 exynos_drm_fn_encoder(plane->crtc, &overlay->zpos, 86 exynos_drm_encoder_crtc_disable); 87 88 exynos_plane->enabled = false; 89 exynos_plane->overlay.zpos = DEFAULT_ZPOS; 90 91 return 0; 92 } 93 94 static void exynos_plane_destroy(struct drm_plane *plane) 95 { 96 struct exynos_plane *exynos_plane = 97 container_of(plane, struct exynos_plane, base); 98 99 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 100 101 exynos_disable_plane(plane); 102 drm_plane_cleanup(plane); 103 kfree(exynos_plane); 104 } 105 106 static struct drm_plane_funcs exynos_plane_funcs = { 107 .update_plane = exynos_update_plane, 108 .disable_plane = exynos_disable_plane, 109 .destroy = exynos_plane_destroy, 110 }; 111 112 int exynos_plane_init(struct drm_device *dev, unsigned int nr) 113 { 114 struct exynos_plane *exynos_plane; 115 uint32_t possible_crtcs; 116 117 exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL); 118 if (!exynos_plane) 119 return -ENOMEM; 120 121 /* all CRTCs are available */ 122 possible_crtcs = (1 << MAX_CRTC) - 1; 123 124 exynos_plane->overlay.zpos = DEFAULT_ZPOS; 125 126 return drm_plane_init(dev, &exynos_plane->base, possible_crtcs, 127 &exynos_plane_funcs, formats, ARRAY_SIZE(formats), 128 false); 129 } 130 131 int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data, 132 struct drm_file *file_priv) 133 { 134 struct drm_exynos_plane_set_zpos *zpos_req = data; 135 struct drm_mode_object *obj; 136 struct drm_plane *plane; 137 struct exynos_plane *exynos_plane; 138 int ret = 0; 139 140 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 141 142 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 143 return -EINVAL; 144 145 if (zpos_req->zpos < 0 || zpos_req->zpos >= MAX_PLANE) { 146 if (zpos_req->zpos != DEFAULT_ZPOS) { 147 DRM_ERROR("zpos not within limits\n"); 148 return -EINVAL; 149 } 150 } 151 152 mutex_lock(&dev->mode_config.mutex); 153 154 obj = drm_mode_object_find(dev, zpos_req->plane_id, 155 DRM_MODE_OBJECT_PLANE); 156 if (!obj) { 157 DRM_DEBUG_KMS("Unknown plane ID %d\n", 158 zpos_req->plane_id); 159 ret = -EINVAL; 160 goto out; 161 } 162 163 plane = obj_to_plane(obj); 164 exynos_plane = container_of(plane, struct exynos_plane, base); 165 166 exynos_plane->overlay.zpos = zpos_req->zpos; 167 168 out: 169 mutex_unlock(&dev->mode_config.mutex); 170 return ret; 171 } 172