zynqmp_kms.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * ZynqMP DisplayPort Subsystem - KMS API
  4. *
  5. * Copyright (C) 2017 - 2021 Xilinx, Inc.
  6. *
  7. * Authors:
  8. * - Hyun Woo Kwon <hyun.kwon@xilinx.com>
  9. * - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  10. */
  11. #include <drm/clients/drm_client_setup.h>
  12. #include <drm/drm_atomic.h>
  13. #include <drm/drm_atomic_helper.h>
  14. #include <drm/drm_blend.h>
  15. #include <drm/drm_bridge.h>
  16. #include <drm/drm_bridge_connector.h>
  17. #include <drm/drm_connector.h>
  18. #include <drm/drm_crtc.h>
  19. #include <drm/drm_device.h>
  20. #include <drm/drm_drv.h>
  21. #include <drm/drm_dumb_buffers.h>
  22. #include <drm/drm_encoder.h>
  23. #include <drm/drm_fbdev_dma.h>
  24. #include <drm/drm_fourcc.h>
  25. #include <drm/drm_framebuffer.h>
  26. #include <drm/drm_gem_dma_helper.h>
  27. #include <drm/drm_gem_framebuffer_helper.h>
  28. #include <drm/drm_managed.h>
  29. #include <drm/drm_mode_config.h>
  30. #include <drm/drm_plane.h>
  31. #include <drm/drm_probe_helper.h>
  32. #include <drm/drm_simple_kms_helper.h>
  33. #include <drm/drm_vblank.h>
  34. #include <linux/clk.h>
  35. #include <linux/delay.h>
  36. #include <linux/pm_runtime.h>
  37. #include <linux/spinlock.h>
  38. #include "zynqmp_disp.h"
  39. #include "zynqmp_dp.h"
  40. #include "zynqmp_dpsub.h"
  41. #include "zynqmp_kms.h"
  42. static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm)
  43. {
  44. return container_of(drm, struct zynqmp_dpsub_drm, dev)->dpsub;
  45. }
  46. /* -----------------------------------------------------------------------------
  47. * DRM Planes
  48. */
  49. static int zynqmp_dpsub_plane_atomic_check(struct drm_plane *plane,
  50. struct drm_atomic_state *state)
  51. {
  52. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
  53. plane);
  54. struct drm_crtc_state *crtc_state;
  55. if (!new_plane_state->crtc)
  56. return 0;
  57. crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc);
  58. if (IS_ERR(crtc_state))
  59. return PTR_ERR(crtc_state);
  60. return drm_atomic_helper_check_plane_state(new_plane_state,
  61. crtc_state,
  62. DRM_PLANE_NO_SCALING,
  63. DRM_PLANE_NO_SCALING,
  64. false, false);
  65. }
  66. static void zynqmp_dpsub_plane_atomic_disable(struct drm_plane *plane,
  67. struct drm_atomic_state *state)
  68. {
  69. struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
  70. plane);
  71. struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev);
  72. struct zynqmp_disp_layer *layer = dpsub->layers[plane->index];
  73. if (!old_state->fb)
  74. return;
  75. zynqmp_disp_layer_disable(layer);
  76. if (plane->index == ZYNQMP_DPSUB_LAYER_GFX)
  77. zynqmp_disp_blend_set_global_alpha(dpsub->disp, false,
  78. plane->state->alpha >> 8);
  79. }
  80. static void zynqmp_dpsub_plane_atomic_update(struct drm_plane *plane,
  81. struct drm_atomic_state *state)
  82. {
  83. struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
  84. struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
  85. struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(plane->dev);
  86. struct zynqmp_disp_layer *layer = dpsub->layers[plane->index];
  87. bool format_changed = false;
  88. if (!old_state->fb ||
  89. old_state->fb->format->format != new_state->fb->format->format)
  90. format_changed = true;
  91. /*
  92. * If the format has changed (including going from a previously
  93. * disabled state to any format), reconfigure the format. Disable the
  94. * plane first if needed.
  95. */
  96. if (format_changed) {
  97. if (old_state->fb)
  98. zynqmp_disp_layer_disable(layer);
  99. zynqmp_disp_layer_set_format(layer, new_state->fb->format);
  100. }
  101. zynqmp_disp_layer_update(layer, new_state);
  102. if (plane->index == ZYNQMP_DPSUB_LAYER_GFX)
  103. zynqmp_disp_blend_set_global_alpha(dpsub->disp, true,
  104. plane->state->alpha >> 8);
  105. /*
  106. * Unconditionally enable the layer, as it may have been disabled
  107. * previously either explicitly to reconfigure layer format, or
  108. * implicitly after DPSUB reset during display mode change. DRM
  109. * framework calls this callback for enabled planes only.
  110. */
  111. zynqmp_disp_layer_enable(layer);
  112. }
  113. static const struct drm_plane_helper_funcs zynqmp_dpsub_plane_helper_funcs = {
  114. .atomic_check = zynqmp_dpsub_plane_atomic_check,
  115. .atomic_update = zynqmp_dpsub_plane_atomic_update,
  116. .atomic_disable = zynqmp_dpsub_plane_atomic_disable,
  117. };
  118. static const struct drm_plane_funcs zynqmp_dpsub_plane_funcs = {
  119. .update_plane = drm_atomic_helper_update_plane,
  120. .disable_plane = drm_atomic_helper_disable_plane,
  121. .destroy = drm_plane_cleanup,
  122. .reset = drm_atomic_helper_plane_reset,
  123. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  124. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  125. };
  126. static int zynqmp_dpsub_create_planes(struct zynqmp_dpsub *dpsub)
  127. {
  128. unsigned int i;
  129. int ret;
  130. for (i = 0; i < ARRAY_SIZE(dpsub->drm->planes); i++) {
  131. struct zynqmp_disp_layer *layer = dpsub->layers[i];
  132. struct drm_plane *plane = &dpsub->drm->planes[i];
  133. enum drm_plane_type type;
  134. unsigned int num_formats;
  135. u32 *formats;
  136. formats = zynqmp_disp_layer_drm_formats(layer, &num_formats);
  137. if (!formats)
  138. return -ENOMEM;
  139. /* Graphics layer is primary, and video layer is overlay. */
  140. type = i == ZYNQMP_DPSUB_LAYER_VID
  141. ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
  142. ret = drm_universal_plane_init(&dpsub->drm->dev, plane, 0,
  143. &zynqmp_dpsub_plane_funcs,
  144. formats, num_formats,
  145. NULL, type, NULL);
  146. kfree(formats);
  147. if (ret)
  148. return ret;
  149. drm_plane_helper_add(plane, &zynqmp_dpsub_plane_helper_funcs);
  150. drm_plane_create_zpos_immutable_property(plane, i);
  151. if (i == ZYNQMP_DPSUB_LAYER_GFX)
  152. drm_plane_create_alpha_property(plane);
  153. }
  154. return 0;
  155. }
  156. /* -----------------------------------------------------------------------------
  157. * DRM CRTC
  158. */
  159. static inline struct zynqmp_dpsub *crtc_to_dpsub(struct drm_crtc *crtc)
  160. {
  161. return container_of(crtc, struct zynqmp_dpsub_drm, crtc)->dpsub;
  162. }
  163. static void zynqmp_dpsub_crtc_atomic_enable(struct drm_crtc *crtc,
  164. struct drm_atomic_state *state)
  165. {
  166. struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
  167. struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
  168. int ret, vrefresh;
  169. pm_runtime_get_sync(dpsub->dev);
  170. zynqmp_disp_setup_clock(dpsub->disp, adjusted_mode->clock * 1000);
  171. ret = clk_prepare_enable(dpsub->vid_clk);
  172. if (ret) {
  173. dev_err(dpsub->dev, "failed to enable a pixel clock\n");
  174. pm_runtime_put_sync(dpsub->dev);
  175. return;
  176. }
  177. zynqmp_disp_enable(dpsub->disp);
  178. /* Delay of 3 vblank intervals for timing gen to be stable */
  179. vrefresh = (adjusted_mode->clock * 1000) /
  180. (adjusted_mode->vtotal * adjusted_mode->htotal);
  181. msleep(3 * 1000 / vrefresh);
  182. }
  183. static void zynqmp_dpsub_crtc_atomic_disable(struct drm_crtc *crtc,
  184. struct drm_atomic_state *state)
  185. {
  186. struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
  187. struct drm_plane_state *old_plane_state;
  188. /*
  189. * Disable the plane if active. The old plane state can be NULL in the
  190. * .shutdown() path if the plane is already disabled, skip
  191. * zynqmp_disp_plane_atomic_disable() in that case.
  192. */
  193. old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary);
  194. if (old_plane_state)
  195. zynqmp_dpsub_plane_atomic_disable(crtc->primary, state);
  196. zynqmp_disp_disable(dpsub->disp);
  197. drm_crtc_vblank_off(crtc);
  198. spin_lock_irq(&crtc->dev->event_lock);
  199. if (crtc->state->event) {
  200. drm_crtc_send_vblank_event(crtc, crtc->state->event);
  201. crtc->state->event = NULL;
  202. }
  203. spin_unlock_irq(&crtc->dev->event_lock);
  204. clk_disable_unprepare(dpsub->vid_clk);
  205. pm_runtime_put_sync(dpsub->dev);
  206. }
  207. static int zynqmp_dpsub_crtc_atomic_check(struct drm_crtc *crtc,
  208. struct drm_atomic_state *state)
  209. {
  210. return drm_atomic_add_affected_planes(state, crtc);
  211. }
  212. static void zynqmp_dpsub_crtc_atomic_begin(struct drm_crtc *crtc,
  213. struct drm_atomic_state *state)
  214. {
  215. drm_crtc_vblank_on(crtc);
  216. }
  217. static void zynqmp_dpsub_crtc_atomic_flush(struct drm_crtc *crtc,
  218. struct drm_atomic_state *state)
  219. {
  220. if (crtc->state->event) {
  221. struct drm_pending_vblank_event *event;
  222. /* Consume the flip_done event from atomic helper. */
  223. event = crtc->state->event;
  224. crtc->state->event = NULL;
  225. event->pipe = drm_crtc_index(crtc);
  226. WARN_ON(drm_crtc_vblank_get(crtc) != 0);
  227. spin_lock_irq(&crtc->dev->event_lock);
  228. drm_crtc_arm_vblank_event(crtc, event);
  229. spin_unlock_irq(&crtc->dev->event_lock);
  230. }
  231. }
  232. static const struct drm_crtc_helper_funcs zynqmp_dpsub_crtc_helper_funcs = {
  233. .atomic_enable = zynqmp_dpsub_crtc_atomic_enable,
  234. .atomic_disable = zynqmp_dpsub_crtc_atomic_disable,
  235. .atomic_check = zynqmp_dpsub_crtc_atomic_check,
  236. .atomic_begin = zynqmp_dpsub_crtc_atomic_begin,
  237. .atomic_flush = zynqmp_dpsub_crtc_atomic_flush,
  238. };
  239. static int zynqmp_dpsub_crtc_enable_vblank(struct drm_crtc *crtc)
  240. {
  241. struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
  242. zynqmp_dp_enable_vblank(dpsub->dp);
  243. return 0;
  244. }
  245. static void zynqmp_dpsub_crtc_disable_vblank(struct drm_crtc *crtc)
  246. {
  247. struct zynqmp_dpsub *dpsub = crtc_to_dpsub(crtc);
  248. zynqmp_dp_disable_vblank(dpsub->dp);
  249. }
  250. static const struct drm_crtc_funcs zynqmp_dpsub_crtc_funcs = {
  251. .destroy = drm_crtc_cleanup,
  252. .set_config = drm_atomic_helper_set_config,
  253. .page_flip = drm_atomic_helper_page_flip,
  254. .reset = drm_atomic_helper_crtc_reset,
  255. .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
  256. .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
  257. .enable_vblank = zynqmp_dpsub_crtc_enable_vblank,
  258. .disable_vblank = zynqmp_dpsub_crtc_disable_vblank,
  259. };
  260. static int zynqmp_dpsub_create_crtc(struct zynqmp_dpsub *dpsub)
  261. {
  262. struct drm_plane *plane = &dpsub->drm->planes[ZYNQMP_DPSUB_LAYER_GFX];
  263. struct drm_crtc *crtc = &dpsub->drm->crtc;
  264. int ret;
  265. ret = drm_crtc_init_with_planes(&dpsub->drm->dev, crtc, plane,
  266. NULL, &zynqmp_dpsub_crtc_funcs, NULL);
  267. if (ret < 0)
  268. return ret;
  269. drm_crtc_helper_add(crtc, &zynqmp_dpsub_crtc_helper_funcs);
  270. /* Start with vertical blanking interrupt reporting disabled. */
  271. drm_crtc_vblank_off(crtc);
  272. return 0;
  273. }
  274. static void zynqmp_dpsub_map_crtc_to_plane(struct zynqmp_dpsub *dpsub)
  275. {
  276. u32 possible_crtcs = drm_crtc_mask(&dpsub->drm->crtc);
  277. unsigned int i;
  278. for (i = 0; i < ARRAY_SIZE(dpsub->drm->planes); i++)
  279. dpsub->drm->planes[i].possible_crtcs = possible_crtcs;
  280. }
  281. /**
  282. * zynqmp_dpsub_drm_handle_vblank - Handle the vblank event
  283. * @dpsub: DisplayPort subsystem
  284. *
  285. * This function handles the vblank interrupt, and sends an event to
  286. * CRTC object. This will be called by the DP vblank interrupt handler.
  287. */
  288. void zynqmp_dpsub_drm_handle_vblank(struct zynqmp_dpsub *dpsub)
  289. {
  290. drm_crtc_handle_vblank(&dpsub->drm->crtc);
  291. }
  292. /* -----------------------------------------------------------------------------
  293. * Dumb Buffer & Framebuffer Allocation
  294. */
  295. static int zynqmp_dpsub_dumb_create(struct drm_file *file_priv,
  296. struct drm_device *drm,
  297. struct drm_mode_create_dumb *args)
  298. {
  299. struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
  300. int ret;
  301. /* Enforce the alignment constraints of the DMA engine. */
  302. ret = drm_mode_size_dumb(drm, args, dpsub->dma_align, 0);
  303. if (ret)
  304. return ret;
  305. return drm_gem_dma_dumb_create_internal(file_priv, drm, args);
  306. }
  307. static struct drm_framebuffer *
  308. zynqmp_dpsub_fb_create(struct drm_device *drm, struct drm_file *file_priv,
  309. const struct drm_format_info *info,
  310. const struct drm_mode_fb_cmd2 *mode_cmd)
  311. {
  312. struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
  313. struct drm_mode_fb_cmd2 cmd = *mode_cmd;
  314. unsigned int i;
  315. /* Enforce the alignment constraints of the DMA engine. */
  316. for (i = 0; i < ARRAY_SIZE(cmd.pitches); ++i)
  317. cmd.pitches[i] = ALIGN(cmd.pitches[i], dpsub->dma_align);
  318. return drm_gem_fb_create(drm, file_priv, info, &cmd);
  319. }
  320. static const struct drm_mode_config_funcs zynqmp_dpsub_mode_config_funcs = {
  321. .fb_create = zynqmp_dpsub_fb_create,
  322. .atomic_check = drm_atomic_helper_check,
  323. .atomic_commit = drm_atomic_helper_commit,
  324. };
  325. /* -----------------------------------------------------------------------------
  326. * DRM/KMS Driver
  327. */
  328. DEFINE_DRM_GEM_DMA_FOPS(zynqmp_dpsub_drm_fops);
  329. static const struct drm_driver zynqmp_dpsub_drm_driver = {
  330. .driver_features = DRIVER_MODESET | DRIVER_GEM |
  331. DRIVER_ATOMIC,
  332. DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(zynqmp_dpsub_dumb_create),
  333. DRM_FBDEV_DMA_DRIVER_OPS,
  334. .fops = &zynqmp_dpsub_drm_fops,
  335. .name = "zynqmp-dpsub",
  336. .desc = "Xilinx DisplayPort Subsystem Driver",
  337. .major = 1,
  338. .minor = 0,
  339. };
  340. static int zynqmp_dpsub_kms_init(struct zynqmp_dpsub *dpsub)
  341. {
  342. struct drm_encoder *encoder = &dpsub->drm->encoder;
  343. struct drm_connector *connector;
  344. int ret;
  345. /* Create the planes and the CRTC. */
  346. ret = zynqmp_dpsub_create_planes(dpsub);
  347. if (ret)
  348. return ret;
  349. ret = zynqmp_dpsub_create_crtc(dpsub);
  350. if (ret < 0)
  351. return ret;
  352. zynqmp_dpsub_map_crtc_to_plane(dpsub);
  353. /* Create the encoder and attach the bridge. */
  354. encoder->possible_crtcs |= drm_crtc_mask(&dpsub->drm->crtc);
  355. drm_simple_encoder_init(&dpsub->drm->dev, encoder, DRM_MODE_ENCODER_NONE);
  356. ret = drm_bridge_attach(encoder, dpsub->bridge, NULL,
  357. DRM_BRIDGE_ATTACH_NO_CONNECTOR);
  358. if (ret) {
  359. dev_err(dpsub->dev, "failed to attach bridge to encoder\n");
  360. goto err_encoder;
  361. }
  362. /* Create the connector for the chain of bridges. */
  363. connector = drm_bridge_connector_init(&dpsub->drm->dev, encoder);
  364. if (IS_ERR(connector)) {
  365. dev_err(dpsub->dev, "failed to created connector\n");
  366. ret = PTR_ERR(connector);
  367. goto err_encoder;
  368. }
  369. ret = drm_connector_attach_encoder(connector, encoder);
  370. if (ret < 0) {
  371. dev_err(dpsub->dev, "failed to attach connector to encoder\n");
  372. goto err_encoder;
  373. }
  374. return 0;
  375. err_encoder:
  376. drm_encoder_cleanup(encoder);
  377. return ret;
  378. }
  379. static void zynqmp_dpsub_drm_release(struct drm_device *drm, void *res)
  380. {
  381. struct zynqmp_dpsub_drm *dpdrm = res;
  382. zynqmp_dpsub_release(dpdrm->dpsub);
  383. }
  384. int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
  385. {
  386. struct zynqmp_dpsub_drm *dpdrm;
  387. struct drm_device *drm;
  388. int ret;
  389. /*
  390. * Allocate the drm_device and immediately add a cleanup action to
  391. * release the zynqmp_dpsub instance. If any of those operations fail,
  392. * dpsub->drm will remain NULL, which tells the caller that it must
  393. * cleanup manually.
  394. */
  395. dpdrm = devm_drm_dev_alloc(dpsub->dev, &zynqmp_dpsub_drm_driver,
  396. struct zynqmp_dpsub_drm, dev);
  397. if (IS_ERR(dpdrm))
  398. return PTR_ERR(dpdrm);
  399. dpdrm->dpsub = dpsub;
  400. drm = &dpdrm->dev;
  401. ret = drmm_add_action(drm, zynqmp_dpsub_drm_release, dpdrm);
  402. if (ret < 0)
  403. return ret;
  404. dpsub->drm = dpdrm;
  405. /* Initialize mode config, vblank and the KMS poll helper. */
  406. ret = drmm_mode_config_init(drm);
  407. if (ret < 0)
  408. return ret;
  409. drm->mode_config.funcs = &zynqmp_dpsub_mode_config_funcs;
  410. drm->mode_config.min_width = 0;
  411. drm->mode_config.min_height = 0;
  412. drm->mode_config.max_width = ZYNQMP_DISP_MAX_WIDTH;
  413. drm->mode_config.max_height = ZYNQMP_DISP_MAX_HEIGHT;
  414. ret = drm_vblank_init(drm, 1);
  415. if (ret)
  416. return ret;
  417. ret = zynqmp_dpsub_kms_init(dpsub);
  418. if (ret < 0)
  419. goto err_poll_fini;
  420. drm_kms_helper_poll_init(drm);
  421. /* Reset all components and register the DRM device. */
  422. drm_mode_config_reset(drm);
  423. ret = drm_dev_register(drm, 0);
  424. if (ret < 0)
  425. goto err_poll_fini;
  426. /* Initialize fbdev generic emulation. */
  427. drm_client_setup_with_fourcc(drm, DRM_FORMAT_RGB888);
  428. return 0;
  429. err_poll_fini:
  430. drm_kms_helper_poll_fini(drm);
  431. return ret;
  432. }
  433. void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub)
  434. {
  435. struct drm_device *drm = &dpsub->drm->dev;
  436. drm_dev_unplug(drm);
  437. drm_atomic_helper_shutdown(drm);
  438. drm_encoder_cleanup(&dpsub->drm->encoder);
  439. drm_kms_helper_poll_fini(drm);
  440. }