nv50.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Copyright 2011 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 "mxms.h"
  25. #include <subdev/bios.h>
  26. #include <subdev/bios/conn.h>
  27. #include <subdev/bios/dcb.h>
  28. #include <subdev/bios/mxm.h>
  29. struct context {
  30. u32 *outp;
  31. struct mxms_odev desc;
  32. };
  33. static bool
  34. mxm_match_tmds_partner(struct nvkm_mxm *mxm, u8 *data, void *info)
  35. {
  36. struct context *ctx = info;
  37. struct mxms_odev desc;
  38. mxms_output_device(mxm, data, &desc);
  39. if (desc.outp_type == 2 &&
  40. desc.dig_conn == ctx->desc.dig_conn)
  41. return false;
  42. return true;
  43. }
  44. static bool
  45. mxm_match_dcb(struct nvkm_mxm *mxm, u8 *data, void *info)
  46. {
  47. struct nvkm_bios *bios = mxm->subdev.device->bios;
  48. struct context *ctx = info;
  49. u64 desc = *(u64 *)data;
  50. mxms_output_device(mxm, data, &ctx->desc);
  51. /* match dcb encoder type to mxm-ods device type */
  52. if ((ctx->outp[0] & 0x0000000f) != ctx->desc.outp_type)
  53. return true;
  54. /* digital output, have some extra stuff to match here, there's a
  55. * table in the vbios that provides a mapping from the mxm digital
  56. * connection enum values to SOR/link
  57. */
  58. if ((desc & 0x00000000000000f0) >= 0x20) {
  59. /* check against sor index */
  60. u8 link = mxm_sor_map(bios, ctx->desc.dig_conn);
  61. if ((ctx->outp[0] & 0x0f000000) != (link & 0x0f) << 24)
  62. return true;
  63. /* check dcb entry has a compatible link field */
  64. link = (link & 0x30) >> 4;
  65. if ((link & ((ctx->outp[1] & 0x00000030) >> 4)) != link)
  66. return true;
  67. }
  68. /* mark this descriptor accounted for by setting invalid device type,
  69. * except of course some manufactures don't follow specs properly and
  70. * we need to avoid killing off the TMDS function on DP connectors
  71. * if MXM-SIS is missing an entry for it.
  72. */
  73. data[0] &= ~0xf0;
  74. if (ctx->desc.outp_type == 6 && ctx->desc.conn_type == 6 &&
  75. mxms_foreach(mxm, 0x01, mxm_match_tmds_partner, ctx)) {
  76. data[0] |= 0x20; /* modify descriptor to match TMDS now */
  77. } else {
  78. data[0] |= 0xf0;
  79. }
  80. return false;
  81. }
  82. static int
  83. mxm_dcb_sanitise_entry(struct nvkm_bios *bios, void *data, int idx, u16 pdcb)
  84. {
  85. struct nvkm_mxm *mxm = data;
  86. struct context ctx = { .outp = (u32 *)(bios->data + pdcb) };
  87. u8 type, i2cidx, link, ver, len;
  88. u8 *conn;
  89. /* look for an output device structure that matches this dcb entry.
  90. * if one isn't found, disable it.
  91. */
  92. if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) {
  93. nvkm_debug(&mxm->subdev, "disable %d: %08x %08x\n",
  94. idx, ctx.outp[0], ctx.outp[1]);
  95. ctx.outp[0] |= 0x0000000f;
  96. return 0;
  97. }
  98. /* modify the output's ddc/aux port, there's a pointer to a table
  99. * with the mapping from mxm ddc/aux port to dcb i2c_index in the
  100. * vbios mxm table
  101. */
  102. i2cidx = mxm_ddc_map(bios, ctx.desc.ddc_port);
  103. if ((ctx.outp[0] & 0x0000000f) != DCB_OUTPUT_DP)
  104. i2cidx = (i2cidx & 0x0f) << 4;
  105. else
  106. i2cidx = (i2cidx & 0xf0);
  107. if (i2cidx != 0xf0) {
  108. ctx.outp[0] &= ~0x000000f0;
  109. ctx.outp[0] |= i2cidx;
  110. }
  111. /* override dcb sorconf.link, based on what mxm data says */
  112. switch (ctx.desc.outp_type) {
  113. case 0x00: /* Analog CRT */
  114. case 0x01: /* Analog TV/HDTV */
  115. break;
  116. default:
  117. link = mxm_sor_map(bios, ctx.desc.dig_conn) & 0x30;
  118. ctx.outp[1] &= ~0x00000030;
  119. ctx.outp[1] |= link;
  120. break;
  121. }
  122. /* we may need to fixup various other vbios tables based on what
  123. * the descriptor says the connector type should be.
  124. *
  125. * in a lot of cases, the vbios tables will claim DVI-I is possible,
  126. * and the mxm data says the connector is really HDMI. another
  127. * common example is DP->eDP.
  128. */
  129. conn = bios->data;
  130. conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len);
  131. type = conn[0];
  132. switch (ctx.desc.conn_type) {
  133. case 0x01: /* LVDS */
  134. ctx.outp[1] |= 0x00000004; /* use_power_scripts */
  135. /* XXX: modify default link width in LVDS table */
  136. break;
  137. case 0x02: /* HDMI */
  138. type = DCB_CONNECTOR_HDMI_1;
  139. break;
  140. case 0x03: /* DVI-D */
  141. type = DCB_CONNECTOR_DVI_D;
  142. break;
  143. case 0x0e: /* eDP, falls through to DPint */
  144. ctx.outp[1] |= 0x00010000;
  145. case 0x07: /* DP internal, wtf is this?? HP8670w */
  146. ctx.outp[1] |= 0x00000004; /* use_power_scripts? */
  147. type = DCB_CONNECTOR_eDP;
  148. break;
  149. default:
  150. break;
  151. }
  152. if (mxms_version(mxm) >= 0x0300)
  153. conn[0] = type;
  154. return 0;
  155. }
  156. static bool
  157. mxm_show_unmatched(struct nvkm_mxm *mxm, u8 *data, void *info)
  158. {
  159. struct nvkm_subdev *subdev = &mxm->subdev;
  160. u64 desc = *(u64 *)data;
  161. if ((desc & 0xf0) != 0xf0)
  162. nvkm_info(subdev, "unmatched output device %016llx\n", desc);
  163. return true;
  164. }
  165. static void
  166. mxm_dcb_sanitise(struct nvkm_mxm *mxm)
  167. {
  168. struct nvkm_subdev *subdev = &mxm->subdev;
  169. struct nvkm_bios *bios = subdev->device->bios;
  170. u8 ver, hdr, cnt, len;
  171. u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
  172. if (dcb == 0x0000 || (ver != 0x40 && ver != 0x41)) {
  173. nvkm_warn(subdev, "unsupported DCB version\n");
  174. return;
  175. }
  176. dcb_outp_foreach(bios, mxm, mxm_dcb_sanitise_entry);
  177. mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL);
  178. }
  179. int
  180. nv50_mxm_new(struct nvkm_device *device, int index, struct nvkm_subdev **pmxm)
  181. {
  182. struct nvkm_mxm *mxm;
  183. int ret;
  184. ret = nvkm_mxm_new_(device, index, &mxm);
  185. if (mxm)
  186. *pmxm = &mxm->subdev;
  187. if (ret)
  188. return ret;
  189. if (mxm->action & MXM_SANITISE_DCB)
  190. mxm_dcb_sanitise(mxm);
  191. return 0;
  192. }