static void nv10_devinit_meminit(struct nouveau_devinit *devinit) { struct nv10_devinit_priv *priv = (void *)devinit; const int mem_width[] = { 0x10, 0x00, 0x20 }; const int mem_width_count = nv_device(priv)->chipset >= 0x17 ? 3 : 2; uint32_t patt = 0xdeadbeef; struct io_mapping *fb; int i, j, k; /* Map the framebuffer aperture */ fb = fbmem_init(nv_device(priv)->pdev); if (!fb) { nv_error(priv, "failed to map fb\n"); return; } nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); /* Probe memory bus width */ for (i = 0; i < mem_width_count; i++) { nv_mask(priv, NV04_PFB_CFG0, 0x30, mem_width[i]); for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) fbmem_poke(fb, 0x1c, 0); fbmem_poke(fb, 0x1c, patt); fbmem_poke(fb, 0x3c, 0); if (fbmem_peek(fb, 0x1c) == patt) goto mem_width_found; } } mem_width_found: patt <<= 1; /* Probe amount of installed memory */ for (i = 0; i < 4; i++) { int off = nv_rd32(priv, 0x10020c) - 0x100000; fbmem_poke(fb, off, patt); fbmem_poke(fb, 0, 0); fbmem_peek(fb, 0); fbmem_peek(fb, 0); fbmem_peek(fb, 0); fbmem_peek(fb, 0); if (fbmem_peek(fb, off) == patt) goto amount_found; } /* IC missing - disable the upper half memory space. */ nv_mask(priv, NV04_PFB_CFG0, 0x1000, 0); amount_found: fbmem_fini(fb); }
static void nv20_devinit_meminit(struct nouveau_devinit *devinit) { struct nv20_devinit_priv *priv = (void *)devinit; struct nouveau_device *device = nv_device(priv); uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900); uint32_t amount, off; struct io_mapping *fb; /* Map the framebuffer aperture */ fb = fbmem_init(nv_device(priv)->pdev); if (!fb) { nv_error(priv, "failed to map fb\n"); return; } nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); /* Allow full addressing */ nv_mask(priv, NV04_PFB_CFG0, 0, mask); amount = nv_rd32(priv, 0x10020c); for (off = amount; off > 0x2000000; off -= 0x2000000) fbmem_poke(fb, off - 4, off); amount = nv_rd32(priv, 0x10020c); if (amount != fbmem_peek(fb, amount - 4)) /* IC missing - disable the upper half memory space. */ nv_mask(priv, NV04_PFB_CFG0, mask, 0); fbmem_fini(fb); }
/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied) * it affects only the 8 bit vga io regs, which we access using mmio at * 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d* * in general, the set value of cr44 does not matter: reg access works as * expected and values can be set for the appropriate head by using a 0x2000 * offset as required * however: * a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and * cr44 must be set to 0 or 3 for accessing values on the correct head * through the common 0xc03c* addresses * b) in tied mode (4) head B is programmed to the values set on head A, and * access using the head B addresses can have strange results, ergo we leave * tied mode in init once we know to what cr44 should be restored on exit * * the owner parameter is slightly abused: * 0 and 1 are treated as head values and so the set value is (owner * 3) * other values are treated as literal values to set */ u8 nv_rdvgaowner(void *obj) { if (nv_device(obj)->card_type < NV_50) { if (nv_device(obj)->chipset == 0x11) { u32 tied = nv_rd32(obj, 0x001084) & 0x10000000; if (tied == 0) { u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80; u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01; u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80; u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01; if (slA && !tvA) return 0x00; if (slB && !tvB) return 0x03; if (slA) return 0x00; if (slB) return 0x03; return 0x00; } return 0x04; } return nv_rdvgac(obj, 0, 0x44); } nv_error(obj, "rdvgaowner after nv4x\n"); return 0x00; }
static void gk20a_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) { struct gk20a_mem *mem = to_gk20a_mem(*pmem); *pmem = NULL; if (unlikely(mem == NULL)) return; #if defined(__NetBSD__) if (likely(mem->base.pages)) { const bus_dma_tag_t dmat = nv_device(pfb)->platformdev->dmat; bus_dmamap_unload(dmat, mem->base.pages); bus_dmamem_unmap(dmat, mem->cpuaddr, mem->dmasize); bus_dmamap_destroy(dmat, mem->base.pages); bus_dmamem_free(dmat, &mem->dmaseg, 1); } #else struct device *dev = nv_device_base(nv_device(pfb)); if (likely(mem->cpuaddr)) dma_free_coherent(dev, mem->base.size << PAGE_SHIFT, mem->cpuaddr, mem->handle); kfree(mem->base.pages); #endif kfree(mem); }
static void nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update) { struct drm_device *dev = nv_crtc->base.dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_channel *evo = nv50_display(dev)->master; int ret; NV_DEBUG(drm, "\n"); if (update && !nv_crtc->cursor.visible) return; ret = RING_SPACE(evo, (nv_device(drm->device)->chipset != 0x50 ? 5 : 3) + update * 2); if (ret) { NV_ERROR(drm, "no space while hiding cursor\n"); return; } BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2); OUT_RING(evo, NV50_EVO_CRTC_CURSOR_CTRL_HIDE); OUT_RING(evo, 0); if (nv_device(drm->device)->chipset != 0x50) { BEGIN_NV04(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1); OUT_RING(evo, NV84_EVO_CRTC_CURSOR_DMA_HANDLE_NONE); } if (update) { BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1); OUT_RING(evo, 0); FIRE_RING(evo); nv_crtc->cursor.visible = false; } }
u8 * nouveau_perf_rammap(struct drm_device *dev, u32 freq, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { struct nouveau_drm *drm = nouveau_drm(dev); struct bit_entry P; u8 *perf, i = 0; if (!bit_table(dev, 'P', &P) && P.version == 2) { u8 *rammap = ROMPTR(dev, P.data[4]); if (rammap) { u8 *ramcfg = rammap + rammap[1]; *ver = rammap[0]; *hdr = rammap[2]; *cnt = rammap[4]; *len = rammap[3]; freq /= 1000; for (i = 0; i < rammap[5]; i++) { if (freq >= ROM16(ramcfg[0]) && freq <= ROM16(ramcfg[2])) return ramcfg; ramcfg += *hdr + (*cnt * *len); } } return NULL; } if (nv_device(drm->device)->chipset == 0x49 || nv_device(drm->device)->chipset == 0x4b) freq /= 2; while ((perf = nouveau_perf_entry(dev, i++, ver, hdr, cnt, len))) { if (*ver >= 0x20 && *ver < 0x25) { if (perf[0] != 0xff && freq <= ROM16(perf[11]) * 1000) break; } else if (*ver >= 0x25 && *ver < 0x40) { if (perf[0] != 0xff && freq <= ROM16(perf[12]) * 1000) break; } } if (perf) { u8 *ramcfg = perf + *hdr; *ver = 0x00; *hdr = 0; return ramcfg; } return NULL; }
static void * prom_init(struct nvkm_bios *bios, const char *name) { if (nv_device(bios)->card_type < NV_50) { if (nv_device(bios)->card_type == NV_40 && nv_device(bios)->chipset >= 0x4c) return ERR_PTR(-ENODEV); nv_mask(bios, 0x001850, 0x00000001, 0x00000000); } else { nv_mask(bios, 0x088050, 0x00000001, 0x00000000); } return bios; }
int nv50_fan_pwm_clock(struct nouveau_therm *therm, int line) { int chipset = nv_device(therm)->chipset; int crystal = nv_device(therm)->crystal; int pwm_clock; /* determine the PWM source clock */ if (chipset > 0x50 && chipset < 0x94) { u8 pwm_div = nv_rd32(therm, 0x410c); if (nv_rd32(therm, 0xc040) & 0x800000) { /* Use the HOST clock (100 MHz) * Where does this constant(2.4) comes from? */ pwm_clock = (100000000 >> pwm_div) * 10 / 24; } else {
int nouveau_therm_fan_get(struct nouveau_therm *therm) { struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_gpio *gpio = nouveau_gpio(therm); struct dcb_gpio_func func; int card_type = nv_device(therm)->card_type; u32 divs, duty; int ret; if (!priv->fan.pwm_get) return -ENODEV; ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func); if (ret == 0) { ret = priv->fan.pwm_get(therm, func.line, &divs, &duty); if (ret == 0 && divs) { divs = max(divs, duty); if (card_type <= NV_40 || (func.log[0] & 1)) duty = divs - duty; return (duty * 100) / divs; } return gpio->get(gpio, 0, func.func, func.line) * 100; } return -ENODEV; }
static void * acpi_init(struct nvkm_bios *bios, const char *name) { if (!nouveau_acpi_rom_supported(nv_device(bios)->pdev)) return ERR_PTR(-ENODEV); return NULL; }
static enum nv40_sensor_style nv40_sensor_style(struct nouveau_therm *therm) { struct nouveau_device *device = nv_device(therm); switch (device->chipset) { case 0x43: case 0x44: case 0x4a: case 0x47: return OLD_STYLE; case 0x46: case 0x49: case 0x4b: case 0x4e: case 0x4c: case 0x67: case 0x68: case 0x63: return NEW_STYLE; default: return INVALID_STYLE; } }
static int nvkm_fanpwm_set(struct nvkm_therm *therm, int percent) { struct nvkm_therm_priv *tpriv = (void *)therm; struct nvkm_fanpwm_priv *priv = (void *)tpriv->fan; int card_type = nv_device(therm)->card_type; u32 divs, duty; int ret; divs = priv->base.perf.pwm_divisor; if (priv->base.bios.pwm_freq) { divs = 1; if (therm->pwm_clock) divs = therm->pwm_clock(therm, priv->func.line); divs /= priv->base.bios.pwm_freq; } duty = ((divs * percent) + 99) / 100; if (card_type <= NV_40 || (priv->func.log[0] & 1)) duty = divs - duty; ret = therm->pwm_set(therm, priv->func.line, divs, duty); if (ret == 0) ret = therm->pwm_ctrl(therm, priv->func.line, true); return ret; }
int nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode) { struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_device *device = nv_device(therm); static const char *name[] = { "disabled", "manual", "automatic" }; /* The default PDAEMON ucode interferes with fan management */ if ((mode >= ARRAY_SIZE(name)) || (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0)) return -EINVAL; /* do not allow automatic fan management if the thermal sensor is * not available */ if (priv->mode == 2 && therm->temp_get(therm) < 0) return -EINVAL; if (priv->mode == mode) return 0; nv_info(therm, "fan management: %s\n", name[mode]); nouveau_therm_update(therm, mode); return 0; }
int nouveau_subdev_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, u32 pclass, const char *subname, const char *sysname, int size, void **pobject) { struct nouveau_subdev *subdev; int ret; ret = nouveau_object_create_(parent, engine, oclass, pclass | NV_SUBDEV_CLASS, size, pobject); subdev = *pobject; if (ret) return ret; __mutex_init(&subdev->mutex, subname, &oclass->lock_class_key); subdev->name = subname; if (parent) { struct nouveau_device *device = nv_device(parent); subdev->debug = nouveau_dbgopt(device->dbgopt, subname); subdev->mmio = nv_subdev(device)->mmio; } return 0; }
static int nv40_temp_get(struct nouveau_therm *therm) { struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_device *device = nv_device(therm); struct nvbios_therm_sensor *sensor = &priv->bios_sensor; int core_temp; if (device->chipset >= 0x46) { nv_wr32(therm, 0x15b0, 0x80003fff); core_temp = nv_rd32(therm, 0x15b4) & 0x3fff; } else { nv_wr32(therm, 0x15b0, 0xff); core_temp = nv_rd32(therm, 0x15b4) & 0xff; } /* Setup the sensor if the temperature is 0 */ if (core_temp == 0) core_temp = nv40_sensor_setup(therm); if (sensor->slope_div == 0) sensor->slope_div = 1; if (sensor->offset_den == 0) sensor->offset_den = 1; if (sensor->slope_mult < 1) sensor->slope_mult = 1; core_temp = core_temp * sensor->slope_mult / sensor->slope_div; core_temp = core_temp + sensor->offset_num / sensor->offset_den; core_temp = core_temp + sensor->offset_constant - 8; return core_temp; }
static void nv50_fb_intr(struct nouveau_subdev *subdev) { struct nouveau_device *device = nv_device(subdev); struct nouveau_engine *engine; struct nv50_fb_priv *priv = (void *)subdev; const struct nouveau_enum *en, *cl; struct nouveau_object *engctx = NULL; u32 trap[6], idx, chan; u8 st0, st1, st2, st3; int i; idx = nv_rd32(priv, 0x100c90); if (!(idx & 0x80000000)) return; idx &= 0x00ffffff; for (i = 0; i < 6; i++) { nv_wr32(priv, 0x100c90, idx | i << 24); trap[i] = nv_rd32(priv, 0x100c94); } nv_wr32(priv, 0x100c90, idx | 0x80000000); /* decode status bits into something more useful */ if (device->chipset < 0xa3 || device->chipset == 0xaa || device->chipset == 0xac) { st0 = (trap[0] & 0x0000000f) >> 0; st1 = (trap[0] & 0x000000f0) >> 4; st2 = (trap[0] & 0x00000f00) >> 8; st3 = (trap[0] & 0x0000f000) >> 12; } else {
void nouveau_subdev_destroy(struct nouveau_subdev *subdev) { int subidx = nv_hclass(subdev) & 0xff; nv_device(subdev)->subdev[subidx] = NULL; nouveau_object_destroy(&subdev->base); }
int nvkm_fanpwm_create(struct nvkm_therm *therm, struct dcb_gpio_func *func) { struct nvkm_device *device = nv_device(therm); struct nvkm_therm_priv *tpriv = (void *)therm; struct nvkm_bios *bios = nvkm_bios(therm); struct nvkm_fanpwm_priv *priv; struct nvbios_therm_fan fan; u32 divs, duty; nvbios_fan_parse(bios, &fan); if (!nvkm_boolopt(device->cfgopt, "NvFanPWM", func->param) || !therm->pwm_ctrl || fan.type == NVBIOS_THERM_FAN_TOGGLE || therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV) return -ENODEV; priv = kzalloc(sizeof(*priv), GFP_KERNEL); tpriv->fan = &priv->base; if (!priv) return -ENOMEM; priv->base.type = "PWM"; priv->base.get = nvkm_fanpwm_get; priv->base.set = nvkm_fanpwm_set; priv->func = *func; return 0; }
static inline u32 init_nvreg(struct nvbios_init *init, u32 reg) { /* C51 (at least) sometimes has the lower bits set which the VBIOS * interprets to mean that access needs to go through certain IO * ports instead. The NVIDIA binary driver has been seen to access * these through the NV register address, so lets assume we can * do the same */ reg &= ~0x00000003; /* GF8+ display scripts need register addresses mangled a bit to * select a specific CRTC/OR */ if (nv_device(init->bios)->card_type >= NV_50) { if (reg & 0x80000000) { reg += init_crtc(init) * 0x800; reg &= ~0x80000000; } if (reg & 0x40000000) { reg += init_or(init) * 0x800; reg &= ~0x40000000; if (reg & 0x20000000) { reg += init_link(init) * 0x80; reg &= ~0x20000000; } } } if (reg & ~0x00fffffc) warn("unknown bits in register 0x%08x\n", reg); return reg; }
void _nouveau_mc_dtor(struct nouveau_object *object) { struct nouveau_device *device = nv_device(object); struct nouveau_mc *pmc = (void *)object; free_irq(device->pdev->irq, pmc); nouveau_subdev_destroy(&pmc->base); }
int nouveau_i2c_port_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, u8 index, const struct i2c_algorithm *algo, int size, void **pobject) { struct nouveau_device *device = nv_device(parent); struct nouveau_i2c *i2c = (void *)engine; struct nouveau_i2c_port *port; int ret; ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject); port = *pobject; if (ret) return ret; snprintf(port->adapter.name, sizeof(port->adapter.name), "nouveau-%s-%d", device->name, index); port->adapter.owner = THIS_MODULE; port->adapter.dev.parent = &device->pdev->dev; port->index = index; i2c_set_adapdata(&port->adapter, i2c); if ( algo == &nouveau_i2c_bit_algo && !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) { struct i2c_algo_bit_data *bit; bit = kzalloc(sizeof(*bit), GFP_KERNEL); if (!bit) return -ENOMEM; bit->udelay = 10; bit->timeout = usecs_to_jiffies(2200); bit->data = port; bit->pre_xfer = nouveau_i2c_pre_xfer; bit->setsda = nouveau_i2c_setsda; bit->setscl = nouveau_i2c_setscl; bit->getsda = nouveau_i2c_getsda; bit->getscl = nouveau_i2c_getscl; port->adapter.algo_data = bit; ret = i2c_bit_add_bus(&port->adapter); } else { port->adapter.algo_data = port; port->adapter.algo = algo; ret = i2c_add_adapter(&port->adapter); } /* drop port's i2c subdev refcount, i2c handles this itself */ if (ret == 0) { list_add_tail(&port->head, &i2c->ports); atomic_dec(&parent->refcount); atomic_dec(&engine->refcount); } return ret; }
static int nve0_ram_prog(struct nouveau_fb *pfb) { struct nouveau_device *device = nv_device(pfb); struct nve0_ram *ram = (void *)pfb->ram; struct nve0_ramfuc *fuc = &ram->fuc; ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true)); return (ram->base.next == &ram->base.xition); }
static void prom_fini(void *data) { struct nvkm_bios *bios = data; if (nv_device(bios)->card_type < NV_50) nv_mask(bios, 0x001850, 0x00000001, 0x00000001); else nv_mask(bios, 0x088050, 0x00000001, 0x00000001); }
static int nvc0_ram_prog(struct nouveau_fb *pfb) { struct nouveau_device *device = nv_device(pfb); struct nvc0_ram *ram = (void *)pfb->ram; struct nvc0_ramfuc *fuc = &ram->fuc; ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", false)); return 0; }
int nouveau_i2c_port_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, u8 index, const struct i2c_algorithm *algo, const struct nouveau_i2c_func *func, int size, void **pobject) { struct nouveau_device *device = nv_device(engine); struct nouveau_i2c *i2c = (void *)engine; struct nouveau_i2c_port *port; int ret; ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject); port = *pobject; if (ret) return ret; snprintf(port->adapter.name, sizeof(port->adapter.name), "nouveau-%s-%d", device->name, index); port->adapter.owner = THIS_MODULE; port->adapter.dev.parent = nv_device_base(device); port->index = index; port->aux = -1; port->func = func; mutex_init(&port->mutex); if ( algo == &nouveau_i2c_bit_algo && !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) { struct i2c_algo_bit_data *bit; bit = kzalloc(sizeof(*bit), GFP_KERNEL); if (!bit) return -ENOMEM; bit->udelay = 10; bit->timeout = usecs_to_jiffies(2200); bit->data = port; bit->pre_xfer = nouveau_i2c_pre_xfer; bit->post_xfer = nouveau_i2c_post_xfer; bit->setsda = nouveau_i2c_setsda; bit->setscl = nouveau_i2c_setscl; bit->getsda = nouveau_i2c_getsda; bit->getscl = nouveau_i2c_getscl; port->adapter.algo_data = bit; ret = i2c_bit_add_bus(&port->adapter); } else { port->adapter.algo_data = port; port->adapter.algo = algo; ret = i2c_add_adapter(&port->adapter); } if (ret == 0) list_add_tail(&port->head, &i2c->ports); return ret; }
static void nouveau_bios_shadow_pramin(struct nouveau_bios *bios) { struct nouveau_device *device = nv_device(bios); u64 addr = 0; u32 bar0 = 0; int i; if (device->card_type >= NV_50) { if (device->card_type >= NV_C0 && device->card_type < GM100) { if (nv_rd32(bios, 0x022500) & 0x00000001) return; } else if (device->card_type >= GM100) { if (nv_rd32(bios, 0x021c04) & 0x00000001) return; } addr = nv_rd32(bios, 0x619f04); if (!(addr & 0x00000008)) { nv_debug(bios, "... not enabled\n"); return; } if ( (addr & 0x00000003) != 1) { nv_debug(bios, "... not in vram\n"); return; } addr = (addr & 0xffffff00) << 8; if (!addr) { addr = (u64)nv_rd32(bios, 0x001700) << 16; addr += 0xf0000; } bar0 = nv_mask(bios, 0x001700, 0xffffffff, addr >> 16); } /* bail if no rom signature */ if (nv_rd08(bios, 0x700000) != 0x55 || nv_rd08(bios, 0x700001) != 0xaa) goto out; bios->size = nv_rd08(bios, 0x700002) * 512; if (!bios->size) goto out; bios->data = kmalloc(bios->size, GFP_KERNEL); if (bios->data) { for (i = 0; i < bios->size; i++) nv_wo08(bios, i, nv_rd08(bios, 0x700000 + i)); } out: if (device->card_type >= NV_50) nv_wr32(bios, 0x001700, bar0); }
void nv_wrvgaowner(void *obj, u8 select) { if (nv_device(obj)->card_type < NV_50) { u8 owner = (select == 1) ? 3 : select; if (nv_device(obj)->chipset == 0x11) { /* workaround hw lockup bug */ nv_rdvgac(obj, 0, 0x1f); nv_rdvgac(obj, 1, 0x1f); } nv_wrvgac(obj, 0, 0x44, owner); if (nv_device(obj)->chipset == 0x11) { nv_wrvgac(obj, 0, 0x2e, owner); nv_wrvgac(obj, 0, 0x2e, owner); } } else nv_error(obj, "wrvgaowner after nv4x\n"); }
static void init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value) { /* force head 0 for updates to cr44, it only exists on first head */ if (nv_device(init->subdev)->card_type < NV_50) { if (port == 0x03d4 && index == 0x44) init->crtc = 0; } if (init_exec(init)) { int head = init->crtc < 0 ? 0 : init->crtc; nv_wrvgai(init->subdev, head, port, index, value); } /* select head 1 if cr44 write selected it */ if (nv_device(init->subdev)->card_type < NV_50) { if (port == 0x03d4 && index == 0x44 && value == 3) init->crtc = 1; } }
static void nouveau_bios_shadow_prom(struct nouveau_bios *bios) { struct nouveau_device *device = nv_device(bios); u32 pcireg, access; u16 pcir; int i; /* enable access to rom */ if (device->card_type >= NV_50) pcireg = 0x088050; else pcireg = 0x001850; access = nv_mask(bios, pcireg, 0x00000001, 0x00000000); /* bail if no rom signature, with a workaround for a PROM reading * issue on some chipsets. the first read after a period of * inactivity returns the wrong result, so retry the first header * byte a few times before giving up as a workaround */ i = 16; do { if (nv_rd08(bios, 0x300000) == 0x55) break; } while (i--); if (!i || nv_rd08(bios, 0x300001) != 0xaa) goto out; /* additional check (see note below) - read PCI record header */ pcir = nv_rd08(bios, 0x300018) | nv_rd08(bios, 0x300019) << 8; if (nv_rd08(bios, 0x300000 + pcir) != 'P' || nv_rd08(bios, 0x300001 + pcir) != 'C' || nv_rd08(bios, 0x300002 + pcir) != 'I' || nv_rd08(bios, 0x300003 + pcir) != 'R') goto out; /* read entire bios image to system memory */ bios->size = nv_rd08(bios, 0x300002) * 512; if (!bios->size) goto out; bios->data = kmalloc(bios->size, GFP_KERNEL); if (bios->data) { for (i = 0; i < bios->size; i++) nv_wo08(bios, i, nv_rd08(bios, 0x300000 + i)); } out: /* disable access to rom */ nv_wr32(bios, pcireg, access); }
bool nv_lockvgac(void *obj, bool lock) { bool locked = !nv_rdvgac(obj, 0, 0x1f); u8 data = lock ? 0x99 : 0x57; nv_wrvgac(obj, 0, 0x1f, data); if (nv_device(obj)->chipset == 0x11) { if (!(nv_rd32(obj, 0x001084) & 0x10000000)) nv_wrvgac(obj, 1, 0x1f, data); } return locked; }