int nouveau_volt_create(struct nouveau_device *device) { struct nouveau_volt *volt = &device->volt; struct nvbios_volt_entry ivid; struct nvbios_volt info; u8 ver, hdr, cnt, len; u16 data; int ret = -EUNKNOWN, i; volt->get = nouveau_volt_get; data = nvbios_volt_parse(device, &ver, &hdr, &cnt, &len, &info); if (data && info.vidmask && info.base && info.step) { for (i = 0; i < info.vidmask + 1; i++) { if (info.base >= info.min && info.base <= info.max) { volt->vid[volt->vid_nr].uv = info.base; volt->vid[volt->vid_nr].vid = i; volt->vid_nr++; } info.base += info.step; } volt->vid_mask = info.vidmask; } else if (data && info.vidmask) { for (i = 0; i < cnt; i++) { data = nvbios_volt_entry_parse(device, i, &ver, &hdr, &ivid); if (data) { volt->vid[volt->vid_nr].uv = ivid.voltage; volt->vid[volt->vid_nr].vid = ivid.vid; volt->vid_nr++; } } volt->vid_mask = info.vidmask; } if (volt->vid_nr) { for (i = 0; i < volt->vid_nr; i++) { nv_debug(device, "VID %02x: %duv\n", volt->vid[i].vid, volt->vid[i].uv); } /*XXX: this is an assumption.. there probably exists boards * out there with i2c-connected voltage controllers too.. */ ret = nouveau_voltgpio_init(device); if (ret == 0) { volt->vid_get = nouveau_voltgpio_get; } } return ret; }
int gk104_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) { const struct nvkm_volt_func *volt_func = &gk104_volt_gpio; struct dcb_gpio_func gpio; struct nvbios_volt bios; struct gk104_volt *volt; u8 ver, hdr, cnt, len; const char *mode; if (!nvbios_volt_parse(device->bios, &ver, &hdr, &cnt, &len, &bios)) return 0; if (!nvkm_gpio_find(device->gpio, 0, DCB_GPIO_VID_PWM, 0xff, &gpio) && bios.type == NVBIOS_VOLT_PWM) { volt_func = &gk104_volt_pwm; } if (!(volt = kzalloc(sizeof(*volt), GFP_KERNEL))) return -ENOMEM; nvkm_volt_ctor(volt_func, device, index, &volt->base); *pvolt = &volt->base; volt->bios = bios; /* now that we have a subdev, we can show an error if we found through * the voltage table that we were supposed to use the PWN mode but we * did not find the right GPIO for it. */ if (bios.type == NVBIOS_VOLT_PWM && volt_func != &gk104_volt_pwm) { nvkm_error(&volt->base.subdev, "Type mismatch between the voltage table type and " "the GPIO table. Fallback to GPIO mode.\n"); } if (volt_func == &gk104_volt_gpio) { nvkm_voltgpio_init(&volt->base); mode = "GPIO"; } else mode = "PWM"; nvkm_debug(&volt->base.subdev, "Using %s mode\n", mode); return 0; }
int nouveau_volt_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, int length, void **pobject) { struct nouveau_bios *bios = nouveau_bios(parent); struct nouveau_volt *volt; struct nvbios_volt_entry ivid; struct nvbios_volt info; u8 ver, hdr, cnt, len; u16 data; int ret, i; ret = nouveau_subdev_create_(parent, engine, oclass, 0, "VOLT", "voltage", length, pobject); volt = *pobject; if (ret) return ret; volt->get = nouveau_volt_get; volt->set = nouveau_volt_set; volt->set_id = nouveau_volt_set_id; data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info); if (data && info.vidmask && info.base && info.step) { for (i = 0; i < info.vidmask + 1; i++) { if (info.base >= info.min && info.base <= info.max) { volt->vid[volt->vid_nr].uv = info.base; volt->vid[volt->vid_nr].vid = i; volt->vid_nr++; } info.base += info.step; } volt->vid_mask = info.vidmask; } else if (data && info.vidmask) { for (i = 0; i < cnt; i++) { data = nvbios_volt_entry_parse(bios, i, &ver, &hdr, &ivid); if (data) { volt->vid[volt->vid_nr].uv = ivid.voltage; volt->vid[volt->vid_nr].vid = ivid.vid; volt->vid_nr++; } } volt->vid_mask = info.vidmask; } if (volt->vid_nr) { for (i = 0; i < volt->vid_nr; i++) { nv_debug(volt, "VID %02x: %duv\n", volt->vid[i].vid, volt->vid[i].uv); } /*XXX: this is an assumption.. there probably exists boards * out there with i2c-connected voltage controllers too.. */ ret = nouveau_voltgpio_init(volt); if (ret == 0) { volt->vid_get = nouveau_voltgpio_get; volt->vid_set = nouveau_voltgpio_set; } } return ret; }