0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include <linux/list.h>
0027
0028 #include <drm/drm_atomic.h>
0029 #include <drm/drm_atomic_helper.h>
0030 #include <drm/drm_atomic_uapi.h>
0031 #include <drm/drm_crtc_helper.h>
0032 #include <drm/drm_device.h>
0033 #include <drm/drm_encoder.h>
0034 #include <drm/drm_plane_helper.h>
0035 #include <drm/drm_rect.h>
0036
0037 #define SUBPIXEL_MASK 0xffff
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 static int get_connectors_for_crtc(struct drm_crtc *crtc,
0072 struct drm_connector **connector_list,
0073 int num_connectors)
0074 {
0075 struct drm_device *dev = crtc->dev;
0076 struct drm_connector *connector;
0077 struct drm_connector_list_iter conn_iter;
0078 int count = 0;
0079
0080
0081
0082
0083
0084
0085 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
0086
0087 drm_connector_list_iter_begin(dev, &conn_iter);
0088 drm_for_each_connector_iter(connector, &conn_iter) {
0089 if (connector->encoder && connector->encoder->crtc == crtc) {
0090 if (connector_list != NULL && count < num_connectors)
0091 *(connector_list++) = connector;
0092
0093 count++;
0094 }
0095 }
0096 drm_connector_list_iter_end(&conn_iter);
0097
0098 return count;
0099 }
0100
0101 static int drm_plane_helper_check_update(struct drm_plane *plane,
0102 struct drm_crtc *crtc,
0103 struct drm_framebuffer *fb,
0104 struct drm_rect *src,
0105 struct drm_rect *dst,
0106 unsigned int rotation,
0107 int min_scale,
0108 int max_scale,
0109 bool can_position,
0110 bool can_update_disabled,
0111 bool *visible)
0112 {
0113 struct drm_plane_state plane_state = {
0114 .plane = plane,
0115 .crtc = crtc,
0116 .fb = fb,
0117 .src_x = src->x1,
0118 .src_y = src->y1,
0119 .src_w = drm_rect_width(src),
0120 .src_h = drm_rect_height(src),
0121 .crtc_x = dst->x1,
0122 .crtc_y = dst->y1,
0123 .crtc_w = drm_rect_width(dst),
0124 .crtc_h = drm_rect_height(dst),
0125 .rotation = rotation,
0126 };
0127 struct drm_crtc_state crtc_state = {
0128 .crtc = crtc,
0129 .enable = crtc->enabled,
0130 .mode = crtc->mode,
0131 };
0132 int ret;
0133
0134 ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
0135 min_scale, max_scale,
0136 can_position,
0137 can_update_disabled);
0138 if (ret)
0139 return ret;
0140
0141 *src = plane_state.src;
0142 *dst = plane_state.dst;
0143 *visible = plane_state.visible;
0144
0145 return 0;
0146 }
0147
0148 static int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
0149 struct drm_framebuffer *fb,
0150 int crtc_x, int crtc_y,
0151 unsigned int crtc_w, unsigned int crtc_h,
0152 uint32_t src_x, uint32_t src_y,
0153 uint32_t src_w, uint32_t src_h,
0154 struct drm_modeset_acquire_ctx *ctx)
0155 {
0156 struct drm_mode_set set = {
0157 .crtc = crtc,
0158 .fb = fb,
0159 .mode = &crtc->mode,
0160 .x = src_x >> 16,
0161 .y = src_y >> 16,
0162 };
0163 struct drm_rect src = {
0164 .x1 = src_x,
0165 .y1 = src_y,
0166 .x2 = src_x + src_w,
0167 .y2 = src_y + src_h,
0168 };
0169 struct drm_rect dest = {
0170 .x1 = crtc_x,
0171 .y1 = crtc_y,
0172 .x2 = crtc_x + crtc_w,
0173 .y2 = crtc_y + crtc_h,
0174 };
0175 struct drm_connector **connector_list;
0176 int num_connectors, ret;
0177 bool visible;
0178
0179 ret = drm_plane_helper_check_update(plane, crtc, fb,
0180 &src, &dest,
0181 DRM_MODE_ROTATE_0,
0182 DRM_PLANE_HELPER_NO_SCALING,
0183 DRM_PLANE_HELPER_NO_SCALING,
0184 false, false, &visible);
0185 if (ret)
0186 return ret;
0187
0188 if (!visible)
0189
0190
0191
0192
0193
0194 return plane->funcs->disable_plane(plane, ctx);
0195
0196
0197 num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
0198 BUG_ON(num_connectors == 0);
0199 connector_list = kcalloc(num_connectors, sizeof(*connector_list),
0200 GFP_KERNEL);
0201 if (!connector_list)
0202 return -ENOMEM;
0203 get_connectors_for_crtc(crtc, connector_list, num_connectors);
0204
0205 set.connectors = connector_list;
0206 set.num_connectors = num_connectors;
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216 ret = crtc->funcs->set_config(&set, ctx);
0217
0218 kfree(connector_list);
0219 return ret;
0220 }
0221
0222 static int drm_primary_helper_disable(struct drm_plane *plane,
0223 struct drm_modeset_acquire_ctx *ctx)
0224 {
0225 return -EINVAL;
0226 }
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 void drm_primary_helper_destroy(struct drm_plane *plane)
0237 {
0238 drm_plane_cleanup(plane);
0239 kfree(plane);
0240 }
0241 EXPORT_SYMBOL(drm_primary_helper_destroy);
0242
0243 const struct drm_plane_funcs drm_primary_helper_funcs = {
0244 .update_plane = drm_primary_helper_update,
0245 .disable_plane = drm_primary_helper_disable,
0246 .destroy = drm_primary_helper_destroy,
0247 };
0248 EXPORT_SYMBOL(drm_primary_helper_funcs);