0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include "mxms.h"
0025
0026 #define ROM16(x) get_unaligned_le16(&(x))
0027 #define ROM32(x) get_unaligned_le32(&(x))
0028
0029 static u8 *
0030 mxms_data(struct nvkm_mxm *mxm)
0031 {
0032 return mxm->mxms;
0033
0034 }
0035
0036 u16
0037 mxms_version(struct nvkm_mxm *mxm)
0038 {
0039 u8 *mxms = mxms_data(mxm);
0040 u16 version = (mxms[4] << 8) | mxms[5];
0041 switch (version ) {
0042 case 0x0200:
0043 case 0x0201:
0044 case 0x0300:
0045 return version;
0046 default:
0047 break;
0048 }
0049
0050 nvkm_debug(&mxm->subdev, "unknown version %d.%d\n", mxms[4], mxms[5]);
0051 return 0x0000;
0052 }
0053
0054 u16
0055 mxms_headerlen(struct nvkm_mxm *mxm)
0056 {
0057 return 8;
0058 }
0059
0060 u16
0061 mxms_structlen(struct nvkm_mxm *mxm)
0062 {
0063 return *(u16 *)&mxms_data(mxm)[6];
0064 }
0065
0066 bool
0067 mxms_checksum(struct nvkm_mxm *mxm)
0068 {
0069 u16 size = mxms_headerlen(mxm) + mxms_structlen(mxm);
0070 u8 *mxms = mxms_data(mxm), sum = 0;
0071 while (size--)
0072 sum += *mxms++;
0073 if (sum) {
0074 nvkm_debug(&mxm->subdev, "checksum invalid\n");
0075 return false;
0076 }
0077 return true;
0078 }
0079
0080 bool
0081 mxms_valid(struct nvkm_mxm *mxm)
0082 {
0083 u8 *mxms = mxms_data(mxm);
0084 if (*(u32 *)mxms != 0x5f4d584d) {
0085 nvkm_debug(&mxm->subdev, "signature invalid\n");
0086 return false;
0087 }
0088
0089 if (!mxms_version(mxm) || !mxms_checksum(mxm))
0090 return false;
0091
0092 return true;
0093 }
0094
0095 bool
0096 mxms_foreach(struct nvkm_mxm *mxm, u8 types,
0097 bool (*exec)(struct nvkm_mxm *, u8 *, void *), void *info)
0098 {
0099 struct nvkm_subdev *subdev = &mxm->subdev;
0100 u8 *mxms = mxms_data(mxm);
0101 u8 *desc = mxms + mxms_headerlen(mxm);
0102 u8 *fini = desc + mxms_structlen(mxm) - 1;
0103 while (desc < fini) {
0104 u8 type = desc[0] & 0x0f;
0105 u8 headerlen = 0;
0106 u8 recordlen = 0;
0107 u8 entries = 0;
0108
0109 switch (type) {
0110 case 0:
0111 if (mxms_version(mxm) >= 0x0300)
0112 headerlen = 8;
0113 else
0114 headerlen = 6;
0115 break;
0116 case 1:
0117 case 2:
0118 case 3:
0119 headerlen = 4;
0120 break;
0121 case 4:
0122 headerlen = 4;
0123 recordlen = 2;
0124 entries = (ROM32(desc[0]) & 0x01f00000) >> 20;
0125 break;
0126 case 5:
0127 headerlen = 8;
0128 break;
0129 case 6:
0130 if (mxms_version(mxm) >= 0x0300) {
0131 headerlen = 4;
0132 recordlen = 8;
0133 entries = (desc[1] & 0xf0) >> 4;
0134 } else {
0135 headerlen = 8;
0136 }
0137 break;
0138 case 7:
0139 headerlen = 8;
0140 recordlen = 4;
0141 entries = desc[1] & 0x07;
0142 break;
0143 default:
0144 nvkm_debug(subdev, "unknown descriptor type %d\n", type);
0145 return false;
0146 }
0147
0148 if (mxm->subdev.debug >= NV_DBG_DEBUG && (exec == NULL)) {
0149 static const char * mxms_desc[] = {
0150 "ODS", "SCCS", "TS", "IPS",
0151 "GSD", "VSS", "BCS", "FCS",
0152 };
0153 u8 *dump = desc;
0154 char data[32], *ptr;
0155 int i, j;
0156
0157 for (j = headerlen - 1, ptr = data; j >= 0; j--)
0158 ptr += sprintf(ptr, "%02x", dump[j]);
0159 dump += headerlen;
0160
0161 nvkm_debug(subdev, "%4s: %s\n", mxms_desc[type], data);
0162 for (i = 0; i < entries; i++, dump += recordlen) {
0163 for (j = recordlen - 1, ptr = data; j >= 0; j--)
0164 ptr += sprintf(ptr, "%02x", dump[j]);
0165 nvkm_debug(subdev, " %s\n", data);
0166 }
0167 }
0168
0169 if (types & (1 << type)) {
0170 if (!exec(mxm, desc, info))
0171 return false;
0172 }
0173
0174 desc += headerlen + (entries * recordlen);
0175 }
0176
0177 return true;
0178 }
0179
0180 void
0181 mxms_output_device(struct nvkm_mxm *mxm, u8 *pdata, struct mxms_odev *desc)
0182 {
0183 u64 data = ROM32(pdata[0]);
0184 if (mxms_version(mxm) >= 0x0300)
0185 data |= (u64)ROM16(pdata[4]) << 32;
0186
0187 desc->outp_type = (data & 0x00000000000000f0ULL) >> 4;
0188 desc->ddc_port = (data & 0x0000000000000f00ULL) >> 8;
0189 desc->conn_type = (data & 0x000000000001f000ULL) >> 12;
0190 desc->dig_conn = (data & 0x0000000000780000ULL) >> 19;
0191 }