0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/iosys-map.h>
0014 #include <linux/export.h>
0015
0016 #include <drm/drm_atomic.h>
0017 #include <drm/drm_atomic_helper.h>
0018 #include <drm/drm_edid.h>
0019 #include <drm/drm_fb_helper.h>
0020 #include <drm/drm_fourcc.h>
0021 #include <drm/drm_framebuffer.h>
0022 #include <drm/drm_gem_atomic_helper.h>
0023 #include <drm/drm_gem_framebuffer_helper.h>
0024 #include <drm/drm_plane_helper.h>
0025 #include <drm/drm_probe_helper.h>
0026
0027 #include "hgsmi_channels.h"
0028 #include "vbox_drv.h"
0029 #include "vboxvideo.h"
0030
0031
0032
0033
0034
0035 static void vbox_do_modeset(struct drm_crtc *crtc)
0036 {
0037 struct drm_framebuffer *fb = crtc->primary->state->fb;
0038 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
0039 struct vbox_private *vbox;
0040 int width, height, bpp, pitch;
0041 u16 flags;
0042 s32 x_offset, y_offset;
0043
0044 vbox = to_vbox_dev(crtc->dev);
0045 width = vbox_crtc->width ? vbox_crtc->width : 640;
0046 height = vbox_crtc->height ? vbox_crtc->height : 480;
0047 bpp = fb ? fb->format->cpp[0] * 8 : 32;
0048 pitch = fb ? fb->pitches[0] : width * bpp / 8;
0049 x_offset = vbox->single_framebuffer ? vbox_crtc->x : vbox_crtc->x_hint;
0050 y_offset = vbox->single_framebuffer ? vbox_crtc->y : vbox_crtc->y_hint;
0051
0052
0053
0054
0055
0056
0057
0058 if (vbox_crtc->crtc_id == 0 && fb &&
0059 vbox_crtc->fb_offset / pitch < 0xffff - crtc->y &&
0060 vbox_crtc->fb_offset % (bpp / 8) == 0) {
0061 vbox_write_ioport(VBE_DISPI_INDEX_XRES, width);
0062 vbox_write_ioport(VBE_DISPI_INDEX_YRES, height);
0063 vbox_write_ioport(VBE_DISPI_INDEX_VIRT_WIDTH, pitch * 8 / bpp);
0064 vbox_write_ioport(VBE_DISPI_INDEX_BPP, bpp);
0065 vbox_write_ioport(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);
0066 vbox_write_ioport(VBE_DISPI_INDEX_X_OFFSET,
0067 vbox_crtc->fb_offset % pitch / bpp * 8 + vbox_crtc->x);
0068 vbox_write_ioport(VBE_DISPI_INDEX_Y_OFFSET,
0069 vbox_crtc->fb_offset / pitch + vbox_crtc->y);
0070 }
0071
0072 flags = VBVA_SCREEN_F_ACTIVE;
0073 flags |= (fb && crtc->state->enable) ? 0 : VBVA_SCREEN_F_BLANK;
0074 flags |= vbox_crtc->disconnected ? VBVA_SCREEN_F_DISABLED : 0;
0075 hgsmi_process_display_info(vbox->guest_pool, vbox_crtc->crtc_id,
0076 x_offset, y_offset,
0077 vbox_crtc->x * bpp / 8 +
0078 vbox_crtc->y * pitch,
0079 pitch, width, height, bpp, flags);
0080 }
0081
0082 static int vbox_set_view(struct drm_crtc *crtc)
0083 {
0084 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
0085 struct vbox_private *vbox = to_vbox_dev(crtc->dev);
0086 struct vbva_infoview *p;
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099 p = hgsmi_buffer_alloc(vbox->guest_pool, sizeof(*p),
0100 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
0101 if (!p)
0102 return -ENOMEM;
0103
0104 p->view_index = vbox_crtc->crtc_id;
0105 p->view_offset = vbox_crtc->fb_offset;
0106 p->view_size = vbox->available_vram_size - vbox_crtc->fb_offset +
0107 vbox_crtc->crtc_id * VBVA_MIN_BUFFER_SIZE;
0108 p->max_screen_size = vbox->available_vram_size - vbox_crtc->fb_offset;
0109
0110 hgsmi_buffer_submit(vbox->guest_pool, p);
0111 hgsmi_buffer_free(vbox->guest_pool, p);
0112
0113 return 0;
0114 }
0115
0116
0117
0118
0119
0120
0121 static bool vbox_set_up_input_mapping(struct vbox_private *vbox)
0122 {
0123 struct drm_crtc *crtci;
0124 struct drm_connector *connectori;
0125 struct drm_framebuffer *fb, *fb1 = NULL;
0126 bool single_framebuffer = true;
0127 bool old_single_framebuffer = vbox->single_framebuffer;
0128 u16 width = 0, height = 0;
0129
0130
0131
0132
0133
0134
0135 list_for_each_entry(crtci, &vbox->ddev.mode_config.crtc_list, head) {
0136 fb = crtci->primary->state->fb;
0137 if (!fb)
0138 continue;
0139
0140 if (!fb1) {
0141 fb1 = fb;
0142 if (fb1 == vbox->ddev.fb_helper->fb)
0143 break;
0144 } else if (fb != fb1) {
0145 single_framebuffer = false;
0146 }
0147 }
0148 if (!fb1)
0149 return false;
0150
0151 if (single_framebuffer) {
0152 vbox->single_framebuffer = true;
0153 vbox->input_mapping_width = fb1->width;
0154 vbox->input_mapping_height = fb1->height;
0155 return old_single_framebuffer != vbox->single_framebuffer;
0156 }
0157
0158 list_for_each_entry(connectori, &vbox->ddev.mode_config.connector_list,
0159 head) {
0160 struct vbox_connector *vbox_connector =
0161 to_vbox_connector(connectori);
0162 struct vbox_crtc *vbox_crtc = vbox_connector->vbox_crtc;
0163
0164 width = max_t(u16, width, vbox_crtc->x_hint +
0165 vbox_connector->mode_hint.width);
0166 height = max_t(u16, height, vbox_crtc->y_hint +
0167 vbox_connector->mode_hint.height);
0168 }
0169
0170 vbox->single_framebuffer = false;
0171 vbox->input_mapping_width = width;
0172 vbox->input_mapping_height = height;
0173
0174 return old_single_framebuffer != vbox->single_framebuffer;
0175 }
0176
0177 static void vbox_crtc_set_base_and_mode(struct drm_crtc *crtc,
0178 struct drm_framebuffer *fb,
0179 int x, int y)
0180 {
0181 struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(fb->obj[0]);
0182 struct vbox_private *vbox = to_vbox_dev(crtc->dev);
0183 struct vbox_crtc *vbox_crtc = to_vbox_crtc(crtc);
0184 bool needs_modeset = drm_atomic_crtc_needs_modeset(crtc->state);
0185
0186 mutex_lock(&vbox->hw_mutex);
0187
0188 if (crtc->state->enable) {
0189 vbox_crtc->width = crtc->state->mode.hdisplay;
0190 vbox_crtc->height = crtc->state->mode.vdisplay;
0191 }
0192
0193 vbox_crtc->x = x;
0194 vbox_crtc->y = y;
0195 vbox_crtc->fb_offset = drm_gem_vram_offset(gbo);
0196
0197
0198 if (needs_modeset && vbox_set_up_input_mapping(vbox)) {
0199 struct drm_crtc *crtci;
0200
0201 list_for_each_entry(crtci, &vbox->ddev.mode_config.crtc_list,
0202 head) {
0203 if (crtci == crtc)
0204 continue;
0205 vbox_do_modeset(crtci);
0206 }
0207 }
0208
0209 vbox_set_view(crtc);
0210 vbox_do_modeset(crtc);
0211
0212 if (needs_modeset)
0213 hgsmi_update_input_mapping(vbox->guest_pool, 0, 0,
0214 vbox->input_mapping_width,
0215 vbox->input_mapping_height);
0216
0217 mutex_unlock(&vbox->hw_mutex);
0218 }
0219
0220 static void vbox_crtc_atomic_enable(struct drm_crtc *crtc,
0221 struct drm_atomic_state *state)
0222 {
0223 }
0224
0225 static void vbox_crtc_atomic_disable(struct drm_crtc *crtc,
0226 struct drm_atomic_state *state)
0227 {
0228 }
0229
0230 static void vbox_crtc_atomic_flush(struct drm_crtc *crtc,
0231 struct drm_atomic_state *state)
0232 {
0233 }
0234
0235 static const struct drm_crtc_helper_funcs vbox_crtc_helper_funcs = {
0236 .atomic_enable = vbox_crtc_atomic_enable,
0237 .atomic_disable = vbox_crtc_atomic_disable,
0238 .atomic_flush = vbox_crtc_atomic_flush,
0239 };
0240
0241 static void vbox_crtc_destroy(struct drm_crtc *crtc)
0242 {
0243 drm_crtc_cleanup(crtc);
0244 kfree(crtc);
0245 }
0246
0247 static const struct drm_crtc_funcs vbox_crtc_funcs = {
0248 .set_config = drm_atomic_helper_set_config,
0249 .page_flip = drm_atomic_helper_page_flip,
0250
0251 .destroy = vbox_crtc_destroy,
0252 .reset = drm_atomic_helper_crtc_reset,
0253 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
0254 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
0255 };
0256
0257 static int vbox_primary_atomic_check(struct drm_plane *plane,
0258 struct drm_atomic_state *state)
0259 {
0260 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0261 plane);
0262 struct drm_crtc_state *crtc_state = NULL;
0263
0264 if (new_state->crtc) {
0265 crtc_state = drm_atomic_get_existing_crtc_state(state,
0266 new_state->crtc);
0267 if (WARN_ON(!crtc_state))
0268 return -EINVAL;
0269 }
0270
0271 return drm_atomic_helper_check_plane_state(new_state, crtc_state,
0272 DRM_PLANE_HELPER_NO_SCALING,
0273 DRM_PLANE_HELPER_NO_SCALING,
0274 false, true);
0275 }
0276
0277 static void vbox_primary_atomic_update(struct drm_plane *plane,
0278 struct drm_atomic_state *state)
0279 {
0280 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0281 plane);
0282 struct drm_crtc *crtc = new_state->crtc;
0283 struct drm_framebuffer *fb = new_state->fb;
0284 struct vbox_private *vbox = to_vbox_dev(fb->dev);
0285 struct drm_mode_rect *clips;
0286 uint32_t num_clips, i;
0287
0288 vbox_crtc_set_base_and_mode(crtc, fb,
0289 new_state->src_x >> 16,
0290 new_state->src_y >> 16);
0291
0292
0293
0294 clips = drm_plane_get_damage_clips(new_state);
0295 num_clips = drm_plane_get_damage_clips_count(new_state);
0296
0297 if (!num_clips)
0298 return;
0299
0300 mutex_lock(&vbox->hw_mutex);
0301
0302 for (i = 0; i < num_clips; ++i, ++clips) {
0303 struct vbva_cmd_hdr cmd_hdr;
0304 unsigned int crtc_id = to_vbox_crtc(crtc)->crtc_id;
0305
0306 cmd_hdr.x = (s16)clips->x1;
0307 cmd_hdr.y = (s16)clips->y1;
0308 cmd_hdr.w = (u16)clips->x2 - clips->x1;
0309 cmd_hdr.h = (u16)clips->y2 - clips->y1;
0310
0311 if (!vbva_buffer_begin_update(&vbox->vbva_info[crtc_id],
0312 vbox->guest_pool))
0313 continue;
0314
0315 vbva_write(&vbox->vbva_info[crtc_id], vbox->guest_pool,
0316 &cmd_hdr, sizeof(cmd_hdr));
0317 vbva_buffer_end_update(&vbox->vbva_info[crtc_id]);
0318 }
0319
0320 mutex_unlock(&vbox->hw_mutex);
0321 }
0322
0323 static void vbox_primary_atomic_disable(struct drm_plane *plane,
0324 struct drm_atomic_state *state)
0325 {
0326 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0327 plane);
0328 struct drm_crtc *crtc = old_state->crtc;
0329
0330
0331 vbox_crtc_set_base_and_mode(crtc, old_state->fb,
0332 old_state->src_x >> 16,
0333 old_state->src_y >> 16);
0334 }
0335
0336 static int vbox_cursor_atomic_check(struct drm_plane *plane,
0337 struct drm_atomic_state *state)
0338 {
0339 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0340 plane);
0341 struct drm_crtc_state *crtc_state = NULL;
0342 u32 width = new_state->crtc_w;
0343 u32 height = new_state->crtc_h;
0344 int ret;
0345
0346 if (new_state->crtc) {
0347 crtc_state = drm_atomic_get_existing_crtc_state(state,
0348 new_state->crtc);
0349 if (WARN_ON(!crtc_state))
0350 return -EINVAL;
0351 }
0352
0353 ret = drm_atomic_helper_check_plane_state(new_state, crtc_state,
0354 DRM_PLANE_HELPER_NO_SCALING,
0355 DRM_PLANE_HELPER_NO_SCALING,
0356 true, true);
0357 if (ret)
0358 return ret;
0359
0360 if (!new_state->fb)
0361 return 0;
0362
0363 if (width > VBOX_MAX_CURSOR_WIDTH || height > VBOX_MAX_CURSOR_HEIGHT ||
0364 width == 0 || height == 0)
0365 return -EINVAL;
0366
0367 return 0;
0368 }
0369
0370
0371
0372
0373
0374
0375 static void copy_cursor_image(u8 *src, u8 *dst, u32 width, u32 height,
0376 size_t mask_size)
0377 {
0378 size_t line_size = (width + 7) / 8;
0379 u32 i, j;
0380
0381 memcpy(dst + mask_size, src, width * height * 4);
0382 for (i = 0; i < height; ++i)
0383 for (j = 0; j < width; ++j)
0384 if (((u32 *)src)[i * width + j] > 0xf0000000)
0385 dst[i * line_size + j / 8] |= (0x80 >> (j % 8));
0386 }
0387
0388 static void vbox_cursor_atomic_update(struct drm_plane *plane,
0389 struct drm_atomic_state *state)
0390 {
0391 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0392 plane);
0393 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0394 plane);
0395 struct vbox_private *vbox =
0396 container_of(plane->dev, struct vbox_private, ddev);
0397 struct vbox_crtc *vbox_crtc = to_vbox_crtc(new_state->crtc);
0398 struct drm_framebuffer *fb = new_state->fb;
0399 u32 width = new_state->crtc_w;
0400 u32 height = new_state->crtc_h;
0401 struct drm_shadow_plane_state *shadow_plane_state =
0402 to_drm_shadow_plane_state(new_state);
0403 struct iosys_map map = shadow_plane_state->data[0];
0404 u8 *src = map.vaddr;
0405 size_t data_size, mask_size;
0406 u32 flags;
0407
0408
0409
0410
0411
0412 if (fb == old_state->fb)
0413 return;
0414
0415 mutex_lock(&vbox->hw_mutex);
0416
0417 vbox_crtc->cursor_enabled = true;
0418
0419
0420
0421
0422
0423
0424 mask_size = ((width + 7) / 8 * height + 3) & ~3;
0425 data_size = width * height * 4 + mask_size;
0426
0427 copy_cursor_image(src, vbox->cursor_data, width, height, mask_size);
0428
0429 flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE |
0430 VBOX_MOUSE_POINTER_ALPHA;
0431 hgsmi_update_pointer_shape(vbox->guest_pool, flags,
0432 min_t(u32, max(fb->hot_x, 0), width),
0433 min_t(u32, max(fb->hot_y, 0), height),
0434 width, height, vbox->cursor_data, data_size);
0435
0436 mutex_unlock(&vbox->hw_mutex);
0437 }
0438
0439 static void vbox_cursor_atomic_disable(struct drm_plane *plane,
0440 struct drm_atomic_state *state)
0441 {
0442 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0443 plane);
0444 struct vbox_private *vbox =
0445 container_of(plane->dev, struct vbox_private, ddev);
0446 struct vbox_crtc *vbox_crtc = to_vbox_crtc(old_state->crtc);
0447 bool cursor_enabled = false;
0448 struct drm_crtc *crtci;
0449
0450 mutex_lock(&vbox->hw_mutex);
0451
0452 vbox_crtc->cursor_enabled = false;
0453
0454 list_for_each_entry(crtci, &vbox->ddev.mode_config.crtc_list, head) {
0455 if (to_vbox_crtc(crtci)->cursor_enabled)
0456 cursor_enabled = true;
0457 }
0458
0459 if (!cursor_enabled)
0460 hgsmi_update_pointer_shape(vbox->guest_pool, 0, 0, 0,
0461 0, 0, NULL, 0);
0462
0463 mutex_unlock(&vbox->hw_mutex);
0464 }
0465
0466 static const u32 vbox_cursor_plane_formats[] = {
0467 DRM_FORMAT_ARGB8888,
0468 };
0469
0470 static const struct drm_plane_helper_funcs vbox_cursor_helper_funcs = {
0471 .atomic_check = vbox_cursor_atomic_check,
0472 .atomic_update = vbox_cursor_atomic_update,
0473 .atomic_disable = vbox_cursor_atomic_disable,
0474 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
0475 };
0476
0477 static const struct drm_plane_funcs vbox_cursor_plane_funcs = {
0478 .update_plane = drm_atomic_helper_update_plane,
0479 .disable_plane = drm_atomic_helper_disable_plane,
0480 .destroy = drm_primary_helper_destroy,
0481 DRM_GEM_SHADOW_PLANE_FUNCS,
0482 };
0483
0484 static const u32 vbox_primary_plane_formats[] = {
0485 DRM_FORMAT_XRGB8888,
0486 DRM_FORMAT_ARGB8888,
0487 };
0488
0489 static const struct drm_plane_helper_funcs vbox_primary_helper_funcs = {
0490 .atomic_check = vbox_primary_atomic_check,
0491 .atomic_update = vbox_primary_atomic_update,
0492 .atomic_disable = vbox_primary_atomic_disable,
0493 DRM_GEM_VRAM_PLANE_HELPER_FUNCS,
0494 };
0495
0496 static const struct drm_plane_funcs vbox_primary_plane_funcs = {
0497 .update_plane = drm_atomic_helper_update_plane,
0498 .disable_plane = drm_atomic_helper_disable_plane,
0499 .destroy = drm_primary_helper_destroy,
0500 .reset = drm_atomic_helper_plane_reset,
0501 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
0502 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
0503 };
0504
0505 static struct drm_plane *vbox_create_plane(struct vbox_private *vbox,
0506 unsigned int possible_crtcs,
0507 enum drm_plane_type type)
0508 {
0509 const struct drm_plane_helper_funcs *helper_funcs = NULL;
0510 const struct drm_plane_funcs *funcs;
0511 struct drm_plane *plane;
0512 const u32 *formats;
0513 int num_formats;
0514 int err;
0515
0516 if (type == DRM_PLANE_TYPE_PRIMARY) {
0517 funcs = &vbox_primary_plane_funcs;
0518 formats = vbox_primary_plane_formats;
0519 helper_funcs = &vbox_primary_helper_funcs;
0520 num_formats = ARRAY_SIZE(vbox_primary_plane_formats);
0521 } else if (type == DRM_PLANE_TYPE_CURSOR) {
0522 funcs = &vbox_cursor_plane_funcs;
0523 formats = vbox_cursor_plane_formats;
0524 helper_funcs = &vbox_cursor_helper_funcs;
0525 num_formats = ARRAY_SIZE(vbox_cursor_plane_formats);
0526 } else {
0527 return ERR_PTR(-EINVAL);
0528 }
0529
0530 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
0531 if (!plane)
0532 return ERR_PTR(-ENOMEM);
0533
0534 err = drm_universal_plane_init(&vbox->ddev, plane, possible_crtcs,
0535 funcs, formats, num_formats,
0536 NULL, type, NULL);
0537 if (err)
0538 goto free_plane;
0539
0540 drm_plane_helper_add(plane, helper_funcs);
0541
0542 return plane;
0543
0544 free_plane:
0545 kfree(plane);
0546 return ERR_PTR(-EINVAL);
0547 }
0548
0549 static struct vbox_crtc *vbox_crtc_init(struct drm_device *dev, unsigned int i)
0550 {
0551 struct vbox_private *vbox =
0552 container_of(dev, struct vbox_private, ddev);
0553 struct drm_plane *cursor = NULL;
0554 struct vbox_crtc *vbox_crtc;
0555 struct drm_plane *primary;
0556 u32 caps = 0;
0557 int ret;
0558
0559 ret = hgsmi_query_conf(vbox->guest_pool,
0560 VBOX_VBVA_CONF32_CURSOR_CAPABILITIES, &caps);
0561 if (ret)
0562 return ERR_PTR(ret);
0563
0564 vbox_crtc = kzalloc(sizeof(*vbox_crtc), GFP_KERNEL);
0565 if (!vbox_crtc)
0566 return ERR_PTR(-ENOMEM);
0567
0568 primary = vbox_create_plane(vbox, 1 << i, DRM_PLANE_TYPE_PRIMARY);
0569 if (IS_ERR(primary)) {
0570 ret = PTR_ERR(primary);
0571 goto free_mem;
0572 }
0573
0574 if ((caps & VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE)) {
0575 cursor = vbox_create_plane(vbox, 1 << i, DRM_PLANE_TYPE_CURSOR);
0576 if (IS_ERR(cursor)) {
0577 ret = PTR_ERR(cursor);
0578 goto clean_primary;
0579 }
0580 } else {
0581 DRM_WARN("VirtualBox host is too old, no cursor support\n");
0582 }
0583
0584 vbox_crtc->crtc_id = i;
0585
0586 ret = drm_crtc_init_with_planes(dev, &vbox_crtc->base, primary, cursor,
0587 &vbox_crtc_funcs, NULL);
0588 if (ret)
0589 goto clean_cursor;
0590
0591 drm_mode_crtc_set_gamma_size(&vbox_crtc->base, 256);
0592 drm_crtc_helper_add(&vbox_crtc->base, &vbox_crtc_helper_funcs);
0593
0594 return vbox_crtc;
0595
0596 clean_cursor:
0597 if (cursor) {
0598 drm_plane_cleanup(cursor);
0599 kfree(cursor);
0600 }
0601 clean_primary:
0602 drm_plane_cleanup(primary);
0603 kfree(primary);
0604 free_mem:
0605 kfree(vbox_crtc);
0606 return ERR_PTR(ret);
0607 }
0608
0609 static void vbox_encoder_destroy(struct drm_encoder *encoder)
0610 {
0611 drm_encoder_cleanup(encoder);
0612 kfree(encoder);
0613 }
0614
0615 static const struct drm_encoder_funcs vbox_enc_funcs = {
0616 .destroy = vbox_encoder_destroy,
0617 };
0618
0619 static struct drm_encoder *vbox_encoder_init(struct drm_device *dev,
0620 unsigned int i)
0621 {
0622 struct vbox_encoder *vbox_encoder;
0623
0624 vbox_encoder = kzalloc(sizeof(*vbox_encoder), GFP_KERNEL);
0625 if (!vbox_encoder)
0626 return NULL;
0627
0628 drm_encoder_init(dev, &vbox_encoder->base, &vbox_enc_funcs,
0629 DRM_MODE_ENCODER_DAC, NULL);
0630
0631 vbox_encoder->base.possible_crtcs = 1 << i;
0632 return &vbox_encoder->base;
0633 }
0634
0635
0636
0637
0638
0639
0640
0641 static void vbox_set_edid(struct drm_connector *connector, int width,
0642 int height)
0643 {
0644 enum { EDID_SIZE = 128 };
0645 unsigned char edid[EDID_SIZE] = {
0646 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0647 0x58, 0x58,
0648 0x00, 0x00,
0649 0x00, 0x00, 0x00, 0x00,
0650 0x01,
0651 0x00,
0652 0x01, 0x03,
0653 0x80,
0654 0x00,
0655 0x00,
0656 0x78,
0657 0xEE,
0658
0659 0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54,
0660
0661 0x00, 0x00, 0x00,
0662 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0663 0x01, 0x01,
0664 0x01, 0x01, 0x01, 0x01,
0665 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x02, 0x02,
0666 0x02, 0x02,
0667
0668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0669
0670 0x00, 0x00, 0x00, 0xFD, 0x00,
0671 0x00, 0xC8, 0x00, 0xC8, 0x64, 0x00, 0x0A, 0x20, 0x20, 0x20,
0672 0x20, 0x20,
0673
0674 0x20,
0675
0676 0x00, 0x00, 0x00, 0xFC, 0x00,
0677 'V', 'B', 'O', 'X', ' ', 'm', 'o', 'n', 'i', 't', 'o', 'r',
0678 '\n',
0679
0680 0x00, 0x00, 0x00, 0x10, 0x00,
0681 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
0682 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0683 0x20,
0684 0x00,
0685 0x00
0686 };
0687 int clock = (width + 6) * (height + 6) * 60 / 10000;
0688 unsigned int i, sum = 0;
0689
0690 edid[12] = width & 0xff;
0691 edid[13] = width >> 8;
0692 edid[14] = height & 0xff;
0693 edid[15] = height >> 8;
0694 edid[54] = clock & 0xff;
0695 edid[55] = clock >> 8;
0696 edid[56] = width & 0xff;
0697 edid[58] = (width >> 4) & 0xf0;
0698 edid[59] = height & 0xff;
0699 edid[61] = (height >> 4) & 0xf0;
0700 for (i = 0; i < EDID_SIZE - 1; ++i)
0701 sum += edid[i];
0702 edid[EDID_SIZE - 1] = (0x100 - (sum & 0xFF)) & 0xFF;
0703 drm_connector_update_edid_property(connector, (struct edid *)edid);
0704 }
0705
0706 static int vbox_get_modes(struct drm_connector *connector)
0707 {
0708 struct vbox_connector *vbox_connector = NULL;
0709 struct drm_display_mode *mode = NULL;
0710 struct vbox_private *vbox = NULL;
0711 unsigned int num_modes = 0;
0712 int preferred_width, preferred_height;
0713
0714 vbox_connector = to_vbox_connector(connector);
0715 vbox = to_vbox_dev(connector->dev);
0716
0717 hgsmi_report_flags_location(vbox->guest_pool, GUEST_HEAP_OFFSET(vbox) +
0718 HOST_FLAGS_OFFSET);
0719 if (vbox_connector->vbox_crtc->crtc_id == 0)
0720 vbox_report_caps(vbox);
0721
0722 num_modes = drm_add_modes_noedid(connector, 2560, 1600);
0723 preferred_width = vbox_connector->mode_hint.width ?
0724 vbox_connector->mode_hint.width : 1024;
0725 preferred_height = vbox_connector->mode_hint.height ?
0726 vbox_connector->mode_hint.height : 768;
0727 mode = drm_cvt_mode(connector->dev, preferred_width, preferred_height,
0728 60, false, false, false);
0729 if (mode) {
0730 mode->type |= DRM_MODE_TYPE_PREFERRED;
0731 drm_mode_probed_add(connector, mode);
0732 ++num_modes;
0733 }
0734 vbox_set_edid(connector, preferred_width, preferred_height);
0735
0736 if (vbox_connector->vbox_crtc->x_hint != -1)
0737 drm_object_property_set_value(&connector->base,
0738 vbox->ddev.mode_config.suggested_x_property,
0739 vbox_connector->vbox_crtc->x_hint);
0740 else
0741 drm_object_property_set_value(&connector->base,
0742 vbox->ddev.mode_config.suggested_x_property, 0);
0743
0744 if (vbox_connector->vbox_crtc->y_hint != -1)
0745 drm_object_property_set_value(&connector->base,
0746 vbox->ddev.mode_config.suggested_y_property,
0747 vbox_connector->vbox_crtc->y_hint);
0748 else
0749 drm_object_property_set_value(&connector->base,
0750 vbox->ddev.mode_config.suggested_y_property, 0);
0751
0752 return num_modes;
0753 }
0754
0755 static void vbox_connector_destroy(struct drm_connector *connector)
0756 {
0757 drm_connector_unregister(connector);
0758 drm_connector_cleanup(connector);
0759 kfree(connector);
0760 }
0761
0762 static enum drm_connector_status
0763 vbox_connector_detect(struct drm_connector *connector, bool force)
0764 {
0765 struct vbox_connector *vbox_connector;
0766
0767 vbox_connector = to_vbox_connector(connector);
0768
0769 return vbox_connector->mode_hint.disconnected ?
0770 connector_status_disconnected : connector_status_connected;
0771 }
0772
0773 static int vbox_fill_modes(struct drm_connector *connector, u32 max_x,
0774 u32 max_y)
0775 {
0776 struct vbox_connector *vbox_connector;
0777 struct drm_device *dev;
0778 struct drm_display_mode *mode, *iterator;
0779
0780 vbox_connector = to_vbox_connector(connector);
0781 dev = vbox_connector->base.dev;
0782 list_for_each_entry_safe(mode, iterator, &connector->modes, head) {
0783 list_del(&mode->head);
0784 drm_mode_destroy(dev, mode);
0785 }
0786
0787 return drm_helper_probe_single_connector_modes(connector, max_x, max_y);
0788 }
0789
0790 static const struct drm_connector_helper_funcs vbox_connector_helper_funcs = {
0791 .get_modes = vbox_get_modes,
0792 };
0793
0794 static const struct drm_connector_funcs vbox_connector_funcs = {
0795 .detect = vbox_connector_detect,
0796 .fill_modes = vbox_fill_modes,
0797 .destroy = vbox_connector_destroy,
0798 .reset = drm_atomic_helper_connector_reset,
0799 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
0800 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
0801 };
0802
0803 static int vbox_connector_init(struct drm_device *dev,
0804 struct vbox_crtc *vbox_crtc,
0805 struct drm_encoder *encoder)
0806 {
0807 struct vbox_connector *vbox_connector;
0808 struct drm_connector *connector;
0809
0810 vbox_connector = kzalloc(sizeof(*vbox_connector), GFP_KERNEL);
0811 if (!vbox_connector)
0812 return -ENOMEM;
0813
0814 connector = &vbox_connector->base;
0815 vbox_connector->vbox_crtc = vbox_crtc;
0816
0817 drm_connector_init(dev, connector, &vbox_connector_funcs,
0818 DRM_MODE_CONNECTOR_VGA);
0819 drm_connector_helper_add(connector, &vbox_connector_helper_funcs);
0820
0821 connector->interlace_allowed = 0;
0822 connector->doublescan_allowed = 0;
0823
0824 drm_mode_create_suggested_offset_properties(dev);
0825 drm_object_attach_property(&connector->base,
0826 dev->mode_config.suggested_x_property, 0);
0827 drm_object_attach_property(&connector->base,
0828 dev->mode_config.suggested_y_property, 0);
0829
0830 drm_connector_attach_encoder(connector, encoder);
0831
0832 return 0;
0833 }
0834
0835 static const struct drm_mode_config_funcs vbox_mode_funcs = {
0836 .fb_create = drm_gem_fb_create_with_dirty,
0837 .mode_valid = drm_vram_helper_mode_valid,
0838 .atomic_check = drm_atomic_helper_check,
0839 .atomic_commit = drm_atomic_helper_commit,
0840 };
0841
0842 int vbox_mode_init(struct vbox_private *vbox)
0843 {
0844 struct drm_device *dev = &vbox->ddev;
0845 struct drm_encoder *encoder;
0846 struct vbox_crtc *vbox_crtc;
0847 unsigned int i;
0848 int ret;
0849
0850 drm_mode_config_init(dev);
0851
0852 dev->mode_config.funcs = (void *)&vbox_mode_funcs;
0853 dev->mode_config.min_width = 0;
0854 dev->mode_config.min_height = 0;
0855 dev->mode_config.preferred_depth = 24;
0856 dev->mode_config.max_width = VBE_DISPI_MAX_XRES;
0857 dev->mode_config.max_height = VBE_DISPI_MAX_YRES;
0858
0859 for (i = 0; i < vbox->num_crtcs; ++i) {
0860 vbox_crtc = vbox_crtc_init(dev, i);
0861 if (IS_ERR(vbox_crtc)) {
0862 ret = PTR_ERR(vbox_crtc);
0863 goto err_drm_mode_cleanup;
0864 }
0865 encoder = vbox_encoder_init(dev, i);
0866 if (!encoder) {
0867 ret = -ENOMEM;
0868 goto err_drm_mode_cleanup;
0869 }
0870 ret = vbox_connector_init(dev, vbox_crtc, encoder);
0871 if (ret)
0872 goto err_drm_mode_cleanup;
0873 }
0874
0875 drm_mode_config_reset(dev);
0876 return 0;
0877
0878 err_drm_mode_cleanup:
0879 drm_mode_config_cleanup(dev);
0880 return ret;
0881 }
0882
0883 void vbox_mode_fini(struct vbox_private *vbox)
0884 {
0885 drm_mode_config_cleanup(&vbox->ddev);
0886 }