Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012 Nouveau Community
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: Martin Peres
0023  */
0024 #include <subdev/bios.h>
0025 #include <subdev/bios/bit.h>
0026 #include <subdev/bios/perf.h>
0027 #include <subdev/pci.h>
0028 
0029 u32
0030 nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr,
0031           u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
0032 {
0033     struct bit_entry bit_P;
0034     u32 perf = 0;
0035 
0036     if (!bit_entry(bios, 'P', &bit_P)) {
0037         if (bit_P.version <= 2) {
0038             perf = nvbios_rd32(bios, bit_P.offset + 0);
0039             if (perf) {
0040                 *ver = nvbios_rd08(bios, perf + 0);
0041                 *hdr = nvbios_rd08(bios, perf + 1);
0042                 if (*ver >= 0x40 && *ver < 0x41) {
0043                     *cnt = nvbios_rd08(bios, perf + 5);
0044                     *len = nvbios_rd08(bios, perf + 2);
0045                     *snr = nvbios_rd08(bios, perf + 4);
0046                     *ssz = nvbios_rd08(bios, perf + 3);
0047                     return perf;
0048                 } else
0049                 if (*ver >= 0x20 && *ver < 0x40) {
0050                     *cnt = nvbios_rd08(bios, perf + 2);
0051                     *len = nvbios_rd08(bios, perf + 3);
0052                     *snr = nvbios_rd08(bios, perf + 4);
0053                     *ssz = nvbios_rd08(bios, perf + 5);
0054                     return perf;
0055                 }
0056             }
0057         }
0058     }
0059 
0060     if (bios->bmp_offset) {
0061         if (nvbios_rd08(bios, bios->bmp_offset + 6) >= 0x25) {
0062             perf = nvbios_rd16(bios, bios->bmp_offset + 0x94);
0063             if (perf) {
0064                 *hdr = nvbios_rd08(bios, perf + 0);
0065                 *ver = nvbios_rd08(bios, perf + 1);
0066                 *cnt = nvbios_rd08(bios, perf + 2);
0067                 *len = nvbios_rd08(bios, perf + 3);
0068                 *snr = 0;
0069                 *ssz = 0;
0070                 return perf;
0071             }
0072         }
0073     }
0074 
0075     return 0;
0076 }
0077 
0078 u32
0079 nvbios_perf_entry(struct nvkm_bios *bios, int idx,
0080           u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
0081 {
0082     u8  snr, ssz;
0083     u32 perf = nvbios_perf_table(bios, ver, hdr, cnt, len, &snr, &ssz);
0084     if (perf && idx < *cnt) {
0085         perf = perf + *hdr + (idx * (*len + (snr * ssz)));
0086         *hdr = *len;
0087         *cnt = snr;
0088         *len = ssz;
0089         return perf;
0090     }
0091     return 0;
0092 }
0093 
0094 u32
0095 nvbios_perfEp(struct nvkm_bios *bios, int idx,
0096           u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *info)
0097 {
0098     u32 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len);
0099     memset(info, 0x00, sizeof(*info));
0100     info->pstate = nvbios_rd08(bios, perf + 0x00);
0101     switch (!!perf * *ver) {
0102     case 0x12:
0103     case 0x13:
0104     case 0x14:
0105         info->core     = nvbios_rd32(bios, perf + 0x01) * 10;
0106         info->memory   = nvbios_rd32(bios, perf + 0x05) * 20;
0107         info->fanspeed = nvbios_rd08(bios, perf + 0x37);
0108         if (*hdr > 0x38)
0109             info->voltage = nvbios_rd08(bios, perf + 0x38);
0110         break;
0111     case 0x21:
0112     case 0x23:
0113     case 0x24:
0114         info->fanspeed = nvbios_rd08(bios, perf + 0x04);
0115         info->voltage  = nvbios_rd08(bios, perf + 0x05);
0116         info->shader   = nvbios_rd16(bios, perf + 0x06) * 1000;
0117         info->core     = info->shader + (signed char)
0118                  nvbios_rd08(bios, perf + 0x08) * 1000;
0119         switch (bios->subdev.device->chipset) {
0120         case 0x49:
0121         case 0x4b:
0122             info->memory = nvbios_rd16(bios, perf + 0x0b) * 1000;
0123             break;
0124         default:
0125             info->memory = nvbios_rd16(bios, perf + 0x0b) * 2000;
0126             break;
0127         }
0128         break;
0129     case 0x25:
0130         info->fanspeed = nvbios_rd08(bios, perf + 0x04);
0131         info->voltage  = nvbios_rd08(bios, perf + 0x05);
0132         info->core     = nvbios_rd16(bios, perf + 0x06) * 1000;
0133         info->shader   = nvbios_rd16(bios, perf + 0x0a) * 1000;
0134         info->memory   = nvbios_rd16(bios, perf + 0x0c) * 1000;
0135         break;
0136     case 0x30:
0137         info->script   = nvbios_rd16(bios, perf + 0x02);
0138         fallthrough;
0139     case 0x35:
0140         info->fanspeed = nvbios_rd08(bios, perf + 0x06);
0141         info->voltage  = nvbios_rd08(bios, perf + 0x07);
0142         info->core     = nvbios_rd16(bios, perf + 0x08) * 1000;
0143         info->shader   = nvbios_rd16(bios, perf + 0x0a) * 1000;
0144         info->memory   = nvbios_rd16(bios, perf + 0x0c) * 1000;
0145         info->vdec     = nvbios_rd16(bios, perf + 0x10) * 1000;
0146         info->disp     = nvbios_rd16(bios, perf + 0x14) * 1000;
0147         break;
0148     case 0x40:
0149         info->voltage  = nvbios_rd08(bios, perf + 0x02);
0150         switch (nvbios_rd08(bios, perf + 0xb) & 0x3) {
0151         case 0:
0152             info->pcie_speed = NVKM_PCIE_SPEED_5_0;
0153             break;
0154         case 3:
0155         case 1:
0156             info->pcie_speed = NVKM_PCIE_SPEED_2_5;
0157             break;
0158         case 2:
0159             info->pcie_speed = NVKM_PCIE_SPEED_8_0;
0160             break;
0161         default:
0162             break;
0163         }
0164         info->pcie_width = 0xff;
0165         break;
0166     default:
0167         return 0;
0168     }
0169     return perf;
0170 }
0171 
0172 u32
0173 nvbios_perfSe(struct nvkm_bios *bios, u32 perfE, int idx,
0174           u8 *ver, u8 *hdr, u8 cnt, u8 len)
0175 {
0176     u32 data = 0x00000000;
0177     if (idx < cnt) {
0178         data = perfE + *hdr + (idx * len);
0179         *hdr = len;
0180     }
0181     return data;
0182 }
0183 
0184 u32
0185 nvbios_perfSp(struct nvkm_bios *bios, u32 perfE, int idx,
0186           u8 *ver, u8 *hdr, u8 cnt, u8 len,
0187           struct nvbios_perfS *info)
0188 {
0189     u32 data = nvbios_perfSe(bios, perfE, idx, ver, hdr, cnt, len);
0190     memset(info, 0x00, sizeof(*info));
0191     switch (!!data * *ver) {
0192     case 0x40:
0193         info->v40.freq = (nvbios_rd16(bios, data + 0x00) & 0x3fff) * 1000;
0194         break;
0195     default:
0196         break;
0197     }
0198     return data;
0199 }
0200 
0201 int
0202 nvbios_perf_fan_parse(struct nvkm_bios *bios,
0203               struct nvbios_perf_fan *fan)
0204 {
0205     u8  ver, hdr, cnt, len, snr, ssz;
0206     u32 perf = nvbios_perf_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
0207     if (!perf)
0208         return -ENODEV;
0209 
0210     if (ver >= 0x20 && ver < 0x40 && hdr > 6)
0211         fan->pwm_divisor = nvbios_rd16(bios, perf + 6);
0212     else
0213         fan->pwm_divisor = 0;
0214 
0215     return 0;
0216 }