diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/subdev')
59 files changed, 1962 insertions, 1182 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c index 649f1ced1fe0..160d27f3c7b4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c @@ -53,7 +53,6 @@ nv50_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem, return ret; nouveau_vm_map(vma, mem); - nv50_vm_flush_engine(nv_subdev(bar), 6); return 0; } @@ -69,7 +68,6 @@ nv50_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem, return ret; nouveau_vm_map(vma, mem); - nv50_vm_flush_engine(nv_subdev(bar), 6); return 0; } @@ -77,7 +75,6 @@ static void nv50_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma) { nouveau_vm_unmap(vma); - nv50_vm_flush_engine(nv_subdev(bar), 6); nouveau_vm_put(vma); } @@ -147,6 +144,8 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + ret = nouveau_gpuobj_new(nv_object(priv), heap, ((limit-- - start) >> 12) * 8, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]); @@ -179,6 +178,8 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + ret = nouveau_vm_ref(vm, &priv->bar1_vm, priv->pgd); nouveau_vm_ref(NULL, &vm, NULL); if (ret) @@ -237,7 +238,11 @@ nv50_bar_init(struct nouveau_object *object) nv_mask(priv, 0x000200, 0x00000100, 0x00000000); nv_mask(priv, 0x000200, 0x00000100, 0x00000100); - nv50_vm_flush_engine(nv_subdev(priv), 6); + nv_wr32(priv, 0x100c80, 0x00060001); + if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) { + nv_error(priv, "vm flush timeout\n"); + return -EBUSY; + } nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12); nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12); diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c index f8a44956dec1..b2ec7411eb2e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c @@ -51,7 +51,6 @@ nvc0_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem, return ret; nouveau_vm_map(vma, mem); - nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[0].pgd->addr, 5); return 0; } @@ -68,18 +67,13 @@ nvc0_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem, return ret; nouveau_vm_map(vma, mem); - nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[1].pgd->addr, 5); return 0; } 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); } @@ -116,6 +110,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + ret = nouveau_gpuobj_new(nv_object(priv), NULL, (pci_resource_len(pdev, 3) >> 12) * 8, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, @@ -150,6 +146,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + ret = nouveau_vm_ref(vm, &priv->bar[1].vm, priv->bar[1].pgd); nouveau_vm_ref(NULL, &vm, NULL); if (ret) diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index 0e2c1a4f1659..aa0fbbec7f08 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -85,11 +85,15 @@ 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) { - u64 addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8; + if ( device->card_type < NV_C0 || + !(nv_rd32(bios, 0x022500) & 0x00000001)) + addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8; + if (!addr) { addr = (u64)nv_rd32(bios, 0x001700) << 16; addr += 0xf0000; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index c434d398d16f..0687e6481438 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -10,7 +10,6 @@ #include <subdev/bios/gpio.h> #include <subdev/bios/init.h> #include <subdev/devinit.h> -#include <subdev/clock.h> #include <subdev/i2c.h> #include <subdev/vga.h> #include <subdev/gpio.h> @@ -300,9 +299,9 @@ init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) static void init_prog_pll(struct nvbios_init *init, u32 id, u32 freq) { - struct nouveau_clock *clk = nouveau_clock(init->bios); - if (clk && clk->pll_set && init_exec(init)) { - int ret = clk->pll_set(clk, id, freq); + struct nouveau_devinit *devinit = nouveau_devinit(init->bios); + if (devinit->pll_set && init_exec(init)) { + int ret = devinit->pll_set(devinit, id, freq); if (ret) warn("failed to prog pll 0x%08x to %dkHz\n", id, freq); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c index b7fd1151166e..a14277586595 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c @@ -22,9 +22,10 @@ * Authors: Ben Skeggs */ -#include <subdev/clock.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> +#include <subdev/clock.h> +#include <subdev/devinit/priv.h> #include "pll.h" @@ -32,272 +33,12 @@ struct nv04_clock_priv { struct nouveau_clock base; }; -static int -powerctrl_1_shift(int chip_version, int reg) -{ - int shift = -4; - - if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20) - return shift; - - switch (reg) { - case 0x680520: - shift += 4; - case 0x680508: - shift += 4; - case 0x680504: - shift += 4; - case 0x680500: - shift += 4; - } - - /* - * the shift for vpll regs is only used for nv3x chips with a single - * stage pll - */ - if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 || - chip_version == 0x36 || chip_version >= 0x40)) - shift = -4; - - return shift; -} - -static void -setPLL_single(struct nv04_clock_priv *priv, u32 reg, - struct nouveau_pll_vals *pv) -{ - int chip_version = nouveau_bios(priv)->version.chip; - uint32_t oldpll = nv_rd32(priv, reg); - int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff; - uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1; - uint32_t saved_powerctrl_1 = 0; - int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg); - - if (oldpll == pll) - return; /* already set */ - - if (shift_powerctrl_1 >= 0) { - saved_powerctrl_1 = nv_rd32(priv, 0x001584); - nv_wr32(priv, 0x001584, - (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | - 1 << shift_powerctrl_1); - } - - if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1)) - /* upclock -- write new post divider first */ - nv_wr32(priv, reg, pv->log2P << 16 | (oldpll & 0xffff)); - else - /* downclock -- write new NM first */ - nv_wr32(priv, reg, (oldpll & 0xffff0000) | pv->NM1); - - if (chip_version < 0x17 && chip_version != 0x11) - /* wait a bit on older chips */ - msleep(64); - nv_rd32(priv, reg); - - /* then write the other half as well */ - nv_wr32(priv, reg, pll); - - if (shift_powerctrl_1 >= 0) - nv_wr32(priv, 0x001584, saved_powerctrl_1); -} - -static uint32_t -new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580) -{ - bool head_a = (reg1 == 0x680508); - - if (ss) /* single stage pll mode */ - ramdac580 |= head_a ? 0x00000100 : 0x10000000; - else - ramdac580 &= head_a ? 0xfffffeff : 0xefffffff; - - return ramdac580; -} - -static void -setPLL_double_highregs(struct nv04_clock_priv *priv, u32 reg1, - struct nouveau_pll_vals *pv) -{ - int chip_version = nouveau_bios(priv)->version.chip; - bool nv3035 = chip_version == 0x30 || chip_version == 0x35; - uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70); - uint32_t oldpll1 = nv_rd32(priv, reg1); - uint32_t oldpll2 = !nv3035 ? nv_rd32(priv, reg2) : 0; - uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1; - uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2; - uint32_t oldramdac580 = 0, ramdac580 = 0; - bool single_stage = !pv->NM2 || pv->N2 == pv->M2; /* nv41+ only */ - uint32_t saved_powerctrl_1 = 0, savedc040 = 0; - int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1); - - /* model specific additions to generic pll1 and pll2 set up above */ - if (nv3035) { - pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 | - (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4; - pll2 = 0; - } - if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */ - oldramdac580 = nv_rd32(priv, 0x680580); - ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580); - if (oldramdac580 != ramdac580) - oldpll1 = ~0; /* force mismatch */ - if (single_stage) - /* magic value used by nvidia in single stage mode */ - pll2 |= 0x011f; - } - if (chip_version > 0x70) - /* magic bits set by the blob (but not the bios) on g71-73 */ - pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28; - - if (oldpll1 == pll1 && oldpll2 == pll2) - return; /* already set */ - - if (shift_powerctrl_1 >= 0) { - saved_powerctrl_1 = nv_rd32(priv, 0x001584); - nv_wr32(priv, 0x001584, - (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | - 1 << shift_powerctrl_1); - } - - if (chip_version >= 0x40) { - int shift_c040 = 14; - - switch (reg1) { - case 0x680504: - shift_c040 += 2; - case 0x680500: - shift_c040 += 2; - case 0x680520: - shift_c040 += 2; - case 0x680508: - shift_c040 += 2; - } - - savedc040 = nv_rd32(priv, 0xc040); - if (shift_c040 != 14) - nv_wr32(priv, 0xc040, savedc040 & ~(3 << shift_c040)); - } - - if (oldramdac580 != ramdac580) - nv_wr32(priv, 0x680580, ramdac580); - - if (!nv3035) - nv_wr32(priv, reg2, pll2); - nv_wr32(priv, reg1, pll1); - - if (shift_powerctrl_1 >= 0) - nv_wr32(priv, 0x001584, saved_powerctrl_1); - if (chip_version >= 0x40) - nv_wr32(priv, 0xc040, savedc040); -} - -static void -setPLL_double_lowregs(struct nv04_clock_priv *priv, u32 NMNMreg, - struct nouveau_pll_vals *pv) -{ - /* When setting PLLs, there is a merry game of disabling and enabling - * various bits of hardware during the process. This function is a - * synthesis of six nv4x traces, nearly each card doing a subtly - * different thing. With luck all the necessary bits for each card are - * combined herein. Without luck it deviates from each card's formula - * so as to not work on any :) - */ - - uint32_t Preg = NMNMreg - 4; - bool mpll = Preg == 0x4020; - uint32_t oldPval = nv_rd32(priv, Preg); - uint32_t NMNM = pv->NM2 << 16 | pv->NM1; - uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) | - 0xc << 28 | pv->log2P << 16; - uint32_t saved4600 = 0; - /* some cards have different maskc040s */ - uint32_t maskc040 = ~(3 << 14), savedc040; - bool single_stage = !pv->NM2 || pv->N2 == pv->M2; - - if (nv_rd32(priv, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval) - return; - - if (Preg == 0x4000) - maskc040 = ~0x333; - if (Preg == 0x4058) - maskc040 = ~(0xc << 24); - - if (mpll) { - struct nvbios_pll info; - uint8_t Pval2; - - if (nvbios_pll_parse(nouveau_bios(priv), Preg, &info)) - return; - - Pval2 = pv->log2P + info.bias_p; - if (Pval2 > info.max_p) - Pval2 = info.max_p; - Pval |= 1 << 28 | Pval2 << 20; - - saved4600 = nv_rd32(priv, 0x4600); - nv_wr32(priv, 0x4600, saved4600 | 8 << 28); - } - if (single_stage) - Pval |= mpll ? 1 << 12 : 1 << 8; - - nv_wr32(priv, Preg, oldPval | 1 << 28); - nv_wr32(priv, Preg, Pval & ~(4 << 28)); - if (mpll) { - Pval |= 8 << 20; - nv_wr32(priv, 0x4020, Pval & ~(0xc << 28)); - nv_wr32(priv, 0x4038, Pval & ~(0xc << 28)); - } - - savedc040 = nv_rd32(priv, 0xc040); - nv_wr32(priv, 0xc040, savedc040 & maskc040); - - nv_wr32(priv, NMNMreg, NMNM); - if (NMNMreg == 0x4024) - nv_wr32(priv, 0x403c, NMNM); - - nv_wr32(priv, Preg, Pval); - if (mpll) { - Pval &= ~(8 << 20); - nv_wr32(priv, 0x4020, Pval); - nv_wr32(priv, 0x4038, Pval); - nv_wr32(priv, 0x4600, saved4600); - } - - nv_wr32(priv, 0xc040, savedc040); - - if (mpll) { - nv_wr32(priv, 0x4020, Pval & ~(1 << 28)); - nv_wr32(priv, 0x4038, Pval & ~(1 << 28)); - } -} - -int -nv04_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) -{ - struct nv04_clock_priv *priv = (void *)clk; - struct nouveau_pll_vals pv; - struct nvbios_pll info; - int ret; - - ret = nvbios_pll_parse(nouveau_bios(priv), type > 0x405c ? - type : type - 4, &info); - if (ret) - return ret; - - ret = clk->pll_calc(clk, &info, freq, &pv); - if (!ret) - return ret; - - return clk->pll_prog(clk, type, &pv); -} - int nv04_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, struct nouveau_pll_vals *pv) { int N1, M1, N2, M2, P; - int ret = nv04_pll_calc(clock, info, clk, &N1, &M1, &N2, &M2, &P); + int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P); if (ret) { pv->refclk = info->refclk; pv->N1 = N1; @@ -313,17 +54,17 @@ int nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1, struct nouveau_pll_vals *pv) { - struct nv04_clock_priv *priv = (void *)clk; + struct nouveau_devinit *devinit = nouveau_devinit(clk); int cv = nouveau_bios(clk)->version.chip; if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 || cv >= 0x40) { if (reg1 > 0x405c) - setPLL_double_highregs(priv, reg1, pv); + setPLL_double_highregs(devinit, reg1, pv); else - setPLL_double_lowregs(priv, reg1, pv); + setPLL_double_lowregs(devinit, reg1, pv); } else - setPLL_single(priv, reg1, pv); + setPLL_single(devinit, reg1, pv); return 0; } @@ -341,7 +82,6 @@ nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.pll_set = nv04_clock_pll_set; priv->base.pll_calc = nv04_clock_pll_calc; priv->base.pll_prog = nv04_clock_pll_prog; return 0; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c index a4b2b7ebf9af..0db5dbfd91b5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c @@ -41,7 +41,6 @@ nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.pll_set = nv04_clock_pll_set; priv->base.pll_calc = nv04_clock_pll_calc; priv->base.pll_prog = nv04_clock_pll_prog; return 0; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c index f4147f67eda6..d09d3e78040c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c @@ -33,50 +33,6 @@ struct nv50_clock_priv { }; static int -nv50_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) -{ - struct nv50_clock_priv *priv = (void *)clk; - 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(clk, "failed to retrieve pll data, %d\n", ret); - return ret; - } - - ret = nv04_pll_calc(clk, &info, freq, &N1, &M1, &N2, &M2, &P); - if (!ret) { - nv_error(clk, "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_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -89,7 +45,6 @@ nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.pll_set = nv50_clock_pll_set; priv->base.pll_calc = nv04_clock_pll_calc; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c index 9068c98b96f6..f074cd20bc9c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -32,47 +32,13 @@ struct nva3_clock_priv { struct nouveau_clock base; }; -static int -nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) -{ - struct nva3_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_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; -} - int nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, struct nouveau_pll_vals *pv) { int ret, N, M, P; - ret = nva3_pll_calc(clock, info, clk, &N, NULL, &M, &P); + ret = nva3_pll_calc(nv_subdev(clock), info, clk, &N, NULL, &M, &P); if (ret > 0) { pv->refclk = info->refclk; @@ -97,7 +63,6 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.pll_set = nva3_clock_pll_set; priv->base.pll_calc = nva3_clock_pll_calc; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index 7c9626258a46..439d81c26130 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c @@ -33,41 +33,6 @@ struct nvc0_clock_priv { }; 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: - case PLL_VPLL2: - case PLL_VPLL3: - 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; -} - -static int nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -80,7 +45,6 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - priv->base.pll_set = nvc0_clock_pll_set; priv->base.pll_calc = nva3_clock_pll_calc; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h index ef2c0078f337..445b14c33a98 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h @@ -1,9 +1,9 @@ #ifndef __NOUVEAU_PLL_H__ #define __NOUVEAU_PLL_H__ -int nv04_pll_calc(struct nouveau_clock *, struct nvbios_pll *, u32 freq, +int nv04_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq, int *N1, int *M1, int *N2, int *M2, int *P); -int nva3_pll_calc(struct nouveau_clock *, struct nvbios_pll *, u32 freq, +int nva3_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq, int *N, int *fN, int *M, int *P); #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c index a2ab6d051ba8..cf1ed0dc9bc9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c @@ -21,14 +21,13 @@ * SOFTWARE. */ -#include <subdev/clock.h> #include <subdev/bios.h> #include <subdev/bios/pll.h> #include "pll.h" static int -getMNP_single(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, +getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, int *pN, int *pM, int *pP) { /* Find M, N and P for a single stage PLL @@ -39,7 +38,7 @@ getMNP_single(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, * "clk" parameter in kHz * returns calculated clock */ - int cv = nouveau_bios(clock)->version.chip; + int cv = nouveau_bios(subdev)->version.chip; int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq; int minM = info->vco1.min_m, maxM = info->vco1.max_m; int minN = info->vco1.min_n, maxN = info->vco1.max_n; @@ -124,7 +123,7 @@ getMNP_single(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, } static int -getMNP_double(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, +getMNP_double(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk, int *pN1, int *pM1, int *pN2, int *pM2, int *pP) { /* Find M, N and P for a two stage PLL @@ -135,7 +134,7 @@ getMNP_double(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, * "clk" parameter in kHz * returns calculated clock */ - int chip_version = nouveau_bios(clock)->version.chip; + int chip_version = nouveau_bios(subdev)->version.chip; int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq; int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq; int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq; @@ -223,20 +222,20 @@ getMNP_double(struct nouveau_clock *clock, struct nvbios_pll *info, int clk, } int -nv04_pll_calc(struct nouveau_clock *clk, struct nvbios_pll *info, u32 freq, +nv04_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, u32 freq, int *N1, int *M1, int *N2, int *M2, int *P) { int ret; if (!info->vco2.max_freq) { - ret = getMNP_single(clk, info, freq, N1, M1, P); + ret = getMNP_single(subdev, info, freq, N1, M1, P); *N2 = 1; *M2 = 1; } else { - ret = getMNP_double(clk, info, freq, N1, M1, N2, M2, P); + ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P); } if (!ret) - nv_error(clk, "unable to compute acceptable pll values\n"); + nv_error(subdev, "unable to compute acceptable pll values\n"); return ret; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c index eed5c16cf610..2fe1f712eefa 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c @@ -29,7 +29,7 @@ #include "pll.h" int -nva3_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, +nva3_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, u32 freq, int *pN, int *pfN, int *pM, int *P) { u32 best_err = ~0, err; @@ -50,8 +50,15 @@ nva3_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, u32 tmp = freq * *P * M; N = tmp / info->refclk; fN = tmp % info->refclk; - if (!pfN && fN >= info->refclk / 2) - N++; + + if (!pfN) { + if (fN >= info->refclk / 2) + N++; + } else { + if (fN < info->refclk / 2) + N--; + fN = tmp - (N * info->refclk); + } if (N < info->vco1.min_n) continue; @@ -66,13 +73,14 @@ nva3_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, } if (pfN) { - *pfN = (((fN << 13) / info->refclk) - 4096) & 0xffff; + *pfN = ((fN << 13) + info->refclk / 2) / info->refclk; + *pfN = (*pfN - 4096) & 0xffff; return freq; } } if (unlikely(best_err == ~0)) { - nv_error(clock, "unable to find matching pll values\n"); + nv_error(subdev, "unable to find matching pll values\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c index 5a07a39c1735..79c81d3d9bac 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c @@ -29,18 +29,10 @@ #include <subdev/bios/init.h> int -nouveau_devinit_init(struct nouveau_devinit *devinit) +_nouveau_devinit_fini(struct nouveau_object *object, bool suspend) { - int ret = nouveau_subdev_init(&devinit->base); - if (ret) - return ret; + struct nouveau_devinit *devinit = (void *)object; - return nvbios_init(&devinit->base, devinit->post); -} - -int -nouveau_devinit_fini(struct nouveau_devinit *devinit, bool suspend) -{ /* force full reinit on resume */ if (suspend) devinit->post = true; @@ -49,6 +41,17 @@ nouveau_devinit_fini(struct nouveau_devinit *devinit, bool suspend) } int +_nouveau_devinit_init(struct nouveau_object *object) +{ + struct nouveau_devinit *devinit = (void *)object; + int ret = nouveau_subdev_init(&devinit->base); + if (ret) + return ret; + + return nvbios_init(&devinit->base, devinit->post); +} + +int nouveau_devinit_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c index 7a72d9394340..b22357d9b821 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c @@ -24,10 +24,10 @@ * */ -#include <subdev/devinit.h> #include <subdev/vga.h> #include "fbmem.h" +#include "priv.h" struct nv04_devinit_priv { struct nouveau_devinit base; @@ -111,33 +111,298 @@ nv04_devinit_meminit(struct nouveau_devinit *devinit) } static int -nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +powerctrl_1_shift(int chip_version, int reg) { - struct nv04_devinit_priv *priv; + int shift = -4; + + if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20) + return shift; + + switch (reg) { + case 0x680520: + shift += 4; + case 0x680508: + shift += 4; + case 0x680504: + shift += 4; + case 0x680500: + shift += 4; + } + + /* + * the shift for vpll regs is only used for nv3x chips with a single + * stage pll + */ + if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 || + chip_version == 0x36 || chip_version >= 0x40)) + shift = -4; + + return shift; +} + +void +setPLL_single(struct nouveau_devinit *devinit, u32 reg, + struct nouveau_pll_vals *pv) +{ + int chip_version = nouveau_bios(devinit)->version.chip; + uint32_t oldpll = nv_rd32(devinit, reg); + int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff; + uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1; + uint32_t saved_powerctrl_1 = 0; + int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg); + + if (oldpll == pll) + return; /* already set */ + + if (shift_powerctrl_1 >= 0) { + saved_powerctrl_1 = nv_rd32(devinit, 0x001584); + nv_wr32(devinit, 0x001584, + (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | + 1 << shift_powerctrl_1); + } + + if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1)) + /* upclock -- write new post divider first */ + nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff)); + else + /* downclock -- write new NM first */ + nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1); + + if (chip_version < 0x17 && chip_version != 0x11) + /* wait a bit on older chips */ + msleep(64); + nv_rd32(devinit, reg); + + /* then write the other half as well */ + nv_wr32(devinit, reg, pll); + + if (shift_powerctrl_1 >= 0) + nv_wr32(devinit, 0x001584, saved_powerctrl_1); +} + +static uint32_t +new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580) +{ + bool head_a = (reg1 == 0x680508); + + if (ss) /* single stage pll mode */ + ramdac580 |= head_a ? 0x00000100 : 0x10000000; + else + ramdac580 &= head_a ? 0xfffffeff : 0xefffffff; + + return ramdac580; +} + +void +setPLL_double_highregs(struct nouveau_devinit *devinit, u32 reg1, + struct nouveau_pll_vals *pv) +{ + int chip_version = nouveau_bios(devinit)->version.chip; + bool nv3035 = chip_version == 0x30 || chip_version == 0x35; + uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70); + uint32_t oldpll1 = nv_rd32(devinit, reg1); + uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0; + uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1; + uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2; + uint32_t oldramdac580 = 0, ramdac580 = 0; + bool single_stage = !pv->NM2 || pv->N2 == pv->M2; /* nv41+ only */ + uint32_t saved_powerctrl_1 = 0, savedc040 = 0; + int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1); + + /* model specific additions to generic pll1 and pll2 set up above */ + if (nv3035) { + pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 | + (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4; + pll2 = 0; + } + if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */ + oldramdac580 = nv_rd32(devinit, 0x680580); + ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580); + if (oldramdac580 != ramdac580) + oldpll1 = ~0; /* force mismatch */ + if (single_stage) + /* magic value used by nvidia in single stage mode */ + pll2 |= 0x011f; + } + if (chip_version > 0x70) + /* magic bits set by the blob (but not the bios) on g71-73 */ + pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28; + + if (oldpll1 == pll1 && oldpll2 == pll2) + return; /* already set */ + + if (shift_powerctrl_1 >= 0) { + saved_powerctrl_1 = nv_rd32(devinit, 0x001584); + nv_wr32(devinit, 0x001584, + (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | + 1 << shift_powerctrl_1); + } + + if (chip_version >= 0x40) { + int shift_c040 = 14; + + switch (reg1) { + case 0x680504: + shift_c040 += 2; + case 0x680500: + shift_c040 += 2; + case 0x680520: + shift_c040 += 2; + case 0x680508: + shift_c040 += 2; + } + + savedc040 = nv_rd32(devinit, 0xc040); + if (shift_c040 != 14) + nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040)); + } + + if (oldramdac580 != ramdac580) + nv_wr32(devinit, 0x680580, ramdac580); + + if (!nv3035) + nv_wr32(devinit, reg2, pll2); + nv_wr32(devinit, reg1, pll1); + + if (shift_powerctrl_1 >= 0) + nv_wr32(devinit, 0x001584, saved_powerctrl_1); + if (chip_version >= 0x40) + nv_wr32(devinit, 0xc040, savedc040); +} + +void +setPLL_double_lowregs(struct nouveau_devinit *devinit, u32 NMNMreg, + struct nouveau_pll_vals *pv) +{ + /* When setting PLLs, there is a merry game of disabling and enabling + * various bits of hardware during the process. This function is a + * synthesis of six nv4x traces, nearly each card doing a subtly + * different thing. With luck all the necessary bits for each card are + * combined herein. Without luck it deviates from each card's formula + * so as to not work on any :) + */ + + uint32_t Preg = NMNMreg - 4; + bool mpll = Preg == 0x4020; + uint32_t oldPval = nv_rd32(devinit, Preg); + uint32_t NMNM = pv->NM2 << 16 | pv->NM1; + uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) | + 0xc << 28 | pv->log2P << 16; + uint32_t saved4600 = 0; + /* some cards have different maskc040s */ + uint32_t maskc040 = ~(3 << 14), savedc040; + bool single_stage = !pv->NM2 || pv->N2 == pv->M2; + + if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval) + return; + + if (Preg == 0x4000) + maskc040 = ~0x333; + if (Preg == 0x4058) + maskc040 = ~(0xc << 24); + + if (mpll) { + struct nvbios_pll info; + uint8_t Pval2; + + if (nvbios_pll_parse(nouveau_bios(devinit), Preg, &info)) + return; + + Pval2 = pv->log2P + info.bias_p; + if (Pval2 > info.max_p) + Pval2 = info.max_p; + Pval |= 1 << 28 | Pval2 << 20; + + saved4600 = nv_rd32(devinit, 0x4600); + nv_wr32(devinit, 0x4600, saved4600 | 8 << 28); + } + if (single_stage) + Pval |= mpll ? 1 << 12 : 1 << 8; + + nv_wr32(devinit, Preg, oldPval | 1 << 28); + nv_wr32(devinit, Preg, Pval & ~(4 << 28)); + if (mpll) { + Pval |= 8 << 20; + nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28)); + nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28)); + } + + savedc040 = nv_rd32(devinit, 0xc040); + nv_wr32(devinit, 0xc040, savedc040 & maskc040); + + nv_wr32(devinit, NMNMreg, NMNM); + if (NMNMreg == 0x4024) + nv_wr32(devinit, 0x403c, NMNM); + + nv_wr32(devinit, Preg, Pval); + if (mpll) { + Pval &= ~(8 << 20); + nv_wr32(devinit, 0x4020, Pval); + nv_wr32(devinit, 0x4038, Pval); + nv_wr32(devinit, 0x4600, saved4600); + } + + nv_wr32(devinit, 0xc040, savedc040); + + if (mpll) { + nv_wr32(devinit, 0x4020, Pval & ~(1 << 28)); + nv_wr32(devinit, 0x4038, Pval & ~(1 << 28)); + } +} + +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 = nouveau_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info); if (ret) return ret; - priv->base.meminit = nv04_devinit_meminit; - priv->owner = -1; + 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; } -void -nv04_devinit_dtor(struct nouveau_object *object) +int +nv04_devinit_fini(struct nouveau_object *object, bool suspend) { struct nv04_devinit_priv *priv = (void *)object; - /* restore vga owner saved at first init, and lock crtc regs */ - nv_wrvgaowner(priv, priv->owner); - nv_lockvgac(priv, true); + /* make i2c busses accessible */ + nv_mask(priv, 0x000200, 0x00000001, 0x00000001); - nouveau_devinit_destroy(&priv->base); + /* unlock extended vga crtc regs, and unslave crtcs */ + nv_lockvgac(priv, false); + if (priv->owner < 0) + priv->owner = nv_rdvgaowner(priv); + nv_wrvgaowner(priv, 0); + + return nouveau_devinit_fini(&priv->base, suspend); } int @@ -160,21 +425,35 @@ nv04_devinit_init(struct nouveau_object *object) return nouveau_devinit_init(&priv->base); } -int -nv04_devinit_fini(struct nouveau_object *object, bool suspend) +void +nv04_devinit_dtor(struct nouveau_object *object) { struct nv04_devinit_priv *priv = (void *)object; - /* make i2c busses accessible */ - nv_mask(priv, 0x000200, 0x00000001, 0x00000001); + /* restore vga owner saved at first init, and lock crtc regs */ + nv_wrvgaowner(priv, priv->owner); + nv_lockvgac(priv, true); - /* unlock extended vga crtc regs, and unslave crtcs */ - nv_lockvgac(priv, false); - if (priv->owner < 0) - priv->owner = nv_rdvgaowner(priv); - nv_wrvgaowner(priv, 0); + nouveau_devinit_destroy(&priv->base); +} - return nouveau_devinit_fini(&priv->base, suspend); +static int +nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_devinit_priv *priv; + int ret; + + ret = nouveau_devinit_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.meminit = nv04_devinit_meminit; + priv->base.pll_set = nv04_devinit_pll_set; + priv->owner = -1; + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c index 191447d0d252..b1912a8a8942 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c @@ -24,12 +24,12 @@ * */ -#include <subdev/devinit.h> #include <subdev/bios.h> #include <subdev/bios/bmp.h> #include <subdev/vga.h> #include "fbmem.h" +#include "priv.h" struct nv05_devinit_priv { struct nouveau_devinit base; @@ -144,6 +144,7 @@ nv05_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; priv->base.meminit = nv05_devinit_meminit; + priv->base.pll_set = nv04_devinit_pll_set; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c index eb76ffab6b0c..463b08fa0968 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c @@ -24,10 +24,10 @@ * */ -#include <subdev/devinit.h> #include <subdev/vga.h> #include "fbmem.h" +#include "priv.h" struct nv10_devinit_priv { struct nouveau_devinit base; @@ -109,6 +109,7 @@ nv10_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; priv->base.meminit = nv10_devinit_meminit; + priv->base.pll_set = nv04_devinit_pll_set; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c index 5b2ba630d913..e9743cdabe75 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c @@ -22,8 +22,7 @@ * Authors: Ben Skeggs */ -#include <subdev/devinit.h> -#include <subdev/vga.h> +#include "priv.h" struct nv1a_devinit_priv { struct nouveau_devinit base; @@ -43,6 +42,7 @@ nv1a_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + priv->base.pll_set = nv04_devinit_pll_set; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c index eb32e99005e4..6cc6080d3bc0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c @@ -24,9 +24,7 @@ * */ -#include <subdev/devinit.h> -#include <subdev/vga.h> - +#include "priv.h" #include "fbmem.h" struct nv20_devinit_priv { @@ -81,6 +79,7 @@ nv20_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; priv->base.meminit = nv20_devinit_meminit; + priv->base.pll_set = nv04_devinit_pll_set; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c index 4a8577838417..6df72247c477 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat Inc. + * Copyright 2013 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -26,37 +26,55 @@ #include <subdev/bios/dcb.h> #include <subdev/bios/disp.h> #include <subdev/bios/init.h> -#include <subdev/devinit.h> #include <subdev/vga.h> -struct nv50_devinit_priv { - struct nouveau_devinit base; -}; +#include "priv.h" 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) +nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { - struct nv50_devinit_priv *priv; + 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 = nouveau_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) + ret = nvbios_pll_parse(bios, type, &info); + if (ret) { + nv_error(devinit, "failed to retrieve pll data, %d\n", ret); return ret; + } - return 0; -} + 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; + } -static void -nv50_devinit_dtor(struct nouveau_object *object) -{ - struct nv50_devinit_priv *priv = (void *)object; - nouveau_devinit_destroy(&priv->base); + 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 +int nv50_devinit_init(struct nouveau_object *object) { struct nouveau_bios *bios = nouveau_bios(object); @@ -103,10 +121,20 @@ nv50_devinit_init(struct nouveau_object *object) } static int -nv50_devinit_fini(struct nouveau_object *object, bool suspend) +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 = (void *)object; - return nouveau_devinit_fini(&priv->base, suspend); + 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 @@ -114,8 +142,8 @@ nv50_devinit_oclass = { .handle = NV_SUBDEV(DEVINIT, 0x50), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_devinit_ctor, - .dtor = nv50_devinit_dtor, + .dtor = _nouveau_devinit_dtor, .init = nv50_devinit_init, - .fini = nv50_devinit_fini, + .fini = _nouveau_devinit_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c new file mode 100644 index 000000000000..76a68b290141 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c @@ -0,0 +1,87 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +static int +nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) +{ + struct nva3_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; +} + +static int +nva3_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 = nva3_devinit_pll_set; + return 0; +} + +struct nouveau_oclass +nva3_devinit_oclass = { + .handle = NV_SUBDEV(DEVINIT, 0xa3), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nva3_devinit_ctor, + .dtor = _nouveau_devinit_dtor, + .init = nv50_devinit_init, + .fini = _nouveau_devinit_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c new file mode 100644 index 000000000000..19e265bf4574 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c @@ -0,0 +1,90 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +static int +nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) +{ + struct nvc0_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: + case PLL_VPLL2: + case PLL_VPLL3: + 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; +} + +static int +nvc0_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 = nvc0_devinit_pll_set; + if (nv_rd32(priv, 0x022500) & 0x00000001) + priv->base.post = true; + return 0; +} + +struct nouveau_oclass +nvc0_devinit_oclass = { + .handle = NV_SUBDEV(DEVINIT, 0xc0), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_devinit_ctor, + .dtor = _nouveau_devinit_dtor, + .init = nv50_devinit_init, + .fini = _nouveau_devinit_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h new file mode 100644 index 000000000000..7d622e2b0171 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h @@ -0,0 +1,25 @@ +#ifndef __NVKM_DEVINIT_PRIV_H__ +#define __NVKM_DEVINIT_PRIV_H__ + +#include <subdev/bios.h> +#include <subdev/bios/pll.h> +#include <subdev/clock/pll.h> +#include <subdev/devinit.h> + +void nv04_devinit_dtor(struct nouveau_object *); +int nv04_devinit_init(struct nouveau_object *); +int nv04_devinit_fini(struct nouveau_object *, bool); +int nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32); + +void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *); +void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *); +void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *); + + +struct nv50_devinit_priv { + struct nouveau_devinit base; +}; + +int nv50_devinit_init(struct nouveau_object *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c index d62045f454b2..821cd75b86a3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c @@ -57,7 +57,57 @@ nouveau_fb_bios_memtype(struct nouveau_bios *bios) } int -nouveau_fb_preinit(struct nouveau_fb *pfb) +_nouveau_fb_fini(struct nouveau_object *object, bool suspend) +{ + struct nouveau_fb *pfb = (void *)object; + int ret; + + ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend); + if (ret && suspend) + return ret; + + return nouveau_subdev_fini(&pfb->base, suspend); +} + +int +_nouveau_fb_init(struct nouveau_object *object) +{ + struct nouveau_fb *pfb = (void *)object; + int ret, i; + + ret = nouveau_subdev_init(&pfb->base); + if (ret) + return ret; + + ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram)); + if (ret) + return ret; + + for (i = 0; i < pfb->tile.regions; i++) + pfb->tile.prog(pfb, i, &pfb->tile.region[i]); + + return 0; +} + +void +_nouveau_fb_dtor(struct nouveau_object *object) +{ + struct nouveau_fb *pfb = (void *)object; + int i; + + for (i = 0; i < pfb->tile.regions; i++) + pfb->tile.fini(pfb, i, &pfb->tile.region[i]); + nouveau_mm_fini(&pfb->tags); + nouveau_mm_fini(&pfb->vram); + + nouveau_object_ref(NULL, (struct nouveau_object **)&pfb->ram); + nouveau_subdev_destroy(&pfb->base); +} + +int +nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, struct nouveau_oclass *ramcls, + int length, void **pobject) { static const char *name[] = { [NV_MEM_TYPE_UNKNOWN] = "unknown", @@ -72,69 +122,42 @@ nouveau_fb_preinit(struct nouveau_fb *pfb) [NV_MEM_TYPE_GDDR4 ] = "GDDR4", [NV_MEM_TYPE_GDDR5 ] = "GDDR5", }; - int ret, tags; + struct nouveau_object *ram; + struct nouveau_fb *pfb; + int ret; - tags = pfb->ram.init(pfb); - if (tags < 0 || !pfb->ram.size) { + ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PFB", "fb", + length, pobject); + pfb = *pobject; + if (ret) + return ret; + + ret = nouveau_object_ctor(nv_object(pfb), nv_object(pfb), + ramcls, NULL, 0, &ram); + if (ret) { nv_fatal(pfb, "error detecting memory configuration!!\n"); - return (tags < 0) ? tags : -ERANGE; + return ret; } + atomic_dec(&ram->parent->refcount); + atomic_dec(&ram->engine->refcount); + pfb->ram = (void *)ram; + if (!nouveau_mm_initialised(&pfb->vram)) { - ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram.size >> 12, 1); + ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1); if (ret) return ret; } if (!nouveau_mm_initialised(&pfb->tags)) { - ret = nouveau_mm_init(&pfb->tags, 0, tags ? ++tags : 0, 1); + ret = nouveau_mm_init(&pfb->tags, 0, pfb->ram->tags ? + ++pfb->ram->tags : 0, 1); if (ret) return ret; } - nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]); - nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20)); - nv_info(pfb, " ZCOMP: %d tags\n", tags); + nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]); + nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20)); + nv_info(pfb, " ZCOMP: %d tags\n", pfb->ram->tags); return 0; } - -void -nouveau_fb_destroy(struct nouveau_fb *pfb) -{ - int i; - - for (i = 0; i < pfb->tile.regions; i++) - pfb->tile.fini(pfb, i, &pfb->tile.region[i]); - nouveau_mm_fini(&pfb->tags); - nouveau_mm_fini(&pfb->vram); - - nouveau_subdev_destroy(&pfb->base); -} - -void -_nouveau_fb_dtor(struct nouveau_object *object) -{ - struct nouveau_fb *pfb = (void *)object; - nouveau_fb_destroy(pfb); -} -int -nouveau_fb_init(struct nouveau_fb *pfb) -{ - int ret, i; - - ret = nouveau_subdev_init(&pfb->base); - if (ret) - return ret; - - for (i = 0; i < pfb->tile.regions; i++) - pfb->tile.prog(pfb, i, &pfb->tile.region[i]); - - return 0; -} - -int -_nouveau_fb_init(struct nouveau_object *object) -{ - struct nouveau_fb *pfb = (void *)object; - return nouveau_fb_init(pfb); -} diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c index 6e369f85361e..1f103c7b89fa 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c @@ -22,24 +22,8 @@ * Authors: Ben Skeggs */ -#include <subdev/fb.h> +#include "priv.h" -#define NV04_PFB_BOOT_0 0x00100000 -# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 -# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 -# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004 -# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028 -# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000 -# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008 -# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010 -# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018 -# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020 -# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028 -# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100 -# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000 #define NV04_PFB_CFG0 0x00100200 struct nv04_fb_priv { @@ -56,37 +40,6 @@ nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags) } static int -nv04_fb_vram_init(struct nouveau_fb *pfb) -{ - u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0); - if (boot0 & 0x00000100) { - pfb->ram.size = ((boot0 >> 12) & 0xf) * 2 + 2; - pfb->ram.size *= 1024 * 1024; - } else { - switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) { - case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB: - pfb->ram.size = 32 * 1024 * 1024; - break; - case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB: - pfb->ram.size = 16 * 1024 * 1024; - break; - case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB: - pfb->ram.size = 8 * 1024 * 1024; - break; - case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB: - pfb->ram.size = 4 * 1024 * 1024; - break; - } - } - - if ((boot0 & 0x00000038) <= 0x10) - pfb->ram.type = NV_MEM_TYPE_SGRAM; - else - pfb->ram.type = NV_MEM_TYPE_SDRAM; - return 0; -} - -static int nv04_fb_init(struct nouveau_object *object) { struct nv04_fb_priv *priv = (void *)object; @@ -112,14 +65,13 @@ nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv04_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv04_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv04_fb_vram_init; - return nouveau_fb_preinit(&priv->base); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c index edbbe26e858d..be069b5306b6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c @@ -24,25 +24,12 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv10_fb_priv { struct nouveau_fb base; }; -static int -nv10_fb_vram_init(struct nouveau_fb *pfb) -{ - u32 cfg0 = nv_rd32(pfb, 0x100200); - if (cfg0 & 0x00000001) - pfb->ram.type = NV_MEM_TYPE_DDR1; - else - pfb->ram.type = NV_MEM_TYPE_SDRAM; - - pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - return 0; -} - void nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nouveau_fb_tile *tile) @@ -78,18 +65,17 @@ nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv10_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv10_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv10_fb_vram_init; priv->base.tile.regions = 8; priv->base.tile.init = nv10_fb_tile_init; priv->base.tile.fini = nv10_fb_tile_fini; priv->base.tile.prog = nv10_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c index 48366841db4a..57a2af0079b3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c @@ -24,38 +24,13 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv1a_fb_priv { struct nouveau_fb base; }; static int -nv1a_fb_vram_init(struct nouveau_fb *pfb) -{ - struct pci_dev *bridge; - u32 mem, mib; - - bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1)); - if (!bridge) { - nv_fatal(pfb, "no bridge device\n"); - return -ENODEV; - } - - if (nv_device(pfb)->chipset == 0x1a) { - pci_read_config_dword(bridge, 0x7c, &mem); - mib = ((mem >> 6) & 31) + 1; - } else { - pci_read_config_dword(bridge, 0x84, &mem); - mib = ((mem >> 4) & 127) + 1; - } - - pfb->ram.type = NV_MEM_TYPE_STOLEN; - pfb->ram.size = mib * 1024 * 1024; - return 0; -} - -static int nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -63,18 +38,17 @@ nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv1a_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv1a_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv1a_fb_vram_init; priv->base.tile.regions = 8; priv->base.tile.init = nv10_fb_tile_init; priv->base.tile.fini = nv10_fb_tile_fini; priv->base.tile.prog = nv10_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c index 5d14612a2c8e..b18c4e63bb47 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c @@ -24,29 +24,12 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv20_fb_priv { struct nouveau_fb base; }; -int -nv20_fb_vram_init(struct nouveau_fb *pfb) -{ - u32 pbus1218 = nv_rd32(pfb, 0x001218); - - switch (pbus1218 & 0x00000300) { - case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break; - case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break; - case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break; - case 0x00000300: pfb->ram.type = NV_MEM_TYPE_GDDR2; break; - } - pfb->ram.size = (nv_rd32(pfb, 0x10020c) & 0xff000000); - pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - - return nv_rd32(pfb, 0x100320); -} - void nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nouveau_fb_tile *tile) @@ -65,7 +48,7 @@ nv20_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, struct nouveau_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram.parts, 0x40); + u32 tags = round_up(tiles / pfb->ram->parts, 0x40); if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */ else tile->zcomp = 0x04000000; /* Z24S8 */ @@ -105,19 +88,18 @@ nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv20_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv20_fb_vram_init; priv->base.tile.regions = 8; priv->base.tile.init = nv20_fb_tile_init; priv->base.tile.comp = nv20_fb_tile_comp; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv20_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c index 0042ace6bef9..32ccabf10c45 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c @@ -24,7 +24,7 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv25_fb_priv { struct nouveau_fb base; @@ -35,7 +35,7 @@ nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, struct nouveau_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram.parts, 0x40); + u32 tags = round_up(tiles / pfb->ram->parts, 0x40); if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */ else tile->zcomp = 0x00200000; /* Z24S8 */ @@ -54,19 +54,18 @@ nv25_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv25_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv20_fb_vram_init; priv->base.tile.regions = 8; priv->base.tile.init = nv20_fb_tile_init; priv->base.tile.comp = nv25_fb_tile_comp; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv20_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c index a7ba0d048aec..bef756d43d33 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c @@ -24,7 +24,7 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv30_fb_priv { struct nouveau_fb base; @@ -54,7 +54,7 @@ nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, struct nouveau_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram.parts, 0x40); + u32 tags = round_up(tiles / pfb->ram->parts, 0x40); if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */ else tile->zcomp |= 0x02000000; /* Z24S8 */ @@ -132,19 +132,18 @@ nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv30_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv20_fb_vram_init; priv->base.tile.regions = 8; priv->base.tile.init = nv30_fb_tile_init; priv->base.tile.comp = nv30_fb_tile_comp; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv20_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c index 092f6f4f3521..097d8e3824f2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c @@ -24,7 +24,7 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv35_fb_priv { struct nouveau_fb base; @@ -35,7 +35,7 @@ nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, struct nouveau_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram.parts, 0x40); + u32 tags = round_up(tiles / pfb->ram->parts, 0x40); if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */ else tile->zcomp |= 0x08000000; /* Z24S8 */ @@ -55,19 +55,18 @@ nv35_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv35_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv20_fb_vram_init; priv->base.tile.regions = 8; priv->base.tile.init = nv30_fb_tile_init; priv->base.tile.comp = nv35_fb_tile_comp; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv20_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c index 797ab3b821b9..9d6d9df896d9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c @@ -24,7 +24,7 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv36_fb_priv { struct nouveau_fb base; @@ -35,7 +35,7 @@ nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, struct nouveau_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram.parts, 0x40); + u32 tags = round_up(tiles / pfb->ram->parts, 0x40); if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */ else tile->zcomp |= 0x20000000; /* Z24S8 */ @@ -55,19 +55,18 @@ nv36_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv36_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv20_fb_vram_init; priv->base.tile.regions = 8; priv->base.tile.init = nv30_fb_tile_init; priv->base.tile.comp = nv36_fb_tile_comp; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv20_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c index 65e131b90f37..33b4393a7829 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c @@ -24,34 +24,18 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv40_fb_priv { struct nouveau_fb base; }; -static int -nv40_fb_vram_init(struct nouveau_fb *pfb) -{ - u32 pbus1218 = nv_rd32(pfb, 0x001218); - switch (pbus1218 & 0x00000300) { - case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break; - case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break; - case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break; - case 0x00000300: pfb->ram.type = NV_MEM_TYPE_DDR2; break; - } - - pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - return nv_rd32(pfb, 0x100320); -} - void nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags, struct nouveau_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x80); - u32 tags = round_up(tiles / pfb->ram.parts, 0x100); + u32 tags = round_up(tiles / pfb->ram->parts, 0x100); if ( (flags & 2) && !nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) { tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */ @@ -85,19 +69,18 @@ nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv40_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv40_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv40_fb_vram_init; priv->base.tile.regions = 8; priv->base.tile.init = nv30_fb_tile_init; priv->base.tile.comp = nv40_fb_tile_comp; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv20_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c index e9e5a08c41a1..02cd83789cd4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c @@ -24,28 +24,12 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv41_fb_priv { struct nouveau_fb base; }; -int -nv41_fb_vram_init(struct nouveau_fb *pfb) -{ - u32 pfb474 = nv_rd32(pfb, 0x100474); - if (pfb474 & 0x00000004) - pfb->ram.type = NV_MEM_TYPE_GDDR3; - if (pfb474 & 0x00000002) - pfb->ram.type = NV_MEM_TYPE_DDR2; - if (pfb474 & 0x00000001) - pfb->ram.type = NV_MEM_TYPE_DDR1; - - pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - return nv_rd32(pfb, 0x100320); -} - void nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile) { @@ -78,19 +62,18 @@ nv41_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv41_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv41_fb_vram_init; priv->base.tile.regions = 12; priv->base.tile.init = nv30_fb_tile_init; priv->base.tile.comp = nv40_fb_tile_comp; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv41_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c index ae89b5006f7a..c5246c29f293 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c @@ -24,27 +24,12 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv44_fb_priv { struct nouveau_fb base; }; -int -nv44_fb_vram_init(struct nouveau_fb *pfb) -{ - u32 pfb474 = nv_rd32(pfb, 0x100474); - if (pfb474 & 0x00000004) - pfb->ram.type = NV_MEM_TYPE_GDDR3; - if (pfb474 & 0x00000002) - pfb->ram.type = NV_MEM_TYPE_DDR2; - if (pfb474 & 0x00000001) - pfb->ram.type = NV_MEM_TYPE_DDR1; - - pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - return 0; -} - static void nv44_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nouveau_fb_tile *tile) @@ -87,18 +72,17 @@ nv44_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv44_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv44_fb_vram_init; priv->base.tile.regions = 12; priv->base.tile.init = nv44_fb_tile_init; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv44_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c index 589b93ea2994..e2b57909bfca 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c @@ -24,7 +24,7 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv46_fb_priv { struct nouveau_fb base; @@ -52,18 +52,17 @@ nv46_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv46_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv44_fb_vram_init; priv->base.tile.regions = 15; priv->base.tile.init = nv46_fb_tile_init; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv44_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c index 818bba35b368..fe6a2278621d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c @@ -24,7 +24,7 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv47_fb_priv { struct nouveau_fb base; @@ -38,19 +38,18 @@ nv47_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv47_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv41_fb_vram_init; priv->base.tile.regions = 15; priv->base.tile.init = nv30_fb_tile_init; priv->base.tile.comp = nv40_fb_tile_comp; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv41_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c index 84a31af16ab4..5eca99b8c7e2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c @@ -24,30 +24,13 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv49_fb_priv { struct nouveau_fb base; }; static int -nv49_fb_vram_init(struct nouveau_fb *pfb) -{ - u32 pfb914 = nv_rd32(pfb, 0x100914); - - switch (pfb914 & 0x00000003) { - case 0x00000000: pfb->ram.type = NV_MEM_TYPE_DDR1; break; - case 0x00000001: pfb->ram.type = NV_MEM_TYPE_DDR2; break; - case 0x00000002: pfb->ram.type = NV_MEM_TYPE_GDDR3; break; - case 0x00000003: break; - } - - pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - return nv_rd32(pfb, 0x100320); -} - -static int nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -55,20 +38,18 @@ nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv49_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv49_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv49_fb_vram_init; priv->base.tile.regions = 15; priv->base.tile.init = nv30_fb_tile_init; priv->base.tile.comp = nv40_fb_tile_comp; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv41_fb_tile_prog; - - return nouveau_fb_preinit(&priv->base); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c index 797fd558170b..1190b78a1e91 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c @@ -24,21 +24,13 @@ * */ -#include <subdev/fb.h> +#include "priv.h" struct nv4e_fb_priv { struct nouveau_fb base; }; static int -nv4e_fb_vram_init(struct nouveau_fb *pfb) -{ - pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - pfb->ram.type = NV_MEM_TYPE_STOLEN; - return 0; -} - -static int nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) @@ -46,18 +38,17 @@ nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv4e_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv4e_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nv04_fb_memtype_valid; - priv->base.ram.init = nv4e_fb_vram_init; priv->base.tile.regions = 12; priv->base.tile.init = nv46_fb_tile_init; priv->base.tile.fini = nv20_fb_tile_fini; priv->base.tile.prog = nv44_fb_tile_prog; - return nouveau_fb_preinit(&priv->base); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c index 0772ec978165..da614ec5564b 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c @@ -27,7 +27,7 @@ #include <core/engctx.h> #include <core/object.h> -#include <subdev/fb.h> +#include "priv.h" #include <subdev/bios.h> struct nv50_fb_priv { @@ -36,7 +36,8 @@ struct nv50_fb_priv { dma_addr_t r100c08; }; -static int types[0x80] = { +int +nv50_fb_memtype[0x80] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0, @@ -50,192 +51,7 @@ static int types[0x80] = { static bool nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype) { - return types[(memtype & 0xff00) >> 8] != 0; -} - -static u32 -nv50_fb_vram_rblock(struct nouveau_fb *pfb) -{ - int i, parts, colbits, rowbitsa, rowbitsb, banks; - u64 rowsize, predicted; - u32 r0, r4, rt, ru, rblock_size; - - r0 = nv_rd32(pfb, 0x100200); - r4 = nv_rd32(pfb, 0x100204); - rt = nv_rd32(pfb, 0x100250); - ru = nv_rd32(pfb, 0x001540); - nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru); - - for (i = 0, parts = 0; i < 8; i++) { - if (ru & (0x00010000 << i)) - parts++; - } - - colbits = (r4 & 0x0000f000) >> 12; - rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; - rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; - banks = 1 << (((r4 & 0x03000000) >> 24) + 2); - - rowsize = parts * banks * (1 << colbits) * 8; - predicted = rowsize << rowbitsa; - if (r0 & 0x00000004) - predicted += rowsize << rowbitsb; - - if (predicted != pfb->ram.size) { - nv_warn(pfb, "memory controller reports %d MiB VRAM\n", - (u32)(pfb->ram.size >> 20)); - } - - rblock_size = rowsize; - if (rt & 1) - rblock_size *= 3; - - nv_debug(pfb, "rblock %d bytes\n", rblock_size); - return rblock_size; -} - -static int -nv50_fb_vram_init(struct nouveau_fb *pfb) -{ - struct nouveau_device *device = nv_device(pfb); - struct nouveau_bios *bios = nouveau_bios(device); - const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ - const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - u32 size, tags = 0; - int ret; - - pfb->ram.size = nv_rd32(pfb, 0x10020c); - pfb->ram.size = (pfb->ram.size & 0xffffff00) | - ((pfb->ram.size & 0x000000ff) << 32); - - size = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail; - switch (device->chipset) { - case 0xaa: - case 0xac: - case 0xaf: /* IGPs, no reordering, no real VRAM */ - ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1); - if (ret) - return ret; - - pfb->ram.type = NV_MEM_TYPE_STOLEN; - pfb->ram.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12; - break; - default: - switch (nv_rd32(pfb, 0x100714) & 0x00000007) { - case 0: pfb->ram.type = NV_MEM_TYPE_DDR1; break; - case 1: - if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) - pfb->ram.type = NV_MEM_TYPE_DDR3; - else - pfb->ram.type = NV_MEM_TYPE_DDR2; - break; - case 2: pfb->ram.type = NV_MEM_TYPE_GDDR3; break; - case 3: pfb->ram.type = NV_MEM_TYPE_GDDR4; break; - case 4: pfb->ram.type = NV_MEM_TYPE_GDDR5; break; - default: - break; - } - - ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, - nv50_fb_vram_rblock(pfb) >> 12); - if (ret) - return ret; - - pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1; - tags = nv_rd32(pfb, 0x100320); - break; - } - - return tags; -} - -static int -nv50_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, - u32 memtype, struct nouveau_mem **pmem) -{ - struct nv50_fb_priv *priv = (void *)pfb; - struct nouveau_mm *heap = &priv->base.vram; - struct nouveau_mm *tags = &priv->base.tags; - struct nouveau_mm_node *r; - struct nouveau_mem *mem; - int comp = (memtype & 0x300) >> 8; - int type = (memtype & 0x07f); - int back = (memtype & 0x800); - int min, max, ret; - - max = (size >> 12); - min = ncmin ? (ncmin >> 12) : max; - align >>= 12; - - mem = kzalloc(sizeof(*mem), GFP_KERNEL); - if (!mem) - return -ENOMEM; - - mutex_lock(&pfb->base.mutex); - if (comp) { - if (align == 16) { - int n = (max >> 4) * comp; - - ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag); - if (ret) - mem->tag = NULL; - } - - if (unlikely(!mem->tag)) - comp = 0; - } - - INIT_LIST_HEAD(&mem->regions); - mem->memtype = (comp << 7) | type; - mem->size = max; - - type = types[type]; - do { - if (back) - ret = nouveau_mm_tail(heap, type, max, min, align, &r); - else - ret = nouveau_mm_head(heap, type, max, min, align, &r); - if (ret) { - mutex_unlock(&pfb->base.mutex); - pfb->ram.put(pfb, &mem); - return ret; - } - - list_add_tail(&r->rl_entry, &mem->regions); - max -= r->length; - } while (max); - mutex_unlock(&pfb->base.mutex); - - r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); - mem->offset = (u64)r->offset << 12; - *pmem = mem; - return 0; -} - -void -nv50_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem) -{ - struct nv50_fb_priv *priv = (void *)pfb; - struct nouveau_mm_node *this; - struct nouveau_mem *mem; - - mem = *pmem; - *pmem = NULL; - if (unlikely(mem == NULL)) - return; - - mutex_lock(&pfb->base.mutex); - while (!list_empty(&mem->regions)) { - this = list_first_entry(&mem->regions, typeof(*this), rl_entry); - - list_del(&this->rl_entry); - nouveau_mm_free(&priv->base.vram, &this); - } - - nouveau_mm_free(&priv->base.tags, &mem->tag); - mutex_unlock(&pfb->base.mutex); - - kfree(mem); + return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0; } static const struct nouveau_enum vm_dispatch_subclients[] = { @@ -432,7 +248,7 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv50_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nv50_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; @@ -449,11 +265,8 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, } priv->base.memtype_valid = nv50_fb_memtype_valid; - priv->base.ram.init = nv50_fb_vram_init; - priv->base.ram.get = nv50_fb_vram_new; - priv->base.ram.put = nv50_fb_vram_del; nv_subdev(priv)->intr = nv50_fb_intr; - return nouveau_fb_preinit(&priv->base); + return 0; } static void diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c index 86ad59203c8b..f35d76fd746d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c @@ -22,9 +22,7 @@ * Authors: Ben Skeggs */ -#include <subdev/fb.h> -#include <subdev/ltcg.h> -#include <subdev/bios.h> +#include "priv.h" struct nvc0_fb_priv { struct nouveau_fb base; @@ -34,7 +32,6 @@ struct nvc0_fb_priv { extern const u8 nvc0_pte_storage_type_map[256]; - static bool nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags) { @@ -43,137 +40,6 @@ nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags) } static int -nvc0_fb_vram_init(struct nouveau_fb *pfb) -{ - struct nouveau_bios *bios = nouveau_bios(pfb); - const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ - const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - u32 parts = nv_rd32(pfb, 0x022438); - u32 pmask = nv_rd32(pfb, 0x022554); - u32 bsize = nv_rd32(pfb, 0x10f20c); - u32 offset, length; - bool uniform = true; - int ret, part; - - nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800)); - nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask); - - pfb->ram.type = nouveau_fb_bios_memtype(bios); - pfb->ram.ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1; - - /* read amount of vram attached to each memory controller */ - for (part = 0; part < parts; part++) { - if (!(pmask & (1 << part))) { - u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000)); - if (psize != bsize) { - if (psize < bsize) - bsize = psize; - uniform = false; - } - - nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize); - pfb->ram.size += (u64)psize << 20; - } - } - - /* if all controllers have the same amount attached, there's no holes */ - if (uniform) { - offset = rsvd_head; - length = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail; - return nouveau_mm_init(&pfb->vram, offset, length, 1); - } - - /* otherwise, address lowest common amount from 0GiB */ - ret = nouveau_mm_init(&pfb->vram, rsvd_head, (bsize << 8) * parts, 1); - if (ret) - return ret; - - /* and the rest starting from (8GiB + common_size) */ - offset = (0x0200000000ULL >> 12) + (bsize << 8); - length = (pfb->ram.size >> 12) - (bsize << 8) - rsvd_tail; - - ret = nouveau_mm_init(&pfb->vram, offset, length, 0); - if (ret) { - nouveau_mm_fini(&pfb->vram); - return ret; - } - - return 0; -} - -static int -nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, - u32 memtype, struct nouveau_mem **pmem) -{ - struct nouveau_mm *mm = &pfb->vram; - struct nouveau_mm_node *r; - struct nouveau_mem *mem; - int type = (memtype & 0x0ff); - int back = (memtype & 0x800); - int ret; - const bool comp = nvc0_pte_storage_type_map[type] != type; - - size >>= 12; - align >>= 12; - ncmin >>= 12; - if (!ncmin) - ncmin = size; - - mem = kzalloc(sizeof(*mem), GFP_KERNEL); - if (!mem) - return -ENOMEM; - - INIT_LIST_HEAD(&mem->regions); - mem->size = size; - - mutex_lock(&pfb->base.mutex); - if (comp) { - struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb->base.base.parent); - - /* compression only works with lpages */ - if (align == (1 << (17 - 12))) { - int n = size >> 5; - ltcg->tags_alloc(ltcg, n, &mem->tag); - } - if (unlikely(!mem->tag)) - type = nvc0_pte_storage_type_map[type]; - } - mem->memtype = type; - - do { - if (back) - ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); - else - ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); - if (ret) { - mutex_unlock(&pfb->base.mutex); - pfb->ram.put(pfb, &mem); - return ret; - } - - list_add_tail(&r->rl_entry, &mem->regions); - size -= r->length; - } while (size); - mutex_unlock(&pfb->base.mutex); - - r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); - mem->offset = (u64)r->offset << 12; - *pmem = mem; - return 0; -} - -static void -nvc0_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem) -{ - struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb->base.base.parent); - - if ((*pmem)->tag) - ltcg->tags_free(ltcg, &(*pmem)->tag); - - nv50_fb_vram_del(pfb, pmem); -} - -static int nvc0_fb_init(struct nouveau_object *object) { struct nvc0_fb_priv *priv = (void *)object; @@ -212,15 +78,12 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvc0_fb_priv *priv; int ret; - ret = nouveau_fb_create(parent, engine, oclass, &priv); + ret = nouveau_fb_create(parent, engine, oclass, &nvc0_ram_oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.memtype_valid = nvc0_fb_memtype_valid; - priv->base.ram.init = nvc0_fb_vram_init; - priv->base.ram.get = nvc0_fb_vram_new; - priv->base.ram.put = nvc0_fb_vram_del; priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (priv->r100c10_page) { @@ -231,7 +94,7 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return -EFAULT; } - return nouveau_fb_preinit(&priv->base); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h new file mode 100644 index 000000000000..6c974dd83e8b --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h @@ -0,0 +1,87 @@ +#ifndef __NVKM_FB_PRIV_H__ +#define __NVKM_FB_PRIV_H__ + +#include <subdev/fb.h> + +#define nouveau_ram_create(p,e,o,d) \ + nouveau_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d) +#define nouveau_ram_destroy(p) \ + nouveau_object_destroy(&(p)->base) +#define nouveau_ram_init(p) \ + nouveau_object_init(&(p)->base) +#define nouveau_ram_fini(p,s) \ + nouveau_object_fini(&(p)->base, (s)) + +#define _nouveau_ram_dtor nouveau_object_destroy +#define _nouveau_ram_init nouveau_object_init +#define _nouveau_ram_fini nouveau_object_fini + +extern struct nouveau_oclass nv04_ram_oclass; +extern struct nouveau_oclass nv10_ram_oclass; +extern struct nouveau_oclass nv1a_ram_oclass; +extern struct nouveau_oclass nv20_ram_oclass; +extern struct nouveau_oclass nv40_ram_oclass; +extern struct nouveau_oclass nv41_ram_oclass; +extern struct nouveau_oclass nv44_ram_oclass; +extern struct nouveau_oclass nv49_ram_oclass; +extern struct nouveau_oclass nv4e_ram_oclass; +extern struct nouveau_oclass nv50_ram_oclass; +extern struct nouveau_oclass nvc0_ram_oclass; + +#define nouveau_fb_create(p,e,c,r,d) \ + nouveau_fb_create_((p), (e), (c), (r), sizeof(**d), (void **)d) +#define nouveau_fb_destroy(p) ({ \ + struct nouveau_fb *pfb = (p); \ + _nouveau_fb_dtor(nv_object(pfb)); \ +}) +#define nouveau_fb_init(p) ({ \ + struct nouveau_fb *pfb = (p); \ + _nouveau_fb_init(nv_object(pfb)); \ +}) +#define nouveau_fb_fini(p,s) ({ \ + struct nouveau_fb *pfb = (p); \ + _nouveau_fb_fini(nv_object(pfb), (s)); \ +}) + +int nouveau_fb_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, struct nouveau_oclass *, + int length, void **pobject); +void _nouveau_fb_dtor(struct nouveau_object *); +int _nouveau_fb_init(struct nouveau_object *); +int _nouveau_fb_fini(struct nouveau_object *, bool); + +struct nouveau_bios; +int nouveau_fb_bios_memtype(struct nouveau_bios *); + +bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype); + +void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); +void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *); +void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); +void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *); +void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +int nv30_fb_init(struct nouveau_object *); +void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); + +void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags, + struct nouveau_fb_tile *); + +int nv41_fb_init(struct nouveau_object *); +void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +int nv44_fb_init(struct nouveau_object *); +void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); + +void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nouveau_fb_tile *); + +void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **); +extern int nv50_fb_memtype[0x80]; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c new file mode 100644 index 000000000000..e781080d3327 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c @@ -0,0 +1,95 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#define NV04_PFB_BOOT_0 0x00100000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 +# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004 +# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028 +# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100 +# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000 + +#include "priv.h" + +static int +nv04_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 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0); + int ret; + + ret = nouveau_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + if (boot0 & 0x00000100) { + ram->size = ((boot0 >> 12) & 0xf) * 2 + 2; + ram->size *= 1024 * 1024; + } else { + switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) { + case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB: + ram->size = 32 * 1024 * 1024; + break; + case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB: + ram->size = 16 * 1024 * 1024; + break; + case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB: + ram->size = 8 * 1024 * 1024; + break; + case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB: + ram->size = 4 * 1024 * 1024; + break; + } + } + + if ((boot0 & 0x00000038) <= 0x10) + ram->type = NV_MEM_TYPE_SGRAM; + else + ram->type = NV_MEM_TYPE_SDRAM; + return 0; +} + +struct nouveau_oclass +nv04_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c new file mode 100644 index 000000000000..8311f3774edf --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c @@ -0,0 +1,61 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +static int +nv10_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 cfg0 = nv_rd32(pfb, 0x100200); + int ret; + + ret = nouveau_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + if (cfg0 & 0x00000001) + ram->type = NV_MEM_TYPE_DDR1; + else + ram->type = NV_MEM_TYPE_SDRAM; + + ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; + return 0; +} + + +struct nouveau_oclass +nv10_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv10_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c new file mode 100644 index 000000000000..d0caddfb9db0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c @@ -0,0 +1,71 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +static int +nv1a_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; + struct pci_dev *bridge; + u32 mem, mib; + int ret; + + bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1)); + if (!bridge) { + nv_fatal(pfb, "no bridge device\n"); + return -ENODEV; + } + + ret = nouveau_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + if (nv_device(pfb)->chipset == 0x1a) { + pci_read_config_dword(bridge, 0x7c, &mem); + mib = ((mem >> 6) & 31) + 1; + } else { + pci_read_config_dword(bridge, 0x84, &mem); + mib = ((mem >> 4) & 127) + 1; + } + + ram->type = NV_MEM_TYPE_STOLEN; + ram->size = mib * 1024 * 1024; + return 0; +} + +struct nouveau_oclass +nv1a_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv1a_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c new file mode 100644 index 000000000000..fdc11bba226d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c @@ -0,0 +1,63 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +static int +nv20_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 pbus1218 = nv_rd32(pfb, 0x001218); + int ret; + + ret = nouveau_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + switch (pbus1218 & 0x00000300) { + case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break; + case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break; + case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break; + case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break; + } + ram->size = (nv_rd32(pfb, 0x10020c) & 0xff000000); + ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; + ram->tags = nv_rd32(pfb, 0x100320); + return 0; +} + +struct nouveau_oclass +nv20_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv20_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c new file mode 100644 index 000000000000..ee49ac4dbdb6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c @@ -0,0 +1,65 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +static int +nv40_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 pbus1218 = nv_rd32(pfb, 0x001218); + int ret; + + ret = nouveau_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + switch (pbus1218 & 0x00000300) { + case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break; + case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break; + case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break; + case 0x00000300: ram->type = NV_MEM_TYPE_DDR2; break; + } + + ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; + ram->tags = nv_rd32(pfb, 0x100320); + return 0; +} + + +struct nouveau_oclass +nv40_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv40_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c new file mode 100644 index 000000000000..1dab7e12abab --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c @@ -0,0 +1,64 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +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; +} + +struct nouveau_oclass +nv41_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv41_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c new file mode 100644 index 000000000000..25fff842e5c1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c @@ -0,0 +1,62 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +static int +nv44_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; + return 0; +} + +struct nouveau_oclass +nv44_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv44_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c new file mode 100644 index 000000000000..19e3a9a63a02 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c @@ -0,0 +1,64 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +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 nouveau_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: pfb->ram->type = NV_MEM_TYPE_DDR1; break; + case 0x00000001: pfb->ram->type = NV_MEM_TYPE_DDR2; break; + case 0x00000002: pfb->ram->type = NV_MEM_TYPE_GDDR3; break; + case 0x00000003: break; + } + + pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; + pfb->ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; + pfb->ram->tags = nv_rd32(pfb, 0x100320); + return 0; +} + +struct nouveau_oclass +nv49_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv49_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c new file mode 100644 index 000000000000..7192aa6e5577 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c @@ -0,0 +1,55 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "priv.h" + +static int +nv4e_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; + int ret; + + ret = nouveau_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; + pfb->ram->type = NV_MEM_TYPE_STOLEN; + return 0; +} + +struct nouveau_oclass +nv4e_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv4e_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c new file mode 100644 index 000000000000..af5aa7ee8ad9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c @@ -0,0 +1,232 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/bios.h> +#include <core/mm.h> +#include "priv.h" + +void +nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) +{ + struct nouveau_mm_node *this; + struct nouveau_mem *mem; + + mem = *pmem; + *pmem = NULL; + if (unlikely(mem == NULL)) + return; + + mutex_lock(&pfb->base.mutex); + while (!list_empty(&mem->regions)) { + this = list_first_entry(&mem->regions, typeof(*this), rl_entry); + + list_del(&this->rl_entry); + nouveau_mm_free(&pfb->vram, &this); + } + + nouveau_mm_free(&pfb->tags, &mem->tag); + mutex_unlock(&pfb->base.mutex); + + kfree(mem); +} + +static int +nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, + u32 memtype, struct nouveau_mem **pmem) +{ + struct nouveau_mm *heap = &pfb->vram; + struct nouveau_mm *tags = &pfb->tags; + struct nouveau_mm_node *r; + struct nouveau_mem *mem; + int comp = (memtype & 0x300) >> 8; + int type = (memtype & 0x07f); + int back = (memtype & 0x800); + int min, max, ret; + + max = (size >> 12); + min = ncmin ? (ncmin >> 12) : max; + align >>= 12; + + mem = kzalloc(sizeof(*mem), GFP_KERNEL); + if (!mem) + return -ENOMEM; + + mutex_lock(&pfb->base.mutex); + if (comp) { + if (align == 16) { + int n = (max >> 4) * comp; + + ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag); + if (ret) + mem->tag = NULL; + } + + if (unlikely(!mem->tag)) + comp = 0; + } + + INIT_LIST_HEAD(&mem->regions); + mem->memtype = (comp << 7) | type; + mem->size = max; + + type = nv50_fb_memtype[type]; + do { + if (back) + ret = nouveau_mm_tail(heap, type, max, min, align, &r); + else + ret = nouveau_mm_head(heap, type, max, min, align, &r); + if (ret) { + mutex_unlock(&pfb->base.mutex); + pfb->ram->put(pfb, &mem); + return ret; + } + + list_add_tail(&r->rl_entry, &mem->regions); + max -= r->length; + } while (max); + mutex_unlock(&pfb->base.mutex); + + r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); + mem->offset = (u64)r->offset << 12; + *pmem = mem; + return 0; +} + +static u32 +nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram) +{ + int i, parts, colbits, rowbitsa, rowbitsb, banks; + u64 rowsize, predicted; + u32 r0, r4, rt, ru, rblock_size; + + r0 = nv_rd32(pfb, 0x100200); + r4 = nv_rd32(pfb, 0x100204); + rt = nv_rd32(pfb, 0x100250); + ru = nv_rd32(pfb, 0x001540); + nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru); + + for (i = 0, parts = 0; i < 8; i++) { + if (ru & (0x00010000 << i)) + parts++; + } + + colbits = (r4 & 0x0000f000) >> 12; + rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; + rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; + banks = 1 << (((r4 & 0x03000000) >> 24) + 2); + + rowsize = parts * banks * (1 << colbits) * 8; + predicted = rowsize << rowbitsa; + if (r0 & 0x00000004) + predicted += rowsize << rowbitsb; + + if (predicted != ram->size) { + nv_warn(pfb, "memory controller reports %d MiB VRAM\n", + (u32)(ram->size >> 20)); + } + + rblock_size = rowsize; + if (rt & 1) + rblock_size *= 3; + + nv_debug(pfb, "rblock %d bytes\n", rblock_size); + return rblock_size; +} + +static int +nv50_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 datasize, + struct nouveau_object **pobject) +{ + struct nouveau_fb *pfb = nouveau_fb(parent); + struct nouveau_device *device = nv_device(pfb); + struct nouveau_bios *bios = nouveau_bios(device); + struct nouveau_ram *ram; + const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ + const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ + u32 size; + 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); + + size = (ram->size >> 12) - rsvd_head - rsvd_tail; + switch (device->chipset) { + case 0xaa: + case 0xac: + case 0xaf: /* IGPs, no reordering, no real VRAM */ + ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1); + if (ret) + return ret; + + ram->type = NV_MEM_TYPE_STOLEN; + ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12; + break; + default: + switch (nv_rd32(pfb, 0x100714) & 0x00000007) { + case 0: ram->type = NV_MEM_TYPE_DDR1; break; + case 1: + if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) + ram->type = NV_MEM_TYPE_DDR3; + else + ram->type = NV_MEM_TYPE_DDR2; + break; + case 2: ram->type = NV_MEM_TYPE_GDDR3; break; + case 3: ram->type = NV_MEM_TYPE_GDDR4; break; + case 4: ram->type = NV_MEM_TYPE_GDDR5; break; + default: + break; + } + + ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, + nv50_fb_vram_rblock(pfb, ram) >> 12); + if (ret) + return ret; + + ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1; + ram->tags = nv_rd32(pfb, 0x100320); + break; + } + + ram->get = nv50_ram_get; + ram->put = nv50_ram_put; + return 0; +} + +struct nouveau_oclass +nv50_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c new file mode 100644 index 000000000000..9c3634acbb9d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c @@ -0,0 +1,186 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/bios.h> +#include <subdev/ltcg.h> + +#include "priv.h" + +extern const u8 nvc0_pte_storage_type_map[256]; + +void +nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) +{ + struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb); + + if ((*pmem)->tag) + ltcg->tags_free(ltcg, &(*pmem)->tag); + + nv50_ram_put(pfb, pmem); +} + +int +nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, + u32 memtype, struct nouveau_mem **pmem) +{ + struct nouveau_mm *mm = &pfb->vram; + struct nouveau_mm_node *r; + struct nouveau_mem *mem; + int type = (memtype & 0x0ff); + int back = (memtype & 0x800); + const bool comp = nvc0_pte_storage_type_map[type] != type; + int ret; + + size >>= 12; + align >>= 12; + ncmin >>= 12; + if (!ncmin) + ncmin = size; + + mem = kzalloc(sizeof(*mem), GFP_KERNEL); + if (!mem) + return -ENOMEM; + + INIT_LIST_HEAD(&mem->regions); + mem->size = size; + + mutex_lock(&pfb->base.mutex); + if (comp) { + struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb); + + /* compression only works with lpages */ + if (align == (1 << (17 - 12))) { + int n = size >> 5; + ltcg->tags_alloc(ltcg, n, &mem->tag); + } + + if (unlikely(!mem->tag)) + type = nvc0_pte_storage_type_map[type]; + } + mem->memtype = type; + + do { + if (back) + ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r); + else + ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r); + if (ret) { + mutex_unlock(&pfb->base.mutex); + pfb->ram->put(pfb, &mem); + return ret; + } + + list_add_tail(&r->rl_entry, &mem->regions); + size -= r->length; + } while (size); + mutex_unlock(&pfb->base.mutex); + + r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); + mem->offset = (u64)r->offset << 12; + *pmem = mem; + return 0; +} + +static int +nvc0_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_bios *bios = nouveau_bios(pfb); + struct nouveau_ram *ram; + const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ + const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ + u32 parts = nv_rd32(pfb, 0x022438); + u32 pmask = nv_rd32(pfb, 0x022554); + u32 bsize = nv_rd32(pfb, 0x10f20c); + u32 offset, length; + bool uniform = true; + int ret, part; + + ret = nouveau_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800)); + nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask); + + ram->type = nouveau_fb_bios_memtype(bios); + ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1; + + /* read amount of vram attached to each memory controller */ + for (part = 0; part < parts; part++) { + if (!(pmask & (1 << part))) { + u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000)); + if (psize != bsize) { + if (psize < bsize) + bsize = psize; + uniform = false; + } + + nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize); + ram->size += (u64)psize << 20; + } + } + + /* if all controllers have the same amount attached, there's no holes */ + if (uniform) { + offset = rsvd_head; + length = (ram->size >> 12) - rsvd_head - rsvd_tail; + ret = nouveau_mm_init(&pfb->vram, offset, length, 1); + } else { + /* otherwise, address lowest common amount from 0GiB */ + ret = nouveau_mm_init(&pfb->vram, rsvd_head, + (bsize << 8) * parts, 1); + if (ret) + return ret; + + /* and the rest starting from (8GiB + common_size) */ + offset = (0x0200000000ULL >> 12) + (bsize << 8); + length = (ram->size >> 12) - (bsize << 8) - rsvd_tail; + + ret = nouveau_mm_init(&pfb->vram, offset, length, 0); + if (ret) + nouveau_mm_fini(&pfb->vram); + } + + if (ret) + return ret; + + ram->get = nvc0_ram_get; + ram->put = nvc0_ram_put; + return 0; +} + +struct nouveau_oclass +nvc0_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_ram_create, + .dtor = _nouveau_ram_dtor, + .init = _nouveau_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c index cfc7e31461de..97bc5dff93e7 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c @@ -56,7 +56,7 @@ nv50_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - ret = pfb->ram.get(pfb, size, align, 0, 0x800, &node->mem); + ret = pfb->ram->get(pfb, size, align, 0, 0x800, &node->mem); if (ret) return ret; @@ -71,7 +71,7 @@ nv50_instobj_dtor(struct nouveau_object *object) { struct nv50_instobj_priv *node = (void *)object; struct nouveau_fb *pfb = nouveau_fb(object); - pfb->ram.put(pfb, &node->mem); + pfb->ram->put(pfb, &node->mem); nouveau_instobj_destroy(&node->base); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c index fb794e997fbc..bcca883018f4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c @@ -122,7 +122,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) nv_wr32(priv, 0x17e000, priv->part_nr); /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ - priv->num_tags = (pfb->ram.size >> 17) / 4; + priv->num_tags = (pfb->ram->size >> 17) / 4; if (priv->num_tags > (1 << 17)) priv->num_tags = 1 << 17; /* we have 17 bits in PTE */ priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */ diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c index d796924f9930..0cb322a5e72c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c @@ -35,6 +35,7 @@ nv50_mc_intr[] = { { 0x00001000, NVDEV_ENGINE_GR }, { 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84- */ { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */ + { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */ { 0x00100000, NVDEV_SUBDEV_TIMER }, { 0x00200000, NVDEV_SUBDEV_GPIO }, { 0x04000000, NVDEV_ENGINE_DISP }, diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c index 737bd4b682e1..c5da3babbc62 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c @@ -33,6 +33,7 @@ nvc0_mc_intr[] = { { 0x00000001, NVDEV_ENGINE_PPP }, { 0x00000020, NVDEV_ENGINE_COPY0 }, { 0x00000040, NVDEV_ENGINE_COPY1 }, + { 0x00000080, NVDEV_ENGINE_COPY2 }, { 0x00000100, NVDEV_ENGINE_FIFO }, { 0x00001000, NVDEV_ENGINE_GR }, { 0x00008000, NVDEV_ENGINE_BSP }, diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c index 77c67fc970e6..67fcb6c852ac 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c @@ -236,9 +236,9 @@ nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde) vmm->map_pgt(vpgd->obj, pde, vpgt->obj); } - mutex_unlock(&vm->mm.mutex); + mutex_unlock(&nv_subdev(vmm)->mutex); nouveau_gpuobj_ref(NULL, &pgt); - mutex_lock(&vm->mm.mutex); + mutex_lock(&nv_subdev(vmm)->mutex); } } @@ -256,18 +256,18 @@ nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type) pgt_size = (1 << (vmm->pgt_bits + 12)) >> type; pgt_size *= 8; - mutex_unlock(&vm->mm.mutex); + mutex_unlock(&nv_subdev(vmm)->mutex); ret = nouveau_gpuobj_new(nv_object(vm->vmm), NULL, pgt_size, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &pgt); - mutex_lock(&vm->mm.mutex); + mutex_lock(&nv_subdev(vmm)->mutex); if (unlikely(ret)) return ret; /* someone beat us to filling the PDE while we didn't have the lock */ if (unlikely(vpgt->refcount[big]++)) { - mutex_unlock(&vm->mm.mutex); + mutex_unlock(&nv_subdev(vmm)->mutex); nouveau_gpuobj_ref(NULL, &pgt); - mutex_lock(&vm->mm.mutex); + mutex_lock(&nv_subdev(vmm)->mutex); return 0; } @@ -289,11 +289,11 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, u32 fpde, lpde, pde; int ret; - mutex_lock(&vm->mm.mutex); + mutex_lock(&nv_subdev(vmm)->mutex); ret = nouveau_mm_head(&vm->mm, page_shift, msize, msize, align, &vma->node); if (unlikely(ret != 0)) { - mutex_unlock(&vm->mm.mutex); + mutex_unlock(&nv_subdev(vmm)->mutex); return ret; } @@ -314,13 +314,14 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, if (pde != fpde) nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1); nouveau_mm_free(&vm->mm, &vma->node); - mutex_unlock(&vm->mm.mutex); + mutex_unlock(&nv_subdev(vmm)->mutex); return ret; } } - mutex_unlock(&vm->mm.mutex); + mutex_unlock(&nv_subdev(vmm)->mutex); - vma->vm = vm; + vma->vm = NULL; + nouveau_vm_ref(vm, &vma->vm, NULL); vma->offset = (u64)vma->node->offset << 12; vma->access = access; return 0; @@ -338,10 +339,12 @@ nouveau_vm_put(struct nouveau_vma *vma) fpde = (vma->node->offset >> vmm->pgt_bits); lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits; - mutex_lock(&vm->mm.mutex); + mutex_lock(&nv_subdev(vmm)->mutex); nouveau_vm_unmap_pgt(vm, vma->node->type != vmm->spg_shift, fpde, lpde); nouveau_mm_free(&vm->mm, &vma->node); - mutex_unlock(&vm->mm.mutex); + mutex_unlock(&nv_subdev(vmm)->mutex); + + nouveau_vm_ref(NULL, &vma->vm, NULL); } int @@ -362,7 +365,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, vm->fpde = offset >> (vmm->pgt_bits + 12); vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12); - vm->pgt = kcalloc(vm->lpde - vm->fpde + 1, sizeof(*vm->pgt), GFP_KERNEL); + vm->pgt = vzalloc((vm->lpde - vm->fpde + 1) * sizeof(*vm->pgt)); if (!vm->pgt) { kfree(vm); return -ENOMEM; @@ -371,7 +374,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12, block >> 12); if (ret) { - kfree(vm->pgt); + vfree(vm->pgt); kfree(vm); return ret; } @@ -405,24 +408,25 @@ nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) nouveau_gpuobj_ref(pgd, &vpgd->obj); - mutex_lock(&vm->mm.mutex); + mutex_lock(&nv_subdev(vmm)->mutex); for (i = vm->fpde; i <= vm->lpde; i++) vmm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); list_add(&vpgd->head, &vm->pgd_list); - mutex_unlock(&vm->mm.mutex); + mutex_unlock(&nv_subdev(vmm)->mutex); return 0; } static void nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) { + struct nouveau_vmmgr *vmm = vm->vmm; struct nouveau_vm_pgd *vpgd, *tmp; struct nouveau_gpuobj *pgd = NULL; if (!mpgd) return; - mutex_lock(&vm->mm.mutex); + mutex_lock(&nv_subdev(vmm)->mutex); list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { if (vpgd->obj == mpgd) { pgd = vpgd->obj; @@ -431,7 +435,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) break; } } - mutex_unlock(&vm->mm.mutex); + mutex_unlock(&nv_subdev(vmm)->mutex); nouveau_gpuobj_ref(NULL, &pgd); } @@ -446,7 +450,7 @@ nouveau_vm_del(struct nouveau_vm *vm) } nouveau_mm_fini(&vm->mm); - kfree(vm->pgt); + vfree(vm->pgt); kfree(vm); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c index e067f81c97b3..07dd1fe2d6fb 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c @@ -27,11 +27,11 @@ #include <subdev/timer.h> #include <subdev/fb.h> +#include <subdev/bar.h> #include <subdev/vm.h> struct nv50_vmmgr_priv { struct nouveau_vmmgr base; - spinlock_t lock; }; static void @@ -86,8 +86,8 @@ nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, /* IGPs don't have real VRAM, re-target to stolen system memory */ target = 0; - if (nouveau_fb(vma->vm->vmm)->ram.stolen) { - phys += nouveau_fb(vma->vm->vmm)->ram.stolen; + if (nouveau_fb(vma->vm->vmm)->ram->stolen) { + phys += nouveau_fb(vma->vm->vmm)->ram->stolen; target = 3; } @@ -151,29 +151,42 @@ nv50_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) static void nv50_vm_flush(struct nouveau_vm *vm) { + struct nv50_vmmgr_priv *priv = (void *)vm->vmm; + struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_engine *engine; - int i; + int i, vme; + + bar->flush(bar); + mutex_lock(&nv_subdev(priv)->mutex); for (i = 0; i < NVDEV_SUBDEV_NR; i++) { - if (atomic_read(&vm->engref[i])) { - engine = nouveau_engine(vm->vmm, i); - if (engine && engine->tlb_flush) - engine->tlb_flush(engine); + if (!atomic_read(&vm->engref[i])) + continue; + + /* unfortunate hw bug workaround... */ + engine = nouveau_engine(priv, i); + if (engine && engine->tlb_flush) { + engine->tlb_flush(engine); + continue; } - } -} -void -nv50_vm_flush_engine(struct nouveau_subdev *subdev, int engine) -{ - struct nv50_vmmgr_priv *priv = (void *)nouveau_vmmgr(subdev); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - nv_wr32(subdev, 0x100c80, (engine << 16) | 1); - if (!nv_wait(subdev, 0x100c80, 0x00000001, 0x00000000)) - nv_error(subdev, "vm flush timeout: engine %d\n", engine); - spin_unlock_irqrestore(&priv->lock, flags); + switch (i) { + case NVDEV_ENGINE_GR : vme = 0x00; break; + case NVDEV_ENGINE_VP : vme = 0x01; break; + case NVDEV_SUBDEV_BAR : vme = 0x06; break; + case NVDEV_ENGINE_MPEG : vme = 0x08; break; + case NVDEV_ENGINE_BSP : vme = 0x09; break; + case NVDEV_ENGINE_CRYPT: vme = 0x0a; break; + case NVDEV_ENGINE_COPY0: vme = 0x0d; break; + default: + continue; + } + + nv_wr32(priv, 0x100c80, (vme << 16) | 1); + if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) + nv_error(priv, "vm flush timeout: engine %d\n", vme); + } + mutex_unlock(&nv_subdev(priv)->mutex); } static int @@ -211,7 +224,6 @@ nv50_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->base.map_sg = nv50_vm_map_sg; priv->base.unmap = nv50_vm_unmap; priv->base.flush = nv50_vm_flush; - spin_lock_init(&priv->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c index 4c3b0a23b9d6..668cf964e4a9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c @@ -29,10 +29,10 @@ #include <subdev/fb.h> #include <subdev/vm.h> #include <subdev/ltcg.h> +#include <subdev/bar.h> struct nvc0_vmmgr_priv { struct nouveau_vmmgr base; - spinlock_t lock; }; @@ -160,40 +160,40 @@ nvc0_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) } } -void -nvc0_vm_flush_engine(struct nouveau_subdev *subdev, u64 addr, int type) -{ - struct nvc0_vmmgr_priv *priv = (void *)nouveau_vmmgr(subdev); - unsigned long flags; - - /* looks like maybe a "free flush slots" counter, the - * faster you write to 0x100cbc to more it decreases - */ - spin_lock_irqsave(&priv->lock, flags); - if (!nv_wait_ne(subdev, 0x100c80, 0x00ff0000, 0x00000000)) { - nv_error(subdev, "vm timeout 0: 0x%08x %d\n", - nv_rd32(subdev, 0x100c80), type); - } - - nv_wr32(subdev, 0x100cb8, addr >> 8); - nv_wr32(subdev, 0x100cbc, 0x80000000 | type); - - /* wait for flush to be queued? */ - if (!nv_wait(subdev, 0x100c80, 0x00008000, 0x00008000)) { - nv_error(subdev, "vm timeout 1: 0x%08x %d\n", - nv_rd32(subdev, 0x100c80), type); - } - spin_unlock_irqrestore(&priv->lock, flags); -} - static void nvc0_vm_flush(struct nouveau_vm *vm) { + struct nvc0_vmmgr_priv *priv = (void *)vm->vmm; + struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_vm_pgd *vpgd; + u32 type; + + bar->flush(bar); + + type = 0x00000001; /* PAGE_ALL */ + if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR])) + type |= 0x00000004; /* HUB_ONLY */ + mutex_lock(&nv_subdev(priv)->mutex); list_for_each_entry(vpgd, &vm->pgd_list, head) { - nvc0_vm_flush_engine(nv_subdev(vm->vmm), vpgd->obj->addr, 1); + /* looks like maybe a "free flush slots" counter, the + * faster you write to 0x100cbc to more it decreases + */ + if (!nv_wait_ne(priv, 0x100c80, 0x00ff0000, 0x00000000)) { + nv_error(priv, "vm timeout 0: 0x%08x %d\n", + nv_rd32(priv, 0x100c80), type); + } + + nv_wr32(priv, 0x100cb8, vpgd->obj->addr >> 8); + nv_wr32(priv, 0x100cbc, 0x80000000 | type); + + /* wait for flush to be queued? */ + if (!nv_wait(priv, 0x100c80, 0x00008000, 0x00008000)) { + nv_error(priv, "vm timeout 1: 0x%08x %d\n", + nv_rd32(priv, 0x100c80), type); + } } + mutex_unlock(&nv_subdev(priv)->mutex); } static int @@ -227,7 +227,6 @@ nvc0_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->base.map_sg = nvc0_vm_map_sg; priv->base.unmap = nvc0_vm_unmap; priv->base.flush = nvc0_vm_flush; - spin_lock_init(&priv->lock); return 0; } |