mxms.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright 2012 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. #define ROM16(x) get_unaligned_le16(&(x))
  26. #define ROM32(x) get_unaligned_le32(&(x))
  27. static u8 *
  28. mxms_data(struct nvkm_mxm *mxm)
  29. {
  30. return mxm->mxms;
  31. }
  32. u16
  33. mxms_version(struct nvkm_mxm *mxm)
  34. {
  35. u8 *mxms = mxms_data(mxm);
  36. u16 version = (mxms[4] << 8) | mxms[5];
  37. switch (version ) {
  38. case 0x0200:
  39. case 0x0201:
  40. case 0x0300:
  41. return version;
  42. default:
  43. break;
  44. }
  45. nvkm_debug(&mxm->subdev, "unknown version %d.%d\n", mxms[4], mxms[5]);
  46. return 0x0000;
  47. }
  48. u16
  49. mxms_headerlen(struct nvkm_mxm *mxm)
  50. {
  51. return 8;
  52. }
  53. u16
  54. mxms_structlen(struct nvkm_mxm *mxm)
  55. {
  56. return *(u16 *)&mxms_data(mxm)[6];
  57. }
  58. bool
  59. mxms_checksum(struct nvkm_mxm *mxm)
  60. {
  61. u16 size = mxms_headerlen(mxm) + mxms_structlen(mxm);
  62. u8 *mxms = mxms_data(mxm), sum = 0;
  63. while (size--)
  64. sum += *mxms++;
  65. if (sum) {
  66. nvkm_debug(&mxm->subdev, "checksum invalid\n");
  67. return false;
  68. }
  69. return true;
  70. }
  71. bool
  72. mxms_valid(struct nvkm_mxm *mxm)
  73. {
  74. u8 *mxms = mxms_data(mxm);
  75. if (*(u32 *)mxms != 0x5f4d584d) {
  76. nvkm_debug(&mxm->subdev, "signature invalid\n");
  77. return false;
  78. }
  79. if (!mxms_version(mxm) || !mxms_checksum(mxm))
  80. return false;
  81. return true;
  82. }
  83. bool
  84. mxms_foreach(struct nvkm_mxm *mxm, u8 types,
  85. bool (*exec)(struct nvkm_mxm *, u8 *, void *), void *info)
  86. {
  87. struct nvkm_subdev *subdev = &mxm->subdev;
  88. u8 *mxms = mxms_data(mxm);
  89. u8 *desc = mxms + mxms_headerlen(mxm);
  90. u8 *fini = desc + mxms_structlen(mxm) - 1;
  91. while (desc < fini) {
  92. u8 type = desc[0] & 0x0f;
  93. u8 headerlen = 0;
  94. u8 recordlen = 0;
  95. u8 entries = 0;
  96. switch (type) {
  97. case 0: /* Output Device Structure */
  98. if (mxms_version(mxm) >= 0x0300)
  99. headerlen = 8;
  100. else
  101. headerlen = 6;
  102. break;
  103. case 1: /* System Cooling Capability Structure */
  104. case 2: /* Thermal Structure */
  105. case 3: /* Input Power Structure */
  106. headerlen = 4;
  107. break;
  108. case 4: /* GPIO Device Structure */
  109. headerlen = 4;
  110. recordlen = 2;
  111. entries = (ROM32(desc[0]) & 0x01f00000) >> 20;
  112. break;
  113. case 5: /* Vendor Specific Structure */
  114. headerlen = 8;
  115. break;
  116. case 6: /* Backlight Control Structure */
  117. if (mxms_version(mxm) >= 0x0300) {
  118. headerlen = 4;
  119. recordlen = 8;
  120. entries = (desc[1] & 0xf0) >> 4;
  121. } else {
  122. headerlen = 8;
  123. }
  124. break;
  125. case 7: /* Fan Control Structure */
  126. headerlen = 8;
  127. recordlen = 4;
  128. entries = desc[1] & 0x07;
  129. break;
  130. default:
  131. nvkm_debug(subdev, "unknown descriptor type %d\n", type);
  132. return false;
  133. }
  134. if (mxm->subdev.debug >= NV_DBG_DEBUG && (exec == NULL)) {
  135. static const char * mxms_desc[] = {
  136. "ODS", "SCCS", "TS", "IPS",
  137. "GSD", "VSS", "BCS", "FCS",
  138. };
  139. u8 *dump = desc;
  140. char data[32], *ptr;
  141. int i, j;
  142. for (j = headerlen - 1, ptr = data; j >= 0; j--)
  143. ptr += sprintf(ptr, "%02x", dump[j]);
  144. dump += headerlen;
  145. nvkm_debug(subdev, "%4s: %s\n", mxms_desc[type], data);
  146. for (i = 0; i < entries; i++, dump += recordlen) {
  147. for (j = recordlen - 1, ptr = data; j >= 0; j--)
  148. ptr += sprintf(ptr, "%02x", dump[j]);
  149. nvkm_debug(subdev, " %s\n", data);
  150. }
  151. }
  152. if (types & (1 << type)) {
  153. if (!exec(mxm, desc, info))
  154. return false;
  155. }
  156. desc += headerlen + (entries * recordlen);
  157. }
  158. return true;
  159. }
  160. void
  161. mxms_output_device(struct nvkm_mxm *mxm, u8 *pdata, struct mxms_odev *desc)
  162. {
  163. u64 data = ROM32(pdata[0]);
  164. if (mxms_version(mxm) >= 0x0300)
  165. data |= (u64)ROM16(pdata[4]) << 32;
  166. desc->outp_type = (data & 0x00000000000000f0ULL) >> 4;
  167. desc->ddc_port = (data & 0x0000000000000f00ULL) >> 8;
  168. desc->conn_type = (data & 0x000000000001f000ULL) >> 12;
  169. desc->dig_conn = (data & 0x0000000000780000ULL) >> 19;
  170. }