drm_sysfb_modeset.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/export.h>
  3. #include <linux/slab.h>
  4. #include <drm/drm_atomic.h>
  5. #include <drm/drm_atomic_helper.h>
  6. #include <drm/drm_atomic_state_helper.h>
  7. #include <drm/drm_damage_helper.h>
  8. #include <drm/drm_drv.h>
  9. #include <drm/drm_edid.h>
  10. #include <drm/drm_fourcc.h>
  11. #include <drm/drm_framebuffer.h>
  12. #include <drm/drm_gem_framebuffer_helper.h>
  13. #include <drm/drm_panic.h>
  14. #include <drm/drm_print.h>
  15. #include <drm/drm_probe_helper.h>
  16. #include "drm_sysfb_helper.h"
  17. struct drm_display_mode drm_sysfb_mode(unsigned int width,
  18. unsigned int height,
  19. unsigned int width_mm,
  20. unsigned int height_mm)
  21. {
  22. /*
  23. * Assume a monitor resolution of 96 dpi to
  24. * get a somewhat reasonable screen size.
  25. */
  26. if (!width_mm)
  27. width_mm = DRM_MODE_RES_MM(width, 96ul);
  28. if (!height_mm)
  29. height_mm = DRM_MODE_RES_MM(height, 96ul);
  30. {
  31. const struct drm_display_mode mode = {
  32. DRM_MODE_INIT(60, width, height, width_mm, height_mm)
  33. };
  34. return mode;
  35. }
  36. }
  37. EXPORT_SYMBOL(drm_sysfb_mode);
  38. /*
  39. * Plane
  40. */
  41. static u32 to_nonalpha_fourcc(u32 fourcc)
  42. {
  43. /* only handle formats with depth != 0 and alpha channel */
  44. switch (fourcc) {
  45. case DRM_FORMAT_ARGB1555:
  46. return DRM_FORMAT_XRGB1555;
  47. case DRM_FORMAT_ABGR1555:
  48. return DRM_FORMAT_XBGR1555;
  49. case DRM_FORMAT_RGBA5551:
  50. return DRM_FORMAT_RGBX5551;
  51. case DRM_FORMAT_BGRA5551:
  52. return DRM_FORMAT_BGRX5551;
  53. case DRM_FORMAT_ARGB8888:
  54. return DRM_FORMAT_XRGB8888;
  55. case DRM_FORMAT_ABGR8888:
  56. return DRM_FORMAT_XBGR8888;
  57. case DRM_FORMAT_RGBA8888:
  58. return DRM_FORMAT_RGBX8888;
  59. case DRM_FORMAT_BGRA8888:
  60. return DRM_FORMAT_BGRX8888;
  61. case DRM_FORMAT_ARGB2101010:
  62. return DRM_FORMAT_XRGB2101010;
  63. case DRM_FORMAT_ABGR2101010:
  64. return DRM_FORMAT_XBGR2101010;
  65. case DRM_FORMAT_RGBA1010102:
  66. return DRM_FORMAT_RGBX1010102;
  67. case DRM_FORMAT_BGRA1010102:
  68. return DRM_FORMAT_BGRX1010102;
  69. }
  70. return fourcc;
  71. }
  72. static bool is_listed_fourcc(const u32 *fourccs, size_t nfourccs, u32 fourcc)
  73. {
  74. const u32 *fourccs_end = fourccs + nfourccs;
  75. while (fourccs < fourccs_end) {
  76. if (*fourccs == fourcc)
  77. return true;
  78. ++fourccs;
  79. }
  80. return false;
  81. }
  82. /**
  83. * drm_sysfb_build_fourcc_list - Filters a list of supported color formats against
  84. * the device's native formats
  85. * @dev: DRM device
  86. * @native_fourccs: 4CC codes of natively supported color formats
  87. * @native_nfourccs: The number of entries in @native_fourccs
  88. * @fourccs_out: Returns 4CC codes of supported color formats
  89. * @nfourccs_out: The number of available entries in @fourccs_out
  90. *
  91. * This function create a list of supported color format from natively
  92. * supported formats and additional emulated formats.
  93. * At a minimum, most userspace programs expect at least support for
  94. * XRGB8888 on the primary plane. Sysfb devices that have to emulate
  95. * the format should use drm_sysfb_build_fourcc_list() to create a list
  96. * of supported color formats. The returned list can be handed over to
  97. * drm_universal_plane_init() et al. Native formats will go before
  98. * emulated formats. Native formats with alpha channel will be replaced
  99. * by equal formats without alpha channel, as primary planes usually
  100. * don't support alpha. Other heuristics might be applied to optimize
  101. * the sorting order. Formats near the beginning of the list are usually
  102. * preferred over formats near the end of the list.
  103. *
  104. * Returns:
  105. * The number of color-formats 4CC codes returned in @fourccs_out.
  106. */
  107. size_t drm_sysfb_build_fourcc_list(struct drm_device *dev,
  108. const u32 *native_fourccs, size_t native_nfourccs,
  109. u32 *fourccs_out, size_t nfourccs_out)
  110. {
  111. /*
  112. * XRGB8888 is the default fallback format for most of userspace
  113. * and it's currently the only format that should be emulated for
  114. * the primary plane. Only if there's ever another default fallback,
  115. * it should be added here.
  116. */
  117. static const u32 extra_fourccs[] = {
  118. DRM_FORMAT_XRGB8888,
  119. };
  120. static const size_t extra_nfourccs = ARRAY_SIZE(extra_fourccs);
  121. u32 *fourccs = fourccs_out;
  122. const u32 *fourccs_end = fourccs_out + nfourccs_out;
  123. size_t i;
  124. /*
  125. * The device's native formats go first.
  126. */
  127. for (i = 0; i < native_nfourccs; ++i) {
  128. /*
  129. * Several DTs, boot loaders and firmware report native
  130. * alpha formats that are non-alpha formats instead. So
  131. * replace alpha formats by non-alpha formats.
  132. */
  133. u32 fourcc = to_nonalpha_fourcc(native_fourccs[i]);
  134. if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
  135. continue; /* skip duplicate entries */
  136. } else if (fourccs == fourccs_end) {
  137. drm_warn(dev, "Ignoring native format %p4cc\n", &fourcc);
  138. continue; /* end of available output buffer */
  139. }
  140. drm_dbg_kms(dev, "adding native format %p4cc\n", &fourcc);
  141. *fourccs = fourcc;
  142. ++fourccs;
  143. }
  144. /*
  145. * The extra formats, emulated by the driver, go second.
  146. */
  147. for (i = 0; (i < extra_nfourccs) && (fourccs < fourccs_end); ++i) {
  148. u32 fourcc = extra_fourccs[i];
  149. if (is_listed_fourcc(fourccs_out, fourccs - fourccs_out, fourcc)) {
  150. continue; /* skip duplicate and native entries */
  151. } else if (fourccs == fourccs_end) {
  152. drm_warn(dev, "Ignoring emulated format %p4cc\n", &fourcc);
  153. continue; /* end of available output buffer */
  154. }
  155. drm_dbg_kms(dev, "adding emulated format %p4cc\n", &fourcc);
  156. *fourccs = fourcc;
  157. ++fourccs;
  158. }
  159. return fourccs - fourccs_out;
  160. }
  161. EXPORT_SYMBOL(drm_sysfb_build_fourcc_list);
  162. static void drm_sysfb_plane_state_destroy(struct drm_sysfb_plane_state *sysfb_plane_state)
  163. {
  164. __drm_gem_destroy_shadow_plane_state(&sysfb_plane_state->base);
  165. kfree(sysfb_plane_state);
  166. }
  167. static void drm_sysfb_memcpy(struct iosys_map *dst, const unsigned int *dst_pitch,
  168. const struct iosys_map *src, const struct drm_framebuffer *fb,
  169. const struct drm_rect *clip, struct drm_format_conv_state *state)
  170. {
  171. drm_fb_memcpy(dst, dst_pitch, src, fb, clip);
  172. }
  173. static drm_sysfb_blit_func drm_sysfb_get_blit_func(u32 dst_format, u32 src_format)
  174. {
  175. if (src_format == dst_format) {
  176. return drm_sysfb_memcpy;
  177. } else if (src_format == DRM_FORMAT_XRGB8888) {
  178. switch (dst_format) {
  179. case DRM_FORMAT_RGB565:
  180. return drm_fb_xrgb8888_to_rgb565;
  181. case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN:
  182. return drm_fb_xrgb8888_to_rgb565be;
  183. case DRM_FORMAT_XRGB1555:
  184. return drm_fb_xrgb8888_to_xrgb1555;
  185. case DRM_FORMAT_ARGB1555:
  186. return drm_fb_xrgb8888_to_argb1555;
  187. case DRM_FORMAT_RGBA5551:
  188. return drm_fb_xrgb8888_to_rgba5551;
  189. case DRM_FORMAT_RGB888:
  190. return drm_fb_xrgb8888_to_rgb888;
  191. case DRM_FORMAT_BGR888:
  192. return drm_fb_xrgb8888_to_bgr888;
  193. case DRM_FORMAT_ARGB8888:
  194. return drm_fb_xrgb8888_to_argb8888;
  195. case DRM_FORMAT_XBGR8888:
  196. return drm_fb_xrgb8888_to_xbgr8888;
  197. case DRM_FORMAT_ABGR8888:
  198. return drm_fb_xrgb8888_to_abgr8888;
  199. case DRM_FORMAT_XRGB2101010:
  200. return drm_fb_xrgb8888_to_xrgb2101010;
  201. case DRM_FORMAT_ARGB2101010:
  202. return drm_fb_xrgb8888_to_argb2101010;
  203. case DRM_FORMAT_BGRX8888:
  204. return drm_fb_xrgb8888_to_bgrx8888;
  205. case DRM_FORMAT_RGB332:
  206. return drm_fb_xrgb8888_to_rgb332;
  207. }
  208. }
  209. return NULL;
  210. }
  211. int drm_sysfb_plane_helper_begin_fb_access(struct drm_plane *plane,
  212. struct drm_plane_state *plane_state)
  213. {
  214. struct drm_device *dev = plane->dev;
  215. struct drm_sysfb_plane_state *sysfb_plane_state = to_drm_sysfb_plane_state(plane_state);
  216. struct drm_framebuffer *fb = plane_state->fb;
  217. struct drm_crtc_state *crtc_state;
  218. struct drm_sysfb_crtc_state *sysfb_crtc_state;
  219. drm_sysfb_blit_func blit_to_crtc;
  220. int ret;
  221. ret = drm_gem_begin_shadow_fb_access(plane, plane_state);
  222. if (ret)
  223. return ret;
  224. if (!fb)
  225. return 0;
  226. ret = -EINVAL;
  227. crtc_state = drm_atomic_get_new_crtc_state(plane_state->state, plane_state->crtc);
  228. if (drm_WARN_ON_ONCE(dev, !crtc_state))
  229. goto err_drm_gem_end_shadow_fb_access;
  230. sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state);
  231. if (drm_WARN_ON_ONCE(dev, !sysfb_crtc_state->format))
  232. goto err_drm_gem_end_shadow_fb_access;
  233. blit_to_crtc = drm_sysfb_get_blit_func(sysfb_crtc_state->format->format,
  234. fb->format->format);
  235. if (!blit_to_crtc) {
  236. drm_warn_once(dev, "No blit helper from %p4cc to %p4cc found.\n",
  237. &fb->format->format, &sysfb_crtc_state->format->format);
  238. goto err_drm_gem_end_shadow_fb_access;
  239. }
  240. sysfb_plane_state->blit_to_crtc = blit_to_crtc;
  241. return 0;
  242. err_drm_gem_end_shadow_fb_access:
  243. drm_gem_end_shadow_fb_access(plane, plane_state);
  244. return ret;
  245. }
  246. EXPORT_SYMBOL(drm_sysfb_plane_helper_begin_fb_access);
  247. int drm_sysfb_plane_helper_atomic_check(struct drm_plane *plane,
  248. struct drm_atomic_state *new_state)
  249. {
  250. struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
  251. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
  252. struct drm_shadow_plane_state *new_shadow_plane_state =
  253. to_drm_shadow_plane_state(new_plane_state);
  254. struct drm_framebuffer *new_fb = new_plane_state->fb;
  255. struct drm_crtc *new_crtc = new_plane_state->crtc;
  256. struct drm_crtc_state *new_crtc_state = NULL;
  257. struct drm_sysfb_crtc_state *new_sysfb_crtc_state;
  258. int ret;
  259. if (new_crtc)
  260. new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
  261. ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
  262. DRM_PLANE_NO_SCALING,
  263. DRM_PLANE_NO_SCALING,
  264. false, false);
  265. if (ret)
  266. return ret;
  267. else if (!new_plane_state->visible)
  268. return 0;
  269. new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
  270. new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state);
  271. new_sysfb_crtc_state->format = sysfb->fb_format;
  272. if (new_fb->format != new_sysfb_crtc_state->format) {
  273. void *buf;
  274. /* format conversion necessary; reserve buffer */
  275. buf = drm_format_conv_state_reserve(&new_shadow_plane_state->fmtcnv_state,
  276. sysfb->fb_pitch, GFP_KERNEL);
  277. if (!buf)
  278. return -ENOMEM;
  279. }
  280. return 0;
  281. }
  282. EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_check);
  283. void drm_sysfb_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state)
  284. {
  285. struct drm_device *dev = plane->dev;
  286. struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
  287. struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
  288. struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
  289. struct drm_sysfb_plane_state *sysfb_plane_state = to_drm_sysfb_plane_state(plane_state);
  290. struct drm_shadow_plane_state *shadow_plane_state = &sysfb_plane_state->base;
  291. struct drm_framebuffer *fb = plane_state->fb;
  292. unsigned int dst_pitch = sysfb->fb_pitch;
  293. struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
  294. struct drm_sysfb_crtc_state *sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state);
  295. const struct drm_format_info *dst_format = sysfb_crtc_state->format;
  296. drm_sysfb_blit_func blit_to_crtc = sysfb_plane_state->blit_to_crtc;
  297. struct drm_atomic_helper_damage_iter iter;
  298. struct drm_rect damage;
  299. int ret, idx;
  300. ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
  301. if (ret)
  302. return;
  303. if (!drm_dev_enter(dev, &idx))
  304. goto out_drm_gem_fb_end_cpu_access;
  305. drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
  306. drm_atomic_for_each_plane_damage(&iter, &damage) {
  307. struct iosys_map dst = sysfb->fb_addr;
  308. struct drm_rect dst_clip = plane_state->dst;
  309. if (!drm_rect_intersect(&dst_clip, &damage))
  310. continue;
  311. iosys_map_incr(&dst, drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip));
  312. blit_to_crtc(&dst, &dst_pitch, shadow_plane_state->data, fb, &damage,
  313. &shadow_plane_state->fmtcnv_state);
  314. }
  315. drm_dev_exit(idx);
  316. out_drm_gem_fb_end_cpu_access:
  317. drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
  318. }
  319. EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_update);
  320. void drm_sysfb_plane_helper_atomic_disable(struct drm_plane *plane,
  321. struct drm_atomic_state *state)
  322. {
  323. struct drm_device *dev = plane->dev;
  324. struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
  325. struct iosys_map dst = sysfb->fb_addr;
  326. struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
  327. void __iomem *dst_vmap = dst.vaddr_iomem; /* TODO: Use mapping abstraction */
  328. unsigned int dst_pitch = sysfb->fb_pitch;
  329. const struct drm_format_info *dst_format = sysfb->fb_format;
  330. struct drm_rect dst_clip;
  331. unsigned long lines, linepixels, i;
  332. int idx;
  333. drm_rect_init(&dst_clip,
  334. plane_state->src_x >> 16, plane_state->src_y >> 16,
  335. plane_state->src_w >> 16, plane_state->src_h >> 16);
  336. lines = drm_rect_height(&dst_clip);
  337. linepixels = drm_rect_width(&dst_clip);
  338. if (!drm_dev_enter(dev, &idx))
  339. return;
  340. /* Clear buffer to black if disabled */
  341. dst_vmap += drm_fb_clip_offset(dst_pitch, dst_format, &dst_clip);
  342. for (i = 0; i < lines; ++i) {
  343. memset_io(dst_vmap, 0, linepixels * dst_format->cpp[0]);
  344. dst_vmap += dst_pitch;
  345. }
  346. drm_dev_exit(idx);
  347. }
  348. EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_disable);
  349. int drm_sysfb_plane_helper_get_scanout_buffer(struct drm_plane *plane,
  350. struct drm_scanout_buffer *sb)
  351. {
  352. struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
  353. sb->width = sysfb->fb_mode.hdisplay;
  354. sb->height = sysfb->fb_mode.vdisplay;
  355. sb->format = sysfb->fb_format;
  356. sb->pitch[0] = sysfb->fb_pitch;
  357. sb->map[0] = sysfb->fb_addr;
  358. return 0;
  359. }
  360. EXPORT_SYMBOL(drm_sysfb_plane_helper_get_scanout_buffer);
  361. void drm_sysfb_plane_reset(struct drm_plane *plane)
  362. {
  363. struct drm_sysfb_plane_state *sysfb_plane_state;
  364. if (plane->state)
  365. drm_sysfb_plane_state_destroy(to_drm_sysfb_plane_state(plane->state));
  366. sysfb_plane_state = kzalloc_obj(*sysfb_plane_state);
  367. if (sysfb_plane_state)
  368. __drm_gem_reset_shadow_plane(plane, &sysfb_plane_state->base);
  369. else
  370. __drm_gem_reset_shadow_plane(plane, NULL);
  371. }
  372. EXPORT_SYMBOL(drm_sysfb_plane_reset);
  373. struct drm_plane_state *drm_sysfb_plane_atomic_duplicate_state(struct drm_plane *plane)
  374. {
  375. struct drm_device *dev = plane->dev;
  376. struct drm_plane_state *plane_state = plane->state;
  377. struct drm_sysfb_plane_state *sysfb_plane_state;
  378. struct drm_sysfb_plane_state *new_sysfb_plane_state;
  379. struct drm_shadow_plane_state *new_shadow_plane_state;
  380. if (drm_WARN_ON(dev, !plane_state))
  381. return NULL;
  382. sysfb_plane_state = to_drm_sysfb_plane_state(plane_state);
  383. new_sysfb_plane_state = kzalloc_obj(*new_sysfb_plane_state);
  384. if (!new_sysfb_plane_state)
  385. return NULL;
  386. new_shadow_plane_state = &new_sysfb_plane_state->base;
  387. __drm_gem_duplicate_shadow_plane_state(plane, new_shadow_plane_state);
  388. new_sysfb_plane_state->blit_to_crtc = sysfb_plane_state->blit_to_crtc;
  389. return &new_shadow_plane_state->base;
  390. }
  391. EXPORT_SYMBOL(drm_sysfb_plane_atomic_duplicate_state);
  392. void drm_sysfb_plane_atomic_destroy_state(struct drm_plane *plane,
  393. struct drm_plane_state *plane_state)
  394. {
  395. drm_sysfb_plane_state_destroy(to_drm_sysfb_plane_state(plane_state));
  396. }
  397. EXPORT_SYMBOL(drm_sysfb_plane_atomic_destroy_state);
  398. /*
  399. * CRTC
  400. */
  401. static void drm_sysfb_crtc_state_destroy(struct drm_sysfb_crtc_state *sysfb_crtc_state)
  402. {
  403. __drm_atomic_helper_crtc_destroy_state(&sysfb_crtc_state->base);
  404. kfree(sysfb_crtc_state);
  405. }
  406. enum drm_mode_status drm_sysfb_crtc_helper_mode_valid(struct drm_crtc *crtc,
  407. const struct drm_display_mode *mode)
  408. {
  409. struct drm_sysfb_device *sysfb = to_drm_sysfb_device(crtc->dev);
  410. return drm_crtc_helper_mode_valid_fixed(crtc, mode, &sysfb->fb_mode);
  411. }
  412. EXPORT_SYMBOL(drm_sysfb_crtc_helper_mode_valid);
  413. int drm_sysfb_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
  414. {
  415. struct drm_device *dev = crtc->dev;
  416. struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev);
  417. struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
  418. int ret;
  419. if (!new_crtc_state->enable)
  420. return 0;
  421. ret = drm_atomic_helper_check_crtc_primary_plane(new_crtc_state);
  422. if (ret)
  423. return ret;
  424. if (new_crtc_state->color_mgmt_changed) {
  425. const size_t gamma_lut_length =
  426. sysfb->fb_gamma_lut_size * sizeof(struct drm_color_lut);
  427. const struct drm_property_blob *gamma_lut = new_crtc_state->gamma_lut;
  428. if (gamma_lut && (gamma_lut->length != gamma_lut_length)) {
  429. drm_dbg(dev, "Incorrect gamma_lut length %zu\n", gamma_lut->length);
  430. return -EINVAL;
  431. }
  432. }
  433. return 0;
  434. }
  435. EXPORT_SYMBOL(drm_sysfb_crtc_helper_atomic_check);
  436. void drm_sysfb_crtc_reset(struct drm_crtc *crtc)
  437. {
  438. struct drm_sysfb_device *sysfb = to_drm_sysfb_device(crtc->dev);
  439. struct drm_sysfb_crtc_state *sysfb_crtc_state;
  440. if (crtc->state)
  441. drm_sysfb_crtc_state_destroy(to_drm_sysfb_crtc_state(crtc->state));
  442. sysfb_crtc_state = kzalloc_obj(*sysfb_crtc_state);
  443. if (sysfb_crtc_state) {
  444. sysfb_crtc_state->format = sysfb->fb_format;
  445. __drm_atomic_helper_crtc_reset(crtc, &sysfb_crtc_state->base);
  446. } else {
  447. __drm_atomic_helper_crtc_reset(crtc, NULL);
  448. }
  449. }
  450. EXPORT_SYMBOL(drm_sysfb_crtc_reset);
  451. struct drm_crtc_state *drm_sysfb_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
  452. {
  453. struct drm_device *dev = crtc->dev;
  454. struct drm_crtc_state *crtc_state = crtc->state;
  455. struct drm_sysfb_crtc_state *new_sysfb_crtc_state;
  456. struct drm_sysfb_crtc_state *sysfb_crtc_state;
  457. if (drm_WARN_ON(dev, !crtc_state))
  458. return NULL;
  459. new_sysfb_crtc_state = kzalloc_obj(*new_sysfb_crtc_state);
  460. if (!new_sysfb_crtc_state)
  461. return NULL;
  462. sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state);
  463. __drm_atomic_helper_crtc_duplicate_state(crtc, &new_sysfb_crtc_state->base);
  464. new_sysfb_crtc_state->format = sysfb_crtc_state->format;
  465. return &new_sysfb_crtc_state->base;
  466. }
  467. EXPORT_SYMBOL(drm_sysfb_crtc_atomic_duplicate_state);
  468. void drm_sysfb_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
  469. {
  470. drm_sysfb_crtc_state_destroy(to_drm_sysfb_crtc_state(crtc_state));
  471. }
  472. EXPORT_SYMBOL(drm_sysfb_crtc_atomic_destroy_state);
  473. /*
  474. * Connector
  475. */
  476. static int drm_sysfb_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
  477. {
  478. struct drm_sysfb_device *sysfb = data;
  479. const u8 *edid = sysfb->edid;
  480. size_t off = block * EDID_LENGTH;
  481. size_t end = off + len;
  482. if (!edid)
  483. return -EINVAL;
  484. if (end > EDID_LENGTH)
  485. return -EINVAL;
  486. memcpy(buf, &edid[off], len);
  487. /*
  488. * We don't have EDID extensions available and reporting them
  489. * will upset DRM helpers. Thus clear the extension field and
  490. * update the checksum. Adding the extension flag to the checksum
  491. * does this.
  492. */
  493. buf[127] += buf[126];
  494. buf[126] = 0;
  495. return 0;
  496. }
  497. int drm_sysfb_connector_helper_get_modes(struct drm_connector *connector)
  498. {
  499. struct drm_sysfb_device *sysfb = to_drm_sysfb_device(connector->dev);
  500. const struct drm_edid *drm_edid;
  501. if (sysfb->edid) {
  502. drm_edid = drm_edid_read_custom(connector, drm_sysfb_get_edid_block, sysfb);
  503. drm_edid_connector_update(connector, drm_edid);
  504. drm_edid_free(drm_edid);
  505. }
  506. /* Return the fixed mode even with EDID */
  507. return drm_connector_helper_get_modes_fixed(connector, &sysfb->fb_mode);
  508. }
  509. EXPORT_SYMBOL(drm_sysfb_connector_helper_get_modes);