summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nvkm/subdev/fb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/fb')
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c42
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h33
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c148
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf108.c62
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c70
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c25
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm200.c68
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c68
10 files changed, 375 insertions, 146 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
index 63566ba12fbb..1c5e5ba487a8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
@@ -20,6 +20,7 @@ nvkm-y += nvkm/subdev/fb/gt215.o
nvkm-y += nvkm/subdev/fb/mcp77.o
nvkm-y += nvkm/subdev/fb/mcp89.o
nvkm-y += nvkm/subdev/fb/gf100.o
+nvkm-y += nvkm/subdev/fb/gf108.o
nvkm-y += nvkm/subdev/fb/gk104.o
nvkm-y += nvkm/subdev/fb/gk20a.o
nvkm-y += nvkm/subdev/fb/gm107.o
@@ -42,8 +43,10 @@ nvkm-y += nvkm/subdev/fb/ramnv50.o
nvkm-y += nvkm/subdev/fb/ramgt215.o
nvkm-y += nvkm/subdev/fb/rammcp77.o
nvkm-y += nvkm/subdev/fb/ramgf100.o
+nvkm-y += nvkm/subdev/fb/ramgf108.o
nvkm-y += nvkm/subdev/fb/ramgk104.o
nvkm-y += nvkm/subdev/fb/ramgm107.o
+nvkm-y += nvkm/subdev/fb/ramgm200.o
nvkm-y += nvkm/subdev/fb/ramgp100.o
nvkm-y += nvkm/subdev/fb/sddr2.o
nvkm-y += nvkm/subdev/fb/sddr3.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c
new file mode 100644
index 000000000000..56af84aa333b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 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 <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ram.h"
+
+static const struct nvkm_fb_func
+gf108_fb = {
+ .dtor = gf100_fb_dtor,
+ .oneinit = gf100_fb_oneinit,
+ .init = gf100_fb_init,
+ .init_page = gf100_fb_init_page,
+ .intr = gf100_fb_intr,
+ .ram_new = gf108_ram_new,
+ .memtype_valid = gf100_fb_memtype_valid,
+};
+
+int
+gf108_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb)
+{
+ return gf100_fb_new_(&gf108_fb, device, index, pfb);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c
index fe5886013ac0..d83da5ddbc1e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm200.c
@@ -68,7 +68,7 @@ gm200_fb = {
.init = gm200_fb_init,
.init_page = gm200_fb_init_page,
.intr = gf100_fb_intr,
- .ram_new = gm107_ram_new,
+ .ram_new = gm200_ram_new,
.memtype_valid = gf100_fb_memtype_valid,
};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h
index b60068b7d8f9..fac7e73c3ddf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h
@@ -19,13 +19,38 @@ int nv50_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **);
void nv50_ram_put(struct nvkm_ram *, struct nvkm_mem **);
void __nv50_ram_put(struct nvkm_ram *, struct nvkm_mem *);
+int gf100_ram_new_(const struct nvkm_ram_func *, struct nvkm_fb *,
+ struct nvkm_ram **);
int gf100_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *,
- u32, struct nvkm_ram *);
+ struct nvkm_ram *);
+u32 gf100_ram_probe_fbp(const struct nvkm_ram_func *,
+ struct nvkm_device *, int, int *);
+u32 gf100_ram_probe_fbp_amount(const struct nvkm_ram_func *, u32,
+ struct nvkm_device *, int, int *);
+u32 gf100_ram_probe_fbpa_amount(struct nvkm_device *, int);
int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **);
void gf100_ram_put(struct nvkm_ram *, struct nvkm_mem **);
+int gf100_ram_init(struct nvkm_ram *);
+int gf100_ram_calc(struct nvkm_ram *, u32);
+int gf100_ram_prog(struct nvkm_ram *);
+void gf100_ram_tidy(struct nvkm_ram *);
+
+u32 gf108_ram_probe_fbp_amount(const struct nvkm_ram_func *, u32,
+ struct nvkm_device *, int, int *);
+
+int gk104_ram_new_(const struct nvkm_ram_func *, struct nvkm_fb *,
+ struct nvkm_ram **);
+void *gk104_ram_dtor(struct nvkm_ram *);
+int gk104_ram_init(struct nvkm_ram *);
+int gk104_ram_calc(struct nvkm_ram *, u32);
+int gk104_ram_prog(struct nvkm_ram *);
+void gk104_ram_tidy(struct nvkm_ram *);
+
+u32 gm107_ram_probe_fbp(const struct nvkm_ram_func *,
+ struct nvkm_device *, int, int *);
-int gk104_ram_ctor(struct nvkm_fb *, struct nvkm_ram **, u32);
-int gk104_ram_init(struct nvkm_ram *ram);
+u32 gm200_ram_probe_fbp_amount(const struct nvkm_ram_func *, u32,
+ struct nvkm_device *, int, int *);
/* RAM type-specific MR calculation routines */
int nvkm_sddr2_calc(struct nvkm_ram *);
@@ -46,7 +71,9 @@ int nv50_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int gt215_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int mcp77_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int gf100_ram_new(struct nvkm_fb *, struct nvkm_ram **);
+int gf108_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int gk104_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int gm107_ram_new(struct nvkm_fb *, struct nvkm_ram **);
+int gm200_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int gp100_ram_new(struct nvkm_fb *, struct nvkm_ram **);
#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
index 6758da93a3a1..53c32fc694e9 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 += 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);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf108.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf108.c
new file mode 100644
index 000000000000..985ec64cf369
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf108.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 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 <bskeggs@redhat.com>
+ */
+#include "ram.h"
+
+u32
+gf108_ram_probe_fbp_amount(const struct nvkm_ram_func *func, u32 fbpao,
+ struct nvkm_device *device, int fbp, int *pltcs)
+{
+ u32 fbpt = nvkm_rd32(device, 0x022438);
+ u32 fbpat = nvkm_rd32(device, 0x02243c);
+ u32 fbpas = fbpat / fbpt;
+ u32 fbpa = fbp * fbpas;
+ u32 size = 0;
+ while (fbpas--) {
+ if (!(fbpao & BIT(fbpa)))
+ size += func->probe_fbpa_amount(device, fbpa);
+ fbpa++;
+ }
+ *pltcs = 1;
+ return size;
+}
+
+static const struct nvkm_ram_func
+gf108_ram = {
+ .upper = 0x0200000000,
+ .probe_fbp = gf100_ram_probe_fbp,
+ .probe_fbp_amount = gf108_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
+gf108_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
+{
+ return gf100_ram_new_(&gf108_ram, fb, pram);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
index fb8a1239743d..f6c00791722c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
@@ -1108,7 +1108,7 @@ gk104_ram_calc_xits(struct gk104_ram *ram, struct nvkm_ram_data *next)
return ret;
}
-static int
+int
gk104_ram_calc(struct nvkm_ram *base, u32 freq)
{
struct gk104_ram *ram = gk104_ram(base);
@@ -1227,7 +1227,7 @@ gk104_ram_prog_0(struct gk104_ram *ram, u32 freq)
nvkm_mask(device, 0x10f444, mask, data);
}
-static int
+int
gk104_ram_prog(struct nvkm_ram *base)
{
struct gk104_ram *ram = gk104_ram(base);
@@ -1247,7 +1247,7 @@ gk104_ram_prog(struct nvkm_ram *base)
return (ram->base.next == &ram->base.xition);
}
-static void
+void
gk104_ram_tidy(struct nvkm_ram *base)
{
struct gk104_ram *ram = gk104_ram(base);
@@ -1509,7 +1509,7 @@ done:
return ret;
}
-static void *
+void *
gk104_ram_dtor(struct nvkm_ram *base)
{
struct gk104_ram *ram = gk104_ram(base);
@@ -1522,31 +1522,14 @@ gk104_ram_dtor(struct nvkm_ram *base)
return ram;
}
-static const struct nvkm_ram_func
-gk104_ram_func = {
- .dtor = gk104_ram_dtor,
- .init = gk104_ram_init,
- .get = gf100_ram_get,
- .put = gf100_ram_put,
- .calc = gk104_ram_calc,
- .prog = gk104_ram_prog,
- .tidy = gk104_ram_tidy,
-};
-
int
-gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
-{
- return gk104_ram_ctor(fb, pram, 0x022554);
-}
-
-int
-gk104_ram_ctor(struct nvkm_fb *fb, struct nvkm_ram **pram, u32 maskaddr)
+gk104_ram_new_(const struct nvkm_ram_func *func, struct nvkm_fb *fb,
+ struct nvkm_ram **pram)
{
struct nvkm_subdev *subdev = &fb->subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_bios *bios = device->bios;
- struct nvkm_gpio *gpio = device->gpio;
- struct dcb_gpio_func func;
+ struct dcb_gpio_func gpio;
struct gk104_ram *ram;
int ret, i;
u8 ramcfg = nvbios_ramcfg_index(subdev);
@@ -1556,7 +1539,7 @@ gk104_ram_ctor(struct nvkm_fb *fb, struct nvkm_ram **pram, u32 maskaddr)
return -ENOMEM;
*pram = &ram->base;
- ret = gf100_ram_ctor(&gk104_ram_func, fb, maskaddr, &ram->base);
+ ret = gf100_ram_ctor(func, fb, &ram->base);
if (ret)
return ret;
@@ -1614,18 +1597,18 @@ gk104_ram_ctor(struct nvkm_fb *fb, struct nvkm_ram **pram, u32 maskaddr)
}
/* lookup memory voltage gpios */
- ret = nvkm_gpio_find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
+ ret = nvkm_gpio_find(device->gpio, 0, 0x18, DCB_GPIO_UNUSED, &gpio);
if (ret == 0) {
- ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
- ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12;
- ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12;
+ ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (gpio.line * 0x04));
+ ram->fuc.r_funcMV[0] = (gpio.log[0] ^ 2) << 12;
+ ram->fuc.r_funcMV[1] = (gpio.log[1] ^ 2) << 12;
}
- ret = nvkm_gpio_find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+ ret = nvkm_gpio_find(device->gpio, 0, 0x2e, DCB_GPIO_UNUSED, &gpio);
if (ret == 0) {
- ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04));
- ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12;
- ram->fuc.r_func2E[1] = (func.log[1] ^ 2) << 12;
+ ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (gpio.line * 0x04));
+ ram->fuc.r_func2E[0] = (gpio.log[0] ^ 2) << 12;
+ ram->fuc.r_func2E[1] = (gpio.log[1] ^ 2) << 12;
}
ram->fuc.r_gpiotrig = ramfuc_reg(0x00d604);
@@ -1717,3 +1700,24 @@ gk104_ram_ctor(struct nvkm_fb *fb, struct nvkm_ram **pram, u32 maskaddr)
ram->fuc.r_0x100750 = ramfuc_reg(0x100750);
return 0;
}
+
+static const struct nvkm_ram_func
+gk104_ram = {
+ .upper = 0x0200000000,
+ .probe_fbp = gf100_ram_probe_fbp,
+ .probe_fbp_amount = gf108_ram_probe_fbp_amount,
+ .probe_fbpa_amount = gf100_ram_probe_fbpa_amount,
+ .dtor = gk104_ram_dtor,
+ .init = gk104_ram_init,
+ .get = gf100_ram_get,
+ .put = gf100_ram_put,
+ .calc = gk104_ram_calc,
+ .prog = gk104_ram_prog,
+ .tidy = gk104_ram_tidy,
+};
+
+int
+gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
+{
+ return gk104_ram_new_(&gk104_ram, fb, pram);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
index ac862d1d77bd..3f0b56347291 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
@@ -23,8 +23,31 @@
*/
#include "ram.h"
+u32
+gm107_ram_probe_fbp(const struct nvkm_ram_func *func,
+ struct nvkm_device *device, int fbp, int *pltcs)
+{
+ u32 fbpao = nvkm_rd32(device, 0x021c14);
+ return func->probe_fbp_amount(func, fbpao, device, fbp, pltcs);
+}
+
+static const struct nvkm_ram_func
+gm107_ram = {
+ .upper = 0x1000000000,
+ .probe_fbp = gm107_ram_probe_fbp,
+ .probe_fbp_amount = gf108_ram_probe_fbp_amount,
+ .probe_fbpa_amount = gf100_ram_probe_fbpa_amount,
+ .dtor = gk104_ram_dtor,
+ .init = gk104_ram_init,
+ .get = gf100_ram_get,
+ .put = gf100_ram_put,
+ .calc = gk104_ram_calc,
+ .prog = gk104_ram_prog,
+ .tidy = gk104_ram_tidy,
+};
+
int
gm107_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
- return gk104_ram_ctor(fb, pram, 0x021c14);
+ return gk104_ram_new_(&gm107_ram, fb, pram);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm200.c
new file mode 100644
index 000000000000..fd8facf90476
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm200.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017 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 <bskeggs@redhat.com>
+ */
+#include "ram.h"
+
+u32
+gm200_ram_probe_fbp_amount(const struct nvkm_ram_func *func, u32 fbpao,
+ struct nvkm_device *device, int fbp, int *pltcs)
+{
+ u32 ltcs = nvkm_rd32(device, 0x022450);
+ u32 fbpas = nvkm_rd32(device, 0x022458);
+ u32 fbpa = fbp * fbpas;
+ u32 size = 0;
+ if (!(nvkm_rd32(device, 0x021d38) & BIT(fbp))) {
+ u32 ltco = nvkm_rd32(device, 0x021d70 + (fbp * 4));
+ u32 ltcm = ~ltco & ((1 << ltcs) - 1);
+
+ while (fbpas--) {
+ if (!(fbpao & (1 << fbpa)))
+ size += func->probe_fbpa_amount(device, fbpa);
+ fbpa++;
+ }
+
+ *pltcs = hweight32(ltcm);
+ }
+ return size;
+}
+
+static const struct nvkm_ram_func
+gm200_ram = {
+ .upper = 0x1000000000,
+ .probe_fbp = gm107_ram_probe_fbp,
+ .probe_fbp_amount = gm200_ram_probe_fbp_amount,
+ .probe_fbpa_amount = gf100_ram_probe_fbpa_amount,
+ .dtor = gk104_ram_dtor,
+ .init = gk104_ram_init,
+ .get = gf100_ram_get,
+ .put = gf100_ram_put,
+ .calc = gk104_ram_calc,
+ .prog = gk104_ram_prog,
+ .tidy = gk104_ram_tidy,
+};
+
+int
+gm200_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
+{
+ return gk104_ram_new_(&gm200_ram, fb, pram);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c
index 405faabe8dcd..cac70047ad5a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c
@@ -76,8 +76,18 @@ gp100_ram_init(struct nvkm_ram *ram)
return 0;
}
+static u32
+gp100_ram_probe_fbpa(struct nvkm_device *device, int fbpa)
+{
+ return nvkm_rd32(device, 0x90020c + (fbpa * 0x4000));
+}
+
static const struct nvkm_ram_func
-gp100_ram_func = {
+gp100_ram = {
+ .upper = 0x1000000000,
+ .probe_fbp = gm107_ram_probe_fbp,
+ .probe_fbp_amount = gm200_ram_probe_fbp_amount,
+ .probe_fbpa_amount = gp100_ram_probe_fbpa,
.init = gp100_ram_init,
.get = gf100_ram_get,
.put = gf100_ram_put,
@@ -87,60 +97,10 @@ int
gp100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_ram *ram;
- struct nvkm_subdev *subdev = &fb->subdev;
- struct nvkm_device *device = subdev->device;
- enum nvkm_ram_type type = nvkm_fb_bios_memtype(device->bios);
- const u32 rsvd_head = ( 256 * 1024); /* vga memory */
- const u32 rsvd_tail = (1024 * 1024); /* vbios etc */
- u32 fbpa_num = nvkm_rd32(device, 0x02243c), fbpa;
- u32 fbio_opt = nvkm_rd32(device, 0x021c14);
- u64 part, size = 0, comm = ~0ULL;
- bool mixed = false;
- int ret;
-
- nvkm_debug(subdev, "02243c: %08x\n", fbpa_num);
- nvkm_debug(subdev, "021c14: %08x\n", fbio_opt);
- for (fbpa = 0; fbpa < fbpa_num; fbpa++) {
- if (!(fbio_opt & (1 << fbpa))) {
- part = nvkm_rd32(device, 0x90020c + (fbpa * 0x4000));
- nvkm_debug(subdev, "fbpa %02x: %lld MiB\n", fbpa, part);
- part = part << 20;
- if (part != comm) {
- if (comm != ~0ULL)
- mixed = true;
- comm = min(comm, part);
- }
- size = size + part;
- }
- }
-
- ret = nvkm_ram_new_(&gp100_ram_func, fb, type, size, 0, &ram);
- *pram = ram;
- if (ret)
- return ret;
- nvkm_mm_fini(&ram->vram);
+ if (!(ram = *pram = kzalloc(sizeof(*ram), GFP_KERNEL)))
+ return -ENOMEM;
- if (mixed) {
- ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT,
- ((comm * fbpa_num) - rsvd_head) >>
- NVKM_RAM_MM_SHIFT, 1);
- if (ret)
- return ret;
+ return gf100_ram_ctor(&gp100_ram, fb, ram);
- ret = nvkm_mm_init(&ram->vram, (0x1000000000ULL + comm) >>
- NVKM_RAM_MM_SHIFT,
- (size - (comm * fbpa_num) - rsvd_tail) >>
- NVKM_RAM_MM_SHIFT, 1);
- if (ret)
- return ret;
- } else {
- ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT,
- (size - rsvd_head - rsvd_tail) >>
- NVKM_RAM_MM_SHIFT, 1);
- if (ret)
- return ret;
- }
-
- return 0;
}