1 /* 2 * Copyright 2015 Martin Peres 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: Martin Peres 23 */ 24 #include "priv.h" 25 26 #include <subdev/volt.h> 27 #include <subdev/gpio.h> 28 #include <subdev/bios.h> 29 #include <subdev/bios/volt.h> 30 #include <subdev/fuse.h> 31 32 #define gk104_volt(p) container_of((p), struct gk104_volt, base) 33 struct gk104_volt { 34 struct nvkm_volt base; 35 struct nvbios_volt bios; 36 }; 37 38 static int 39 gk104_volt_get(struct nvkm_volt *base) 40 { 41 struct nvbios_volt *bios = &gk104_volt(base)->bios; 42 struct nvkm_device *device = base->subdev.device; 43 u32 div, duty; 44 45 div = nvkm_rd32(device, 0x20340); 46 duty = nvkm_rd32(device, 0x20344); 47 48 return bios->base + bios->pwm_range * duty / div; 49 } 50 51 static int 52 gk104_volt_set(struct nvkm_volt *base, u32 uv) 53 { 54 struct nvbios_volt *bios = &gk104_volt(base)->bios; 55 struct nvkm_device *device = base->subdev.device; 56 u32 div, duty; 57 58 /* the blob uses this crystal frequency, let's use it too. */ 59 div = 27648000 / bios->pwm_freq; 60 duty = DIV_ROUND_UP((uv - bios->base) * div, bios->pwm_range); 61 62 nvkm_wr32(device, 0x20340, div); 63 nvkm_wr32(device, 0x20344, 0x80000000 | duty); 64 65 return 0; 66 } 67 68 static int 69 gk104_volt_speedo_read(struct nvkm_volt *volt) 70 { 71 struct nvkm_device *device = volt->subdev.device; 72 struct nvkm_fuse *fuse = device->fuse; 73 int ret; 74 75 if (!fuse) 76 return -EINVAL; 77 78 nvkm_wr32(device, 0x122634, 0x0); 79 ret = nvkm_fuse_read(fuse, 0x3a8); 80 nvkm_wr32(device, 0x122634, 0x41); 81 return ret; 82 } 83 84 static const struct nvkm_volt_func 85 gk104_volt_pwm = { 86 .oneinit = gf100_volt_oneinit, 87 .volt_get = gk104_volt_get, 88 .volt_set = gk104_volt_set, 89 .speedo_read = gk104_volt_speedo_read, 90 }, gk104_volt_gpio = { 91 .oneinit = gf100_volt_oneinit, 92 .vid_get = nvkm_voltgpio_get, 93 .vid_set = nvkm_voltgpio_set, 94 .speedo_read = gk104_volt_speedo_read, 95 }; 96 97 int 98 gk104_volt_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, 99 struct nvkm_volt **pvolt) 100 { 101 const struct nvkm_volt_func *volt_func = &gk104_volt_gpio; 102 struct dcb_gpio_func gpio; 103 struct nvbios_volt bios; 104 struct gk104_volt *volt; 105 u8 ver, hdr, cnt, len; 106 const char *mode; 107 108 if (!nvbios_volt_parse(device->bios, &ver, &hdr, &cnt, &len, &bios)) 109 return 0; 110 111 if (!nvkm_gpio_find(device->gpio, 0, DCB_GPIO_VID_PWM, 0xff, &gpio) && 112 bios.type == NVBIOS_VOLT_PWM) { 113 volt_func = &gk104_volt_pwm; 114 } 115 116 if (!(volt = kzalloc(sizeof(*volt), GFP_KERNEL))) 117 return -ENOMEM; 118 nvkm_volt_ctor(volt_func, device, type, inst, &volt->base); 119 *pvolt = &volt->base; 120 volt->bios = bios; 121 122 /* now that we have a subdev, we can show an error if we found through 123 * the voltage table that we were supposed to use the PWN mode but we 124 * did not find the right GPIO for it. 125 */ 126 if (bios.type == NVBIOS_VOLT_PWM && volt_func != &gk104_volt_pwm) { 127 nvkm_error(&volt->base.subdev, 128 "Type mismatch between the voltage table type and " 129 "the GPIO table. Fallback to GPIO mode.\n"); 130 } 131 132 if (volt_func == &gk104_volt_gpio) { 133 nvkm_voltgpio_init(&volt->base); 134 mode = "GPIO"; 135 } else 136 mode = "PWM"; 137 138 nvkm_debug(&volt->base.subdev, "Using %s mode\n", mode); 139 140 return 0; 141 } 142