lsdc_plane.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2023 Loongson Technology Corporation Limited
  4. */
  5. #include <linux/delay.h>
  6. #include <drm/drm_atomic.h>
  7. #include <drm/drm_atomic_helper.h>
  8. #include <drm/drm_framebuffer.h>
  9. #include <drm/drm_gem_atomic_helper.h>
  10. #include "lsdc_drv.h"
  11. #include "lsdc_regs.h"
  12. #include "lsdc_ttm.h"
  13. static const u32 lsdc_primary_formats[] = {
  14. DRM_FORMAT_XRGB8888,
  15. };
  16. static const u32 lsdc_cursor_formats[] = {
  17. DRM_FORMAT_ARGB8888,
  18. };
  19. static const u64 lsdc_fb_format_modifiers[] = {
  20. DRM_FORMAT_MOD_LINEAR,
  21. DRM_FORMAT_MOD_INVALID
  22. };
  23. static unsigned int lsdc_get_fb_offset(struct drm_framebuffer *fb,
  24. struct drm_plane_state *state)
  25. {
  26. unsigned int offset = fb->offsets[0];
  27. offset += fb->format->cpp[0] * (state->src_x >> 16);
  28. offset += fb->pitches[0] * (state->src_y >> 16);
  29. return offset;
  30. }
  31. static u64 lsdc_fb_base_addr(struct drm_framebuffer *fb)
  32. {
  33. struct lsdc_device *ldev = to_lsdc(fb->dev);
  34. struct lsdc_bo *lbo = gem_to_lsdc_bo(fb->obj[0]);
  35. return lsdc_bo_gpu_offset(lbo) + ldev->vram_base;
  36. }
  37. static int lsdc_primary_atomic_check(struct drm_plane *plane,
  38. struct drm_atomic_state *state)
  39. {
  40. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
  41. struct drm_crtc *crtc = new_plane_state->crtc;
  42. struct drm_crtc_state *new_crtc_state;
  43. if (!crtc)
  44. return 0;
  45. new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
  46. return drm_atomic_helper_check_plane_state(new_plane_state,
  47. new_crtc_state,
  48. DRM_PLANE_NO_SCALING,
  49. DRM_PLANE_NO_SCALING,
  50. false, true);
  51. }
  52. static void lsdc_primary_atomic_update(struct drm_plane *plane,
  53. struct drm_atomic_state *state)
  54. {
  55. struct lsdc_primary *primary = to_lsdc_primary(plane);
  56. const struct lsdc_primary_plane_ops *ops = primary->ops;
  57. struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
  58. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
  59. struct drm_framebuffer *new_fb = new_plane_state->fb;
  60. struct drm_framebuffer *old_fb = old_plane_state->fb;
  61. u64 fb_addr = lsdc_fb_base_addr(new_fb);
  62. fb_addr += lsdc_get_fb_offset(new_fb, new_plane_state);
  63. ops->update_fb_addr(primary, fb_addr);
  64. ops->update_fb_stride(primary, new_fb->pitches[0]);
  65. if (!old_fb || old_fb->format != new_fb->format)
  66. ops->update_fb_format(primary, new_fb->format);
  67. }
  68. static void lsdc_primary_atomic_disable(struct drm_plane *plane,
  69. struct drm_atomic_state *state)
  70. {
  71. /*
  72. * Do nothing, just prevent call into atomic_update().
  73. * Writing the format as LSDC_PF_NONE can disable the primary,
  74. * But it seems not necessary...
  75. */
  76. drm_dbg(plane->dev, "%s disabled\n", plane->name);
  77. }
  78. static int lsdc_plane_prepare_fb(struct drm_plane *plane,
  79. struct drm_plane_state *new_state)
  80. {
  81. struct drm_framebuffer *fb = new_state->fb;
  82. struct lsdc_bo *lbo;
  83. u64 gpu_vaddr;
  84. int ret;
  85. if (!fb)
  86. return 0;
  87. lbo = gem_to_lsdc_bo(fb->obj[0]);
  88. ret = lsdc_bo_reserve(lbo);
  89. if (unlikely(ret)) {
  90. drm_err(plane->dev, "bo %p reserve failed\n", lbo);
  91. return ret;
  92. }
  93. ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_VRAM, &gpu_vaddr);
  94. lsdc_bo_unreserve(lbo);
  95. if (unlikely(ret)) {
  96. drm_err(plane->dev, "bo %p pin failed\n", lbo);
  97. return ret;
  98. }
  99. lsdc_bo_ref(lbo);
  100. if (plane->type != DRM_PLANE_TYPE_CURSOR)
  101. drm_dbg(plane->dev,
  102. "%s[%p] pin at 0x%llx, bo size: %zu\n",
  103. plane->name, lbo, gpu_vaddr, lsdc_bo_size(lbo));
  104. return drm_gem_plane_helper_prepare_fb(plane, new_state);
  105. }
  106. static void lsdc_plane_cleanup_fb(struct drm_plane *plane,
  107. struct drm_plane_state *old_state)
  108. {
  109. struct drm_framebuffer *fb = old_state->fb;
  110. struct lsdc_bo *lbo;
  111. int ret;
  112. if (!fb)
  113. return;
  114. lbo = gem_to_lsdc_bo(fb->obj[0]);
  115. ret = lsdc_bo_reserve(lbo);
  116. if (unlikely(ret)) {
  117. drm_err(plane->dev, "%p reserve failed\n", lbo);
  118. return;
  119. }
  120. lsdc_bo_unpin(lbo);
  121. lsdc_bo_unreserve(lbo);
  122. lsdc_bo_unref(lbo);
  123. if (plane->type != DRM_PLANE_TYPE_CURSOR)
  124. drm_dbg(plane->dev, "%s unpin\n", plane->name);
  125. }
  126. static const struct drm_plane_helper_funcs lsdc_primary_helper_funcs = {
  127. .prepare_fb = lsdc_plane_prepare_fb,
  128. .cleanup_fb = lsdc_plane_cleanup_fb,
  129. .atomic_check = lsdc_primary_atomic_check,
  130. .atomic_update = lsdc_primary_atomic_update,
  131. .atomic_disable = lsdc_primary_atomic_disable,
  132. };
  133. static int lsdc_cursor_plane_atomic_async_check(struct drm_plane *plane,
  134. struct drm_atomic_state *state)
  135. {
  136. struct drm_plane_state *new_state;
  137. struct drm_crtc_state *crtc_state;
  138. new_state = drm_atomic_get_new_plane_state(state, plane);
  139. if (!plane->state || !plane->state->fb) {
  140. drm_dbg(plane->dev, "%s: state is NULL\n", plane->name);
  141. return -EINVAL;
  142. }
  143. if (new_state->crtc_w != new_state->crtc_h) {
  144. drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
  145. new_state->crtc_w, new_state->crtc_h);
  146. return -EINVAL;
  147. }
  148. if (new_state->crtc_w != 64 && new_state->crtc_w != 32) {
  149. drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
  150. new_state->crtc_w, new_state->crtc_h);
  151. return -EINVAL;
  152. }
  153. crtc_state = drm_atomic_get_existing_crtc_state(state, new_state->crtc);
  154. if (!crtc_state->active)
  155. return -EINVAL;
  156. if (plane->state->crtc != new_state->crtc ||
  157. plane->state->src_w != new_state->src_w ||
  158. plane->state->src_h != new_state->src_h ||
  159. plane->state->crtc_w != new_state->crtc_w ||
  160. plane->state->crtc_h != new_state->crtc_h)
  161. return -EINVAL;
  162. if (new_state->visible != plane->state->visible)
  163. return -EINVAL;
  164. return drm_atomic_helper_check_plane_state(plane->state,
  165. crtc_state,
  166. DRM_PLANE_NO_SCALING,
  167. DRM_PLANE_NO_SCALING,
  168. true, true);
  169. }
  170. static void lsdc_cursor_plane_atomic_async_update(struct drm_plane *plane,
  171. struct drm_atomic_state *state)
  172. {
  173. struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
  174. const struct lsdc_cursor_plane_ops *ops = cursor->ops;
  175. struct drm_framebuffer *old_fb = plane->state->fb;
  176. struct drm_framebuffer *new_fb;
  177. struct drm_plane_state *new_state;
  178. new_state = drm_atomic_get_new_plane_state(state, plane);
  179. new_fb = plane->state->fb;
  180. plane->state->crtc_x = new_state->crtc_x;
  181. plane->state->crtc_y = new_state->crtc_y;
  182. plane->state->crtc_h = new_state->crtc_h;
  183. plane->state->crtc_w = new_state->crtc_w;
  184. plane->state->src_x = new_state->src_x;
  185. plane->state->src_y = new_state->src_y;
  186. plane->state->src_h = new_state->src_h;
  187. plane->state->src_w = new_state->src_w;
  188. swap(plane->state->fb, new_state->fb);
  189. if (new_state->visible) {
  190. enum lsdc_cursor_size cursor_size;
  191. switch (new_state->crtc_w) {
  192. case 64:
  193. cursor_size = CURSOR_SIZE_64X64;
  194. break;
  195. case 32:
  196. cursor_size = CURSOR_SIZE_32X32;
  197. break;
  198. default:
  199. cursor_size = CURSOR_SIZE_32X32;
  200. break;
  201. }
  202. ops->update_position(cursor, new_state->crtc_x, new_state->crtc_y);
  203. ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);
  204. if (!old_fb || old_fb != new_fb)
  205. ops->update_bo_addr(cursor, lsdc_fb_base_addr(new_fb));
  206. }
  207. }
  208. /* ls7a1000 cursor plane helpers */
  209. static int ls7a1000_cursor_plane_atomic_check(struct drm_plane *plane,
  210. struct drm_atomic_state *state)
  211. {
  212. struct drm_plane_state *new_plane_state;
  213. struct drm_crtc_state *new_crtc_state;
  214. struct drm_crtc *crtc;
  215. new_plane_state = drm_atomic_get_new_plane_state(state, plane);
  216. crtc = new_plane_state->crtc;
  217. if (!crtc) {
  218. drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);
  219. return 0;
  220. }
  221. if (new_plane_state->crtc_w != 32 || new_plane_state->crtc_h != 32) {
  222. drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
  223. new_plane_state->crtc_w, new_plane_state->crtc_h);
  224. return -EINVAL;
  225. }
  226. new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
  227. return drm_atomic_helper_check_plane_state(new_plane_state,
  228. new_crtc_state,
  229. DRM_PLANE_NO_SCALING,
  230. DRM_PLANE_NO_SCALING,
  231. true, true);
  232. }
  233. static void ls7a1000_cursor_plane_atomic_update(struct drm_plane *plane,
  234. struct drm_atomic_state *state)
  235. {
  236. struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
  237. struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
  238. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
  239. struct drm_framebuffer *new_fb = new_plane_state->fb;
  240. struct drm_framebuffer *old_fb = old_plane_state->fb;
  241. const struct lsdc_cursor_plane_ops *ops = cursor->ops;
  242. u64 addr = lsdc_fb_base_addr(new_fb);
  243. if (!new_plane_state->visible)
  244. return;
  245. ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);
  246. if (!old_fb || old_fb != new_fb)
  247. ops->update_bo_addr(cursor, addr);
  248. ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_ARGB8888);
  249. }
  250. static void ls7a1000_cursor_plane_atomic_disable(struct drm_plane *plane,
  251. struct drm_atomic_state *state)
  252. {
  253. struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
  254. const struct lsdc_cursor_plane_ops *ops = cursor->ops;
  255. ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_DISABLE);
  256. }
  257. static const struct drm_plane_helper_funcs ls7a1000_cursor_plane_helper_funcs = {
  258. .prepare_fb = lsdc_plane_prepare_fb,
  259. .cleanup_fb = lsdc_plane_cleanup_fb,
  260. .atomic_check = ls7a1000_cursor_plane_atomic_check,
  261. .atomic_update = ls7a1000_cursor_plane_atomic_update,
  262. .atomic_disable = ls7a1000_cursor_plane_atomic_disable,
  263. .atomic_async_check = lsdc_cursor_plane_atomic_async_check,
  264. .atomic_async_update = lsdc_cursor_plane_atomic_async_update,
  265. };
  266. /* ls7a2000 cursor plane helpers */
  267. static int ls7a2000_cursor_plane_atomic_check(struct drm_plane *plane,
  268. struct drm_atomic_state *state)
  269. {
  270. struct drm_plane_state *new_plane_state;
  271. struct drm_crtc_state *new_crtc_state;
  272. struct drm_crtc *crtc;
  273. new_plane_state = drm_atomic_get_new_plane_state(state, plane);
  274. crtc = new_plane_state->crtc;
  275. if (!crtc) {
  276. drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);
  277. return 0;
  278. }
  279. if (new_plane_state->crtc_w != new_plane_state->crtc_h) {
  280. drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
  281. new_plane_state->crtc_w, new_plane_state->crtc_h);
  282. return -EINVAL;
  283. }
  284. if (new_plane_state->crtc_w != 64 && new_plane_state->crtc_w != 32) {
  285. drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
  286. new_plane_state->crtc_w, new_plane_state->crtc_h);
  287. return -EINVAL;
  288. }
  289. new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
  290. return drm_atomic_helper_check_plane_state(new_plane_state,
  291. new_crtc_state,
  292. DRM_PLANE_NO_SCALING,
  293. DRM_PLANE_NO_SCALING,
  294. true, true);
  295. }
  296. /* Update the format, size and location of the cursor */
  297. static void ls7a2000_cursor_plane_atomic_update(struct drm_plane *plane,
  298. struct drm_atomic_state *state)
  299. {
  300. struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
  301. struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
  302. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
  303. struct drm_framebuffer *new_fb = new_plane_state->fb;
  304. struct drm_framebuffer *old_fb = old_plane_state->fb;
  305. const struct lsdc_cursor_plane_ops *ops = cursor->ops;
  306. enum lsdc_cursor_size cursor_size;
  307. if (!new_plane_state->visible)
  308. return;
  309. ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);
  310. if (!old_fb || new_fb != old_fb) {
  311. u64 addr = lsdc_fb_base_addr(new_fb);
  312. ops->update_bo_addr(cursor, addr);
  313. }
  314. switch (new_plane_state->crtc_w) {
  315. case 64:
  316. cursor_size = CURSOR_SIZE_64X64;
  317. break;
  318. case 32:
  319. cursor_size = CURSOR_SIZE_32X32;
  320. break;
  321. default:
  322. cursor_size = CURSOR_SIZE_64X64;
  323. break;
  324. }
  325. ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);
  326. }
  327. static void ls7a2000_cursor_plane_atomic_disable(struct drm_plane *plane,
  328. struct drm_atomic_state *state)
  329. {
  330. struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
  331. const struct lsdc_cursor_plane_ops *hw_ops = cursor->ops;
  332. hw_ops->update_cfg(cursor, CURSOR_SIZE_64X64, CURSOR_FORMAT_DISABLE);
  333. }
  334. static const struct drm_plane_helper_funcs ls7a2000_cursor_plane_helper_funcs = {
  335. .prepare_fb = lsdc_plane_prepare_fb,
  336. .cleanup_fb = lsdc_plane_cleanup_fb,
  337. .atomic_check = ls7a2000_cursor_plane_atomic_check,
  338. .atomic_update = ls7a2000_cursor_plane_atomic_update,
  339. .atomic_disable = ls7a2000_cursor_plane_atomic_disable,
  340. .atomic_async_check = lsdc_cursor_plane_atomic_async_check,
  341. .atomic_async_update = lsdc_cursor_plane_atomic_async_update,
  342. };
  343. static void lsdc_plane_atomic_print_state(struct drm_printer *p,
  344. const struct drm_plane_state *state)
  345. {
  346. struct drm_framebuffer *fb = state->fb;
  347. u64 addr;
  348. if (!fb)
  349. return;
  350. addr = lsdc_fb_base_addr(fb);
  351. drm_printf(p, "\tdma addr=%llx\n", addr);
  352. }
  353. static const struct drm_plane_funcs lsdc_plane_funcs = {
  354. .update_plane = drm_atomic_helper_update_plane,
  355. .disable_plane = drm_atomic_helper_disable_plane,
  356. .destroy = drm_plane_cleanup,
  357. .reset = drm_atomic_helper_plane_reset,
  358. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  359. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  360. .atomic_print_state = lsdc_plane_atomic_print_state,
  361. };
  362. /* Primary plane 0 hardware related ops */
  363. static void lsdc_primary0_update_fb_addr(struct lsdc_primary *primary, u64 addr)
  364. {
  365. struct lsdc_device *ldev = primary->ldev;
  366. u32 status;
  367. u32 lo, hi;
  368. /* 40-bit width physical address bus */
  369. lo = addr & 0xFFFFFFFF;
  370. hi = (addr >> 32) & 0xFF;
  371. status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
  372. if (status & FB_REG_IN_USING) {
  373. lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_LO_REG, lo);
  374. lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_HI_REG, hi);
  375. } else {
  376. lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_LO_REG, lo);
  377. lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_HI_REG, hi);
  378. }
  379. }
  380. static void lsdc_primary0_update_fb_stride(struct lsdc_primary *primary, u32 stride)
  381. {
  382. struct lsdc_device *ldev = primary->ldev;
  383. lsdc_wreg32(ldev, LSDC_CRTC0_STRIDE_REG, stride);
  384. }
  385. static void lsdc_primary0_update_fb_format(struct lsdc_primary *primary,
  386. const struct drm_format_info *format)
  387. {
  388. struct lsdc_device *ldev = primary->ldev;
  389. u32 status;
  390. status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
  391. /*
  392. * TODO: add RGB565 support, only support XRBG8888 at present
  393. */
  394. status &= ~CFG_PIX_FMT_MASK;
  395. status |= LSDC_PF_XRGB8888;
  396. lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, status);
  397. }
  398. /* Primary plane 1 hardware related ops */
  399. static void lsdc_primary1_update_fb_addr(struct lsdc_primary *primary, u64 addr)
  400. {
  401. struct lsdc_device *ldev = primary->ldev;
  402. u32 status;
  403. u32 lo, hi;
  404. /* 40-bit width physical address bus */
  405. lo = addr & 0xFFFFFFFF;
  406. hi = (addr >> 32) & 0xFF;
  407. status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
  408. if (status & FB_REG_IN_USING) {
  409. lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_LO_REG, lo);
  410. lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_HI_REG, hi);
  411. } else {
  412. lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_LO_REG, lo);
  413. lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_HI_REG, hi);
  414. }
  415. }
  416. static void lsdc_primary1_update_fb_stride(struct lsdc_primary *primary, u32 stride)
  417. {
  418. struct lsdc_device *ldev = primary->ldev;
  419. lsdc_wreg32(ldev, LSDC_CRTC1_STRIDE_REG, stride);
  420. }
  421. static void lsdc_primary1_update_fb_format(struct lsdc_primary *primary,
  422. const struct drm_format_info *format)
  423. {
  424. struct lsdc_device *ldev = primary->ldev;
  425. u32 status;
  426. status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
  427. /*
  428. * TODO: add RGB565 support, only support XRBG8888 at present
  429. */
  430. status &= ~CFG_PIX_FMT_MASK;
  431. status |= LSDC_PF_XRGB8888;
  432. lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, status);
  433. }
  434. static const struct lsdc_primary_plane_ops lsdc_primary_plane_hw_ops[2] = {
  435. {
  436. .update_fb_addr = lsdc_primary0_update_fb_addr,
  437. .update_fb_stride = lsdc_primary0_update_fb_stride,
  438. .update_fb_format = lsdc_primary0_update_fb_format,
  439. },
  440. {
  441. .update_fb_addr = lsdc_primary1_update_fb_addr,
  442. .update_fb_stride = lsdc_primary1_update_fb_stride,
  443. .update_fb_format = lsdc_primary1_update_fb_format,
  444. },
  445. };
  446. /*
  447. * Update location, format, enable and disable state of the cursor,
  448. * For those who have two hardware cursor, let cursor 0 is attach to CRTC-0,
  449. * cursor 1 is attach to CRTC-1. Compositing the primary plane and cursor
  450. * plane is automatically done by hardware, the cursor is alway on the top of
  451. * the primary plane. In other word, z-order is fixed in hardware and cannot
  452. * be changed. For those old DC who has only one hardware cursor, we made it
  453. * shared by the two screen, this works on extend screen mode.
  454. */
  455. /* cursor plane 0 (for pipe 0) related hardware ops */
  456. static void lsdc_cursor0_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)
  457. {
  458. struct lsdc_device *ldev = cursor->ldev;
  459. /* 40-bit width physical address bus */
  460. lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);
  461. lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);
  462. }
  463. static void lsdc_cursor0_update_position(struct lsdc_cursor *cursor, int x, int y)
  464. {
  465. struct lsdc_device *ldev = cursor->ldev;
  466. if (x < 0)
  467. x = 0;
  468. if (y < 0)
  469. y = 0;
  470. lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);
  471. }
  472. static void lsdc_cursor0_update_cfg(struct lsdc_cursor *cursor,
  473. enum lsdc_cursor_size cursor_size,
  474. enum lsdc_cursor_format fmt)
  475. {
  476. struct lsdc_device *ldev = cursor->ldev;
  477. u32 cfg;
  478. cfg = CURSOR_ON_CRTC0 << CURSOR_LOCATION_SHIFT |
  479. cursor_size << CURSOR_SIZE_SHIFT |
  480. fmt << CURSOR_FORMAT_SHIFT;
  481. lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);
  482. }
  483. /* cursor plane 1 (for pipe 1) related hardware ops */
  484. static void lsdc_cursor1_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)
  485. {
  486. struct lsdc_device *ldev = cursor->ldev;
  487. /* 40-bit width physical address bus */
  488. lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_HI_REG, (addr >> 32) & 0xFF);
  489. lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_LO_REG, addr);
  490. }
  491. static void lsdc_cursor1_update_position(struct lsdc_cursor *cursor, int x, int y)
  492. {
  493. struct lsdc_device *ldev = cursor->ldev;
  494. if (x < 0)
  495. x = 0;
  496. if (y < 0)
  497. y = 0;
  498. lsdc_wreg32(ldev, LSDC_CURSOR1_POSITION_REG, (y << 16) | x);
  499. }
  500. static void lsdc_cursor1_update_cfg(struct lsdc_cursor *cursor,
  501. enum lsdc_cursor_size cursor_size,
  502. enum lsdc_cursor_format fmt)
  503. {
  504. struct lsdc_device *ldev = cursor->ldev;
  505. u32 cfg;
  506. cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |
  507. cursor_size << CURSOR_SIZE_SHIFT |
  508. fmt << CURSOR_FORMAT_SHIFT;
  509. lsdc_wreg32(ldev, LSDC_CURSOR1_CFG_REG, cfg);
  510. }
  511. /* The hardware cursors become normal since ls7a2000/ls2k2000 */
  512. static const struct lsdc_cursor_plane_ops ls7a2000_cursor_hw_ops[2] = {
  513. {
  514. .update_bo_addr = lsdc_cursor0_update_bo_addr,
  515. .update_cfg = lsdc_cursor0_update_cfg,
  516. .update_position = lsdc_cursor0_update_position,
  517. },
  518. {
  519. .update_bo_addr = lsdc_cursor1_update_bo_addr,
  520. .update_cfg = lsdc_cursor1_update_cfg,
  521. .update_position = lsdc_cursor1_update_position,
  522. },
  523. };
  524. /* Quirks for cursor 1, only for old loongson display controller */
  525. static void lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor *cursor, u64 addr)
  526. {
  527. struct lsdc_device *ldev = cursor->ldev;
  528. /* 40-bit width physical address bus */
  529. lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);
  530. lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);
  531. }
  532. static void lsdc_cursor1_update_position_quirk(struct lsdc_cursor *cursor, int x, int y)
  533. {
  534. struct lsdc_device *ldev = cursor->ldev;
  535. if (x < 0)
  536. x = 0;
  537. if (y < 0)
  538. y = 0;
  539. lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);
  540. }
  541. static void lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor *cursor,
  542. enum lsdc_cursor_size cursor_size,
  543. enum lsdc_cursor_format fmt)
  544. {
  545. struct lsdc_device *ldev = cursor->ldev;
  546. u32 cfg;
  547. cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |
  548. cursor_size << CURSOR_SIZE_SHIFT |
  549. fmt << CURSOR_FORMAT_SHIFT;
  550. lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);
  551. }
  552. /*
  553. * The unforgiving LS7A1000/LS2K1000 has only one hardware cursors plane
  554. */
  555. static const struct lsdc_cursor_plane_ops ls7a1000_cursor_hw_ops[2] = {
  556. {
  557. .update_bo_addr = lsdc_cursor0_update_bo_addr,
  558. .update_cfg = lsdc_cursor0_update_cfg,
  559. .update_position = lsdc_cursor0_update_position,
  560. },
  561. {
  562. .update_bo_addr = lsdc_cursor1_update_bo_addr_quirk,
  563. .update_cfg = lsdc_cursor1_update_cfg_quirk,
  564. .update_position = lsdc_cursor1_update_position_quirk,
  565. },
  566. };
  567. int lsdc_primary_plane_init(struct drm_device *ddev,
  568. struct drm_plane *plane,
  569. unsigned int index)
  570. {
  571. struct lsdc_primary *primary = to_lsdc_primary(plane);
  572. int ret;
  573. ret = drm_universal_plane_init(ddev, plane, 1 << index,
  574. &lsdc_plane_funcs,
  575. lsdc_primary_formats,
  576. ARRAY_SIZE(lsdc_primary_formats),
  577. lsdc_fb_format_modifiers,
  578. DRM_PLANE_TYPE_PRIMARY,
  579. "ls-primary-plane-%u", index);
  580. if (ret)
  581. return ret;
  582. drm_plane_helper_add(plane, &lsdc_primary_helper_funcs);
  583. primary->ldev = to_lsdc(ddev);
  584. primary->ops = &lsdc_primary_plane_hw_ops[index];
  585. return 0;
  586. }
  587. int ls7a1000_cursor_plane_init(struct drm_device *ddev,
  588. struct drm_plane *plane,
  589. unsigned int index)
  590. {
  591. struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
  592. int ret;
  593. ret = drm_universal_plane_init(ddev, plane, 1 << index,
  594. &lsdc_plane_funcs,
  595. lsdc_cursor_formats,
  596. ARRAY_SIZE(lsdc_cursor_formats),
  597. lsdc_fb_format_modifiers,
  598. DRM_PLANE_TYPE_CURSOR,
  599. "ls-cursor-plane-%u", index);
  600. if (ret)
  601. return ret;
  602. cursor->ldev = to_lsdc(ddev);
  603. cursor->ops = &ls7a1000_cursor_hw_ops[index];
  604. drm_plane_helper_add(plane, &ls7a1000_cursor_plane_helper_funcs);
  605. return 0;
  606. }
  607. int ls7a2000_cursor_plane_init(struct drm_device *ddev,
  608. struct drm_plane *plane,
  609. unsigned int index)
  610. {
  611. struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
  612. int ret;
  613. ret = drm_universal_plane_init(ddev, plane, 1 << index,
  614. &lsdc_plane_funcs,
  615. lsdc_cursor_formats,
  616. ARRAY_SIZE(lsdc_cursor_formats),
  617. lsdc_fb_format_modifiers,
  618. DRM_PLANE_TYPE_CURSOR,
  619. "ls-cursor-plane-%u", index);
  620. if (ret)
  621. return ret;
  622. cursor->ldev = to_lsdc(ddev);
  623. cursor->ops = &ls7a2000_cursor_hw_ops[index];
  624. drm_plane_helper_add(plane, &ls7a2000_cursor_plane_helper_funcs);
  625. return 0;
  626. }