sde_wb.c 18 KB

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