sde_wb.c 22 KB

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