Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs
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: /* Output Device Structure */
0111             if (mxms_version(mxm) >= 0x0300)
0112                 headerlen = 8;
0113             else
0114                 headerlen = 6;
0115             break;
0116         case 1: /* System Cooling Capability Structure */
0117         case 2: /* Thermal Structure */
0118         case 3: /* Input Power Structure */
0119             headerlen = 4;
0120             break;
0121         case 4: /* GPIO Device Structure */
0122             headerlen = 4;
0123             recordlen = 2;
0124             entries   = (ROM32(desc[0]) & 0x01f00000) >> 20;
0125             break;
0126         case 5: /* Vendor Specific Structure */
0127             headerlen = 8;
0128             break;
0129         case 6: /* Backlight Control Structure */
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: /* Fan Control Structure */
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 }