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 31#define gk104_volt(p) container_of((p), struct gk104_volt, base) 32struct gk104_volt { 33 struct nvkm_volt base; 34 struct nvbios_volt bios; 35}; 36 37int 38gk104_volt_get(struct nvkm_volt *base) 39{ 40 struct nvbios_volt *bios = &gk104_volt(base)->bios; 41 struct nvkm_device *device = base->subdev.device; 42 u32 div, duty; 43 44 div = nvkm_rd32(device, 0x20340); 45 duty = nvkm_rd32(device, 0x20344); 46 47 return bios->base + bios->pwm_range * duty / div; 48} 49 50int 51gk104_volt_set(struct nvkm_volt *base, u32 uv) 52{ 53 struct nvbios_volt *bios = &gk104_volt(base)->bios; 54 struct nvkm_device *device = base->subdev.device; 55 u32 div, duty; 56 57 /* the blob uses this crystal frequency, let's use it too. */ 58 div = 27648000 / bios->pwm_freq; 59 duty = (uv - bios->base) * div / bios->pwm_range; 60 61 nvkm_wr32(device, 0x20340, div); 62 nvkm_wr32(device, 0x20344, 0x80000000 | duty); 63 64 return 0; 65} 66 67static const struct nvkm_volt_func 68gk104_volt_pwm = { 69 .volt_get = gk104_volt_get, 70 .volt_set = gk104_volt_set, 71}, gk104_volt_gpio = { 72 .vid_get = nvkm_voltgpio_get, 73 .vid_set = nvkm_voltgpio_set, 74}; 75 76int 77gk104_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) 78{ 79 const struct nvkm_volt_func *volt_func = &gk104_volt_gpio; 80 struct dcb_gpio_func gpio; 81 struct nvbios_volt bios; 82 struct gk104_volt *volt; 83 u8 ver, hdr, cnt, len; 84 const char *mode; 85 86 if (!nvbios_volt_parse(device->bios, &ver, &hdr, &cnt, &len, &bios)) 87 return 0; 88 89 if (!nvkm_gpio_find(device->gpio, 0, DCB_GPIO_VID_PWM, 0xff, &gpio) && 90 bios.type == NVBIOS_VOLT_PWM) { 91 volt_func = &gk104_volt_pwm; 92 } 93 94 if (!(volt = kzalloc(sizeof(*volt), GFP_KERNEL))) 95 return -ENOMEM; 96 nvkm_volt_ctor(volt_func, device, index, &volt->base); 97 *pvolt = &volt->base; 98 volt->bios = bios; 99 100 /* now that we have a subdev, we can show an error if we found through 101 * the voltage table that we were supposed to use the PWN mode but we 102 * did not find the right GPIO for it. 103 */ 104 if (bios.type == NVBIOS_VOLT_PWM && volt_func != &gk104_volt_pwm) { 105 nvkm_error(&volt->base.subdev, 106 "Type mismatch between the voltage table type and " 107 "the GPIO table. Fallback to GPIO mode.\n"); 108 } 109 110 if (volt_func == &gk104_volt_gpio) { 111 nvkm_voltgpio_init(&volt->base); 112 mode = "GPIO"; 113 } else 114 mode = "PWM"; 115 116 nvkm_debug(&volt->base.subdev, "Using %s mode\n", mode); 117 118 return 0; 119} 120