static int nv50_disp_data_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv50_disp_priv *priv = (void *)engine; struct nouveau_engctx *ectx; int ret = -EBUSY; /* no context needed for channel objects... */ if (nv_mclass(parent) != NV_DEVICE_CLASS) { atomic_inc(&parent->refcount); *pobject = parent; return 1; } /* allocate display hardware to client */ mutex_lock(&nv_subdev(priv)->mutex); if (list_empty(&nv_engine(priv)->contexts)) { ret = nouveau_engctx_create(parent, engine, oclass, NULL, 0x10000, 0x10000, NVOBJ_FLAG_HEAP, &ectx); *pobject = nv_object(ectx); } mutex_unlock(&nv_subdev(priv)->mutex); return ret; }
static int nv25_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv20_graph_priv *priv; int ret; ret = nouveau_graph_create(parent, engine, oclass, true, &priv); *pobject = nv_object(priv); if (ret) return ret; ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); if (ret) return ret; nv_subdev(priv)->unit = 0x00001000; nv_subdev(priv)->intr = nv20_graph_intr; nv_engine(priv)->cclass = &nv25_graph_cclass; nv_engine(priv)->sclass = nv25_graph_sclass; nv_engine(priv)->tile_prog = nv20_graph_tile_prog; return 0; }
static int nv10_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv04_instmem_priv *imem = nv04_instmem(parent); struct nv04_fifo_priv *priv; int ret; ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv); *pobject = nv_object(priv); if (ret) return ret; nouveau_ramht_ref(imem->ramht, &priv->ramht); nouveau_gpuobj_ref(imem->ramro, &priv->ramro); nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc); nv_subdev(priv)->unit = 0x00000100; nv_subdev(priv)->intr = nv04_fifo_intr; nv_engine(priv)->cclass = &nv10_fifo_cclass; nv_engine(priv)->sclass = nv10_fifo_sclass; priv->base.pause = nv04_fifo_pause; priv->base.start = nv04_fifo_start; priv->ramfc_desc = nv10_ramfc; return 0; }
irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = arg; struct nouveau_device *device = nouveau_dev(dev); struct nouveau_mc *pmc = nouveau_mc(device); u32 stat; stat = nv_rd32(device, 0x000100); if (stat == 0 || stat == ~0) return IRQ_NONE; nv_subdev(pmc)->intr(nv_subdev(pmc)); if (device->card_type >= NV_D0) { if (nv_rd32(device, 0x000100) & 0x04000000) nvd0_display_intr(dev); } else if (device->card_type >= NV_50) { if (nv_rd32(device, 0x000100) & 0x04000000) nv50_display_intr(dev); } return IRQ_HANDLED; }
static void nv41_vm_flush(struct nouveau_vm *vm) { struct nv04_vm_priv *priv = (void *)vm->vmm; mutex_lock(&nv_subdev(priv)->mutex); nv_wr32(priv, 0x100810, 0x00000022); if (!nv_wait(priv, 0x100810, 0x00000020, 0x00000020)) { nv_warn(priv, "flush timeout, 0x%08x\n", nv_rd32(priv, 0x100810)); } nv_wr32(priv, 0x100810, 0x00000000); mutex_unlock(&nv_subdev(priv)->mutex); }
irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = arg; struct nouveau_device *device = nouveau_dev(dev); struct nouveau_mc *pmc = nouveau_mc(device); u32 stat; stat = nv_rd32(device, 0x000100); if (stat == 0 || stat == ~0) return IRQ_NONE; nv_subdev(pmc)->intr(nv_subdev(pmc)); return IRQ_HANDLED; }
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 nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv50_disp_priv *priv; int heads = nv_rd32(parent, 0x022448); int ret; ret = nouveau_disp_create(parent, engine, oclass, heads, "PDISP", "display", &priv); *pobject = nv_object(priv); if (ret) return ret; nv_engine(priv)->sclass = nvf0_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nvd0_disp_intr; INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor); priv->sclass = nvf0_disp_sclass; priv->head.nr = heads; priv->dac.nr = 3; priv->sor.nr = 4; priv->dac.power = nv50_dac_power; priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hdmi = nvd0_hdmi_ctrl; return 0; }
static int nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv50_disp_priv *priv; int ret; ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP", "display", &priv); *pobject = nv_object(priv); if (ret) return ret; ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); if (ret) return ret; nv_engine(priv)->sclass = nv94_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nv50_disp_intr; INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); priv->sclass = nv94_disp_sclass; priv->head.nr = 2; priv->dac.nr = 3; priv->sor.nr = 4; priv->pior.nr = 3; priv->dac.power = nv50_dac_power; priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hdmi = nv84_hdmi_ctrl; priv->pior.power = nv50_pior_power; return 0; }
int gf100_ltc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nouveau_fb *pfb = nouveau_fb(parent); struct nvkm_ltc_priv *priv; u32 parts, mask; int ret, i; ret = nvkm_ltc_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; parts = nv_rd32(priv, 0x022438); mask = nv_rd32(priv, 0x022554); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) priv->ltc_nr++; } priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28; ret = gf100_ltc_init_tag_ram(pfb, priv); if (ret) return ret; nv_subdev(priv)->intr = gf100_ltc_intr; return 0; }
int nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { struct nv50_devinit_priv *priv = (void *)devinit; struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_pll info; int N, fN, M, P; int ret; ret = nvbios_pll_parse(bios, type, &info); if (ret) return ret; ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P); if (ret < 0) return ret; switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: nv_wr32(priv, info.reg + 0, 0x50000610); nv_mask(priv, info.reg + 4, 0x003fffff, (P << 16) | (M << 8) | N); nv_wr32(priv, info.reg + 8, fN); break; default: nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } return ret; }
void nv_printk_(struct nouveau_object *object, const char *pfx, int level, const char *fmt, ...) { static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' }; char mfmt[256]; va_list args; if (object && !nv_iclass(object, NV_CLIENT_CLASS)) { struct nouveau_object *device = object; struct nouveau_object *subdev = object; char obuf[64], *ofmt = ""; if (object->engine) { snprintf(obuf, sizeof(obuf), "[0x%08x][%p]", nv_hclass(object), object); ofmt = obuf; subdev = object->engine; device = object->engine; } if (subdev->parent) device = subdev->parent; if (level > nv_subdev(subdev)->debug) return; snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx, name[level], nv_subdev(subdev)->name, nv_device(device)->name, ofmt, fmt); } else if (object && nv_iclass(object, NV_CLIENT_CLASS)) { if (level > nv_client(object)->debug) return; snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s] %s", pfx, name[level], nv_client(object)->name, fmt); } else { snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt); } va_start(args, fmt); vprintk(mfmt, args); va_end(args); }
static void nvc0_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma) { struct nvc0_bar_priv *priv = (void *)bar; int i = !(vma->vm == priv->bar[0].vm); nouveau_vm_unmap(vma); nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[i].pgd->addr, 5); nouveau_vm_put(vma); }
static int nv50_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct nv50_mpeg_priv *priv; int ret; ret = nvkm_mpeg_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; nv_subdev(priv)->unit = 0x00400002; nv_subdev(priv)->intr = nv50_vpe_intr; nv_engine(priv)->cclass = &nv50_mpeg_cclass; nv_engine(priv)->sclass = nv50_mpeg_sclass; return 0; }
static int nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv84_crypt_priv *priv; int ret; ret = nouveau_engine_create(parent, engine, oclass, true, "PCRYPT", "crypt", &priv); *pobject = nv_object(priv); if (ret) return ret; nv_subdev(priv)->unit = 0x00004000; nv_subdev(priv)->intr = nv84_crypt_intr; nv_engine(priv)->cclass = &nv84_crypt_cclass; nv_engine(priv)->sclass = nv84_crypt_sclass; return 0; }
static int g84_cipher_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct g84_cipher_priv *priv; int ret; ret = nvkm_engine_create(parent, engine, oclass, true, "PCIPHER", "cipher", &priv); *pobject = nv_object(priv); if (ret) return ret; nv_subdev(priv)->unit = 0x00004000; nv_subdev(priv)->intr = g84_cipher_intr; nv_engine(priv)->cclass = &g84_cipher_cclass; nv_engine(priv)->sclass = g84_cipher_sclass; return 0; }
static int nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq, struct nouveau_ram_data *data) { struct nouveau_bios *bios = nouveau_bios(pfb); struct nve0_ram *ram = (void *)pfb->ram; u8 strap, cnt, len; /* lookup memory config data relevant to the target frequency */ ram->base.rammap.data = nvbios_rammapEp(bios, freq / 1000, &ram->base.rammap.version, &ram->base.rammap.size, &cnt, &len, &data->bios); if (!ram->base.rammap.data || ram->base.rammap.version != 0x11 || ram->base.rammap.size < 0x09) { nv_error(pfb, "invalid/missing rammap entry\n"); return -EINVAL; } /* locate specific data set for the attached memory */ strap = nvbios_ramcfg_index(nv_subdev(pfb)); ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data, ram->base.rammap.version, ram->base.rammap.size, cnt, len, strap, &ram->base.ramcfg.version, &ram->base.ramcfg.size, &data->bios); if (!ram->base.ramcfg.data || ram->base.ramcfg.version != 0x11 || ram->base.ramcfg.size < 0x08) { nv_error(pfb, "invalid/missing ramcfg entry\n"); return -EINVAL; } /* lookup memory timings, if bios says they're present */ strap = nv_ro08(bios, ram->base.ramcfg.data + 0x00); if (strap != 0xff) { ram->base.timing.data = nvbios_timingEp(bios, strap, &ram->base.timing.version, &ram->base.timing.size, &cnt, &len, &data->bios); if (!ram->base.timing.data || ram->base.timing.version != 0x20 || ram->base.timing.size < 0x33) { nv_error(pfb, "invalid/missing timing entry\n"); return -EINVAL; } } else { ram->base.timing.data = 0; } data->freq = freq; return 0; }
static int nvc0_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem, u32 flags, struct nouveau_vma *vma) { struct nvc0_bar_priv *priv = (void *)bar; int ret; ret = nouveau_vm_get(priv->bar[0].vm, mem->size << 12, 12, flags, vma); if (ret) return ret; nouveau_vm_map(vma, mem); nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[0].pgd->addr, 5); return 0; }
static int nvc0_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nvc0_bus_priv *priv; int ret; ret = nouveau_bus_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; nv_subdev(priv)->intr = nvc0_bus_intr; return 0; }
static int nv04_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct nv04_sw_priv *priv; int ret; ret = nvkm_sw_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; nv_engine(priv)->cclass = &nv04_sw_cclass; nv_engine(priv)->sclass = nv04_sw_sclass; nv_subdev(priv)->intr = nv04_sw_intr; return 0; }
int nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv50_software_oclass *pclass = (void *)oclass; struct nv50_software_priv *priv; int ret; ret = nouveau_software_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; nv_engine(priv)->cclass = pclass->cclass; nv_engine(priv)->sclass = pclass->sclass; nv_subdev(priv)->intr = nv04_software_intr; return 0; }
static int nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { struct nv50_devinit_priv *priv = (void *)devinit; struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_pll info; int N1, M1, N2, M2, P; int ret; ret = nvbios_pll_parse(bios, type, &info); if (ret) { nv_error(devinit, "failed to retrieve pll data, %d\n", ret); return ret; } ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) { nv_error(devinit, "failed pll calculation\n"); return ret; } switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: nv_wr32(priv, info.reg + 0, 0x10000611); nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); nv_mask(priv, info.reg + 8, 0x7fff00ff, (P << 28) | (M2 << 16) | N2); break; case PLL_MEMORY: nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) | (info.bias_p << 19) | (P << 16)); nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); break; default: nv_mask(priv, info.reg + 0, 0x00070000, (P << 16)); nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); break; } return 0; }
static int nvc0_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nvc0_software_priv *priv; int ret; nv_warn(parent, "[%s]\n", __PRETTY_FUNCTION__); ret = nouveau_software_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; nv_engine(priv)->cclass = &nvc0_software_cclass; nv_engine(priv)->sclass = nvc0_software_sclass; nv_subdev(priv)->intr = nv04_software_intr; return 0; }
static int nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nouveau_xtensa *priv; int ret; ret = nouveau_xtensa_create(parent, engine, oclass, 0xf000, true, "PVP", "vp", &priv); *pobject = nv_object(priv); if (ret) return ret; nv_subdev(priv)->unit = 0x01020000; nv_engine(priv)->cclass = &nv84_vp_cclass; nv_engine(priv)->sclass = nv84_vp_sclass; priv->fifo_val = 0x111; priv->unkd28 = 0x9c544; return 0; }
int nouveau_xtensa_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, u32 addr, bool enable, const char *iname, const char *fname, int length, void **pobject) { struct nouveau_xtensa *xtensa; int ret; ret = nouveau_engine_create_(parent, engine, oclass, enable, iname, fname, length, pobject); xtensa = *pobject; if (ret) return ret; nv_subdev(xtensa)->intr = _nouveau_xtensa_intr; xtensa->addr = addr; return 0; }
void nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head, const struct nv50_disp_mthd_chan *chan) { struct nouveau_object *disp = nv_object(priv); const struct nv50_disp_impl *impl = (void *)disp->oclass; const struct nv50_disp_mthd_list *list; int i, j; if (debug > nv_subdev(priv)->debug) return; for (i = 0; (list = chan->data[i].mthd) != NULL; i++) { u32 base = head * chan->addr; for (j = 0; j < chan->data[i].nr; j++, base += list->addr) { const char *cname = chan->name; const char *sname = ""; char cname_[16], sname_[16]; if (chan->addr) { snprintf(cname_, sizeof(cname_), "%s %d", chan->name, head); cname = cname_; } if (chan->data[i].nr > 1) { snprintf(sname_, sizeof(sname_), " - %s %d", chan->data[i].name, j); sname = sname_; } nv_printk_(disp, debug, "%s%s:\n", cname, sname); nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev, list, j); } } }
int nv04_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { struct nouveau_bios *bios = nouveau_bios(devinit); struct nouveau_pll_vals pv; struct nvbios_pll info; int cv = bios->version.chip; int N1, M1, N2, M2, P; int ret; ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info); if (ret) return ret; ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) return -EINVAL; pv.refclk = info.refclk; pv.N1 = N1; pv.M1 = M1; pv.N2 = N2; pv.M2 = M2; pv.log2P = P; if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 || cv >= 0x40) { if (type > 0x405c) setPLL_double_highregs(devinit, type, &pv); else setPLL_double_lowregs(devinit, type, &pv); } else setPLL_single(devinit, type, &pv); return 0; }
static int g84_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct g84_therm_priv *priv; int ret; ret = nvkm_therm_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl; priv->base.base.pwm_get = nv50_fan_pwm_get; priv->base.base.pwm_set = nv50_fan_pwm_set; priv->base.base.pwm_clock = nv50_fan_pwm_clock; priv->base.base.temp_get = g84_temp_get; priv->base.sensor.program_alarms = g84_therm_program_alarms; nv_subdev(priv)->intr = g84_therm_intr; /* init the thresholds */ nvkm_therm_sensor_set_threshold_state(&priv->base.base, NVKM_THERM_THRS_SHUTDOWN, NVKM_THERM_THRS_LOWER); nvkm_therm_sensor_set_threshold_state(&priv->base.base, NVKM_THERM_THRS_FANBOOST, NVKM_THERM_THRS_LOWER); nvkm_therm_sensor_set_threshold_state(&priv->base.base, NVKM_THERM_THRS_CRITICAL, NVKM_THERM_THRS_LOWER); nvkm_therm_sensor_set_threshold_state(&priv->base.base, NVKM_THERM_THRS_DOWNCLOCK, NVKM_THERM_THRS_LOWER); return nvkm_therm_preinit(&priv->base.base); }
static int nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nvc0_ltcg_priv *priv; struct nouveau_fb *pfb = nouveau_fb(parent); u32 parts, mask; int ret, i; ret = nouveau_ltcg_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; parts = nv_rd32(priv, 0x022438); mask = nv_rd32(priv, 0x022554); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) priv->part_nr++; } priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28; nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ ret = nvc0_ltcg_init_tag_ram(pfb, priv); if (ret) return ret; priv->base.tags_alloc = nvc0_ltcg_tags_alloc; priv->base.tags_free = nvc0_ltcg_tags_free; priv->base.tags_clear = nvc0_ltcg_tags_clear; nv_subdev(priv)->intr = nvc0_ltcg_intr; return 0; }
static int nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv50_disp_priv *priv; int ret; ret = nouveau_disp_create(parent, engine, oclass, "PDISP", "display", &priv); *pobject = nv_object(priv); if (ret) return ret; nv_engine(priv)->sclass = nve0_disp_base_oclass; nv_engine(priv)->cclass = &nv50_disp_cclass; nv_subdev(priv)->intr = nvd0_disp_intr; priv->sclass = nve0_disp_sclass; priv->head.nr = nv_rd32(priv, 0x022448); priv->dac.nr = 3; priv->sor.nr = 4; priv->dac.power = nv50_dac_power; priv->dac.sense = nv50_dac_sense; priv->sor.power = nv50_sor_power; priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.dp_train = nvd0_sor_dp_train; priv->sor.dp_train_init = nv94_sor_dp_train_init; priv->sor.dp_train_fini = nv94_sor_dp_train_fini; priv->sor.dp_lnkctl = nvd0_sor_dp_lnkctl; priv->sor.dp_drvctl = nvd0_sor_dp_drvctl; INIT_LIST_HEAD(&priv->base.vblank.list); spin_lock_init(&priv->base.vblank.lock); return 0; }