Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2015 Martin Peres
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/extdev.h>
0027 #include <subdev/bios/iccsense.h>
0028 
0029 static u32
0030 nvbios_iccsense_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt,
0031               u8 *len)
0032 {
0033     struct bit_entry bit_P;
0034     u32 iccsense;
0035 
0036     if (bit_entry(bios, 'P', &bit_P) || bit_P.version != 2 ||
0037         bit_P.length < 0x2c)
0038         return 0;
0039 
0040     iccsense = nvbios_rd32(bios, bit_P.offset + 0x28);
0041     if (!iccsense)
0042         return 0;
0043 
0044     *ver = nvbios_rd08(bios, iccsense + 0);
0045     switch (*ver) {
0046     case 0x10:
0047     case 0x20:
0048         *hdr = nvbios_rd08(bios, iccsense + 1);
0049         *len = nvbios_rd08(bios, iccsense + 2);
0050         *cnt = nvbios_rd08(bios, iccsense + 3);
0051         return iccsense;
0052     default:
0053         break;
0054     }
0055 
0056     return 0;
0057 }
0058 
0059 int
0060 nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense)
0061 {
0062     struct nvkm_subdev *subdev = &bios->subdev;
0063     u8 ver, hdr, cnt, len, i;
0064     u32 table, entry;
0065 
0066     table = nvbios_iccsense_table(bios, &ver, &hdr, &cnt, &len);
0067     if (!table || !cnt)
0068         return -EINVAL;
0069 
0070     if (ver != 0x10 && ver != 0x20) {
0071         nvkm_error(subdev, "ICCSENSE version 0x%02x unknown\n", ver);
0072         return -EINVAL;
0073     }
0074 
0075     iccsense->nr_entry = cnt;
0076     iccsense->rail = kmalloc_array(cnt, sizeof(struct pwr_rail_t),
0077                        GFP_KERNEL);
0078     if (!iccsense->rail)
0079         return -ENOMEM;
0080 
0081     for (i = 0; i < cnt; ++i) {
0082         struct nvbios_extdev_func extdev;
0083         struct pwr_rail_t *rail = &iccsense->rail[i];
0084         u8 res_start = 0;
0085         int r;
0086 
0087         entry = table + hdr + i * len;
0088 
0089         switch(ver) {
0090         case 0x10:
0091             if ((nvbios_rd08(bios, entry + 0x1) & 0xf8) == 0xf8)
0092                 rail->mode = 1;
0093             else
0094                 rail->mode = 0;
0095             rail->extdev_id = nvbios_rd08(bios, entry + 0x2);
0096             res_start = 0x3;
0097             break;
0098         case 0x20:
0099             rail->mode = nvbios_rd08(bios, entry);
0100             rail->extdev_id = nvbios_rd08(bios, entry + 0x1);
0101             res_start = 0x5;
0102             break;
0103         }
0104 
0105         if (nvbios_extdev_parse(bios, rail->extdev_id, &extdev))
0106             continue;
0107 
0108         switch (extdev.type) {
0109         case NVBIOS_EXTDEV_INA209:
0110         case NVBIOS_EXTDEV_INA219:
0111             rail->resistor_count = 1;
0112             break;
0113         case NVBIOS_EXTDEV_INA3221:
0114             rail->resistor_count = 3;
0115             break;
0116         default:
0117             rail->resistor_count = 0;
0118             break;
0119         }
0120 
0121         for (r = 0; r < rail->resistor_count; ++r) {
0122             rail->resistors[r].mohm = nvbios_rd08(bios, entry + res_start + r * 2);
0123             rail->resistors[r].enabled = !(nvbios_rd08(bios, entry + res_start + r * 2 + 1) & 0x40);
0124         }
0125         rail->config = nvbios_rd16(bios, entry + res_start + rail->resistor_count * 2);
0126     }
0127 
0128     return 0;
0129 }