vmwgfx_scrn.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. /**************************************************************************
  2. *
  3. * Copyright © 2011 VMware, Inc., Palo Alto, CA., USA
  4. * All Rights Reserved.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a
  7. * copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sub license, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice (including the
  15. * next paragraph) shall be included in all copies or substantial portions
  16. * of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  21. * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  22. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  23. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  24. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. *
  26. **************************************************************************/
  27. #include "vmwgfx_kms.h"
  28. #define vmw_crtc_to_sou(x) \
  29. container_of(x, struct vmw_screen_object_unit, base.crtc)
  30. #define vmw_encoder_to_sou(x) \
  31. container_of(x, struct vmw_screen_object_unit, base.encoder)
  32. #define vmw_connector_to_sou(x) \
  33. container_of(x, struct vmw_screen_object_unit, base.connector)
  34. struct vmw_screen_object_display {
  35. struct list_head active;
  36. unsigned num_active;
  37. unsigned last_num_active;
  38. struct vmw_framebuffer *fb;
  39. };
  40. /**
  41. * Display unit using screen objects.
  42. */
  43. struct vmw_screen_object_unit {
  44. struct vmw_display_unit base;
  45. unsigned long buffer_size; /**< Size of allocated buffer */
  46. struct vmw_dma_buffer *buffer; /**< Backing store buffer */
  47. bool defined;
  48. struct list_head active;
  49. };
  50. static void vmw_sou_destroy(struct vmw_screen_object_unit *sou)
  51. {
  52. list_del_init(&sou->active);
  53. vmw_display_unit_cleanup(&sou->base);
  54. kfree(sou);
  55. }
  56. /*
  57. * Screen Object Display Unit CRTC functions
  58. */
  59. static void vmw_sou_crtc_destroy(struct drm_crtc *crtc)
  60. {
  61. vmw_sou_destroy(vmw_crtc_to_sou(crtc));
  62. }
  63. static int vmw_sou_del_active(struct vmw_private *vmw_priv,
  64. struct vmw_screen_object_unit *sou)
  65. {
  66. struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
  67. if (list_empty(&sou->active))
  68. return 0;
  69. /* Must init otherwise list_empty(&sou->active) will not work. */
  70. list_del_init(&sou->active);
  71. if (--(ld->num_active) == 0) {
  72. BUG_ON(!ld->fb);
  73. if (ld->fb->unpin)
  74. ld->fb->unpin(ld->fb);
  75. ld->fb = NULL;
  76. }
  77. return 0;
  78. }
  79. static int vmw_sou_add_active(struct vmw_private *vmw_priv,
  80. struct vmw_screen_object_unit *sou,
  81. struct vmw_framebuffer *vfb)
  82. {
  83. struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
  84. struct vmw_screen_object_unit *entry;
  85. struct list_head *at;
  86. BUG_ON(!ld->num_active && ld->fb);
  87. if (vfb != ld->fb) {
  88. if (ld->fb && ld->fb->unpin)
  89. ld->fb->unpin(ld->fb);
  90. if (vfb->pin)
  91. vfb->pin(vfb);
  92. ld->fb = vfb;
  93. }
  94. if (!list_empty(&sou->active))
  95. return 0;
  96. at = &ld->active;
  97. list_for_each_entry(entry, &ld->active, active) {
  98. if (entry->base.unit > sou->base.unit)
  99. break;
  100. at = &entry->active;
  101. }
  102. list_add(&sou->active, at);
  103. ld->num_active++;
  104. return 0;
  105. }
  106. /**
  107. * Send the fifo command to create a screen.
  108. */
  109. static int vmw_sou_fifo_create(struct vmw_private *dev_priv,
  110. struct vmw_screen_object_unit *sou,
  111. uint32_t x, uint32_t y,
  112. struct drm_display_mode *mode)
  113. {
  114. size_t fifo_size;
  115. struct {
  116. struct {
  117. uint32_t cmdType;
  118. } header;
  119. SVGAScreenObject obj;
  120. } *cmd;
  121. BUG_ON(!sou->buffer);
  122. fifo_size = sizeof(*cmd);
  123. cmd = vmw_fifo_reserve(dev_priv, fifo_size);
  124. /* The hardware has hung, nothing we can do about it here. */
  125. if (unlikely(cmd == NULL)) {
  126. DRM_ERROR("Fifo reserve failed.\n");
  127. return -ENOMEM;
  128. }
  129. memset(cmd, 0, fifo_size);
  130. cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN;
  131. cmd->obj.structSize = sizeof(SVGAScreenObject);
  132. cmd->obj.id = sou->base.unit;
  133. cmd->obj.flags = SVGA_SCREEN_HAS_ROOT |
  134. (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0);
  135. cmd->obj.size.width = mode->hdisplay;
  136. cmd->obj.size.height = mode->vdisplay;
  137. cmd->obj.root.x = x;
  138. cmd->obj.root.y = y;
  139. /* Ok to assume that buffer is pinned in vram */
  140. vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr);
  141. cmd->obj.backingStore.pitch = mode->hdisplay * 4;
  142. vmw_fifo_commit(dev_priv, fifo_size);
  143. sou->defined = true;
  144. return 0;
  145. }
  146. /**
  147. * Send the fifo command to destroy a screen.
  148. */
  149. static int vmw_sou_fifo_destroy(struct vmw_private *dev_priv,
  150. struct vmw_screen_object_unit *sou)
  151. {
  152. size_t fifo_size;
  153. int ret;
  154. struct {
  155. struct {
  156. uint32_t cmdType;
  157. } header;
  158. SVGAFifoCmdDestroyScreen body;
  159. } *cmd;
  160. /* no need to do anything */
  161. if (unlikely(!sou->defined))
  162. return 0;
  163. fifo_size = sizeof(*cmd);
  164. cmd = vmw_fifo_reserve(dev_priv, fifo_size);
  165. /* the hardware has hung, nothing we can do about it here */
  166. if (unlikely(cmd == NULL)) {
  167. DRM_ERROR("Fifo reserve failed.\n");
  168. return -ENOMEM;
  169. }
  170. memset(cmd, 0, fifo_size);
  171. cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN;
  172. cmd->body.screenId = sou->base.unit;
  173. vmw_fifo_commit(dev_priv, fifo_size);
  174. /* Force sync */
  175. ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ);
  176. if (unlikely(ret != 0))
  177. DRM_ERROR("Failed to sync with HW");
  178. else
  179. sou->defined = false;
  180. return ret;
  181. }
  182. /**
  183. * Free the backing store.
  184. */
  185. static void vmw_sou_backing_free(struct vmw_private *dev_priv,
  186. struct vmw_screen_object_unit *sou)
  187. {
  188. struct ttm_buffer_object *bo;
  189. if (unlikely(sou->buffer == NULL))
  190. return;
  191. bo = &sou->buffer->base;
  192. ttm_bo_unref(&bo);
  193. sou->buffer = NULL;
  194. sou->buffer_size = 0;
  195. }
  196. /**
  197. * Allocate the backing store for the buffer.
  198. */
  199. static int vmw_sou_backing_alloc(struct vmw_private *dev_priv,
  200. struct vmw_screen_object_unit *sou,
  201. unsigned long size)
  202. {
  203. int ret;
  204. if (sou->buffer_size == size)
  205. return 0;
  206. if (sou->buffer)
  207. vmw_sou_backing_free(dev_priv, sou);
  208. sou->buffer = kzalloc(sizeof(*sou->buffer), GFP_KERNEL);
  209. if (unlikely(sou->buffer == NULL))
  210. return -ENOMEM;
  211. /* After we have alloced the backing store might not be able to
  212. * resume the overlays, this is preferred to failing to alloc.
  213. */
  214. vmw_overlay_pause_all(dev_priv);
  215. ret = vmw_dmabuf_init(dev_priv, sou->buffer, size,
  216. &vmw_vram_ne_placement,
  217. false, &vmw_dmabuf_bo_free);
  218. vmw_overlay_resume_all(dev_priv);
  219. if (unlikely(ret != 0))
  220. sou->buffer = NULL; /* vmw_dmabuf_init frees on error */
  221. else
  222. sou->buffer_size = size;
  223. return ret;
  224. }
  225. static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
  226. {
  227. struct vmw_private *dev_priv;
  228. struct vmw_screen_object_unit *sou;
  229. struct drm_connector *connector;
  230. struct drm_display_mode *mode;
  231. struct drm_encoder *encoder;
  232. struct vmw_framebuffer *vfb;
  233. struct drm_framebuffer *fb;
  234. struct drm_crtc *crtc;
  235. int ret = 0;
  236. if (!set)
  237. return -EINVAL;
  238. if (!set->crtc)
  239. return -EINVAL;
  240. /* get the sou */
  241. crtc = set->crtc;
  242. sou = vmw_crtc_to_sou(crtc);
  243. vfb = set->fb ? vmw_framebuffer_to_vfb(set->fb) : NULL;
  244. dev_priv = vmw_priv(crtc->dev);
  245. if (set->num_connectors > 1) {
  246. DRM_ERROR("to many connectors\n");
  247. return -EINVAL;
  248. }
  249. if (set->num_connectors == 1 &&
  250. set->connectors[0] != &sou->base.connector) {
  251. DRM_ERROR("connector doesn't match %p %p\n",
  252. set->connectors[0], &sou->base.connector);
  253. return -EINVAL;
  254. }
  255. /* sou only supports one fb active at the time */
  256. if (dev_priv->sou_priv->fb && vfb &&
  257. !(dev_priv->sou_priv->num_active == 1 &&
  258. !list_empty(&sou->active)) &&
  259. dev_priv->sou_priv->fb != vfb) {
  260. DRM_ERROR("Multiple framebuffers not supported\n");
  261. return -EINVAL;
  262. }
  263. /* since they always map one to one these are safe */
  264. connector = &sou->base.connector;
  265. encoder = &sou->base.encoder;
  266. /* should we turn the crtc off */
  267. if (set->num_connectors == 0 || !set->mode || !set->fb) {
  268. ret = vmw_sou_fifo_destroy(dev_priv, sou);
  269. /* the hardware has hung don't do anything more */
  270. if (unlikely(ret != 0))
  271. return ret;
  272. connector->encoder = NULL;
  273. encoder->crtc = NULL;
  274. crtc->fb = NULL;
  275. crtc->x = 0;
  276. crtc->y = 0;
  277. vmw_sou_del_active(dev_priv, sou);
  278. vmw_sou_backing_free(dev_priv, sou);
  279. return 0;
  280. }
  281. /* we now know we want to set a mode */
  282. mode = set->mode;
  283. fb = set->fb;
  284. if (set->x + mode->hdisplay > fb->width ||
  285. set->y + mode->vdisplay > fb->height) {
  286. DRM_ERROR("set outside of framebuffer\n");
  287. return -EINVAL;
  288. }
  289. vmw_fb_off(dev_priv);
  290. if (mode->hdisplay != crtc->mode.hdisplay ||
  291. mode->vdisplay != crtc->mode.vdisplay) {
  292. /* no need to check if depth is different, because backing
  293. * store depth is forced to 4 by the device.
  294. */
  295. ret = vmw_sou_fifo_destroy(dev_priv, sou);
  296. /* the hardware has hung don't do anything more */
  297. if (unlikely(ret != 0))
  298. return ret;
  299. vmw_sou_backing_free(dev_priv, sou);
  300. }
  301. if (!sou->buffer) {
  302. /* forced to depth 4 by the device */
  303. size_t size = mode->hdisplay * mode->vdisplay * 4;
  304. ret = vmw_sou_backing_alloc(dev_priv, sou, size);
  305. if (unlikely(ret != 0))
  306. return ret;
  307. }
  308. ret = vmw_sou_fifo_create(dev_priv, sou, set->x, set->y, mode);
  309. if (unlikely(ret != 0)) {
  310. /*
  311. * We are in a bit of a situation here, the hardware has
  312. * hung and we may or may not have a buffer hanging of
  313. * the screen object, best thing to do is not do anything
  314. * if we where defined, if not just turn the crtc of.
  315. * Not what userspace wants but it needs to htfu.
  316. */
  317. if (sou->defined)
  318. return ret;
  319. connector->encoder = NULL;
  320. encoder->crtc = NULL;
  321. crtc->fb = NULL;
  322. crtc->x = 0;
  323. crtc->y = 0;
  324. return ret;
  325. }
  326. vmw_sou_add_active(dev_priv, sou, vfb);
  327. connector->encoder = encoder;
  328. encoder->crtc = crtc;
  329. crtc->mode = *mode;
  330. crtc->fb = fb;
  331. crtc->x = set->x;
  332. crtc->y = set->y;
  333. return 0;
  334. }
  335. static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
  336. .save = vmw_du_crtc_save,
  337. .restore = vmw_du_crtc_restore,
  338. .cursor_set = vmw_du_crtc_cursor_set,
  339. .cursor_move = vmw_du_crtc_cursor_move,
  340. .gamma_set = vmw_du_crtc_gamma_set,
  341. .destroy = vmw_sou_crtc_destroy,
  342. .set_config = vmw_sou_crtc_set_config,
  343. };
  344. /*
  345. * Screen Object Display Unit encoder functions
  346. */
  347. static void vmw_sou_encoder_destroy(struct drm_encoder *encoder)
  348. {
  349. vmw_sou_destroy(vmw_encoder_to_sou(encoder));
  350. }
  351. static struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
  352. .destroy = vmw_sou_encoder_destroy,
  353. };
  354. /*
  355. * Screen Object Display Unit connector functions
  356. */
  357. static void vmw_sou_connector_destroy(struct drm_connector *connector)
  358. {
  359. vmw_sou_destroy(vmw_connector_to_sou(connector));
  360. }
  361. static struct drm_connector_funcs vmw_legacy_connector_funcs = {
  362. .dpms = vmw_du_connector_dpms,
  363. .save = vmw_du_connector_save,
  364. .restore = vmw_du_connector_restore,
  365. .detect = vmw_du_connector_detect,
  366. .fill_modes = vmw_du_connector_fill_modes,
  367. .set_property = vmw_du_connector_set_property,
  368. .destroy = vmw_sou_connector_destroy,
  369. };
  370. static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
  371. {
  372. struct vmw_screen_object_unit *sou;
  373. struct drm_device *dev = dev_priv->dev;
  374. struct drm_connector *connector;
  375. struct drm_encoder *encoder;
  376. struct drm_crtc *crtc;
  377. sou = kzalloc(sizeof(*sou), GFP_KERNEL);
  378. if (!sou)
  379. return -ENOMEM;
  380. sou->base.unit = unit;
  381. crtc = &sou->base.crtc;
  382. encoder = &sou->base.encoder;
  383. connector = &sou->base.connector;
  384. INIT_LIST_HEAD(&sou->active);
  385. sou->base.pref_active = (unit == 0);
  386. sou->base.pref_width = 800;
  387. sou->base.pref_height = 600;
  388. sou->base.pref_mode = NULL;
  389. drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
  390. DRM_MODE_CONNECTOR_LVDS);
  391. connector->status = vmw_du_connector_detect(connector, true);
  392. drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
  393. DRM_MODE_ENCODER_LVDS);
  394. drm_mode_connector_attach_encoder(connector, encoder);
  395. encoder->possible_crtcs = (1 << unit);
  396. encoder->possible_clones = 0;
  397. drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs);
  398. drm_mode_crtc_set_gamma_size(crtc, 256);
  399. drm_connector_attach_property(connector,
  400. dev->mode_config.dirty_info_property,
  401. 1);
  402. return 0;
  403. }
  404. int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv)
  405. {
  406. struct drm_device *dev = dev_priv->dev;
  407. int i;
  408. int ret;
  409. if (dev_priv->sou_priv) {
  410. DRM_INFO("sou system already on\n");
  411. return -EINVAL;
  412. }
  413. if (!(dev_priv->fifo.capabilities & SVGA_FIFO_CAP_SCREEN_OBJECT_2)) {
  414. DRM_INFO("Not using screen objects,"
  415. " missing cap SCREEN_OBJECT_2\n");
  416. return -ENOSYS;
  417. }
  418. ret = -ENOMEM;
  419. dev_priv->sou_priv = kmalloc(sizeof(*dev_priv->sou_priv), GFP_KERNEL);
  420. if (unlikely(!dev_priv->sou_priv))
  421. goto err_no_mem;
  422. INIT_LIST_HEAD(&dev_priv->sou_priv->active);
  423. dev_priv->sou_priv->num_active = 0;
  424. dev_priv->sou_priv->last_num_active = 0;
  425. dev_priv->sou_priv->fb = NULL;
  426. ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
  427. if (unlikely(ret != 0))
  428. goto err_free;
  429. ret = drm_mode_create_dirty_info_property(dev_priv->dev);
  430. if (unlikely(ret != 0))
  431. goto err_vblank_cleanup;
  432. for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
  433. vmw_sou_init(dev_priv, i);
  434. DRM_INFO("Screen objects system initialized\n");
  435. return 0;
  436. err_vblank_cleanup:
  437. drm_vblank_cleanup(dev);
  438. err_free:
  439. kfree(dev_priv->sou_priv);
  440. err_no_mem:
  441. return ret;
  442. }
  443. int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv)
  444. {
  445. struct drm_device *dev = dev_priv->dev;
  446. drm_vblank_cleanup(dev);
  447. if (!dev_priv->sou_priv)
  448. return -ENOSYS;
  449. if (!list_empty(&dev_priv->sou_priv->active))
  450. DRM_ERROR("Still have active outputs when unloading driver");
  451. kfree(dev_priv->sou_priv);
  452. return 0;
  453. }