dport.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. * Copyright 2013 Red Hat Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Authors: Ben Skeggs
  23. */
  24. #include "dport.h"
  25. #include "outpdp.h"
  26. #include "nv50.h"
  27. #include <subdev/bios.h>
  28. #include <subdev/bios/init.h>
  29. #include <subdev/i2c.h>
  30. #include <nvif/class.h>
  31. /******************************************************************************
  32. * link training
  33. *****************************************************************************/
  34. struct dp_state {
  35. struct nvkm_output_dp *outp;
  36. int link_nr;
  37. u32 link_bw;
  38. u8 stat[6];
  39. u8 conf[4];
  40. bool pc2;
  41. u8 pc2stat;
  42. u8 pc2conf[2];
  43. };
  44. static int
  45. dp_set_link_config(struct dp_state *dp)
  46. {
  47. struct nvkm_output_dp *outp = dp->outp;
  48. struct nvkm_disp *disp = outp->base.disp;
  49. struct nvkm_subdev *subdev = &disp->engine.subdev;
  50. struct nvkm_bios *bios = subdev->device->bios;
  51. struct nvbios_init init = {
  52. .subdev = subdev,
  53. .bios = bios,
  54. .offset = 0x0000,
  55. .outp = &outp->base.info,
  56. .crtc = -1,
  57. .execute = 1,
  58. };
  59. u32 lnkcmp;
  60. u8 sink[2];
  61. int ret;
  62. OUTP_DBG(&outp->base, "%d lanes at %d KB/s", dp->link_nr, dp->link_bw);
  63. /* set desired link configuration on the source */
  64. if ((lnkcmp = dp->outp->info.lnkcmp)) {
  65. if (outp->version < 0x30) {
  66. while ((dp->link_bw / 10) < nvbios_rd16(bios, lnkcmp))
  67. lnkcmp += 4;
  68. init.offset = nvbios_rd16(bios, lnkcmp + 2);
  69. } else {
  70. while ((dp->link_bw / 27000) < nvbios_rd08(bios, lnkcmp))
  71. lnkcmp += 3;
  72. init.offset = nvbios_rd16(bios, lnkcmp + 1);
  73. }
  74. nvbios_exec(&init);
  75. }
  76. ret = outp->func->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
  77. outp->dpcd[DPCD_RC02] &
  78. DPCD_RC02_ENHANCED_FRAME_CAP);
  79. if (ret) {
  80. if (ret < 0)
  81. OUTP_ERR(&outp->base, "lnk_ctl failed with %d", ret);
  82. return ret;
  83. }
  84. outp->func->lnk_pwr(outp, dp->link_nr);
  85. /* set desired link configuration on the sink */
  86. sink[0] = dp->link_bw / 27000;
  87. sink[1] = dp->link_nr;
  88. if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
  89. sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
  90. return nvkm_wraux(outp->aux, DPCD_LC00_LINK_BW_SET, sink, 2);
  91. }
  92. static void
  93. dp_set_training_pattern(struct dp_state *dp, u8 pattern)
  94. {
  95. struct nvkm_output_dp *outp = dp->outp;
  96. u8 sink_tp;
  97. OUTP_DBG(&outp->base, "training pattern %d", pattern);
  98. outp->func->pattern(outp, pattern);
  99. nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1);
  100. sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
  101. sink_tp |= pattern;
  102. nvkm_wraux(outp->aux, DPCD_LC02, &sink_tp, 1);
  103. }
  104. static int
  105. dp_link_train_commit(struct dp_state *dp, bool pc)
  106. {
  107. struct nvkm_output_dp *outp = dp->outp;
  108. int ret, i;
  109. for (i = 0; i < dp->link_nr; i++) {
  110. u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
  111. u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3;
  112. u8 lpre = (lane & 0x0c) >> 2;
  113. u8 lvsw = (lane & 0x03) >> 0;
  114. u8 hivs = 3 - lpre;
  115. u8 hipe = 3;
  116. u8 hipc = 3;
  117. if (lpc2 >= hipc)
  118. lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED;
  119. if (lpre >= hipe) {
  120. lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */
  121. lvsw = hivs = 3 - (lpre & 3);
  122. } else
  123. if (lvsw >= hivs) {
  124. lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED;
  125. }
  126. dp->conf[i] = (lpre << 3) | lvsw;
  127. dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
  128. OUTP_DBG(&outp->base, "config lane %d %02x %02x",
  129. i, dp->conf[i], lpc2);
  130. outp->func->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
  131. }
  132. ret = nvkm_wraux(outp->aux, DPCD_LC03(0), dp->conf, 4);
  133. if (ret)
  134. return ret;
  135. if (pc) {
  136. ret = nvkm_wraux(outp->aux, DPCD_LC0F, dp->pc2conf, 2);
  137. if (ret)
  138. return ret;
  139. }
  140. return 0;
  141. }
  142. static int
  143. dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
  144. {
  145. struct nvkm_output_dp *outp = dp->outp;
  146. int ret;
  147. if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
  148. mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
  149. else
  150. udelay(delay);
  151. ret = nvkm_rdaux(outp->aux, DPCD_LS02, dp->stat, 6);
  152. if (ret)
  153. return ret;
  154. if (pc) {
  155. ret = nvkm_rdaux(outp->aux, DPCD_LS0C, &dp->pc2stat, 1);
  156. if (ret)
  157. dp->pc2stat = 0x00;
  158. OUTP_DBG(&outp->base, "status %6ph pc2 %02x",
  159. dp->stat, dp->pc2stat);
  160. } else {
  161. OUTP_DBG(&outp->base, "status %6ph", dp->stat);
  162. }
  163. return 0;
  164. }
  165. static int
  166. dp_link_train_cr(struct dp_state *dp)
  167. {
  168. bool cr_done = false, abort = false;
  169. int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
  170. int tries = 0, i;
  171. dp_set_training_pattern(dp, 1);
  172. do {
  173. if (dp_link_train_commit(dp, false) ||
  174. dp_link_train_update(dp, false, 100))
  175. break;
  176. cr_done = true;
  177. for (i = 0; i < dp->link_nr; i++) {
  178. u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
  179. if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
  180. cr_done = false;
  181. if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
  182. abort = true;
  183. break;
  184. }
  185. }
  186. if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
  187. voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
  188. tries = 0;
  189. }
  190. } while (!cr_done && !abort && ++tries < 5);
  191. return cr_done ? 0 : -1;
  192. }
  193. static int
  194. dp_link_train_eq(struct dp_state *dp)
  195. {
  196. struct nvkm_output_dp *outp = dp->outp;
  197. bool eq_done = false, cr_done = true;
  198. int tries = 0, i;
  199. if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED)
  200. dp_set_training_pattern(dp, 3);
  201. else
  202. dp_set_training_pattern(dp, 2);
  203. do {
  204. if ((tries &&
  205. dp_link_train_commit(dp, dp->pc2)) ||
  206. dp_link_train_update(dp, dp->pc2, 400))
  207. break;
  208. eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
  209. for (i = 0; i < dp->link_nr && eq_done; i++) {
  210. u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
  211. if (!(lane & DPCD_LS02_LANE0_CR_DONE))
  212. cr_done = false;
  213. if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
  214. !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
  215. eq_done = false;
  216. }
  217. } while (!eq_done && cr_done && ++tries <= 5);
  218. return eq_done ? 0 : -1;
  219. }
  220. static void
  221. dp_link_train_init(struct dp_state *dp, bool spread)
  222. {
  223. struct nvkm_output_dp *outp = dp->outp;
  224. struct nvkm_disp *disp = outp->base.disp;
  225. struct nvkm_subdev *subdev = &disp->engine.subdev;
  226. struct nvbios_init init = {
  227. .subdev = subdev,
  228. .bios = subdev->device->bios,
  229. .outp = &outp->base.info,
  230. .crtc = -1,
  231. .execute = 1,
  232. };
  233. /* set desired spread */
  234. if (spread)
  235. init.offset = outp->info.script[2];
  236. else
  237. init.offset = outp->info.script[3];
  238. nvbios_exec(&init);
  239. /* pre-train script */
  240. init.offset = outp->info.script[0];
  241. nvbios_exec(&init);
  242. }
  243. static void
  244. dp_link_train_fini(struct dp_state *dp)
  245. {
  246. struct nvkm_output_dp *outp = dp->outp;
  247. struct nvkm_disp *disp = outp->base.disp;
  248. struct nvkm_subdev *subdev = &disp->engine.subdev;
  249. struct nvbios_init init = {
  250. .subdev = subdev,
  251. .bios = subdev->device->bios,
  252. .outp = &outp->base.info,
  253. .crtc = -1,
  254. .execute = 1,
  255. };
  256. /* post-train script */
  257. init.offset = outp->info.script[1],
  258. nvbios_exec(&init);
  259. }
  260. static const struct dp_rates {
  261. u32 rate;
  262. u8 bw;
  263. u8 nr;
  264. } nvkm_dp_rates[] = {
  265. { 2160000, 0x14, 4 },
  266. { 1080000, 0x0a, 4 },
  267. { 1080000, 0x14, 2 },
  268. { 648000, 0x06, 4 },
  269. { 540000, 0x0a, 2 },
  270. { 540000, 0x14, 1 },
  271. { 324000, 0x06, 2 },
  272. { 270000, 0x0a, 1 },
  273. { 162000, 0x06, 1 },
  274. {}
  275. };
  276. void
  277. nvkm_dp_train(struct nvkm_output_dp *outp)
  278. {
  279. struct nv50_disp *disp = nv50_disp(outp->base.disp);
  280. const struct dp_rates *cfg = nvkm_dp_rates;
  281. struct dp_state _dp = {
  282. .outp = outp,
  283. }, *dp = &_dp;
  284. u32 datarate = 0;
  285. u8 pwr;
  286. int ret;
  287. if (!outp->base.info.location && disp->func->sor.magic)
  288. disp->func->sor.magic(&outp->base);
  289. /* bring capabilities within encoder limits */
  290. if (disp->base.engine.subdev.device->chipset < 0xd0)
  291. outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
  292. if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
  293. outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
  294. outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
  295. }
  296. if (outp->dpcd[1] > outp->base.info.dpconf.link_bw)
  297. outp->dpcd[1] = outp->base.info.dpconf.link_bw;
  298. dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
  299. /* restrict link config to the lowest required rate, if requested */
  300. if (datarate) {
  301. datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */
  302. while (cfg[1].rate >= datarate)
  303. cfg++;
  304. }
  305. cfg--;
  306. /* ensure sink is not in a low-power state */
  307. if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) {
  308. if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
  309. pwr &= ~DPCD_SC00_SET_POWER;
  310. pwr |= DPCD_SC00_SET_POWER_D0;
  311. nvkm_wraux(outp->aux, DPCD_SC00, &pwr, 1);
  312. }
  313. }
  314. /* enable down-spreading and execute pre-train script from vbios */
  315. dp_link_train_init(dp, outp->dpcd[3] & 0x01);
  316. while (ret = -EIO, (++cfg)->rate) {
  317. /* select next configuration supported by encoder and sink */
  318. while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
  319. cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
  320. cfg++;
  321. dp->link_bw = cfg->bw * 27000;
  322. dp->link_nr = cfg->nr;
  323. /* program selected link configuration */
  324. ret = dp_set_link_config(dp);
  325. if (ret == 0) {
  326. /* attempt to train the link at this configuration */
  327. memset(dp->stat, 0x00, sizeof(dp->stat));
  328. if (!dp_link_train_cr(dp) &&
  329. !dp_link_train_eq(dp))
  330. break;
  331. } else
  332. if (ret) {
  333. /* dp_set_link_config() handled training, or
  334. * we failed to communicate with the sink.
  335. */
  336. break;
  337. }
  338. }
  339. /* finish link training and execute post-train script from vbios */
  340. dp_set_training_pattern(dp, 0);
  341. if (ret < 0)
  342. OUTP_ERR(&outp->base, "link training failed");
  343. dp_link_train_fini(dp);
  344. OUTP_DBG(&outp->base, "training complete");
  345. atomic_set(&outp->lt.done, 1);
  346. }