static int nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct nv20_gr_priv *priv; int ret; ret = nvkm_gr_create(parent, engine, oclass, true, &priv); *pobject = nv_object(priv); if (ret) return ret; ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); if (ret) return ret; nv_subdev(priv)->unit = 0x00001000; nv_subdev(priv)->intr = nv20_gr_intr; nv_engine(priv)->cclass = &nv35_gr_cclass; nv_engine(priv)->sclass = nv35_gr_sclass; nv_engine(priv)->tile_prog = nv20_gr_tile_prog; return 0; }
int nouveau_client_create_(const char *name, u64 devname, const char *cfg, const char *dbg, int length, void **pobject) { struct nouveau_object *device; struct nouveau_client *client; int ret; device = (void *)nouveau_device_find(devname); if (!device) return -ENODEV; ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass, NV_CLIENT_CLASS, NULL, (1ULL << NVDEV_ENGINE_DEVICE), length, pobject); client = *pobject; if (ret) return ret; ret = nouveau_handle_create(nv_object(client), ~0, ~0, nv_object(client), &client->root); if (ret) return ret; /* prevent init/fini being called, os in in charge of this */ atomic_set(&nv_object(client)->usecount, 2); nouveau_object_ref(device, &client->device); snprintf(client->name, sizeof(client->name), "%s", name); client->debug = nouveau_dbgopt(dbg, "CLIENT"); return 0; }
int nv50_software_context_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nouveau_disp *pdisp = nouveau_disp(parent); struct nv50_software_cclass *pclass = (void *)oclass; struct nv50_software_chan *chan; int ret, i; ret = nouveau_software_context_create(parent, engine, oclass, &chan); *pobject = nv_object(chan); if (ret) return ret; chan->vblank.nr_event = pdisp ? pdisp->vblank->index_nr : 0; chan->vblank.event = kzalloc(chan->vblank.nr_event * sizeof(*chan->vblank.event), GFP_KERNEL); if (!chan->vblank.event) return -ENOMEM; for (i = 0; i < chan->vblank.nr_event; i++) { ret = nouveau_event_new(pdisp->vblank, i, pclass->vblank, chan, &chan->vblank.event[i]); if (ret) return ret; } chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; return 0; }
int nv50_i2c_sense_sda(struct nouveau_i2c_port *base) { struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine; struct nv50_i2c_port *port = (void *)base; return !!(nv_rd32(priv, port->addr) & 0x00000002); }
static int nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) { struct nouveau_bios *bios = nouveau_bios(gpio); u8 ver, len; u16 data; if (line == 0xff && tag == 0xff) return -EINVAL; data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func); if (data) return 0; /* Apple iMac G4 NV18 */ if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) { if (tag == DCB_GPIO_TVDAC0) { *func = (struct dcb_gpio_func) { .func = DCB_GPIO_TVDAC0, .line = 4, .log[0] = 0, .log[1] = 1, }; return 0; } } return -ENOENT; }
static int nv41_ram_create(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 nouveau_ram *ram; u32 pfb474 = nv_rd32(pfb, 0x100474); int ret; ret = nouveau_ram_create(parent, engine, oclass, &ram); *pobject = nv_object(ram); if (ret) return ret; if (pfb474 & 0x00000004) ram->type = NV_MEM_TYPE_GDDR3; if (pfb474 & 0x00000002) ram->type = NV_MEM_TYPE_DDR2; if (pfb474 & 0x00000001) ram->type = NV_MEM_TYPE_DDR1; ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; ram->tags = nv_rd32(pfb, 0x100320); return 0; }
static int nv04_instobj_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 *priv = (void *)engine; struct nv04_instobj_priv *node; struct nouveau_instobj_args *args = data; int ret; if (!args->align) args->align = 1; ret = nouveau_instobj_create(parent, engine, oclass, &node); *pobject = nv_object(node); if (ret) return ret; ret = nouveau_mm_head(&priv->heap, 1, args->size, args->size, args->align, &node->mem); if (ret) return ret; node->base.addr = node->mem->offset; node->base.size = node->mem->length; return 0; }
static int nvd0_disp_ovly_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv50_display_ovly_class *args = data; struct nv50_disp_priv *priv = (void *)engine; struct nv50_disp_dmac *dmac; int ret; if (size < sizeof(*args) || args->head >= priv->head.nr) return -EINVAL; ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, 5 + args->head, sizeof(*dmac), (void **)&dmac); *pobject = nv_object(dmac); if (ret) return ret; nv_parent(dmac)->object_attach = nvd0_disp_dmac_object_attach; nv_parent(dmac)->object_detach = nvd0_disp_dmac_object_detach; return 0; }
static int nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 index, struct nouveau_object **pobject) { struct dcb_i2c_entry *info = data; struct nv50_i2c_port *port; int ret; ret = nouveau_i2c_port_create(parent, engine, oclass, index, &nouveau_i2c_bit_algo, &nv94_i2c_func, &port); *pobject = nv_object(port); if (ret) return ret; if (info->drive >= nv50_i2c_addr_nr) return -EINVAL; port->state = 7; port->addr = nv50_i2c_addr[info->drive]; if (info->share != DCB_I2C_UNUSED) { port->ctrl = 0x00e500 + (info->share * 0x50); port->data = 0x0000e001; } return 0; }
static int gm107_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, 0x021c14); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) priv->ltc_nr++; } priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28; ret = gf100_ltc_init_tag_ram(pfb, priv); if (ret) return ret; return 0; }
static int nv50_instobj_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 nv50_instobj_priv *node; u32 align = (unsigned long)data; int ret; size = max((size + 4095) & ~4095, (u32)4096); align = max((align + 4095) & ~4095, (u32)4096); ret = nouveau_instobj_create(parent, engine, oclass, &node); *pobject = nv_object(node); if (ret) return ret; ret = pfb->ram.get(pfb, size, align, 0, 0x800, &node->mem); if (ret) return ret; node->base.addr = node->mem->offset; node->base.size = node->mem->size << 12; node->mem->page_shift = 12; 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; }
int nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 index, struct nouveau_object **pobject) { struct dcb_i2c_entry *info = data; struct nv50_i2c_port *port; int ret; ret = nouveau_i2c_port_create(parent, engine, oclass, index, &nouveau_i2c_aux_algo, &nv94_aux_func, &port); *pobject = nv_object(port); if (ret) return ret; port->base.aux = info->drive; port->addr = info->drive; if (info->share != DCB_I2C_UNUSED) { port->ctrl = 0x00e500 + (info->drive * 0x50); port->data = 0x00002002; } return 0; }
static int gf100_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct gf100_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->ltc_nr++; } priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28; ret = gf100_ltcg_init_tag_ram(pfb, priv); if (ret) return ret; priv->base.tags_alloc = gf100_ltcg_tags_alloc; priv->base.tags_free = gf100_ltcg_tags_free; priv->base.tags_clear = gf100_ltcg_tags_clear; nv_subdev(priv)->intr = gf100_ltcg_intr; return 0; }
static int nv84_fence_context_new(struct nouveau_channel *chan) { struct drm_device *dev = chan->drm->dev; struct nouveau_fifo_chan *fifo = (void *)chan->object; struct nv84_fence_priv *priv = chan->drm->fence; struct nv84_fence_chan *fctx; struct nouveau_object *object; int ret, i; fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); if (!fctx) return -ENOMEM; nouveau_fence_context_new(&fctx->base); ret = nouveau_object_new(nv_object(chan->cli), chan->handle, NvSema, 0x0002, &(struct nv_dma_class) { .flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR, .start = priv->mem->addr, .limit = priv->mem->addr + priv->mem->size - 1, }, sizeof(struct nv_dma_class),
static int nvc0_software_mthd_mp_control(struct nouveau_object *object, u32 mthd, void *args, u32 size) { struct nvc0_software_chan *chan = (void *)nv_engctx(object->parent); struct nvc0_software_priv *priv = (void *)nv_object(chan)->engine; u32 data = *(u32 *)args; switch (mthd) { case 0x600: nv_wr32(priv, 0x419e00, data); /* MP.PM_UNK000 */ break; case 0x644: if (data & ~0x1ffffe) return -EINVAL; nv_wr32(priv, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */ break; case 0x6ac: nv_wr32(priv, 0x419eac, data); /* MP.PM_UNK0AC */ break; default: return -EINVAL; } return 0; }
static int anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh) { struct anx9805_i2c_port *chan = (void *)port; struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent; u8 tmp, i; nv_wri2cr(mast, chan->addr, 0xa0, link_bw); nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); nv_wri2cr(mast, chan->addr, 0xa2, 0x01); nv_wri2cr(mast, chan->addr, 0xa8, 0x01); i = 0; while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) { mdelay(5); if (i++ == 100) { nv_error(port, "link training timed out\n"); return -ETIMEDOUT; } } if (tmp & 0x70) { nv_error(port, "link training failed: 0x%02x\n", tmp); return -EIO; } return 1; }
static int nv10_fence_context_new(struct nouveau_channel *chan) { struct nv10_fence_priv *priv = chan->drm->fence; struct nv10_fence_chan *fctx; int ret = 0; fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); if (!fctx) return -ENOMEM; nouveau_fence_context_new(&fctx->base); if (priv->bo) { struct ttm_mem_reg *mem = &priv->bo->bo.mem; struct nouveau_object *object; u32 start = mem->start * PAGE_SIZE; u32 limit = start + mem->size - 1; ret = nouveau_object_new(nv_object(chan->cli), chan->handle, NvSema, 0x0002, &(struct nv_dma_class) { .flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR, .start = start, .limit = limit, }, sizeof(struct nv_dma_class), &object); }
static int nv44_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct nvkm_fb *pfb = nvkm_fb(parent); struct nv40_ram *ram; u32 pfb474 = nv_rd32(pfb, 0x100474); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); *pobject = nv_object(ram); if (ret) return ret; if (pfb474 & 0x00000004) ram->base.type = NV_MEM_TYPE_GDDR3; if (pfb474 & 0x00000002) ram->base.type = NV_MEM_TYPE_DDR2; if (pfb474 & 0x00000001) ram->base.type = NV_MEM_TYPE_DDR1; ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; return 0; }
static int nv50_fence_context_new(struct nouveau_channel *chan) { struct drm_device *dev = chan->drm->dev; struct nv10_fence_priv *priv = chan->drm->fence; struct nv10_fence_chan *fctx; struct ttm_mem_reg *mem = &priv->bo->bo.mem; struct nouveau_object *object; int ret, i; fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); if (!fctx) return -ENOMEM; nouveau_fence_context_new(&fctx->base); fctx->base.emit = nv10_fence_emit; fctx->base.read = nv10_fence_read; fctx->base.sync = nv17_fence_sync; ret = nouveau_object_new(nv_object(chan->cli), chan->handle, NvSema, 0x0002, &(struct nv_dma_class) { .flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR, .start = mem->start * PAGE_SIZE, .limit = mem->size - 1, }, sizeof(struct nv_dma_class),
static int nv49_ram_create(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 nv40_ram *ram; u32 pfb914 = nv_rd32(pfb, 0x100914); int ret; ret = nouveau_ram_create(parent, engine, oclass, &ram); *pobject = nv_object(ram); if (ret) return ret; switch (pfb914 & 0x00000003) { case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break; case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break; case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break; case 0x00000003: break; } ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; ram->base.tags = nv_rd32(pfb, 0x100320); ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; return 0; }
int nv04_pm_clocks_set(struct drm_device *dev, void *pre_state) { struct nouveau_device *device = nouveau_dev(dev); struct nouveau_timer *ptimer = nouveau_timer(device); struct nv04_pm_state *state = pre_state; prog_pll(dev, &state->core); if (state->memory.pll.reg) { prog_pll(dev, &state->memory); if (device->card_type < NV_30) { if (device->card_type == NV_20) nv_mask(device, 0x1002c4, 0, 1 << 20); /* Reset the DLLs */ nv_mask(device, 0x1002c0, 0, 1 << 8); } } nv_ofuncs(ptimer)->init(nv_object(ptimer)); kfree(state); return 0; }
static int nvaa_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 datasize, struct nouveau_object **pobject) { const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ struct nouveau_fb *pfb = nouveau_fb(parent); struct nouveau_ram *ram; int ret; ret = nouveau_ram_create(parent, engine, oclass, &ram); *pobject = nv_object(ram); if (ret) return ret; ram->size = nv_rd32(pfb, 0x10020c); ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32); ret = nouveau_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) - (rsvd_head + rsvd_tail), 1); if (ret) return ret; ram->type = NV_MEM_TYPE_STOLEN; ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12; ram->get = nv50_ram_get; ram->put = nv50_ram_put; return 0; }
void nv50_disp_chan_destroy(struct nv50_disp_chan *chan) { struct nv50_disp_base *base = (void *)nv_object(chan)->parent; base->chan &= ~(1 << chan->chid); nouveau_namedb_destroy(&chan->base); }
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 void nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c, const struct nv50_disp_mthd_list *list, int inst) { struct nouveau_object *disp = nv_object(priv); int i; for (i = 0; list->data[i].mthd; i++) { if (list->data[i].addr) { u32 next = nv_rd32(priv, list->data[i].addr + base + 0); u32 prev = nv_rd32(priv, list->data[i].addr + base + c); u32 mthd = list->data[i].mthd + (list->mthd * inst); const char *name = list->data[i].name; char mods[16]; if (prev != next) snprintf(mods, sizeof(mods), "-> 0x%08x", next); else snprintf(mods, sizeof(mods), "%13c", ' '); nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n", mthd, prev, mods, name ? " // " : "", name ? name : ""); } } }
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; }
static int nouveau_bios_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nouveau_bios *bios; struct bit_entry bit_i; int ret; ret = nouveau_subdev_create(parent, engine, oclass, 0, "VBIOS", "bios", &bios); *pobject = nv_object(bios); if (ret) return ret; ret = nouveau_bios_shadow(bios); if (ret) return ret; /* detect type of vbios we're dealing with */ bios->bmp_offset = nvbios_findstr(bios->data, bios->size, "\xff\x7f""NV\0", 5); if (bios->bmp_offset) { nv_info(bios, "BMP version %x.%x\n", bmp_version(bios) >> 8, bmp_version(bios) & 0xff); }
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; }
int _nvkm_i2c_port_fini(struct nvkm_object *object, bool suspend) { struct nvkm_i2c_port *port = (void *)object; struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); nv_ofuncs(pad)->fini(nv_object(pad), suspend); return nvkm_object_fini(&port->base, suspend); }