sde_wb.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
  4. */
  5. #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
  6. #include <uapi/drm/sde_drm.h>
  7. #include "msm_kms.h"
  8. #include "sde_kms.h"
  9. #include "sde_wb.h"
  10. #include "sde_formats.h"
  11. /* maximum display mode resolution if not available from catalog */
  12. #define SDE_WB_MODE_MAX_WIDTH 4096
  13. #define SDE_WB_MODE_MAX_HEIGHT 4096
  14. /* Serialization lock for sde_wb_list */
  15. static DEFINE_MUTEX(sde_wb_list_lock);
  16. /* List of all writeback devices installed */
  17. static LIST_HEAD(sde_wb_list);
  18. /**
  19. * sde_wb_is_format_valid - check if given format/modifier is supported
  20. * @wb_dev: Pointer to writeback device
  21. * @pixel_format: Fourcc pixel format
  22. * @format_modifier: Format modifier
  23. * Returns: true if valid; false otherwise
  24. */
  25. static int sde_wb_is_format_valid(struct sde_wb_device *wb_dev,
  26. u32 pixel_format, u64 format_modifier)
  27. {
  28. const struct sde_format_extended *fmts = wb_dev->wb_cfg->format_list;
  29. int i;
  30. if (!fmts)
  31. return false;
  32. for (i = 0; fmts[i].fourcc_format; i++)
  33. if ((fmts[i].modifier == format_modifier) &&
  34. (fmts[i].fourcc_format == pixel_format))
  35. return true;
  36. return false;
  37. }
  38. enum drm_connector_status
  39. sde_wb_connector_detect(struct drm_connector *connector,
  40. bool force,
  41. void *display)
  42. {
  43. enum drm_connector_status rc = connector_status_unknown;
  44. SDE_DEBUG("\n");
  45. if (display)
  46. rc = ((struct sde_wb_device *)display)->detect_status;
  47. return rc;
  48. }
  49. int sde_wb_connector_get_modes(struct drm_connector *connector, void *display,
  50. const struct msm_resource_caps_info *avail_res)
  51. {
  52. struct sde_wb_device *wb_dev;
  53. int num_modes = 0;
  54. if (!connector || !display)
  55. return 0;
  56. wb_dev = display;
  57. SDE_DEBUG("\n");
  58. mutex_lock(&wb_dev->wb_lock);
  59. if (wb_dev->count_modes && wb_dev->modes) {
  60. struct drm_display_mode *mode;
  61. int i, ret;
  62. for (i = 0; i < wb_dev->count_modes; i++) {
  63. mode = drm_mode_create(connector->dev);
  64. if (!mode) {
  65. SDE_ERROR("failed to create mode\n");
  66. break;
  67. }
  68. ret = drm_mode_convert_umode(wb_dev->drm_dev, mode,
  69. &wb_dev->modes[i]);
  70. if (ret) {
  71. SDE_ERROR("failed to convert mode %d\n", ret);
  72. break;
  73. }
  74. drm_mode_probed_add(connector, mode);
  75. num_modes++;
  76. }
  77. } else {
  78. u32 max_width = (wb_dev->wb_cfg && wb_dev->wb_cfg->sblk) ?
  79. wb_dev->wb_cfg->sblk->maxlinewidth :
  80. SDE_WB_MODE_MAX_WIDTH;
  81. num_modes = drm_add_modes_noedid(connector, max_width,
  82. SDE_WB_MODE_MAX_HEIGHT);
  83. }
  84. mutex_unlock(&wb_dev->wb_lock);
  85. return num_modes;
  86. }
  87. struct drm_framebuffer *
  88. sde_wb_connector_state_get_output_fb(struct drm_connector_state *state)
  89. {
  90. if (!state || !state->connector ||
  91. (state->connector->connector_type !=
  92. DRM_MODE_CONNECTOR_VIRTUAL)) {
  93. SDE_ERROR("invalid params\n");
  94. return NULL;
  95. }
  96. SDE_DEBUG("\n");
  97. return sde_connector_get_out_fb(state);
  98. }
  99. int sde_wb_connector_state_get_output_roi(struct drm_connector_state *state,
  100. struct sde_rect *roi)
  101. {
  102. if (!state || !roi || !state->connector ||
  103. (state->connector->connector_type !=
  104. DRM_MODE_CONNECTOR_VIRTUAL)) {
  105. SDE_ERROR("invalid params\n");
  106. return -EINVAL;
  107. }
  108. SDE_DEBUG("\n");
  109. roi->x = sde_connector_get_property(state, CONNECTOR_PROP_DST_X);
  110. roi->y = sde_connector_get_property(state, CONNECTOR_PROP_DST_Y);
  111. roi->w = sde_connector_get_property(state, CONNECTOR_PROP_DST_W);
  112. roi->h = sde_connector_get_property(state, CONNECTOR_PROP_DST_H);
  113. return 0;
  114. }
  115. /**
  116. * sde_wb_connector_set_modes - set writeback modes and connection status
  117. * @wb_dev: Pointer to write back device
  118. * @count_modes: Count of modes
  119. * @modes: Pointer to writeback mode requested
  120. * @connected: Connection status requested
  121. * Returns: 0 if success; error code otherwise
  122. */
  123. static
  124. int sde_wb_connector_set_modes(struct sde_wb_device *wb_dev,
  125. u32 count_modes, struct drm_mode_modeinfo __user *modes,
  126. bool connected)
  127. {
  128. struct drm_mode_modeinfo *modeinfo = NULL;
  129. int ret = 0;
  130. int i;
  131. if (!wb_dev || !wb_dev->connector ||
  132. (wb_dev->connector->connector_type !=
  133. DRM_MODE_CONNECTOR_VIRTUAL)) {
  134. SDE_ERROR("invalid params\n");
  135. return -EINVAL;
  136. }
  137. SDE_DEBUG("\n");
  138. if (connected) {
  139. SDE_DEBUG("connect\n");
  140. if (!count_modes || !modes) {
  141. SDE_ERROR("invalid count_modes :%u and modes :%d\n",
  142. count_modes, !modes);
  143. return -EINVAL;
  144. }
  145. modeinfo = kcalloc(count_modes,
  146. sizeof(struct drm_mode_modeinfo),
  147. GFP_KERNEL);
  148. if (!modeinfo) {
  149. SDE_ERROR("invalid params\n");
  150. ret = -ENOMEM;
  151. goto error;
  152. }
  153. if (copy_from_user(modeinfo, modes,
  154. count_modes *
  155. sizeof(struct drm_mode_modeinfo))) {
  156. SDE_ERROR("failed to copy modes\n");
  157. kfree(modeinfo);
  158. ret = -EFAULT;
  159. goto error;
  160. }
  161. for (i = 0; i < count_modes; i++) {
  162. struct drm_display_mode dispmode;
  163. memset(&dispmode, 0, sizeof(dispmode));
  164. ret = drm_mode_convert_umode(wb_dev->drm_dev,
  165. &dispmode, &modeinfo[i]);
  166. if (ret) {
  167. SDE_ERROR(
  168. "failed to convert mode %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x status:%d rc:%d\n",
  169. i,
  170. modeinfo[i].name,
  171. modeinfo[i].vrefresh,
  172. modeinfo[i].clock,
  173. modeinfo[i].hdisplay,
  174. modeinfo[i].hsync_start,
  175. modeinfo[i].hsync_end,
  176. modeinfo[i].htotal,
  177. modeinfo[i].vdisplay,
  178. modeinfo[i].vsync_start,
  179. modeinfo[i].vsync_end,
  180. modeinfo[i].vtotal,
  181. modeinfo[i].type,
  182. modeinfo[i].flags,
  183. dispmode.status,
  184. ret);
  185. kfree(modeinfo);
  186. goto error;
  187. }
  188. }
  189. if (wb_dev->modes) {
  190. wb_dev->count_modes = 0;
  191. kfree(wb_dev->modes);
  192. wb_dev->modes = NULL;
  193. }
  194. wb_dev->count_modes = count_modes;
  195. wb_dev->modes = modeinfo;
  196. wb_dev->detect_status = connector_status_connected;
  197. } else {
  198. SDE_DEBUG("disconnect\n");
  199. if (wb_dev->modes) {
  200. wb_dev->count_modes = 0;
  201. kfree(wb_dev->modes);
  202. wb_dev->modes = NULL;
  203. }
  204. wb_dev->detect_status = connector_status_disconnected;
  205. }
  206. error:
  207. return ret;
  208. }
  209. int sde_wb_connector_set_property(struct drm_connector *connector,
  210. struct drm_connector_state *state,
  211. int property_index,
  212. uint64_t value,
  213. void *display)
  214. {
  215. struct sde_wb_device *wb_dev = display;
  216. struct drm_framebuffer *out_fb;
  217. int rc = 0;
  218. SDE_DEBUG("\n");
  219. if (state && (property_index == CONNECTOR_PROP_OUT_FB)) {
  220. const struct sde_format *sde_format;
  221. out_fb = sde_connector_get_out_fb(state);
  222. if (!out_fb)
  223. goto done;
  224. sde_format = sde_get_sde_format_ext(out_fb->format->format,
  225. out_fb->modifier);
  226. if (!sde_format) {
  227. SDE_ERROR("failed to get sde format\n");
  228. rc = -EINVAL;
  229. goto done;
  230. }
  231. if (!sde_wb_is_format_valid(wb_dev, out_fb->format->format,
  232. out_fb->modifier)) {
  233. SDE_ERROR("unsupported writeback format 0x%x/0x%llx\n",
  234. out_fb->format->format,
  235. out_fb->modifier);
  236. rc = -EINVAL;
  237. goto done;
  238. }
  239. }
  240. done:
  241. return rc;
  242. }
  243. int sde_wb_get_info(struct drm_connector *connector,
  244. struct msm_display_info *info, void *display)
  245. {
  246. struct sde_wb_device *wb_dev = display;
  247. if (!info || !wb_dev) {
  248. pr_err("invalid params\n");
  249. return -EINVAL;
  250. }
  251. memset(info, 0, sizeof(struct msm_display_info));
  252. info->intf_type = DRM_MODE_CONNECTOR_VIRTUAL;
  253. info->num_of_h_tiles = 1;
  254. info->h_tile_instance[0] = sde_wb_get_index(display);
  255. info->is_connected = true;
  256. info->capabilities = MSM_DISPLAY_CAP_HOT_PLUG | MSM_DISPLAY_CAP_EDID;
  257. info->max_width = (wb_dev->wb_cfg && wb_dev->wb_cfg->sblk) ?
  258. wb_dev->wb_cfg->sblk->maxlinewidth :
  259. SDE_WB_MODE_MAX_WIDTH;
  260. info->max_height = SDE_WB_MODE_MAX_HEIGHT;
  261. return 0;
  262. }
  263. int sde_wb_get_mode_info(struct drm_connector *connector,
  264. const struct drm_display_mode *drm_mode,
  265. struct msm_mode_info *mode_info,
  266. void *display, const struct msm_resource_caps_info *avail_res)
  267. {
  268. const u32 dual_lm = 2;
  269. const u32 single_lm = 1;
  270. const u32 single_intf = 1;
  271. const u32 no_enc = 0;
  272. struct msm_display_topology *topology;
  273. struct sde_wb_device *wb_dev = display;
  274. u16 hdisplay;
  275. int i;
  276. if (!drm_mode || !mode_info || !avail_res ||
  277. !avail_res->max_mixer_width || !display) {
  278. pr_err("invalid params\n");
  279. return -EINVAL;
  280. }
  281. hdisplay = drm_mode->hdisplay;
  282. /* find maximum display width to support */
  283. for (i = 0; i < wb_dev->count_modes; i++)
  284. hdisplay = max(hdisplay, wb_dev->modes[i].hdisplay);
  285. topology = &mode_info->topology;
  286. topology->num_lm = (avail_res->max_mixer_width <= hdisplay) ?
  287. dual_lm : single_lm;
  288. topology->num_enc = no_enc;
  289. topology->num_intf = single_intf;
  290. mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
  291. mode_info->wide_bus_en = false;
  292. mode_info->comp_info.comp_ratio = MSM_DISPLAY_COMPRESSION_RATIO_NONE;
  293. return 0;
  294. }
  295. int sde_wb_connector_set_info_blob(struct drm_connector *connector,
  296. void *info, void *display, struct msm_mode_info *mode_info)
  297. {
  298. struct sde_wb_device *wb_dev = display;
  299. const struct sde_format_extended *format_list;
  300. if (!connector || !info || !display || !wb_dev->wb_cfg) {
  301. SDE_ERROR("invalid params\n");
  302. return -EINVAL;
  303. }
  304. format_list = wb_dev->wb_cfg->format_list;
  305. /*
  306. * Populate info buffer
  307. */
  308. if (format_list) {
  309. sde_kms_info_start(info, "pixel_formats");
  310. while (format_list->fourcc_format) {
  311. sde_kms_info_append_format(info,
  312. format_list->fourcc_format,
  313. format_list->modifier);
  314. ++format_list;
  315. }
  316. sde_kms_info_stop(info);
  317. }
  318. sde_kms_info_add_keyint(info,
  319. "wb_intf_index",
  320. wb_dev->wb_idx - WB_0);
  321. sde_kms_info_add_keyint(info,
  322. "maxlinewidth",
  323. wb_dev->wb_cfg->sblk->maxlinewidth);
  324. sde_kms_info_start(info, "features");
  325. if (wb_dev->wb_cfg && (wb_dev->wb_cfg->features & BIT(SDE_WB_UBWC)))
  326. sde_kms_info_append(info, "wb_ubwc");
  327. sde_kms_info_stop(info);
  328. return 0;
  329. }
  330. int sde_wb_connector_post_init(struct drm_connector *connector, void *display)
  331. {
  332. struct sde_connector *c_conn;
  333. struct sde_wb_device *wb_dev = display;
  334. static const struct drm_prop_enum_list e_fb_translation_mode[] = {
  335. {SDE_DRM_FB_NON_SEC, "non_sec"},
  336. {SDE_DRM_FB_SEC, "sec"},
  337. };
  338. if (!connector || !display || !wb_dev->wb_cfg) {
  339. SDE_ERROR("invalid params\n");
  340. return -EINVAL;
  341. }
  342. c_conn = to_sde_connector(connector);
  343. wb_dev->connector = connector;
  344. wb_dev->detect_status = connector_status_connected;
  345. /*
  346. * Add extra connector properties
  347. */
  348. msm_property_install_range(&c_conn->property_info, "FB_ID",
  349. 0x0, 0, ~0, 0, CONNECTOR_PROP_OUT_FB);
  350. msm_property_install_range(&c_conn->property_info, "DST_X",
  351. 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_X);
  352. msm_property_install_range(&c_conn->property_info, "DST_Y",
  353. 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_Y);
  354. msm_property_install_range(&c_conn->property_info, "DST_W",
  355. 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_W);
  356. msm_property_install_range(&c_conn->property_info, "DST_H",
  357. 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_H);
  358. msm_property_install_enum(&c_conn->property_info,
  359. "fb_translation_mode",
  360. 0x0,
  361. 0, e_fb_translation_mode,
  362. ARRAY_SIZE(e_fb_translation_mode),
  363. CONNECTOR_PROP_FB_TRANSLATION_MODE);
  364. return 0;
  365. }
  366. struct drm_framebuffer *sde_wb_get_output_fb(struct sde_wb_device *wb_dev)
  367. {
  368. struct drm_framebuffer *fb;
  369. if (!wb_dev || !wb_dev->connector) {
  370. SDE_ERROR("invalid params\n");
  371. return NULL;
  372. }
  373. SDE_DEBUG("\n");
  374. mutex_lock(&wb_dev->wb_lock);
  375. fb = sde_wb_connector_state_get_output_fb(wb_dev->connector->state);
  376. mutex_unlock(&wb_dev->wb_lock);
  377. return fb;
  378. }
  379. int sde_wb_get_output_roi(struct sde_wb_device *wb_dev, struct sde_rect *roi)
  380. {
  381. int rc;
  382. if (!wb_dev || !wb_dev->connector || !roi) {
  383. SDE_ERROR("invalid params\n");
  384. return -EINVAL;
  385. }
  386. SDE_DEBUG("\n");
  387. mutex_lock(&wb_dev->wb_lock);
  388. rc = sde_wb_connector_state_get_output_roi(
  389. wb_dev->connector->state, roi);
  390. mutex_unlock(&wb_dev->wb_lock);
  391. return rc;
  392. }
  393. u32 sde_wb_get_num_of_displays(void)
  394. {
  395. u32 count = 0;
  396. struct sde_wb_device *wb_dev;
  397. SDE_DEBUG("\n");
  398. mutex_lock(&sde_wb_list_lock);
  399. list_for_each_entry(wb_dev, &sde_wb_list, wb_list) {
  400. count++;
  401. }
  402. mutex_unlock(&sde_wb_list_lock);
  403. return count;
  404. }
  405. int wb_display_get_displays(void **display_array, u32 max_display_count)
  406. {
  407. struct sde_wb_device *curr;
  408. int i = 0;
  409. SDE_DEBUG("\n");
  410. if (!display_array || !max_display_count) {
  411. if (!display_array)
  412. SDE_ERROR("invalid param\n");
  413. return 0;
  414. }
  415. mutex_lock(&sde_wb_list_lock);
  416. list_for_each_entry(curr, &sde_wb_list, wb_list) {
  417. if (i >= max_display_count)
  418. break;
  419. display_array[i++] = curr;
  420. }
  421. mutex_unlock(&sde_wb_list_lock);
  422. return i;
  423. }
  424. int sde_wb_config(struct drm_device *drm_dev, void *data,
  425. struct drm_file *file_priv)
  426. {
  427. struct sde_drm_wb_cfg *config = data;
  428. struct msm_drm_private *priv;
  429. struct sde_wb_device *wb_dev = NULL;
  430. struct sde_wb_device *curr;
  431. struct drm_connector *connector;
  432. uint32_t flags;
  433. uint32_t connector_id;
  434. uint32_t count_modes;
  435. uint64_t modes;
  436. int rc;
  437. if (!drm_dev || !data) {
  438. SDE_ERROR("invalid params\n");
  439. return -EINVAL;
  440. }
  441. SDE_DEBUG("\n");
  442. flags = config->flags;
  443. connector_id = config->connector_id;
  444. count_modes = config->count_modes;
  445. modes = config->modes;
  446. priv = drm_dev->dev_private;
  447. connector = drm_connector_lookup(drm_dev, file_priv, connector_id);
  448. if (!connector) {
  449. SDE_ERROR("failed to find connector\n");
  450. rc = -ENOENT;
  451. goto fail;
  452. }
  453. mutex_lock(&sde_wb_list_lock);
  454. list_for_each_entry(curr, &sde_wb_list, wb_list) {
  455. if (curr->connector == connector) {
  456. wb_dev = curr;
  457. break;
  458. }
  459. }
  460. mutex_unlock(&sde_wb_list_lock);
  461. if (!wb_dev) {
  462. SDE_ERROR("failed to find wb device\n");
  463. rc = -ENOENT;
  464. goto fail;
  465. }
  466. mutex_lock(&wb_dev->wb_lock);
  467. rc = sde_wb_connector_set_modes(wb_dev, count_modes,
  468. (struct drm_mode_modeinfo __user *) (uintptr_t) modes,
  469. (flags & SDE_DRM_WB_CFG_FLAGS_CONNECTED) ? true : false);
  470. mutex_unlock(&wb_dev->wb_lock);
  471. drm_helper_hpd_irq_event(drm_dev);
  472. fail:
  473. return rc;
  474. }
  475. /**
  476. * _sde_wb_dev_init - perform device initialization
  477. * @wb_dev: Pointer to writeback device
  478. */
  479. static int _sde_wb_dev_init(struct sde_wb_device *wb_dev)
  480. {
  481. int rc = 0;
  482. if (!wb_dev) {
  483. SDE_ERROR("invalid params\n");
  484. return -EINVAL;
  485. }
  486. SDE_DEBUG("\n");
  487. return rc;
  488. }
  489. /**
  490. * _sde_wb_dev_deinit - perform device de-initialization
  491. * @wb_dev: Pointer to writeback device
  492. */
  493. static int _sde_wb_dev_deinit(struct sde_wb_device *wb_dev)
  494. {
  495. int rc = 0;
  496. if (!wb_dev) {
  497. SDE_ERROR("invalid params\n");
  498. return -EINVAL;
  499. }
  500. SDE_DEBUG("\n");
  501. return rc;
  502. }
  503. /**
  504. * sde_wb_bind - bind writeback device with controlling device
  505. * @dev: Pointer to base of platform device
  506. * @master: Pointer to container of drm device
  507. * @data: Pointer to private data
  508. * Returns: Zero on success
  509. */
  510. static int sde_wb_bind(struct device *dev, struct device *master, void *data)
  511. {
  512. struct sde_wb_device *wb_dev;
  513. if (!dev || !master) {
  514. SDE_ERROR("invalid params\n");
  515. return -EINVAL;
  516. }
  517. wb_dev = platform_get_drvdata(to_platform_device(dev));
  518. if (!wb_dev) {
  519. SDE_ERROR("invalid wb device\n");
  520. return -EINVAL;
  521. }
  522. SDE_DEBUG("\n");
  523. mutex_lock(&wb_dev->wb_lock);
  524. wb_dev->drm_dev = dev_get_drvdata(master);
  525. mutex_unlock(&wb_dev->wb_lock);
  526. return 0;
  527. }
  528. /**
  529. * sde_wb_unbind - unbind writeback from controlling device
  530. * @dev: Pointer to base of platform device
  531. * @master: Pointer to container of drm device
  532. * @data: Pointer to private data
  533. */
  534. static void sde_wb_unbind(struct device *dev,
  535. struct device *master, void *data)
  536. {
  537. struct sde_wb_device *wb_dev;
  538. if (!dev) {
  539. SDE_ERROR("invalid params\n");
  540. return;
  541. }
  542. wb_dev = platform_get_drvdata(to_platform_device(dev));
  543. if (!wb_dev) {
  544. SDE_ERROR("invalid wb device\n");
  545. return;
  546. }
  547. SDE_DEBUG("\n");
  548. mutex_lock(&wb_dev->wb_lock);
  549. wb_dev->drm_dev = NULL;
  550. mutex_unlock(&wb_dev->wb_lock);
  551. }
  552. static const struct component_ops sde_wb_comp_ops = {
  553. .bind = sde_wb_bind,
  554. .unbind = sde_wb_unbind,
  555. };
  556. /**
  557. * sde_wb_drm_init - perform DRM initialization
  558. * @wb_dev: Pointer to writeback device
  559. * @encoder: Pointer to associated encoder
  560. */
  561. int sde_wb_drm_init(struct sde_wb_device *wb_dev, struct drm_encoder *encoder)
  562. {
  563. int rc = 0;
  564. if (!wb_dev || !wb_dev->drm_dev || !encoder) {
  565. SDE_ERROR("invalid params\n");
  566. return -EINVAL;
  567. }
  568. SDE_DEBUG("\n");
  569. mutex_lock(&wb_dev->wb_lock);
  570. if (wb_dev->drm_dev->dev_private) {
  571. struct msm_drm_private *priv = wb_dev->drm_dev->dev_private;
  572. struct sde_kms *sde_kms = to_sde_kms(priv->kms);
  573. if (wb_dev->index < sde_kms->catalog->wb_count) {
  574. wb_dev->wb_idx = sde_kms->catalog->wb[wb_dev->index].id;
  575. wb_dev->wb_cfg = &sde_kms->catalog->wb[wb_dev->index];
  576. }
  577. }
  578. wb_dev->drm_dev = encoder->dev;
  579. wb_dev->encoder = encoder;
  580. mutex_unlock(&wb_dev->wb_lock);
  581. return rc;
  582. }
  583. int sde_wb_drm_deinit(struct sde_wb_device *wb_dev)
  584. {
  585. int rc = 0;
  586. if (!wb_dev) {
  587. SDE_ERROR("invalid params\n");
  588. return -EINVAL;
  589. }
  590. SDE_DEBUG("\n");
  591. return rc;
  592. }
  593. /**
  594. * sde_wb_probe - load writeback module
  595. * @pdev: Pointer to platform device
  596. */
  597. static int sde_wb_probe(struct platform_device *pdev)
  598. {
  599. struct sde_wb_device *wb_dev;
  600. int ret;
  601. wb_dev = devm_kzalloc(&pdev->dev, sizeof(*wb_dev), GFP_KERNEL);
  602. if (!wb_dev)
  603. return -ENOMEM;
  604. SDE_DEBUG("\n");
  605. ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
  606. &wb_dev->index);
  607. if (ret) {
  608. SDE_DEBUG("cell index not set, default to 0\n");
  609. wb_dev->index = 0;
  610. }
  611. wb_dev->name = of_get_property(pdev->dev.of_node, "label", NULL);
  612. if (!wb_dev->name) {
  613. SDE_DEBUG("label not set, default to unknown\n");
  614. wb_dev->name = "unknown";
  615. }
  616. wb_dev->wb_idx = SDE_NONE;
  617. mutex_init(&wb_dev->wb_lock);
  618. platform_set_drvdata(pdev, wb_dev);
  619. mutex_lock(&sde_wb_list_lock);
  620. list_add(&wb_dev->wb_list, &sde_wb_list);
  621. mutex_unlock(&sde_wb_list_lock);
  622. if (!_sde_wb_dev_init(wb_dev)) {
  623. ret = component_add(&pdev->dev, &sde_wb_comp_ops);
  624. if (ret)
  625. pr_err("component add failed\n");
  626. }
  627. return ret;
  628. }
  629. /**
  630. * sde_wb_remove - unload writeback module
  631. * @pdev: Pointer to platform device
  632. */
  633. static int sde_wb_remove(struct platform_device *pdev)
  634. {
  635. struct sde_wb_device *wb_dev;
  636. struct sde_wb_device *curr, *next;
  637. wb_dev = platform_get_drvdata(pdev);
  638. if (!wb_dev)
  639. return 0;
  640. SDE_DEBUG("\n");
  641. (void)_sde_wb_dev_deinit(wb_dev);
  642. mutex_lock(&sde_wb_list_lock);
  643. list_for_each_entry_safe(curr, next, &sde_wb_list, wb_list) {
  644. if (curr == wb_dev) {
  645. list_del(&wb_dev->wb_list);
  646. break;
  647. }
  648. }
  649. mutex_unlock(&sde_wb_list_lock);
  650. kfree(wb_dev->modes);
  651. mutex_destroy(&wb_dev->wb_lock);
  652. platform_set_drvdata(pdev, NULL);
  653. devm_kfree(&pdev->dev, wb_dev);
  654. return 0;
  655. }
  656. static const struct of_device_id dt_match[] = {
  657. { .compatible = "qcom,wb-display"},
  658. {}
  659. };
  660. static struct platform_driver sde_wb_driver = {
  661. .probe = sde_wb_probe,
  662. .remove = sde_wb_remove,
  663. .driver = {
  664. .name = "sde_wb",
  665. .of_match_table = dt_match,
  666. .suppress_bind_attrs = true,
  667. },
  668. };
  669. static int __init sde_wb_register(void)
  670. {
  671. return platform_driver_register(&sde_wb_driver);
  672. }
  673. static void __exit sde_wb_unregister(void)
  674. {
  675. platform_driver_unregister(&sde_wb_driver);
  676. }
  677. module_init(sde_wb_register);
  678. module_exit(sde_wb_unregister);