rcar_du_crtc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * rcar_du_crtc.c -- R-Car Display Unit CRTCs
  3. *
  4. * Copyright (C) 2013 Renesas Corporation
  5. *
  6. * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. */
  13. #include <linux/clk.h>
  14. #include <linux/mutex.h>
  15. #include <drm/drmP.h>
  16. #include <drm/drm_crtc.h>
  17. #include <drm/drm_crtc_helper.h>
  18. #include <drm/drm_fb_cma_helper.h>
  19. #include <drm/drm_gem_cma_helper.h>
  20. #include "rcar_du_crtc.h"
  21. #include "rcar_du_drv.h"
  22. #include "rcar_du_kms.h"
  23. #include "rcar_du_lvds.h"
  24. #include "rcar_du_plane.h"
  25. #include "rcar_du_regs.h"
  26. #include "rcar_du_vga.h"
  27. #define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc)
  28. static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg)
  29. {
  30. struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
  31. return rcar_du_read(rcdu, rcrtc->mmio_offset + reg);
  32. }
  33. static void rcar_du_crtc_write(struct rcar_du_crtc *rcrtc, u32 reg, u32 data)
  34. {
  35. struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
  36. rcar_du_write(rcdu, rcrtc->mmio_offset + reg, data);
  37. }
  38. static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr)
  39. {
  40. struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
  41. rcar_du_write(rcdu, rcrtc->mmio_offset + reg,
  42. rcar_du_read(rcdu, rcrtc->mmio_offset + reg) & ~clr);
  43. }
  44. static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set)
  45. {
  46. struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
  47. rcar_du_write(rcdu, rcrtc->mmio_offset + reg,
  48. rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set);
  49. }
  50. static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg,
  51. u32 clr, u32 set)
  52. {
  53. struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
  54. u32 value = rcar_du_read(rcdu, rcrtc->mmio_offset + reg);
  55. rcar_du_write(rcdu, rcrtc->mmio_offset + reg, (value & ~clr) | set);
  56. }
  57. static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
  58. {
  59. struct drm_crtc *crtc = &rcrtc->crtc;
  60. struct rcar_du_device *rcdu = crtc->dev->dev_private;
  61. const struct drm_display_mode *mode = &crtc->mode;
  62. unsigned long clk;
  63. u32 value;
  64. u32 div;
  65. /* Dot clock */
  66. clk = clk_get_rate(rcdu->clock);
  67. div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000);
  68. div = clamp(div, 1U, 64U) - 1;
  69. rcar_du_write(rcdu, rcrtc->index ? ESCR2 : ESCR,
  70. ESCR_DCLKSEL_CLKS | div);
  71. rcar_du_write(rcdu, rcrtc->index ? OTAR2 : OTAR, 0);
  72. /* Signal polarities */
  73. value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
  74. | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
  75. | DSMR_DIPM_DE;
  76. rcar_du_crtc_write(rcrtc, DSMR, value);
  77. /* Display timings */
  78. rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);
  79. rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start +
  80. mode->hdisplay - 19);
  81. rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end -
  82. mode->hsync_start - 1);
  83. rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1);
  84. rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2);
  85. rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end +
  86. mode->vdisplay - 2);
  87. rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end +
  88. mode->vsync_start - 1);
  89. rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1);
  90. rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start);
  91. rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay);
  92. }
  93. static void rcar_du_crtc_set_routing(struct rcar_du_crtc *rcrtc)
  94. {
  95. struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
  96. u32 dorcr = rcar_du_read(rcdu, DORCR);
  97. dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK);
  98. /* Set the DU1 pins sources. Select CRTC 0 if explicitly requested and
  99. * CRTC 1 in all other cases to avoid cloning CRTC 0 to DU0 and DU1 by
  100. * default.
  101. */
  102. if (rcrtc->outputs & (1 << 1) && rcrtc->index == 0)
  103. dorcr |= DORCR_PG2D_DS1;
  104. else
  105. dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2;
  106. rcar_du_write(rcdu, DORCR, dorcr);
  107. }
  108. static void __rcar_du_start_stop(struct rcar_du_device *rcdu, bool start)
  109. {
  110. rcar_du_write(rcdu, DSYSR,
  111. (rcar_du_read(rcdu, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) |
  112. (start ? DSYSR_DEN : DSYSR_DRES));
  113. }
  114. static void rcar_du_start_stop(struct rcar_du_device *rcdu, bool start)
  115. {
  116. /* Many of the configuration bits are only updated when the display
  117. * reset (DRES) bit in DSYSR is set to 1, disabling *both* CRTCs. Some
  118. * of those bits could be pre-configured, but others (especially the
  119. * bits related to plane assignment to display timing controllers) need
  120. * to be modified at runtime.
  121. *
  122. * Restart the display controller if a start is requested. Sorry for the
  123. * flicker. It should be possible to move most of the "DRES-update" bits
  124. * setup to driver initialization time and minimize the number of cases
  125. * when the display controller will have to be restarted.
  126. */
  127. if (start) {
  128. if (rcdu->used_crtcs++ != 0)
  129. __rcar_du_start_stop(rcdu, false);
  130. __rcar_du_start_stop(rcdu, true);
  131. } else {
  132. if (--rcdu->used_crtcs == 0)
  133. __rcar_du_start_stop(rcdu, false);
  134. }
  135. }
  136. void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output)
  137. {
  138. struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
  139. /* Store the route from the CRTC output to the DU output. The DU will be
  140. * configured when starting the CRTC.
  141. */
  142. rcrtc->outputs |= 1 << output;
  143. }
  144. void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
  145. {
  146. struct rcar_du_device *rcdu = crtc->dev->dev_private;
  147. struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
  148. struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES];
  149. unsigned int num_planes = 0;
  150. unsigned int prio = 0;
  151. unsigned int i;
  152. u32 dptsr = 0;
  153. u32 dspr = 0;
  154. for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
  155. struct rcar_du_plane *plane = &rcdu->planes.planes[i];
  156. unsigned int j;
  157. if (plane->crtc != &rcrtc->crtc || !plane->enabled)
  158. continue;
  159. /* Insert the plane in the sorted planes array. */
  160. for (j = num_planes++; j > 0; --j) {
  161. if (planes[j-1]->zpos <= plane->zpos)
  162. break;
  163. planes[j] = planes[j-1];
  164. }
  165. planes[j] = plane;
  166. prio += plane->format->planes * 4;
  167. }
  168. for (i = 0; i < num_planes; ++i) {
  169. struct rcar_du_plane *plane = planes[i];
  170. unsigned int index = plane->hwindex;
  171. prio -= 4;
  172. dspr |= (index + 1) << prio;
  173. dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index);
  174. if (plane->format->planes == 2) {
  175. index = (index + 1) % 8;
  176. prio -= 4;
  177. dspr |= (index + 1) << prio;
  178. dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index);
  179. }
  180. }
  181. /* Select display timing and dot clock generator 2 for planes associated
  182. * with superposition controller 2.
  183. */
  184. if (rcrtc->index) {
  185. u32 value = rcar_du_read(rcdu, DPTSR);
  186. /* The DPTSR register is updated when the display controller is
  187. * stopped. We thus need to restart the DU. Once again, sorry
  188. * for the flicker. One way to mitigate the issue would be to
  189. * pre-associate planes with CRTCs (either with a fixed 4/4
  190. * split, or through a module parameter). Flicker would then
  191. * occur only if we need to break the pre-association.
  192. */
  193. if (value != dptsr) {
  194. rcar_du_write(rcdu, DPTSR, dptsr);
  195. if (rcdu->used_crtcs) {
  196. __rcar_du_start_stop(rcdu, false);
  197. __rcar_du_start_stop(rcdu, true);
  198. }
  199. }
  200. }
  201. rcar_du_write(rcdu, rcrtc->index ? DS2PR : DS1PR, dspr);
  202. }
  203. static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
  204. {
  205. struct drm_crtc *crtc = &rcrtc->crtc;
  206. struct rcar_du_device *rcdu = crtc->dev->dev_private;
  207. unsigned int i;
  208. if (rcrtc->started)
  209. return;
  210. if (WARN_ON(rcrtc->plane->format == NULL))
  211. return;
  212. /* Set display off and background to black */
  213. rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
  214. rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
  215. /* Configure display timings and output routing */
  216. rcar_du_crtc_set_display_timing(rcrtc);
  217. rcar_du_crtc_set_routing(rcrtc);
  218. mutex_lock(&rcdu->planes.lock);
  219. rcrtc->plane->enabled = true;
  220. rcar_du_crtc_update_planes(crtc);
  221. mutex_unlock(&rcdu->planes.lock);
  222. /* Setup planes. */
  223. for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
  224. struct rcar_du_plane *plane = &rcdu->planes.planes[i];
  225. if (plane->crtc != crtc || !plane->enabled)
  226. continue;
  227. rcar_du_plane_setup(plane);
  228. }
  229. /* Select master sync mode. This enables display operation in master
  230. * sync mode (with the HSYNC and VSYNC signals configured as outputs and
  231. * actively driven).
  232. */
  233. rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER);
  234. rcar_du_start_stop(rcdu, true);
  235. rcrtc->started = true;
  236. }
  237. static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
  238. {
  239. struct drm_crtc *crtc = &rcrtc->crtc;
  240. struct rcar_du_device *rcdu = crtc->dev->dev_private;
  241. if (!rcrtc->started)
  242. return;
  243. mutex_lock(&rcdu->planes.lock);
  244. rcrtc->plane->enabled = false;
  245. rcar_du_crtc_update_planes(crtc);
  246. mutex_unlock(&rcdu->planes.lock);
  247. /* Select switch sync mode. This stops display operation and configures
  248. * the HSYNC and VSYNC signals as inputs.
  249. */
  250. rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);
  251. rcar_du_start_stop(rcdu, false);
  252. rcrtc->started = false;
  253. }
  254. void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc)
  255. {
  256. struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
  257. rcar_du_crtc_stop(rcrtc);
  258. rcar_du_put(rcdu);
  259. }
  260. void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
  261. {
  262. struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
  263. if (rcrtc->dpms != DRM_MODE_DPMS_ON)
  264. return;
  265. rcar_du_get(rcdu);
  266. rcar_du_crtc_start(rcrtc);
  267. }
  268. static void rcar_du_crtc_update_base(struct rcar_du_crtc *rcrtc)
  269. {
  270. struct drm_crtc *crtc = &rcrtc->crtc;
  271. rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
  272. rcar_du_plane_update_base(rcrtc->plane);
  273. }
  274. static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode)
  275. {
  276. struct rcar_du_device *rcdu = crtc->dev->dev_private;
  277. struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
  278. if (rcrtc->dpms == mode)
  279. return;
  280. if (mode == DRM_MODE_DPMS_ON) {
  281. rcar_du_get(rcdu);
  282. rcar_du_crtc_start(rcrtc);
  283. } else {
  284. rcar_du_crtc_stop(rcrtc);
  285. rcar_du_put(rcdu);
  286. }
  287. rcrtc->dpms = mode;
  288. }
  289. static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc,
  290. const struct drm_display_mode *mode,
  291. struct drm_display_mode *adjusted_mode)
  292. {
  293. /* TODO Fixup modes */
  294. return true;
  295. }
  296. static void rcar_du_crtc_mode_prepare(struct drm_crtc *crtc)
  297. {
  298. struct rcar_du_device *rcdu = crtc->dev->dev_private;
  299. struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
  300. /* We need to access the hardware during mode set, acquire a reference
  301. * to the DU.
  302. */
  303. rcar_du_get(rcdu);
  304. /* Stop the CRTC and release the plane. Force the DPMS mode to off as a
  305. * result.
  306. */
  307. rcar_du_crtc_stop(rcrtc);
  308. rcar_du_plane_release(rcrtc->plane);
  309. rcrtc->dpms = DRM_MODE_DPMS_OFF;
  310. }
  311. static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
  312. struct drm_display_mode *mode,
  313. struct drm_display_mode *adjusted_mode,
  314. int x, int y,
  315. struct drm_framebuffer *old_fb)
  316. {
  317. struct rcar_du_device *rcdu = crtc->dev->dev_private;
  318. struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
  319. const struct rcar_du_format_info *format;
  320. int ret;
  321. format = rcar_du_format_info(crtc->fb->pixel_format);
  322. if (format == NULL) {
  323. dev_dbg(rcdu->dev, "mode_set: unsupported format %08x\n",
  324. crtc->fb->pixel_format);
  325. ret = -EINVAL;
  326. goto error;
  327. }
  328. ret = rcar_du_plane_reserve(rcrtc->plane, format);
  329. if (ret < 0)
  330. goto error;
  331. rcrtc->plane->format = format;
  332. rcrtc->plane->pitch = crtc->fb->pitches[0];
  333. rcrtc->plane->src_x = x;
  334. rcrtc->plane->src_y = y;
  335. rcrtc->plane->width = mode->hdisplay;
  336. rcrtc->plane->height = mode->vdisplay;
  337. rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
  338. rcrtc->outputs = 0;
  339. return 0;
  340. error:
  341. /* There's no rollback/abort operation to clean up in case of error. We
  342. * thus need to release the reference to the DU acquired in prepare()
  343. * here.
  344. */
  345. rcar_du_put(rcdu);
  346. return ret;
  347. }
  348. static void rcar_du_crtc_mode_commit(struct drm_crtc *crtc)
  349. {
  350. struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
  351. /* We're done, restart the CRTC and set the DPMS mode to on. The
  352. * reference to the DU acquired at prepare() time will thus be released
  353. * by the DPMS handler (possibly called by the disable() handler).
  354. */
  355. rcar_du_crtc_start(rcrtc);
  356. rcrtc->dpms = DRM_MODE_DPMS_ON;
  357. }
  358. static int rcar_du_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
  359. struct drm_framebuffer *old_fb)
  360. {
  361. struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
  362. rcrtc->plane->src_x = x;
  363. rcrtc->plane->src_y = y;
  364. rcar_du_crtc_update_base(to_rcar_crtc(crtc));
  365. return 0;
  366. }
  367. static void rcar_du_crtc_disable(struct drm_crtc *crtc)
  368. {
  369. struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
  370. rcar_du_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
  371. rcar_du_plane_release(rcrtc->plane);
  372. }
  373. static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
  374. .dpms = rcar_du_crtc_dpms,
  375. .mode_fixup = rcar_du_crtc_mode_fixup,
  376. .prepare = rcar_du_crtc_mode_prepare,
  377. .commit = rcar_du_crtc_mode_commit,
  378. .mode_set = rcar_du_crtc_mode_set,
  379. .mode_set_base = rcar_du_crtc_mode_set_base,
  380. .disable = rcar_du_crtc_disable,
  381. };
  382. void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
  383. struct drm_file *file)
  384. {
  385. struct drm_pending_vblank_event *event;
  386. struct drm_device *dev = rcrtc->crtc.dev;
  387. unsigned long flags;
  388. /* Destroy the pending vertical blanking event associated with the
  389. * pending page flip, if any, and disable vertical blanking interrupts.
  390. */
  391. spin_lock_irqsave(&dev->event_lock, flags);
  392. event = rcrtc->event;
  393. if (event && event->base.file_priv == file) {
  394. rcrtc->event = NULL;
  395. event->base.destroy(&event->base);
  396. drm_vblank_put(dev, rcrtc->index);
  397. }
  398. spin_unlock_irqrestore(&dev->event_lock, flags);
  399. }
  400. static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
  401. {
  402. struct drm_pending_vblank_event *event;
  403. struct drm_device *dev = rcrtc->crtc.dev;
  404. unsigned long flags;
  405. spin_lock_irqsave(&dev->event_lock, flags);
  406. event = rcrtc->event;
  407. rcrtc->event = NULL;
  408. spin_unlock_irqrestore(&dev->event_lock, flags);
  409. if (event == NULL)
  410. return;
  411. spin_lock_irqsave(&dev->event_lock, flags);
  412. drm_send_vblank_event(dev, rcrtc->index, event);
  413. spin_unlock_irqrestore(&dev->event_lock, flags);
  414. drm_vblank_put(dev, rcrtc->index);
  415. }
  416. static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
  417. struct drm_framebuffer *fb,
  418. struct drm_pending_vblank_event *event)
  419. {
  420. struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
  421. struct drm_device *dev = rcrtc->crtc.dev;
  422. unsigned long flags;
  423. spin_lock_irqsave(&dev->event_lock, flags);
  424. if (rcrtc->event != NULL) {
  425. spin_unlock_irqrestore(&dev->event_lock, flags);
  426. return -EBUSY;
  427. }
  428. spin_unlock_irqrestore(&dev->event_lock, flags);
  429. crtc->fb = fb;
  430. rcar_du_crtc_update_base(rcrtc);
  431. if (event) {
  432. event->pipe = rcrtc->index;
  433. drm_vblank_get(dev, rcrtc->index);
  434. spin_lock_irqsave(&dev->event_lock, flags);
  435. rcrtc->event = event;
  436. spin_unlock_irqrestore(&dev->event_lock, flags);
  437. }
  438. return 0;
  439. }
  440. static const struct drm_crtc_funcs crtc_funcs = {
  441. .destroy = drm_crtc_cleanup,
  442. .set_config = drm_crtc_helper_set_config,
  443. .page_flip = rcar_du_crtc_page_flip,
  444. };
  445. int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index)
  446. {
  447. struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
  448. struct drm_crtc *crtc = &rcrtc->crtc;
  449. int ret;
  450. rcrtc->mmio_offset = index ? DISP2_REG_OFFSET : 0;
  451. rcrtc->index = index;
  452. rcrtc->dpms = DRM_MODE_DPMS_OFF;
  453. rcrtc->plane = &rcdu->planes.planes[index];
  454. rcrtc->plane->crtc = crtc;
  455. ret = drm_crtc_init(rcdu->ddev, crtc, &crtc_funcs);
  456. if (ret < 0)
  457. return ret;
  458. drm_crtc_helper_add(crtc, &crtc_helper_funcs);
  459. return 0;
  460. }
  461. void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable)
  462. {
  463. if (enable) {
  464. rcar_du_crtc_write(rcrtc, DSRCR, DSRCR_VBCL);
  465. rcar_du_crtc_set(rcrtc, DIER, DIER_VBE);
  466. } else {
  467. rcar_du_crtc_clr(rcrtc, DIER, DIER_VBE);
  468. }
  469. }
  470. void rcar_du_crtc_irq(struct rcar_du_crtc *rcrtc)
  471. {
  472. u32 status;
  473. status = rcar_du_crtc_read(rcrtc, DSSR);
  474. rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
  475. if (status & DSSR_VBK) {
  476. drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
  477. rcar_du_crtc_finish_page_flip(rcrtc);
  478. }
  479. }