0001
0002
0003 #include <linux/iosys-map.h>
0004
0005 #include <drm/drm_atomic.h>
0006 #include <drm/drm_atomic_helper.h>
0007 #include <drm/drm_fourcc.h>
0008 #include <drm/drm_gem_atomic_helper.h>
0009 #include <drm/drm_gem_framebuffer_helper.h>
0010 #include <drm/drm_plane_helper.h>
0011
0012 #include "vkms_drv.h"
0013
0014 static const u32 vkms_formats[] = {
0015 DRM_FORMAT_XRGB8888,
0016 };
0017
0018 static const u32 vkms_plane_formats[] = {
0019 DRM_FORMAT_ARGB8888,
0020 DRM_FORMAT_XRGB8888
0021 };
0022
0023 static struct drm_plane_state *
0024 vkms_plane_duplicate_state(struct drm_plane *plane)
0025 {
0026 struct vkms_plane_state *vkms_state;
0027 struct vkms_composer *composer;
0028
0029 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
0030 if (!vkms_state)
0031 return NULL;
0032
0033 composer = kzalloc(sizeof(*composer), GFP_KERNEL);
0034 if (!composer) {
0035 DRM_DEBUG_KMS("Couldn't allocate composer\n");
0036 kfree(vkms_state);
0037 return NULL;
0038 }
0039
0040 vkms_state->composer = composer;
0041
0042 __drm_gem_duplicate_shadow_plane_state(plane, &vkms_state->base);
0043
0044 return &vkms_state->base.base;
0045 }
0046
0047 static void vkms_plane_destroy_state(struct drm_plane *plane,
0048 struct drm_plane_state *old_state)
0049 {
0050 struct vkms_plane_state *vkms_state = to_vkms_plane_state(old_state);
0051 struct drm_crtc *crtc = vkms_state->base.base.crtc;
0052
0053 if (crtc) {
0054
0055
0056
0057 if (drm_framebuffer_read_refcount(&vkms_state->composer->fb))
0058 drm_framebuffer_put(&vkms_state->composer->fb);
0059 }
0060
0061 kfree(vkms_state->composer);
0062 vkms_state->composer = NULL;
0063
0064 __drm_gem_destroy_shadow_plane_state(&vkms_state->base);
0065 kfree(vkms_state);
0066 }
0067
0068 static void vkms_plane_reset(struct drm_plane *plane)
0069 {
0070 struct vkms_plane_state *vkms_state;
0071
0072 if (plane->state) {
0073 vkms_plane_destroy_state(plane, plane->state);
0074 plane->state = NULL;
0075 }
0076
0077 vkms_state = kzalloc(sizeof(*vkms_state), GFP_KERNEL);
0078 if (!vkms_state) {
0079 DRM_ERROR("Cannot allocate vkms_plane_state\n");
0080 return;
0081 }
0082
0083 __drm_gem_reset_shadow_plane(plane, &vkms_state->base);
0084 }
0085
0086 static const struct drm_plane_funcs vkms_plane_funcs = {
0087 .update_plane = drm_atomic_helper_update_plane,
0088 .disable_plane = drm_atomic_helper_disable_plane,
0089 .reset = vkms_plane_reset,
0090 .atomic_duplicate_state = vkms_plane_duplicate_state,
0091 .atomic_destroy_state = vkms_plane_destroy_state,
0092 };
0093
0094 static void vkms_plane_atomic_update(struct drm_plane *plane,
0095 struct drm_atomic_state *state)
0096 {
0097 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0098 plane);
0099 struct vkms_plane_state *vkms_plane_state;
0100 struct drm_shadow_plane_state *shadow_plane_state;
0101 struct drm_framebuffer *fb = new_state->fb;
0102 struct vkms_composer *composer;
0103
0104 if (!new_state->crtc || !fb)
0105 return;
0106
0107 vkms_plane_state = to_vkms_plane_state(new_state);
0108 shadow_plane_state = &vkms_plane_state->base;
0109
0110 composer = vkms_plane_state->composer;
0111 memcpy(&composer->src, &new_state->src, sizeof(struct drm_rect));
0112 memcpy(&composer->dst, &new_state->dst, sizeof(struct drm_rect));
0113 memcpy(&composer->fb, fb, sizeof(struct drm_framebuffer));
0114 memcpy(&composer->map, &shadow_plane_state->data, sizeof(composer->map));
0115 drm_framebuffer_get(&composer->fb);
0116 composer->offset = fb->offsets[0];
0117 composer->pitch = fb->pitches[0];
0118 composer->cpp = fb->format->cpp[0];
0119 }
0120
0121 static int vkms_plane_atomic_check(struct drm_plane *plane,
0122 struct drm_atomic_state *state)
0123 {
0124 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0125 plane);
0126 struct drm_crtc_state *crtc_state;
0127 bool can_position = false;
0128 int ret;
0129
0130 if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
0131 return 0;
0132
0133 crtc_state = drm_atomic_get_crtc_state(state,
0134 new_plane_state->crtc);
0135 if (IS_ERR(crtc_state))
0136 return PTR_ERR(crtc_state);
0137
0138 if (plane->type != DRM_PLANE_TYPE_PRIMARY)
0139 can_position = true;
0140
0141 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
0142 DRM_PLANE_HELPER_NO_SCALING,
0143 DRM_PLANE_HELPER_NO_SCALING,
0144 can_position, true);
0145 if (ret != 0)
0146 return ret;
0147
0148
0149 if (!new_plane_state->visible && !can_position)
0150 return -EINVAL;
0151
0152 return 0;
0153 }
0154
0155 static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
0156 .atomic_update = vkms_plane_atomic_update,
0157 .atomic_check = vkms_plane_atomic_check,
0158 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
0159 };
0160
0161 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
0162 enum drm_plane_type type, int index)
0163 {
0164 struct drm_device *dev = &vkmsdev->drm;
0165 const struct drm_plane_helper_funcs *funcs;
0166 struct vkms_plane *plane;
0167 const u32 *formats;
0168 int nformats;
0169
0170 switch (type) {
0171 case DRM_PLANE_TYPE_PRIMARY:
0172 formats = vkms_formats;
0173 nformats = ARRAY_SIZE(vkms_formats);
0174 funcs = &vkms_primary_helper_funcs;
0175 break;
0176 case DRM_PLANE_TYPE_CURSOR:
0177 case DRM_PLANE_TYPE_OVERLAY:
0178 formats = vkms_plane_formats;
0179 nformats = ARRAY_SIZE(vkms_plane_formats);
0180 funcs = &vkms_primary_helper_funcs;
0181 break;
0182 default:
0183 formats = vkms_formats;
0184 nformats = ARRAY_SIZE(vkms_formats);
0185 funcs = &vkms_primary_helper_funcs;
0186 break;
0187 }
0188
0189 plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index,
0190 &vkms_plane_funcs,
0191 formats, nformats,
0192 NULL, type, NULL);
0193 if (IS_ERR(plane))
0194 return plane;
0195
0196 drm_plane_helper_add(&plane->base, funcs);
0197
0198 return plane;
0199 }