aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-03 11:44:24 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-03 11:44:24 -0700
commit2f34c1231bfc9f2550f934acb268ac7315fb3837 (patch)
treeff8114b3b4ec4723a11b041c6b74c389e9f0eeb9 /drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
parentMerge branch 'generic' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs (diff)
parentMerge branch 'linux-4.12' of git://github.com/skeggsb/linux into drm-next (diff)
downloadlinux-dev-2f34c1231bfc9f2550f934acb268ac7315fb3837.tar.xz
linux-dev-2f34c1231bfc9f2550f934acb268ac7315fb3837.zip
Merge tag 'drm-for-v4.12' of git://people.freedesktop.org/~airlied/linux
Pull drm u pdates from Dave Airlie: "This is the main drm pull request for v4.12. Apart from two fixes pulls, everything should have been in drm-next for at least 2 weeks. The biggest thing in here is AMD released the public headers for their upcoming VEGA GPUs. These as always are quite a sizeable chunk of header files. They've also added initial non-display support for those GPUs, though they aren't available in production yet. Otherwise it's pretty much normal. New bridge drivers: - megachips-stdpxxxx-ge-b850v3-fw LVDS->DP++ - generic LVDS bridge support. Core: - Displayport link train failure reporting to userspace - debugfs interface cleaned up - subsystem TODO in kerneldoc now - Extended fbdev support (flipping and vblank wait) - drm_platform removed - EDP CRC support in helper - HF-VSDB SCDC support in EDID parser - Lots of code cleanups and header extraction - Thunderbolt external GPU awareness - Atomic helper improvements - Documentation improvements panel: - Sitronix and Samsung new panel support amdgpu: - Preliminary vega10 support - Multi-level page table support - GPU sensor support for userspace - PRT support for sparse buffers - SR-IOV improvements - Non-contig VRAM CPU mapping i915: - Atomic modesetting enabled by default on Gen5+ - LSPCON improvements - Atomic state handling for cdclk - GPU reset improvements - In-kernel unit tests - Geminilake improvements and color manager support - Designware i2c fixes - vblank evasion improvements - Hotplug safe connector iterators - GVT scheduler QoS support - GVT Kabylake support nouveau: - Acceleration support for Pascal (GP10x). - Rearchitecture of code handling proprietary signed firmware - Fix GTX 970 with odd MMU configuration - GP10B support - GP107 acceleration support vmwgfx: - Atomic modesetting support for vmwgfx omapdrm: - Support for render nodes - Refactor omapdss code - Fix some probe ordering issues - Fix too dark RGB565 rendering sunxi: - prelim rework for multiple pipes. mali-dp: - Color management support - Plane scaling - Power management improvements imx-drm: - Prefetch Resolve Engine/Gasket on i.MX6QP - Deferred plane disabling - Separate alpha support mediatek: - Mediatek SoC MT2701 support rcar-du: - Gen3 HDMI support msm: - 4k support for newer chips - OPP bindings for gpu - prep work for per-process pagetables vc4: - HDMI audio support - fixes qxl: - minor fixes. dw-hdmi: - PHY improvements - CSC fixes - Amlogic GX SoC support" * tag 'drm-for-v4.12' of git://people.freedesktop.org/~airlied/linux: (1778 commits) drm/nouveau/fb/gf100-: Fix 32 bit wraparound in new ram detection drm/nouveau/secboot/gm20b: fix the error return code in gm20b_secboot_tegra_read_wpr() drm/nouveau/kms: Increase max retries in scanout position queries. drm/nouveau/bios/bitP: check that table is long enough for optional pointers drm/nouveau/fifo/nv40: no ctxsw for pre-nv44 mpeg engine drm: mali-dp: use div_u64 for expensive 64-bit divisions drm/i915: Confirm the request is still active before adding it to the await drm/i915: Avoid busy-spinning on VLV_GLTC_PW_STATUS mmio drm/i915/selftests: Allocate inode/file dynamically drm/i915: Fix system hang with EI UP masked on Haswell drm/i915: checking for NULL instead of IS_ERR() in mock selftests drm/i915: Perform link quality check unconditionally during long pulse drm/i915: Fix use after free in lpe_audio_platdev_destroy() drm/i915: Use the right mapping_gfp_mask for final shmem allocation drm/i915: Make legacy cursor updates more unsynced drm/i915: Apply a cond_resched() to the saturated signaler drm/i915: Park the signaler before sleeping drm: mali-dp: Check the mclk rate and allow up/down scaling drm: mali-dp: Enable image enhancement when scaling drm: mali-dp: Add plane upscaling support ...
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c148
1 files changed, 94 insertions, 54 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
index 6758da93a3a1..c63975907c90 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
@@ -124,7 +124,7 @@ gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic)
}
}
-static int
+int
gf100_ram_calc(struct nvkm_ram *base, u32 freq)
{
struct gf100_ram *ram = gf100_ram(base);
@@ -404,7 +404,7 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq)
return 0;
}
-static int
+int
gf100_ram_prog(struct nvkm_ram *base)
{
struct gf100_ram *ram = gf100_ram(base);
@@ -413,7 +413,7 @@ gf100_ram_prog(struct nvkm_ram *base)
return 0;
}
-static void
+void
gf100_ram_tidy(struct nvkm_ram *base)
{
struct gf100_ram *ram = gf100_ram(base);
@@ -500,7 +500,7 @@ gf100_ram_get(struct nvkm_ram *ram, u64 size, u32 align, u32 ncmin,
return 0;
}
-static int
+int
gf100_ram_init(struct nvkm_ram *base)
{
static const u8 train0[] = {
@@ -543,77 +543,96 @@ gf100_ram_init(struct nvkm_ram *base)
return 0;
}
-static const struct nvkm_ram_func
-gf100_ram_func = {
- .init = gf100_ram_init,
- .get = gf100_ram_get,
- .put = gf100_ram_put,
- .calc = gf100_ram_calc,
- .prog = gf100_ram_prog,
- .tidy = gf100_ram_tidy,
-};
+u32
+gf100_ram_probe_fbpa_amount(struct nvkm_device *device, int fbpa)
+{
+ return nvkm_rd32(device, 0x11020c + (fbpa * 0x1000));
+}
+
+u32
+gf100_ram_probe_fbp_amount(const struct nvkm_ram_func *func, u32 fbpao,
+ struct nvkm_device *device, int fbp, int *pltcs)
+{
+ if (!(fbpao & BIT(fbp))) {
+ *pltcs = 1;
+ return func->probe_fbpa_amount(device, fbp);
+ }
+ return 0;
+}
+
+u32
+gf100_ram_probe_fbp(const struct nvkm_ram_func *func,
+ struct nvkm_device *device, int fbp, int *pltcs)
+{
+ u32 fbpao = nvkm_rd32(device, 0x022554);
+ return func->probe_fbp_amount(func, fbpao, device, fbp, pltcs);
+}
int
gf100_ram_ctor(const struct nvkm_ram_func *func, struct nvkm_fb *fb,
- u32 maskaddr, struct nvkm_ram *ram)
+ struct nvkm_ram *ram)
{
struct nvkm_subdev *subdev = &fb->subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_bios *bios = device->bios;
const u32 rsvd_head = ( 256 * 1024); /* vga memory */
const u32 rsvd_tail = (1024 * 1024); /* vbios etc */
- u32 parts = nvkm_rd32(device, 0x022438);
- u32 pmask = nvkm_rd32(device, maskaddr);
- u64 bsize = (u64)nvkm_rd32(device, 0x10f20c) << 20;
- u64 psize, size = 0;
enum nvkm_ram_type type = nvkm_fb_bios_memtype(bios);
- bool uniform = true;
- int ret, i;
-
- nvkm_debug(subdev, "100800: %08x\n", nvkm_rd32(device, 0x100800));
- nvkm_debug(subdev, "parts %08x mask %08x\n", parts, pmask);
-
- /* read amount of vram attached to each memory controller */
- for (i = 0; i < parts; i++) {
- if (pmask & (1 << i))
- continue;
-
- psize = (u64)nvkm_rd32(device, 0x11020c + (i * 0x1000)) << 20;
- if (psize != bsize) {
- if (psize < bsize)
- bsize = psize;
- uniform = false;
+ u32 fbps = nvkm_rd32(device, 0x022438);
+ u64 total = 0, lcomm = ~0, lower, ubase, usize;
+ int ret, fbp, ltcs, ltcn = 0;
+
+ nvkm_debug(subdev, "%d FBP(s)\n", fbps);
+ for (fbp = 0; fbp < fbps; fbp++) {
+ u32 size = func->probe_fbp(func, device, fbp, &ltcs);
+ if (size) {
+ nvkm_debug(subdev, "FBP %d: %4d MiB, %d LTC(s)\n",
+ fbp, size, ltcs);
+ lcomm = min(lcomm, (u64)(size / ltcs) << 20);
+ total += (u64) size << 20;
+ ltcn += ltcs;
+ } else {
+ nvkm_debug(subdev, "FBP %d: disabled\n", fbp);
}
-
- nvkm_debug(subdev, "%d: %d MiB\n", i, (u32)(psize >> 20));
- size += psize;
}
- ret = nvkm_ram_ctor(func, fb, type, size, 0, ram);
+ lower = lcomm * ltcn;
+ ubase = lcomm + func->upper;
+ usize = total - lower;
+
+ nvkm_debug(subdev, "Lower: %4lld MiB @ %010llx\n", lower >> 20, 0ULL);
+ nvkm_debug(subdev, "Upper: %4lld MiB @ %010llx\n", usize >> 20, ubase);
+ nvkm_debug(subdev, "Total: %4lld MiB\n", total >> 20);
+
+ ret = nvkm_ram_ctor(func, fb, type, total, 0, ram);
if (ret)
return ret;
nvkm_mm_fini(&ram->vram);
- /* if all controllers have the same amount attached, there's no holes */
- if (uniform) {
+ /* Some GPUs are in what's known as a "mixed memory" configuration.
+ *
+ * This is either where some FBPs have more memory than the others,
+ * or where LTCs have been disabled on a FBP.
+ */
+ if (lower != total) {
+ /* The common memory amount is addressed normally. */
ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT,
- (size - rsvd_head - rsvd_tail) >>
- NVKM_RAM_MM_SHIFT, 1);
+ (lower - rsvd_head) >> NVKM_RAM_MM_SHIFT, 1);
if (ret)
return ret;
- } else {
- /* otherwise, address lowest common amount from 0GiB */
- ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT,
- ((bsize * parts) - rsvd_head) >>
- NVKM_RAM_MM_SHIFT, 1);
+
+ /* And the rest is much higher in the physical address
+ * space, and may not be usable for certain operations.
+ */
+ ret = nvkm_mm_init(&ram->vram, ubase >> NVKM_RAM_MM_SHIFT,
+ (usize - rsvd_tail) >> NVKM_RAM_MM_SHIFT, 1);
if (ret)
return ret;
-
- /* and the rest starting from (8GiB + common_size) */
- ret = nvkm_mm_init(&ram->vram, (0x0200000000ULL + bsize) >>
- NVKM_RAM_MM_SHIFT,
- (size - (bsize * parts) - rsvd_tail) >>
+ } else {
+ /* GPUs without mixed-memory are a lot nicer... */
+ ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT,
+ (total - rsvd_head - rsvd_tail) >>
NVKM_RAM_MM_SHIFT, 1);
if (ret)
return ret;
@@ -624,7 +643,8 @@ gf100_ram_ctor(const struct nvkm_ram_func *func, struct nvkm_fb *fb,
}
int
-gf100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
+gf100_ram_new_(const struct nvkm_ram_func *func,
+ struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_subdev *subdev = &fb->subdev;
struct nvkm_bios *bios = subdev->device->bios;
@@ -635,7 +655,7 @@ gf100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
return -ENOMEM;
*pram = &ram->base;
- ret = gf100_ram_ctor(&gf100_ram_func, fb, 0x022554, &ram->base);
+ ret = gf100_ram_ctor(func, fb, &ram->base);
if (ret)
return ret;
@@ -711,3 +731,23 @@ gf100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4);
return 0;
}
+
+static const struct nvkm_ram_func
+gf100_ram = {
+ .upper = 0x0200000000,
+ .probe_fbp = gf100_ram_probe_fbp,
+ .probe_fbp_amount = gf100_ram_probe_fbp_amount,
+ .probe_fbpa_amount = gf100_ram_probe_fbpa_amount,
+ .init = gf100_ram_init,
+ .get = gf100_ram_get,
+ .put = gf100_ram_put,
+ .calc = gf100_ram_calc,
+ .prog = gf100_ram_prog,
+ .tidy = gf100_ram_tidy,
+};
+
+int
+gf100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
+{
+ return gf100_ram_new_(&gf100_ram, fb, pram);
+}