dp_link.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
  4. */
  5. #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
  6. #include <drm/drm_print.h>
  7. #include "dp_reg.h"
  8. #include "dp_link.h"
  9. #include "dp_panel.h"
  10. #define DP_TEST_REQUEST_MASK 0x7F
  11. enum audio_sample_rate {
  12. AUDIO_SAMPLE_RATE_32_KHZ = 0x00,
  13. AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01,
  14. AUDIO_SAMPLE_RATE_48_KHZ = 0x02,
  15. AUDIO_SAMPLE_RATE_88_2_KHZ = 0x03,
  16. AUDIO_SAMPLE_RATE_96_KHZ = 0x04,
  17. AUDIO_SAMPLE_RATE_176_4_KHZ = 0x05,
  18. AUDIO_SAMPLE_RATE_192_KHZ = 0x06,
  19. };
  20. enum audio_pattern_type {
  21. AUDIO_TEST_PATTERN_OPERATOR_DEFINED = 0x00,
  22. AUDIO_TEST_PATTERN_SAWTOOTH = 0x01,
  23. };
  24. struct dp_link_request {
  25. u32 test_requested;
  26. u32 test_link_rate;
  27. u32 test_lane_count;
  28. };
  29. struct dp_link_private {
  30. u32 prev_sink_count;
  31. struct drm_device *drm_dev;
  32. struct drm_dp_aux *aux;
  33. struct dp_link dp_link;
  34. struct dp_link_request request;
  35. struct mutex psm_mutex;
  36. u8 link_status[DP_LINK_STATUS_SIZE];
  37. };
  38. static int dp_aux_link_power_up(struct drm_dp_aux *aux,
  39. struct dp_link_info *link)
  40. {
  41. u8 value;
  42. ssize_t len;
  43. int i;
  44. if (link->revision < 0x11)
  45. return 0;
  46. len = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
  47. if (len < 0)
  48. return len;
  49. value &= ~DP_SET_POWER_MASK;
  50. value |= DP_SET_POWER_D0;
  51. /* retry for 1ms to give the sink time to wake up */
  52. for (i = 0; i < 3; i++) {
  53. len = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
  54. usleep_range(1000, 2000);
  55. if (len == 1)
  56. break;
  57. }
  58. return 0;
  59. }
  60. static int dp_aux_link_power_down(struct drm_dp_aux *aux,
  61. struct dp_link_info *link)
  62. {
  63. u8 value;
  64. int err;
  65. if (link->revision < 0x11)
  66. return 0;
  67. err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
  68. if (err < 0)
  69. return err;
  70. value &= ~DP_SET_POWER_MASK;
  71. value |= DP_SET_POWER_D3;
  72. err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
  73. if (err < 0)
  74. return err;
  75. return 0;
  76. }
  77. static int dp_link_get_period(struct dp_link_private *link, int const addr)
  78. {
  79. int ret = 0;
  80. u8 data;
  81. u32 const max_audio_period = 0xA;
  82. /* TEST_AUDIO_PERIOD_CH_XX */
  83. if (drm_dp_dpcd_readb(link->aux, addr, &data) < 0) {
  84. DRM_ERROR("failed to read test_audio_period (0x%x)\n", addr);
  85. ret = -EINVAL;
  86. goto exit;
  87. }
  88. /* Period - Bits 3:0 */
  89. data = data & 0xF;
  90. if ((int)data > max_audio_period) {
  91. DRM_ERROR("invalid test_audio_period_ch_1 = 0x%x\n", data);
  92. ret = -EINVAL;
  93. goto exit;
  94. }
  95. ret = data;
  96. exit:
  97. return ret;
  98. }
  99. static int dp_link_parse_audio_channel_period(struct dp_link_private *link)
  100. {
  101. int ret = 0;
  102. struct dp_link_test_audio *req = &link->dp_link.test_audio;
  103. ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1);
  104. if (ret == -EINVAL)
  105. goto exit;
  106. req->test_audio_period_ch_1 = ret;
  107. drm_dbg_dp(link->drm_dev, "test_audio_period_ch_1 = 0x%x\n", ret);
  108. ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2);
  109. if (ret == -EINVAL)
  110. goto exit;
  111. req->test_audio_period_ch_2 = ret;
  112. drm_dbg_dp(link->drm_dev, "test_audio_period_ch_2 = 0x%x\n", ret);
  113. /* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */
  114. ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3);
  115. if (ret == -EINVAL)
  116. goto exit;
  117. req->test_audio_period_ch_3 = ret;
  118. drm_dbg_dp(link->drm_dev, "test_audio_period_ch_3 = 0x%x\n", ret);
  119. ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4);
  120. if (ret == -EINVAL)
  121. goto exit;
  122. req->test_audio_period_ch_4 = ret;
  123. drm_dbg_dp(link->drm_dev, "test_audio_period_ch_4 = 0x%x\n", ret);
  124. ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5);
  125. if (ret == -EINVAL)
  126. goto exit;
  127. req->test_audio_period_ch_5 = ret;
  128. drm_dbg_dp(link->drm_dev, "test_audio_period_ch_5 = 0x%x\n", ret);
  129. ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6);
  130. if (ret == -EINVAL)
  131. goto exit;
  132. req->test_audio_period_ch_6 = ret;
  133. drm_dbg_dp(link->drm_dev, "test_audio_period_ch_6 = 0x%x\n", ret);
  134. ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7);
  135. if (ret == -EINVAL)
  136. goto exit;
  137. req->test_audio_period_ch_7 = ret;
  138. drm_dbg_dp(link->drm_dev, "test_audio_period_ch_7 = 0x%x\n", ret);
  139. ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8);
  140. if (ret == -EINVAL)
  141. goto exit;
  142. req->test_audio_period_ch_8 = ret;
  143. drm_dbg_dp(link->drm_dev, "test_audio_period_ch_8 = 0x%x\n", ret);
  144. exit:
  145. return ret;
  146. }
  147. static int dp_link_parse_audio_pattern_type(struct dp_link_private *link)
  148. {
  149. int ret = 0;
  150. u8 data;
  151. ssize_t rlen;
  152. int const max_audio_pattern_type = 0x1;
  153. rlen = drm_dp_dpcd_readb(link->aux,
  154. DP_TEST_AUDIO_PATTERN_TYPE, &data);
  155. if (rlen < 0) {
  156. DRM_ERROR("failed to read link audio mode. rlen=%zd\n", rlen);
  157. return rlen;
  158. }
  159. /* Audio Pattern Type - Bits 7:0 */
  160. if ((int)data > max_audio_pattern_type) {
  161. DRM_ERROR("invalid audio pattern type = 0x%x\n", data);
  162. ret = -EINVAL;
  163. goto exit;
  164. }
  165. link->dp_link.test_audio.test_audio_pattern_type = data;
  166. drm_dbg_dp(link->drm_dev, "audio pattern type = 0x%x\n", data);
  167. exit:
  168. return ret;
  169. }
  170. static int dp_link_parse_audio_mode(struct dp_link_private *link)
  171. {
  172. int ret = 0;
  173. u8 data;
  174. ssize_t rlen;
  175. int const max_audio_sampling_rate = 0x6;
  176. int const max_audio_channel_count = 0x8;
  177. int sampling_rate = 0x0;
  178. int channel_count = 0x0;
  179. rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_AUDIO_MODE, &data);
  180. if (rlen < 0) {
  181. DRM_ERROR("failed to read link audio mode. rlen=%zd\n", rlen);
  182. return rlen;
  183. }
  184. /* Sampling Rate - Bits 3:0 */
  185. sampling_rate = data & 0xF;
  186. if (sampling_rate > max_audio_sampling_rate) {
  187. DRM_ERROR("sampling rate (0x%x) greater than max (0x%x)\n",
  188. sampling_rate, max_audio_sampling_rate);
  189. ret = -EINVAL;
  190. goto exit;
  191. }
  192. /* Channel Count - Bits 7:4 */
  193. channel_count = ((data & 0xF0) >> 4) + 1;
  194. if (channel_count > max_audio_channel_count) {
  195. DRM_ERROR("channel_count (0x%x) greater than max (0x%x)\n",
  196. channel_count, max_audio_channel_count);
  197. ret = -EINVAL;
  198. goto exit;
  199. }
  200. link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate;
  201. link->dp_link.test_audio.test_audio_channel_count = channel_count;
  202. drm_dbg_dp(link->drm_dev,
  203. "sampling_rate = 0x%x, channel_count = 0x%x\n",
  204. sampling_rate, channel_count);
  205. exit:
  206. return ret;
  207. }
  208. static int dp_link_parse_audio_pattern_params(struct dp_link_private *link)
  209. {
  210. int ret = 0;
  211. ret = dp_link_parse_audio_mode(link);
  212. if (ret)
  213. goto exit;
  214. ret = dp_link_parse_audio_pattern_type(link);
  215. if (ret)
  216. goto exit;
  217. ret = dp_link_parse_audio_channel_period(link);
  218. exit:
  219. return ret;
  220. }
  221. static bool dp_link_is_video_pattern_valid(u32 pattern)
  222. {
  223. switch (pattern) {
  224. case DP_NO_TEST_PATTERN:
  225. case DP_COLOR_RAMP:
  226. case DP_BLACK_AND_WHITE_VERTICAL_LINES:
  227. case DP_COLOR_SQUARE:
  228. return true;
  229. default:
  230. return false;
  231. }
  232. }
  233. /**
  234. * dp_link_is_bit_depth_valid() - validates the bit depth requested
  235. * @tbd: bit depth requested by the sink
  236. *
  237. * Returns true if the requested bit depth is supported.
  238. */
  239. static bool dp_link_is_bit_depth_valid(u32 tbd)
  240. {
  241. /* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */
  242. switch (tbd) {
  243. case DP_TEST_BIT_DEPTH_6:
  244. case DP_TEST_BIT_DEPTH_8:
  245. case DP_TEST_BIT_DEPTH_10:
  246. return true;
  247. default:
  248. return false;
  249. }
  250. }
  251. static int dp_link_parse_timing_params1(struct dp_link_private *link,
  252. int addr, int len, u32 *val)
  253. {
  254. u8 bp[2];
  255. int rlen;
  256. if (len != 2)
  257. return -EINVAL;
  258. /* Read the requested video link pattern (Byte 0x221). */
  259. rlen = drm_dp_dpcd_read(link->aux, addr, bp, len);
  260. if (rlen < len) {
  261. DRM_ERROR("failed to read 0x%x\n", addr);
  262. return -EINVAL;
  263. }
  264. *val = bp[1] | (bp[0] << 8);
  265. return 0;
  266. }
  267. static int dp_link_parse_timing_params2(struct dp_link_private *link,
  268. int addr, int len,
  269. u32 *val1, u32 *val2)
  270. {
  271. u8 bp[2];
  272. int rlen;
  273. if (len != 2)
  274. return -EINVAL;
  275. /* Read the requested video link pattern (Byte 0x221). */
  276. rlen = drm_dp_dpcd_read(link->aux, addr, bp, len);
  277. if (rlen < len) {
  278. DRM_ERROR("failed to read 0x%x\n", addr);
  279. return -EINVAL;
  280. }
  281. *val1 = (bp[0] & BIT(7)) >> 7;
  282. *val2 = bp[1] | ((bp[0] & 0x7F) << 8);
  283. return 0;
  284. }
  285. static int dp_link_parse_timing_params3(struct dp_link_private *link,
  286. int addr, u32 *val)
  287. {
  288. u8 bp;
  289. u32 len = 1;
  290. int rlen;
  291. rlen = drm_dp_dpcd_read(link->aux, addr, &bp, len);
  292. if (rlen < 1) {
  293. DRM_ERROR("failed to read 0x%x\n", addr);
  294. return -EINVAL;
  295. }
  296. *val = bp;
  297. return 0;
  298. }
  299. /**
  300. * dp_link_parse_video_pattern_params() - parses video pattern parameters from DPCD
  301. * @link: Display Port Driver data
  302. *
  303. * Returns 0 if it successfully parses the video link pattern and the link
  304. * bit depth requested by the sink and, and if the values parsed are valid.
  305. */
  306. static int dp_link_parse_video_pattern_params(struct dp_link_private *link)
  307. {
  308. int ret = 0;
  309. ssize_t rlen;
  310. u8 bp;
  311. rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_PATTERN, &bp);
  312. if (rlen < 0) {
  313. DRM_ERROR("failed to read link video pattern. rlen=%zd\n",
  314. rlen);
  315. return rlen;
  316. }
  317. if (!dp_link_is_video_pattern_valid(bp)) {
  318. DRM_ERROR("invalid link video pattern = 0x%x\n", bp);
  319. ret = -EINVAL;
  320. return ret;
  321. }
  322. link->dp_link.test_video.test_video_pattern = bp;
  323. /* Read the requested color bit depth and dynamic range (Byte 0x232) */
  324. rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_MISC0, &bp);
  325. if (rlen < 0) {
  326. DRM_ERROR("failed to read link bit depth. rlen=%zd\n", rlen);
  327. return rlen;
  328. }
  329. /* Dynamic Range */
  330. link->dp_link.test_video.test_dyn_range =
  331. (bp & DP_TEST_DYNAMIC_RANGE_CEA);
  332. /* Color bit depth */
  333. bp &= DP_TEST_BIT_DEPTH_MASK;
  334. if (!dp_link_is_bit_depth_valid(bp)) {
  335. DRM_ERROR("invalid link bit depth = 0x%x\n", bp);
  336. ret = -EINVAL;
  337. return ret;
  338. }
  339. link->dp_link.test_video.test_bit_depth = bp;
  340. /* resolution timing params */
  341. ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2,
  342. &link->dp_link.test_video.test_h_total);
  343. if (ret) {
  344. DRM_ERROR("failed to parse test_htotal(DP_TEST_H_TOTAL_HI)\n");
  345. return ret;
  346. }
  347. ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2,
  348. &link->dp_link.test_video.test_v_total);
  349. if (ret) {
  350. DRM_ERROR("failed to parse test_v_total(DP_TEST_V_TOTAL_HI)\n");
  351. return ret;
  352. }
  353. ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2,
  354. &link->dp_link.test_video.test_h_start);
  355. if (ret) {
  356. DRM_ERROR("failed to parse test_h_start(DP_TEST_H_START_HI)\n");
  357. return ret;
  358. }
  359. ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2,
  360. &link->dp_link.test_video.test_v_start);
  361. if (ret) {
  362. DRM_ERROR("failed to parse test_v_start(DP_TEST_V_START_HI)\n");
  363. return ret;
  364. }
  365. ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2,
  366. &link->dp_link.test_video.test_hsync_pol,
  367. &link->dp_link.test_video.test_hsync_width);
  368. if (ret) {
  369. DRM_ERROR("failed to parse (DP_TEST_HSYNC_HI)\n");
  370. return ret;
  371. }
  372. ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2,
  373. &link->dp_link.test_video.test_vsync_pol,
  374. &link->dp_link.test_video.test_vsync_width);
  375. if (ret) {
  376. DRM_ERROR("failed to parse (DP_TEST_VSYNC_HI)\n");
  377. return ret;
  378. }
  379. ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2,
  380. &link->dp_link.test_video.test_h_width);
  381. if (ret) {
  382. DRM_ERROR("failed to parse test_h_width(DP_TEST_H_WIDTH_HI)\n");
  383. return ret;
  384. }
  385. ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2,
  386. &link->dp_link.test_video.test_v_height);
  387. if (ret) {
  388. DRM_ERROR("failed to parse test_v_height\n");
  389. return ret;
  390. }
  391. ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1,
  392. &link->dp_link.test_video.test_rr_d);
  393. link->dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR;
  394. if (ret) {
  395. DRM_ERROR("failed to parse test_rr_d (DP_TEST_MISC1)\n");
  396. return ret;
  397. }
  398. ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR,
  399. &link->dp_link.test_video.test_rr_n);
  400. if (ret) {
  401. DRM_ERROR("failed to parse test_rr_n\n");
  402. return ret;
  403. }
  404. drm_dbg_dp(link->drm_dev,
  405. "link video pattern = 0x%x\n"
  406. "link dynamic range = 0x%x\n"
  407. "link bit depth = 0x%x\n"
  408. "TEST_H_TOTAL = %d, TEST_V_TOTAL = %d\n"
  409. "TEST_H_START = %d, TEST_V_START = %d\n"
  410. "TEST_HSYNC_POL = %d\n"
  411. "TEST_HSYNC_WIDTH = %d\n"
  412. "TEST_VSYNC_POL = %d\n"
  413. "TEST_VSYNC_WIDTH = %d\n"
  414. "TEST_H_WIDTH = %d\n"
  415. "TEST_V_HEIGHT = %d\n"
  416. "TEST_REFRESH_DENOMINATOR = %d\n"
  417. "TEST_REFRESH_NUMERATOR = %d\n",
  418. link->dp_link.test_video.test_video_pattern,
  419. link->dp_link.test_video.test_dyn_range,
  420. link->dp_link.test_video.test_bit_depth,
  421. link->dp_link.test_video.test_h_total,
  422. link->dp_link.test_video.test_v_total,
  423. link->dp_link.test_video.test_h_start,
  424. link->dp_link.test_video.test_v_start,
  425. link->dp_link.test_video.test_hsync_pol,
  426. link->dp_link.test_video.test_hsync_width,
  427. link->dp_link.test_video.test_vsync_pol,
  428. link->dp_link.test_video.test_vsync_width,
  429. link->dp_link.test_video.test_h_width,
  430. link->dp_link.test_video.test_v_height,
  431. link->dp_link.test_video.test_rr_d,
  432. link->dp_link.test_video.test_rr_n);
  433. return ret;
  434. }
  435. /**
  436. * dp_link_parse_link_training_params() - parses link training parameters from
  437. * DPCD
  438. * @link: Display Port Driver data
  439. *
  440. * Returns 0 if it successfully parses the link rate (Byte 0x219) and lane
  441. * count (Byte 0x220), and if these values parse are valid.
  442. */
  443. static int dp_link_parse_link_training_params(struct dp_link_private *link)
  444. {
  445. u8 bp;
  446. ssize_t rlen;
  447. rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_LINK_RATE, &bp);
  448. if (rlen < 0) {
  449. DRM_ERROR("failed to read link rate. rlen=%zd\n", rlen);
  450. return rlen;
  451. }
  452. if (!is_link_rate_valid(bp)) {
  453. DRM_ERROR("invalid link rate = 0x%x\n", bp);
  454. return -EINVAL;
  455. }
  456. link->request.test_link_rate = bp;
  457. drm_dbg_dp(link->drm_dev, "link rate = 0x%x\n",
  458. link->request.test_link_rate);
  459. rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_LANE_COUNT, &bp);
  460. if (rlen < 0) {
  461. DRM_ERROR("failed to read lane count. rlen=%zd\n", rlen);
  462. return rlen;
  463. }
  464. bp &= DP_MAX_LANE_COUNT_MASK;
  465. if (!is_lane_count_valid(bp)) {
  466. DRM_ERROR("invalid lane count = 0x%x\n", bp);
  467. return -EINVAL;
  468. }
  469. link->request.test_lane_count = bp;
  470. drm_dbg_dp(link->drm_dev, "lane count = 0x%x\n",
  471. link->request.test_lane_count);
  472. return 0;
  473. }
  474. /**
  475. * dp_link_parse_phy_test_params() - parses the phy link parameters
  476. * @link: Display Port Driver data
  477. *
  478. * Parses the DPCD (Byte 0x248) for the DP PHY link pattern that is being
  479. * requested.
  480. */
  481. static int dp_link_parse_phy_test_params(struct dp_link_private *link)
  482. {
  483. u8 data;
  484. ssize_t rlen;
  485. rlen = drm_dp_dpcd_readb(link->aux, DP_PHY_TEST_PATTERN,
  486. &data);
  487. if (rlen < 0) {
  488. DRM_ERROR("failed to read phy link pattern. rlen=%zd\n", rlen);
  489. return rlen;
  490. }
  491. link->dp_link.phy_params.phy_test_pattern_sel = data & 0x07;
  492. drm_dbg_dp(link->drm_dev, "phy_test_pattern_sel = 0x%x\n", data);
  493. switch (data) {
  494. case DP_PHY_TEST_PATTERN_SEL_MASK:
  495. case DP_PHY_TEST_PATTERN_NONE:
  496. case DP_PHY_TEST_PATTERN_D10_2:
  497. case DP_PHY_TEST_PATTERN_ERROR_COUNT:
  498. case DP_PHY_TEST_PATTERN_PRBS7:
  499. case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:
  500. case DP_PHY_TEST_PATTERN_CP2520:
  501. return 0;
  502. default:
  503. return -EINVAL;
  504. }
  505. }
  506. /**
  507. * dp_link_is_video_audio_test_requested() - checks for audio/video link request
  508. * @link: link requested by the sink
  509. *
  510. * Returns true if the requested link is a permitted audio/video link.
  511. */
  512. static bool dp_link_is_video_audio_test_requested(u32 link)
  513. {
  514. u8 video_audio_test = (DP_TEST_LINK_VIDEO_PATTERN |
  515. DP_TEST_LINK_AUDIO_PATTERN |
  516. DP_TEST_LINK_AUDIO_DISABLED_VIDEO);
  517. return ((link & video_audio_test) &&
  518. !(link & ~video_audio_test));
  519. }
  520. /**
  521. * dp_link_parse_request() - parses link request parameters from sink
  522. * @link: Display Port Driver data
  523. *
  524. * Parses the DPCD to check if an automated link is requested (Byte 0x201),
  525. * and what type of link automation is being requested (Byte 0x218).
  526. */
  527. static int dp_link_parse_request(struct dp_link_private *link)
  528. {
  529. int ret = 0;
  530. u8 data;
  531. ssize_t rlen;
  532. /**
  533. * Read the device service IRQ vector (Byte 0x201) to determine
  534. * whether an automated link has been requested by the sink.
  535. */
  536. rlen = drm_dp_dpcd_readb(link->aux,
  537. DP_DEVICE_SERVICE_IRQ_VECTOR, &data);
  538. if (rlen < 0) {
  539. DRM_ERROR("aux read failed. rlen=%zd\n", rlen);
  540. return rlen;
  541. }
  542. drm_dbg_dp(link->drm_dev, "device service irq vector = 0x%x\n", data);
  543. if (!(data & DP_AUTOMATED_TEST_REQUEST)) {
  544. drm_dbg_dp(link->drm_dev, "no test requested\n");
  545. return 0;
  546. }
  547. /**
  548. * Read the link request byte (Byte 0x218) to determine what type
  549. * of automated link has been requested by the sink.
  550. */
  551. rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_REQUEST, &data);
  552. if (rlen < 0) {
  553. DRM_ERROR("aux read failed. rlen=%zd\n", rlen);
  554. return rlen;
  555. }
  556. if (!data || (data == DP_TEST_LINK_FAUX_PATTERN)) {
  557. drm_dbg_dp(link->drm_dev, "link 0x%x not supported\n", data);
  558. goto end;
  559. }
  560. drm_dbg_dp(link->drm_dev, "Test:(0x%x) requested\n", data);
  561. link->request.test_requested = data;
  562. if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) {
  563. ret = dp_link_parse_phy_test_params(link);
  564. if (ret)
  565. goto end;
  566. ret = dp_link_parse_link_training_params(link);
  567. if (ret)
  568. goto end;
  569. }
  570. if (link->request.test_requested == DP_TEST_LINK_TRAINING) {
  571. ret = dp_link_parse_link_training_params(link);
  572. if (ret)
  573. goto end;
  574. }
  575. if (dp_link_is_video_audio_test_requested(
  576. link->request.test_requested)) {
  577. ret = dp_link_parse_video_pattern_params(link);
  578. if (ret)
  579. goto end;
  580. ret = dp_link_parse_audio_pattern_params(link);
  581. }
  582. end:
  583. /*
  584. * Send a DP_TEST_ACK if all link parameters are valid, otherwise send
  585. * a DP_TEST_NAK.
  586. */
  587. if (ret) {
  588. link->dp_link.test_response = DP_TEST_NAK;
  589. } else {
  590. if (link->request.test_requested != DP_TEST_LINK_EDID_READ)
  591. link->dp_link.test_response = DP_TEST_ACK;
  592. else
  593. link->dp_link.test_response =
  594. DP_TEST_EDID_CHECKSUM_WRITE;
  595. }
  596. return ret;
  597. }
  598. static int dp_link_parse_sink_status_field(struct dp_link_private *link)
  599. {
  600. int len;
  601. link->prev_sink_count = link->dp_link.sink_count;
  602. len = drm_dp_read_sink_count(link->aux);
  603. if (len < 0) {
  604. DRM_ERROR("DP parse sink count failed\n");
  605. return len;
  606. }
  607. link->dp_link.sink_count = len;
  608. len = drm_dp_dpcd_read_link_status(link->aux,
  609. link->link_status);
  610. if (len < DP_LINK_STATUS_SIZE) {
  611. DRM_ERROR("DP link status read failed\n");
  612. return len;
  613. }
  614. return dp_link_parse_request(link);
  615. }
  616. /**
  617. * dp_link_process_link_training_request() - processes new training requests
  618. * @link: Display Port link data
  619. *
  620. * This function will handle new link training requests that are initiated by
  621. * the sink. In particular, it will update the requested lane count and link
  622. * rate, and then trigger the link retraining procedure.
  623. *
  624. * The function will return 0 if a link training request has been processed,
  625. * otherwise it will return -EINVAL.
  626. */
  627. static int dp_link_process_link_training_request(struct dp_link_private *link)
  628. {
  629. if (link->request.test_requested != DP_TEST_LINK_TRAINING)
  630. return -EINVAL;
  631. drm_dbg_dp(link->drm_dev,
  632. "Test:0x%x link rate = 0x%x, lane count = 0x%x\n",
  633. DP_TEST_LINK_TRAINING,
  634. link->request.test_link_rate,
  635. link->request.test_lane_count);
  636. link->dp_link.link_params.num_lanes = link->request.test_lane_count;
  637. link->dp_link.link_params.rate =
  638. drm_dp_bw_code_to_link_rate(link->request.test_link_rate);
  639. return 0;
  640. }
  641. bool dp_link_send_test_response(struct dp_link *dp_link)
  642. {
  643. struct dp_link_private *link = NULL;
  644. int ret = 0;
  645. if (!dp_link) {
  646. DRM_ERROR("invalid input\n");
  647. return false;
  648. }
  649. link = container_of(dp_link, struct dp_link_private, dp_link);
  650. ret = drm_dp_dpcd_writeb(link->aux, DP_TEST_RESPONSE,
  651. dp_link->test_response);
  652. return ret == 1;
  653. }
  654. int dp_link_psm_config(struct dp_link *dp_link,
  655. struct dp_link_info *link_info, bool enable)
  656. {
  657. struct dp_link_private *link = NULL;
  658. int ret = 0;
  659. if (!dp_link) {
  660. DRM_ERROR("invalid params\n");
  661. return -EINVAL;
  662. }
  663. link = container_of(dp_link, struct dp_link_private, dp_link);
  664. mutex_lock(&link->psm_mutex);
  665. if (enable)
  666. ret = dp_aux_link_power_down(link->aux, link_info);
  667. else
  668. ret = dp_aux_link_power_up(link->aux, link_info);
  669. if (ret)
  670. DRM_ERROR("Failed to %s low power mode\n", enable ?
  671. "enter" : "exit");
  672. mutex_unlock(&link->psm_mutex);
  673. return ret;
  674. }
  675. bool dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum)
  676. {
  677. struct dp_link_private *link = NULL;
  678. int ret = 0;
  679. if (!dp_link) {
  680. DRM_ERROR("invalid input\n");
  681. return false;
  682. }
  683. link = container_of(dp_link, struct dp_link_private, dp_link);
  684. ret = drm_dp_dpcd_writeb(link->aux, DP_TEST_EDID_CHECKSUM,
  685. checksum);
  686. return ret == 1;
  687. }
  688. static void dp_link_parse_vx_px(struct dp_link_private *link)
  689. {
  690. drm_dbg_dp(link->drm_dev, "vx: 0=%d, 1=%d, 2=%d, 3=%d\n",
  691. drm_dp_get_adjust_request_voltage(link->link_status, 0),
  692. drm_dp_get_adjust_request_voltage(link->link_status, 1),
  693. drm_dp_get_adjust_request_voltage(link->link_status, 2),
  694. drm_dp_get_adjust_request_voltage(link->link_status, 3));
  695. drm_dbg_dp(link->drm_dev, "px: 0=%d, 1=%d, 2=%d, 3=%d\n",
  696. drm_dp_get_adjust_request_pre_emphasis(link->link_status, 0),
  697. drm_dp_get_adjust_request_pre_emphasis(link->link_status, 1),
  698. drm_dp_get_adjust_request_pre_emphasis(link->link_status, 2),
  699. drm_dp_get_adjust_request_pre_emphasis(link->link_status, 3));
  700. /**
  701. * Update the voltage and pre-emphasis levels as per DPCD request
  702. * vector.
  703. */
  704. drm_dbg_dp(link->drm_dev,
  705. "Current: v_level = 0x%x, p_level = 0x%x\n",
  706. link->dp_link.phy_params.v_level,
  707. link->dp_link.phy_params.p_level);
  708. link->dp_link.phy_params.v_level =
  709. drm_dp_get_adjust_request_voltage(link->link_status, 0);
  710. link->dp_link.phy_params.p_level =
  711. drm_dp_get_adjust_request_pre_emphasis(link->link_status, 0);
  712. link->dp_link.phy_params.p_level >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
  713. drm_dbg_dp(link->drm_dev,
  714. "Requested: v_level = 0x%x, p_level = 0x%x\n",
  715. link->dp_link.phy_params.v_level,
  716. link->dp_link.phy_params.p_level);
  717. }
  718. /**
  719. * dp_link_process_phy_test_pattern_request() - process new phy link requests
  720. * @link: Display Port Driver data
  721. *
  722. * This function will handle new phy link pattern requests that are initiated
  723. * by the sink. The function will return 0 if a phy link pattern has been
  724. * processed, otherwise it will return -EINVAL.
  725. */
  726. static int dp_link_process_phy_test_pattern_request(
  727. struct dp_link_private *link)
  728. {
  729. if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) {
  730. drm_dbg_dp(link->drm_dev, "no phy test\n");
  731. return -EINVAL;
  732. }
  733. if (!is_link_rate_valid(link->request.test_link_rate) ||
  734. !is_lane_count_valid(link->request.test_lane_count)) {
  735. DRM_ERROR("Invalid: link rate = 0x%x,lane count = 0x%x\n",
  736. link->request.test_link_rate,
  737. link->request.test_lane_count);
  738. return -EINVAL;
  739. }
  740. drm_dbg_dp(link->drm_dev,
  741. "Current: rate = 0x%x, lane count = 0x%x\n",
  742. link->dp_link.link_params.rate,
  743. link->dp_link.link_params.num_lanes);
  744. drm_dbg_dp(link->drm_dev,
  745. "Requested: rate = 0x%x, lane count = 0x%x\n",
  746. link->request.test_link_rate,
  747. link->request.test_lane_count);
  748. link->dp_link.link_params.num_lanes = link->request.test_lane_count;
  749. link->dp_link.link_params.rate =
  750. drm_dp_bw_code_to_link_rate(link->request.test_link_rate);
  751. dp_link_parse_vx_px(link);
  752. return 0;
  753. }
  754. static bool dp_link_read_psr_error_status(struct dp_link_private *link)
  755. {
  756. u8 status;
  757. drm_dp_dpcd_read(link->aux, DP_PSR_ERROR_STATUS, &status, 1);
  758. if (status & DP_PSR_LINK_CRC_ERROR)
  759. DRM_ERROR("PSR LINK CRC ERROR\n");
  760. else if (status & DP_PSR_RFB_STORAGE_ERROR)
  761. DRM_ERROR("PSR RFB STORAGE ERROR\n");
  762. else if (status & DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR)
  763. DRM_ERROR("PSR VSC SDP UNCORRECTABLE ERROR\n");
  764. else
  765. return false;
  766. return true;
  767. }
  768. static bool dp_link_psr_capability_changed(struct dp_link_private *link)
  769. {
  770. u8 status;
  771. drm_dp_dpcd_read(link->aux, DP_PSR_ESI, &status, 1);
  772. if (status & DP_PSR_CAPS_CHANGE) {
  773. drm_dbg_dp(link->drm_dev, "PSR Capability Change\n");
  774. return true;
  775. }
  776. return false;
  777. }
  778. static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
  779. {
  780. return link_status[r - DP_LANE0_1_STATUS];
  781. }
  782. /**
  783. * dp_link_process_link_status_update() - processes link status updates
  784. * @link: Display Port link module data
  785. *
  786. * This function will check for changes in the link status, e.g. clock
  787. * recovery done on all lanes, and trigger link training if there is a
  788. * failure/error on the link.
  789. *
  790. * The function will return 0 if the a link status update has been processed,
  791. * otherwise it will return -EINVAL.
  792. */
  793. static int dp_link_process_link_status_update(struct dp_link_private *link)
  794. {
  795. bool channel_eq_done = drm_dp_channel_eq_ok(link->link_status,
  796. link->dp_link.link_params.num_lanes);
  797. bool clock_recovery_done = drm_dp_clock_recovery_ok(link->link_status,
  798. link->dp_link.link_params.num_lanes);
  799. drm_dbg_dp(link->drm_dev,
  800. "channel_eq_done = %d, clock_recovery_done = %d\n",
  801. channel_eq_done, clock_recovery_done);
  802. if (channel_eq_done && clock_recovery_done)
  803. return -EINVAL;
  804. return 0;
  805. }
  806. /**
  807. * dp_link_process_ds_port_status_change() - process port status changes
  808. * @link: Display Port Driver data
  809. *
  810. * This function will handle downstream port updates that are initiated by
  811. * the sink. If the downstream port status has changed, the EDID is read via
  812. * AUX.
  813. *
  814. * The function will return 0 if a downstream port update has been
  815. * processed, otherwise it will return -EINVAL.
  816. */
  817. static int dp_link_process_ds_port_status_change(struct dp_link_private *link)
  818. {
  819. if (get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
  820. DP_DOWNSTREAM_PORT_STATUS_CHANGED)
  821. goto reset;
  822. if (link->prev_sink_count == link->dp_link.sink_count)
  823. return -EINVAL;
  824. reset:
  825. /* reset prev_sink_count */
  826. link->prev_sink_count = link->dp_link.sink_count;
  827. return 0;
  828. }
  829. static bool dp_link_is_video_pattern_requested(struct dp_link_private *link)
  830. {
  831. return (link->request.test_requested & DP_TEST_LINK_VIDEO_PATTERN)
  832. && !(link->request.test_requested &
  833. DP_TEST_LINK_AUDIO_DISABLED_VIDEO);
  834. }
  835. static bool dp_link_is_audio_pattern_requested(struct dp_link_private *link)
  836. {
  837. return (link->request.test_requested & DP_TEST_LINK_AUDIO_PATTERN);
  838. }
  839. static void dp_link_reset_data(struct dp_link_private *link)
  840. {
  841. link->request = (const struct dp_link_request){ 0 };
  842. link->dp_link.test_video = (const struct dp_link_test_video){ 0 };
  843. link->dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN;
  844. link->dp_link.test_audio = (const struct dp_link_test_audio){ 0 };
  845. link->dp_link.phy_params.phy_test_pattern_sel = 0;
  846. link->dp_link.sink_request = 0;
  847. link->dp_link.test_response = 0;
  848. }
  849. /**
  850. * dp_link_process_request() - handle HPD IRQ transition to HIGH
  851. * @dp_link: pointer to link module data
  852. *
  853. * This function will handle the HPD IRQ state transitions from LOW to HIGH
  854. * (including cases when there are back to back HPD IRQ HIGH) indicating
  855. * the start of a new link training request or sink status update.
  856. */
  857. int dp_link_process_request(struct dp_link *dp_link)
  858. {
  859. int ret = 0;
  860. struct dp_link_private *link;
  861. if (!dp_link) {
  862. DRM_ERROR("invalid input\n");
  863. return -EINVAL;
  864. }
  865. link = container_of(dp_link, struct dp_link_private, dp_link);
  866. dp_link_reset_data(link);
  867. ret = dp_link_parse_sink_status_field(link);
  868. if (ret)
  869. return ret;
  870. if (link->request.test_requested == DP_TEST_LINK_EDID_READ) {
  871. dp_link->sink_request |= DP_TEST_LINK_EDID_READ;
  872. } else if (!dp_link_process_ds_port_status_change(link)) {
  873. dp_link->sink_request |= DS_PORT_STATUS_CHANGED;
  874. } else if (!dp_link_process_link_training_request(link)) {
  875. dp_link->sink_request |= DP_TEST_LINK_TRAINING;
  876. } else if (!dp_link_process_phy_test_pattern_request(link)) {
  877. dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN;
  878. } else if (dp_link_read_psr_error_status(link)) {
  879. DRM_ERROR("PSR IRQ_HPD received\n");
  880. } else if (dp_link_psr_capability_changed(link)) {
  881. drm_dbg_dp(link->drm_dev, "PSR Capability changed\n");
  882. } else {
  883. ret = dp_link_process_link_status_update(link);
  884. if (!ret) {
  885. dp_link->sink_request |= DP_LINK_STATUS_UPDATED;
  886. } else {
  887. if (dp_link_is_video_pattern_requested(link)) {
  888. ret = 0;
  889. dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN;
  890. }
  891. if (dp_link_is_audio_pattern_requested(link)) {
  892. dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN;
  893. ret = -EINVAL;
  894. }
  895. }
  896. }
  897. drm_dbg_dp(link->drm_dev, "sink request=%#x\n",
  898. dp_link->sink_request);
  899. return ret;
  900. }
  901. int dp_link_get_colorimetry_config(struct dp_link *dp_link)
  902. {
  903. u32 cc = DP_MISC0_COLORIMERY_CFG_LEGACY_RGB;
  904. struct dp_link_private *link;
  905. if (!dp_link) {
  906. DRM_ERROR("invalid input\n");
  907. return -EINVAL;
  908. }
  909. link = container_of(dp_link, struct dp_link_private, dp_link);
  910. /*
  911. * Unless a video pattern CTS test is ongoing, use RGB_VESA
  912. * Only RGB_VESA and RGB_CEA supported for now
  913. */
  914. if (dp_link_is_video_pattern_requested(link)) {
  915. if (link->dp_link.test_video.test_dyn_range &
  916. DP_TEST_DYNAMIC_RANGE_CEA)
  917. cc = DP_MISC0_COLORIMERY_CFG_CEA_RGB;
  918. }
  919. return cc;
  920. }
  921. int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
  922. {
  923. int i;
  924. u8 max_p_level;
  925. int v_max = 0, p_max = 0;
  926. struct dp_link_private *link;
  927. if (!dp_link) {
  928. DRM_ERROR("invalid input\n");
  929. return -EINVAL;
  930. }
  931. link = container_of(dp_link, struct dp_link_private, dp_link);
  932. /* use the max level across lanes */
  933. for (i = 0; i < dp_link->link_params.num_lanes; i++) {
  934. u8 data_v = drm_dp_get_adjust_request_voltage(link_status, i);
  935. u8 data_p = drm_dp_get_adjust_request_pre_emphasis(link_status,
  936. i);
  937. drm_dbg_dp(link->drm_dev,
  938. "lane=%d req_vol_swing=%d req_pre_emphasis=%d\n",
  939. i, data_v, data_p);
  940. if (v_max < data_v)
  941. v_max = data_v;
  942. if (p_max < data_p)
  943. p_max = data_p;
  944. }
  945. dp_link->phy_params.v_level = v_max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
  946. dp_link->phy_params.p_level = p_max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
  947. /**
  948. * Adjust the voltage swing and pre-emphasis level combination to within
  949. * the allowable range.
  950. */
  951. if (dp_link->phy_params.v_level > DP_TRAIN_LEVEL_MAX) {
  952. drm_dbg_dp(link->drm_dev,
  953. "Requested vSwingLevel=%d, change to %d\n",
  954. dp_link->phy_params.v_level,
  955. DP_TRAIN_LEVEL_MAX);
  956. dp_link->phy_params.v_level = DP_TRAIN_LEVEL_MAX;
  957. }
  958. if (dp_link->phy_params.p_level > DP_TRAIN_LEVEL_MAX) {
  959. drm_dbg_dp(link->drm_dev,
  960. "Requested preEmphasisLevel=%d, change to %d\n",
  961. dp_link->phy_params.p_level,
  962. DP_TRAIN_LEVEL_MAX);
  963. dp_link->phy_params.p_level = DP_TRAIN_LEVEL_MAX;
  964. }
  965. max_p_level = DP_TRAIN_LEVEL_MAX - dp_link->phy_params.v_level;
  966. if (dp_link->phy_params.p_level > max_p_level) {
  967. drm_dbg_dp(link->drm_dev,
  968. "Requested preEmphasisLevel=%d, change to %d\n",
  969. dp_link->phy_params.p_level,
  970. max_p_level);
  971. dp_link->phy_params.p_level = max_p_level;
  972. }
  973. drm_dbg_dp(link->drm_dev, "adjusted: v_level=%d, p_level=%d\n",
  974. dp_link->phy_params.v_level, dp_link->phy_params.p_level);
  975. return 0;
  976. }
  977. void dp_link_reset_phy_params_vx_px(struct dp_link *dp_link)
  978. {
  979. dp_link->phy_params.v_level = 0;
  980. dp_link->phy_params.p_level = 0;
  981. }
  982. u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp)
  983. {
  984. u32 tbd;
  985. struct dp_link_private *link;
  986. link = container_of(dp_link, struct dp_link_private, dp_link);
  987. /*
  988. * Few simplistic rules and assumptions made here:
  989. * 1. Test bit depth is bit depth per color component
  990. * 2. Assume 3 color components
  991. */
  992. switch (bpp) {
  993. case 18:
  994. tbd = DP_TEST_BIT_DEPTH_6;
  995. break;
  996. case 24:
  997. tbd = DP_TEST_BIT_DEPTH_8;
  998. break;
  999. case 30:
  1000. tbd = DP_TEST_BIT_DEPTH_10;
  1001. break;
  1002. default:
  1003. drm_dbg_dp(link->drm_dev, "bpp=%d not supported, use bpc=8\n",
  1004. bpp);
  1005. tbd = DP_TEST_BIT_DEPTH_8;
  1006. break;
  1007. }
  1008. tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT);
  1009. return tbd;
  1010. }
  1011. struct dp_link *dp_link_get(struct device *dev, struct drm_dp_aux *aux)
  1012. {
  1013. struct dp_link_private *link;
  1014. struct dp_link *dp_link;
  1015. if (!dev || !aux) {
  1016. DRM_ERROR("invalid input\n");
  1017. return ERR_PTR(-EINVAL);
  1018. }
  1019. link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL);
  1020. if (!link)
  1021. return ERR_PTR(-ENOMEM);
  1022. link->aux = aux;
  1023. mutex_init(&link->psm_mutex);
  1024. dp_link = &link->dp_link;
  1025. return dp_link;
  1026. }