static int nv40_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) { u32 mask = enable ? 0x80000000 : 0x0000000; if (line == 2) nv_mask(therm, 0x0010f0, 0x80000000, mask); else if (line == 9) nv_mask(therm, 0x0015f4, 0x80000000, mask); else { nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; } return 0; }
static void gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv) { nv_mask(priv, 0x137250, 0x3f, 0); nv_mask(priv, 0x000200, 0x20, 0); usleep_range(20, 30); nv_mask(priv, 0x000200, 0x20, 0x20); nv_wr32(priv, 0x12004c, 0x4); nv_wr32(priv, 0x122204, 0x2); nv_rd32(priv, 0x122204); }
static int nv17_graph_mthd_lma_enable(struct nouveau_object *object, u32 mthd, void *args, u32 size) { struct nv10_graph_chan *chan = (void *)object->parent; struct nv10_graph_priv *priv = nv10_graph_priv(chan); nv04_graph_idle(priv); nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100); nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000); return 0; }
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_dac_power(NV50_DISP_MTHD_V1) { const u32 doff = outp->or * 0x800; union { struct nv50_disp_dac_pwr_v0 v0; } *args = data; u32 stat; int ret; nv_ioctl(object, "disp dac pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nv_ioctl(object, "disp dac pwr vers %d state %d data %d " "vsync %d hsync %d\n", args->v0.version, args->v0.state, args->v0.data, args->v0.vsync, args->v0.hsync); stat = 0x00000040 * !args->v0.state; stat |= 0x00000010 * !args->v0.data; stat |= 0x00000004 * !args->v0.vsync; stat |= 0x00000001 * !args->v0.hsync; } else return ret; nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); return 0; }
static void nve0_graph_mp_trap(struct nvc0_graph_priv *priv, int gpc, int tp) { int i; u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x648)); u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x650)); nv_error(priv, "GPC%i/TP%i/MP trap:", gpc, tp); for (i = 0; i <= 31; ++i) { if (!(gerr & (1 << i))) continue; pr_cont(" "); nouveau_enum_print(nve0_mp_global_error, i); } if (werr) { pr_cont(" "); nouveau_enum_print(nve0_mp_warp_error, werr & 0xffff); } pr_cont("\n"); /* disable MP trap to avoid spam */ nv_mask(priv, TPC_UNIT(gpc, tp, 0x50c), 0x2, 0x0); /* TODO: figure out how to resume after an MP trap */ }
static int auxch_init(struct nouveau_i2c *aux, int ch) { const u32 unksel = 1; /* nfi which to use, or if it matters.. */ const u32 ureq = unksel ? 0x00100000 : 0x00200000; const u32 urep = unksel ? 0x01000000 : 0x02000000; u32 ctrl, timeout; /* wait up to 1ms for any previous transaction to be done... */ timeout = 1000; do { ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); udelay(1); if (!timeout--) { AUX_ERR("begin idle timeout 0x%08x\n", ctrl); return -EBUSY; } } while (ctrl & 0x03010000); /* set some magic, and wait up to 1ms for it to appear */ nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); timeout = 1000; do { ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); udelay(1); if (!timeout--) { AUX_ERR("magic wait 0x%08x\n", ctrl); auxch_fini(aux, ch); return -EBUSY; } } while ((ctrl & 0x03000000) != urep); return 0; }
static void nvc0_bus_intr(struct nouveau_subdev *subdev) { struct nouveau_bus *pbus = nouveau_bus(subdev); u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); if (stat & 0x0000000e) { u32 addr = nv_rd32(pbus, 0x009084); u32 data = nv_rd32(pbus, 0x009088); nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n", (addr & 0x00000002) ? "write" : "read", data, (addr & 0x00fffffc), (stat & 0x00000002) ? "!ENGINE " : "", (stat & 0x00000004) ? "IBUS " : "", (stat & 0x00000008) ? "TIMEOUT " : ""); nv_wr32(pbus, 0x009084, 0x00000000); nv_wr32(pbus, 0x001100, (stat & 0x0000000e)); stat &= ~0x0000000e; } if (stat) { nv_error(pbus, "unknown intr 0x%08x\n", stat); nv_mask(pbus, 0x001140, stat, 0x00000000); } }
static int nv94_bus_hwsq_exec(struct nouveau_bus *pbus, u32 *data, u32 size) { struct nv50_bus_priv *priv = (void *)pbus; int i; nv_mask(pbus, 0x001098, 0x00000008, 0x00000000); nv_wr32(pbus, 0x001304, 0x00000000); nv_wr32(pbus, 0x001318, 0x00000000); for (i = 0; i < size; i++) nv_wr32(priv, 0x080000 + (i * 4), data[i]); nv_mask(pbus, 0x001098, 0x00000018, 0x00000018); nv_wr32(pbus, 0x00130c, 0x00000001); return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; }
static int nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) { struct nvc0_clock_priv *priv = (void *)clk; 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(clk, &info, freq, &N, &fN, &M, &P); if (ret < 0) return ret; switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); nv_wr32(priv, info.reg + 0x10, fN << 16); break; default: nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } return ret; }
int nv50_pior_power(NV50_DISP_MTHD_V1) { const u32 soff = outp->or * 0x800; union { struct nv50_disp_pior_pwr_v0 v0; } *args = data; u32 ctrl, type; int ret; nv_ioctl(object, "disp pior pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nv_ioctl(object, "disp pior pwr vers %d state %d type %x\n", args->v0.version, args->v0.state, args->v0.type); if (args->v0.type > 0x0f) return -EINVAL; ctrl = !!args->v0.state; type = args->v0.type; } else return ret; nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); priv->pior.type[outp->or] = type; 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 nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match) { struct nvkm_bios *bios = nvkm_bios(gpio); u8 ver, len; u16 entry; int ent = -1; while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { static const u32 regs[] = { 0xe100, 0xe28c }; u32 data = nv_ro32(bios, entry); u8 line = (data & 0x0000001f); u8 func = (data & 0x0000ff00) >> 8; u8 defs = !!(data & 0x01000000); u8 unk0 = !!(data & 0x02000000); u8 unk1 = !!(data & 0x04000000); u32 val = (unk1 << 16) | unk0; u32 reg = regs[line >> 4]; u32 lsh = line & 0x0f; if ( func == DCB_GPIO_UNUSED || (match != DCB_GPIO_UNUSED && match != func)) continue; gpio->set(gpio, 0, func, line, defs); nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh); } }
int nv50_mpeg_init(struct nvkm_object *object) { struct nv50_mpeg_priv *priv = (void *)object; int ret; ret = nvkm_mpeg_init(&priv->base); if (ret) return ret; nv_wr32(priv, 0x00b32c, 0x00000000); nv_wr32(priv, 0x00b314, 0x00000100); nv_wr32(priv, 0x00b0e0, 0x0000001a); nv_wr32(priv, 0x00b220, 0x00000044); nv_wr32(priv, 0x00b300, 0x00801ec1); nv_wr32(priv, 0x00b390, 0x00000000); nv_wr32(priv, 0x00b394, 0x00000000); nv_wr32(priv, 0x00b398, 0x00000000); nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); nv_wr32(priv, 0x00b100, 0xffffffff); nv_wr32(priv, 0x00b140, 0xffffffff); if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) { nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200)); return -EBUSY; } return 0; }
static int nvd0_disp_base_init(struct nouveau_object *object) { struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_base *base = (void *)object; int ret, i; u32 tmp; ret = nouveau_parent_init(&base->base); if (ret) return ret; /* The below segments of code copying values from one register to * another appear to inform EVO of the display capabilities or * something similar. */ /* ... CRTC caps */ for (i = 0; i < priv->head.nr; i++) { tmp = nv_rd32(priv, 0x616104 + (i * 0x800)); nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp); tmp = nv_rd32(priv, 0x616108 + (i * 0x800)); nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp); tmp = nv_rd32(priv, 0x61610c + (i * 0x800)); nv_wr32(priv, 0x6101bc + (i * 0x800), tmp); } /* ... DAC caps */ for (i = 0; i < priv->dac.nr; i++) { tmp = nv_rd32(priv, 0x61a000 + (i * 0x800)); nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp); } /* ... SOR caps */ for (i = 0; i < priv->sor.nr; i++) { tmp = nv_rd32(priv, 0x61c000 + (i * 0x800)); nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp); } /* steal display away from vbios, or something like that */ if (nv_rd32(priv, 0x6100ac) & 0x00000100) { nv_wr32(priv, 0x6100ac, 0x00000100); nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000); if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) { nv_error(priv, "timeout acquiring display\n"); return -EBUSY; } } /* point at display engine memory area (hash table, objects) */ nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ nv_wr32(priv, 0x610090, 0x00000000); nv_wr32(priv, 0x6100a0, 0x00000000); nv_wr32(priv, 0x6100b0, 0x00000307); return 0; }
int nv20_graph_context_fini(struct nouveau_object *object, bool suspend) { struct nv20_graph_priv *priv = (void *)object->engine; struct nv20_graph_chan *chan = (void *)object; int chid = -1; nv_mask(priv, 0x400720, 0x00000001, 0x00000000); if (nv_rd32(priv, 0x400144) & 0x00010000) chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24; if (chan->chid == chid) { nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4); nv_wr32(priv, 0x400788, 0x00000002); nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); nv_wr32(priv, 0x400144, 0x10000000); nv_mask(priv, 0x400148, 0xff000000, 0x1f000000); }
static int gf100_ltc_init(struct nvkm_object *object) { struct nvkm_ltc_priv *priv = (void *)object; u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); int ret; ret = nvkm_ltc_init(priv); if (ret) return ret; nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ nv_wr32(priv, 0x17e8d8, priv->ltc_nr); nv_wr32(priv, 0x17e8d4, priv->tag_base); nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); return 0; }
void nouveau_agp_reset(struct nouveau_drm *drm) { #if __OS_HAS_AGP struct nouveau_device *device = nv_device(drm->device); struct drm_device *dev = drm->dev; u32 save[2]; int ret; if (!nouveau_agp_enabled(drm)) return; /* First of all, disable fast writes, otherwise if it's * already enabled in the AGP bridge and we disable the card's * AGP controller we might be locking ourselves out of it. */ if ((nv_rd32(device, NV04_PBUS_PCI_NV_19) | dev->agp->mode) & PCI_AGP_COMMAND_FW) { struct drm_agp_info info; struct drm_agp_mode mode; ret = drm_agp_info(dev, &info); if (ret) return; mode.mode = get_agp_mode(drm, &info); mode.mode &= ~PCI_AGP_COMMAND_FW; ret = drm_agp_enable(dev, mode); if (ret) return; } /* clear busmaster bit, and disable AGP */ save[0] = nv_mask(device, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000); nv_wr32(device, NV04_PBUS_PCI_NV_19, 0); /* reset PGRAPH, PFIFO and PTIMER */ save[1] = nv_mask(device, 0x000200, 0x00011100, 0x00000000); nv_mask(device, 0x000200, 0x00011100, save[1]); /* and restore bustmaster bit (gives effect of resetting AGP) */ nv_wr32(device, NV04_PBUS_PCI_NV_1, save[0]); #endif }
static void gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4]) { nv_mask(priv, 0x17e338, 0x0000000f, i); nv_wr32(priv, 0x17e33c, color[0]); nv_wr32(priv, 0x17e340, color[1]); nv_wr32(priv, 0x17e344, color[2]); nv_wr32(priv, 0x17e348, color[3]); }
static int nv84_bsp_fini(struct drm_device *dev, int engine, bool suspend) { if (!(nv_rd32(dev, 0x000200) & 0x00008000)) return 0; nv_mask(dev, 0x000200, 0x00008000, 0x00000000); return 0; }
int nv50_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) { u32 data = enable ? 0x00000001 : 0x00000000; int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); if (ret == 0) nv_mask(therm, ctrl, 0x00010001 << line, data << line); return ret; }
void gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4]) { nv_mask(priv, 0x17ea44, 0x0000000f, i); nv_wr32(priv, 0x17ea48, color[0]); nv_wr32(priv, 0x17ea4c, color[1]); nv_wr32(priv, 0x17ea50, color[2]); nv_wr32(priv, 0x17ea54, color[3]); }
static int nvc0_bar_init(struct nouveau_object *object) { struct nvc0_bar_priv *priv = (void *)object; int ret; ret = nouveau_bar_init(&priv->base); if (ret) return ret; nv_mask(priv, 0x000200, 0x00000100, 0x00000000); nv_mask(priv, 0x000200, 0x00000100, 0x00000100); nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12); nv_wr32(priv, 0x001714, 0xc0000000 | priv->bar[0].mem->addr >> 12); return 0; }
int nve0_hdmi_ctrl(NV50_DISP_MTHD_V1) { const u32 hoff = (head * 0x800); const u32 hdmi = (head * 0x400); union { struct nv50_disp_sor_hdmi_pwr_v0 v0; } *args = data; u32 ctrl; int ret; nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " "max_ac_packet %d rekey %d\n", args->v0.version, args->v0.state, args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; ctrl |= args->v0.max_ac_packet << 16; ctrl |= args->v0.rekey; } else return ret; if (!(ctrl & 0x40000000)) { nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000); nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000); nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000); nv_wr32(priv, 0x690008 + hdmi, 0x000d0282); nv_wr32(priv, 0x69000c + hdmi, 0x0000006f); nv_wr32(priv, 0x690010 + hdmi, 0x00000000); nv_wr32(priv, 0x690014 + hdmi, 0x00000000); nv_wr32(priv, 0x690018 + hdmi, 0x00000000); nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001); /* ??? InfoFrame? */ nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000); nv_wr32(priv, 0x6900cc + hdmi, 0x00000010); nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001); /* ??? */ nv_wr32(priv, 0x690080 + hdmi, 0x82000000); /* HDMI_CTRL */ nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl); return 0; }
void nouveau_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_connector *nv_connector; struct drm_device *dev = encoder->dev; u32 max_ac_packet, rekey; nv_connector = nouveau_encoder_connector_get(nv_encoder); if (!mode || !nv_connector || !nv_connector->edid || !drm_detect_hdmi_monitor(nv_connector->edid)) { nouveau_hdmi_disconnect(encoder); return; } nouveau_hdmi_video_infoframe(encoder, mode); nouveau_hdmi_audio_infoframe(encoder, mode); hdmi_mask(encoder, 0x0d0, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ hdmi_mask(encoder, 0x068, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ hdmi_mask(encoder, 0x078, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ nv_mask(dev, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ nv_mask(dev, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ nv_mask(dev, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ /* value matches nvidia binary driver, and tegra constant */ rekey = 56; max_ac_packet = mode->htotal - mode->hdisplay; max_ac_packet -= rekey; max_ac_packet -= 18; /* constant from tegra */ max_ac_packet /= 32; /* enable hdmi */ hdmi_mask(encoder, 0x0a4, 0x5f1f003f, 0x40000000 | /* enable */ 0x1f000000 | /* unknown */ max_ac_packet << 16 | rekey); nouveau_audio_mode_set(encoder, mode); }
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 nv50_disp_mast_fini(struct nouveau_object *object, bool suspend) { struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; /* deactivate channel */ nv_mask(priv, 0x610200, 0x00000010, 0x00000000); nv_mask(priv, 0x610200, 0x00000003, 0x00000000); if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) { nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200)); if (suspend) return -EBUSY; } /* disable error reporting */ nv_mask(priv, 0x610028, 0x00010001, 0x00000000); return nv50_disp_chan_fini(&mast->base, suspend); }
static void nouveau_audio_disconnect(struct drm_encoder *encoder) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct drm_device *dev = encoder->dev; u32 or = nv_encoder->or * 0x800; if (hdmi_sor(encoder)) { nv_mask(dev, 0x61c448 + or, 0x00000003, 0x00000000); } }
int nv50_sor_power(struct nv50_disp_priv *priv, int or, u32 data) { const u32 stat = data & NV50_DISP_SOR_PWR_STATE; const u32 soff = (or * 0x800); nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000); nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000); nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000); return 0; }
int nve0_ram_init(struct nouveau_object *object) { struct nouveau_fb *pfb = (void *)object->parent; struct nve0_ram *ram = (void *)object; struct nouveau_bios *bios = nouveau_bios(pfb); static const u8 train0[] = { 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, }; static const u32 train1[] = { 0x00000000, 0xffffffff, 0x55555555, 0xaaaaaaaa, 0x33333333, 0xcccccccc, 0xf0f0f0f0, 0x0f0f0f0f, 0x00ff00ff, 0xff00ff00, 0x0000ffff, 0xffff0000, }; u8 ver, hdr, cnt, len, snr, ssz; u32 data, save; int ret, i; ret = nouveau_ram_init(&ram->base); if (ret) return ret; /* run a bunch of tables from rammap table. there's actually * individual pointers for each rammap entry too, but, nvidia * seem to just run the last two entries' scripts early on in * their init, and never again.. we'll just run 'em all once * for now. * * i strongly suspect that each script is for a separate mode * (likely selected by 0x10f65c's lower bits?), and the * binary driver skips the one that's already been setup by * the init tables. */ data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz); if (!data || hdr < 0x15) return -EINVAL; cnt = nv_ro08(bios, data + 0x14); /* guess at count */ data = nv_ro32(bios, data + 0x10); /* guess u32... */ save = nv_rd32(pfb, 0x10f65c); for (i = 0; i < cnt; i++) { nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4); nvbios_exec(&(struct nvbios_init) { .subdev = nv_subdev(pfb), .bios = bios, .offset = nv_ro32(bios, data), /* guess u32 */ .execute = 1, }); data += 4; }