sde_wb.c 19 KB

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