/** * INIT_REPEAT - opcode 0x33 * */ static void init_repeat(struct nvbios_init *init) { struct nouveau_bios *bios = init->bios; u8 count = nv_ro08(bios, init->offset + 1); u16 repeat = init->repeat; trace("REPEAT\t0x%02x\n", count); init->offset += 2; init->repeat = init->offset; init->repend = init->offset; while (count--) { init->offset = init->repeat; nvbios_exec(init);
static bool exec_script(struct nv50_disp_priv *priv, int head, int id) { struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_outp info; struct dcb_output dcb; u8 ver, hdr, cnt, len; u16 data; u32 ctrl = 0x00000000; u32 reg; int i; /* DAC */ for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++) ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { if (nv_device(priv)->chipset < 0x90 || nv_device(priv)->chipset == 0x92 || nv_device(priv)->chipset == 0xa0) { reg = 0x610b74; } else { reg = 0x610798; } for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++) ctrl = nv_rd32(priv, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++) ctrl = nv_rd32(priv, 0x610b84 + (i * 8)); i += 8; } if (!(ctrl & (1 << head))) return false; i--; data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); if (data) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = info.script[id], .outp = &dcb, .crtc = head, .execute = 1, }; return nvbios_exec(&init) == 0; } return false; } static u32 exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, struct dcb_output *outp) { struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_outp info1; struct nvbios_ocfg info2; u8 ver, hdr, cnt, len; u32 ctrl = 0x00000000; u32 data, conf = ~0; u32 reg; int i; /* DAC */ for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++) ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { if (nv_device(priv)->chipset < 0x90 || nv_device(priv)->chipset == 0x92 || nv_device(priv)->chipset == 0xa0) { reg = 0x610b70; } else { reg = 0x610794; } for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++) ctrl = nv_rd32(priv, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++) ctrl = nv_rd32(priv, 0x610b80 + (i * 8)); i += 8; } if (!(ctrl & (1 << head))) return conf; i--; data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); if (!data) return conf; if (outp->location == 0) { switch (outp->type) { case DCB_OUTPUT_TMDS: conf = (ctrl & 0x00000f00) >> 8; if (pclk >= 165000) conf |= 0x0100; break; case DCB_OUTPUT_LVDS: conf = priv->sor.lvdsconf; break; case DCB_OUTPUT_DP: conf = (ctrl & 0x00000f00) >> 8; break; case DCB_OUTPUT_ANALOG: default: conf = 0x00ff; break; } } else { conf = (ctrl & 0x00000f00) >> 8; pclk = pclk / 2; } data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); if (data && id < 0xff) { data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = data, .outp = outp, .crtc = head, .execute = 1, }; nvbios_exec(&init); } } return conf; }
static bool exec_script(struct nv50_disp_priv *priv, int head, int id) { struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_outp info; struct dcb_output dcb; u8 ver, hdr, cnt, len; u32 ctrl = 0x00000000; u16 data; int outp; for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { ctrl = nv_rd32(priv, 0x640180 + (outp * 0x20)); if (ctrl & (1 << head)) break; } if (outp == 8) return false; data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); if (data) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = info.script[id], .outp = &dcb, .crtc = head, .execute = 1, }; return nvbios_exec(&init) == 0; } return false; } static u32 exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, struct dcb_output *dcb) { struct nouveau_bios *bios = nouveau_bios(priv); struct nvbios_outp info1; struct nvbios_ocfg info2; u8 ver, hdr, cnt, len; u32 ctrl = 0x00000000; u32 data, conf = ~0; int outp; for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { ctrl = nv_rd32(priv, 0x660180 + (outp * 0x20)); if (ctrl & (1 << head)) break; } if (outp == 8) return false; data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1); if (data == 0x0000) return conf; switch (dcb->type) { case DCB_OUTPUT_TMDS: conf = (ctrl & 0x00000f00) >> 8; if (pclk >= 165000) conf |= 0x0100; break; case DCB_OUTPUT_LVDS: conf = priv->sor.lvdsconf; break; case DCB_OUTPUT_DP: conf = (ctrl & 0x00000f00) >> 8; break; case DCB_OUTPUT_ANALOG: default: conf = 0x00ff; break; } data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); if (data && id < 0xff) { data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = data, .outp = dcb, .crtc = head, .execute = 1, }; nvbios_exec(&init); } } return conf; } static void nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head) { exec_script(priv, head, 1); }
int nv50_devinit_init(struct nouveau_object *object) { struct nouveau_bios *bios = nouveau_bios(object); struct nv50_devinit_priv *priv = (void *)object; struct nvbios_outp info; struct dcb_output outp; u8 ver = 0xff, hdr, cnt, len; int ret, i = 0; if (!priv->base.post) { if (!nv_rdvgac(priv, 0, 0x00) && !nv_rdvgac(priv, 0, 0x1a)) { nv_info(priv, "adaptor not initialised\n"); priv->base.post = true; } } ret = nouveau_devinit_init(&priv->base); if (ret) return ret; /* if we ran the init tables, we have to execute the first script * pointer of each dcb entry's display encoder table in order * to properly initialise each encoder. */ while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { if (nvbios_outp_match(bios, outp.hasht, outp.hashm, &ver, &hdr, &cnt, &len, &info)) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = info.script[0], .outp = &outp, .crtc = -1, .execute = 1, }; nvbios_exec(&init); } i++; } return 0; } static int nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv50_devinit_priv *priv; int ret; ret = nouveau_devinit_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.pll_set = nv50_devinit_pll_set; return 0; } struct nouveau_oclass nv50_devinit_oclass = { .handle = NV_SUBDEV(DEVINIT, 0x50), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_devinit_ctor, .dtor = _nouveau_devinit_dtor, .init = nv50_devinit_init, .fini = _nouveau_devinit_fini, }, };
void nv50_devinit_init(struct nvkm_devinit *base) { struct nv50_devinit *init = nv50_devinit(base); struct nvkm_subdev *subdev = &init->base.subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct nvbios_outp info; struct dcb_output outp; u8 ver = 0xff, hdr, cnt, len; int i = 0; /* if we ran the init tables, we have to execute the first script * pointer of each dcb entry's display encoder table in order * to properly initialise each encoder. */ while (init->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { if (nvbios_outp_match(bios, outp.hasht, outp.hashm, &ver, &hdr, &cnt, &len, &info)) { struct nvbios_init exec = { .subdev = subdev, .bios = bios, .offset = info.script[0], .outp = &outp, .crtc = -1, .execute = 1, }; nvbios_exec(&exec); } i++; } } int nv50_devinit_new_(const struct nvkm_devinit_func *func, struct nvkm_device *device, int index, struct nvkm_devinit **pinit) { struct nv50_devinit *init; if (!(init = kzalloc(sizeof(*init), GFP_KERNEL))) return -ENOMEM; *pinit = &init->base; nvkm_devinit_ctor(func, device, index, &init->base); return 0; } static const struct nvkm_devinit_func nv50_devinit = { .preinit = nv50_devinit_preinit, .init = nv50_devinit_init, .post = nv04_devinit_post, .pll_set = nv50_devinit_pll_set, .disable = nv50_devinit_disable, }; int nv50_devinit_new(struct nvkm_device *device, int index, struct nvkm_devinit **pinit) { return nv50_devinit_new_(&nv50_devinit, device, index, pinit); }