Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,67 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/subdev/fb/base.o
nvkm-y += nvkm/subdev/fb/nv04.o
nvkm-y += nvkm/subdev/fb/nv10.o
nvkm-y += nvkm/subdev/fb/nv1a.o
nvkm-y += nvkm/subdev/fb/nv20.o
nvkm-y += nvkm/subdev/fb/nv25.o
nvkm-y += nvkm/subdev/fb/nv30.o
nvkm-y += nvkm/subdev/fb/nv35.o
nvkm-y += nvkm/subdev/fb/nv36.o
nvkm-y += nvkm/subdev/fb/nv40.o
nvkm-y += nvkm/subdev/fb/nv41.o
nvkm-y += nvkm/subdev/fb/nv44.o
nvkm-y += nvkm/subdev/fb/nv46.o
nvkm-y += nvkm/subdev/fb/nv47.o
nvkm-y += nvkm/subdev/fb/nv49.o
nvkm-y += nvkm/subdev/fb/nv4e.o
nvkm-y += nvkm/subdev/fb/nv50.o
nvkm-y += nvkm/subdev/fb/g84.o
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/gk110.o
nvkm-y += nvkm/subdev/fb/gk20a.o
nvkm-y += nvkm/subdev/fb/gm107.o
nvkm-y += nvkm/subdev/fb/gm200.o
nvkm-y += nvkm/subdev/fb/gm20b.o
nvkm-y += nvkm/subdev/fb/gp100.o
nvkm-y += nvkm/subdev/fb/gp102.o
nvkm-y += nvkm/subdev/fb/gp10b.o
nvkm-y += nvkm/subdev/fb/gv100.o
nvkm-y += nvkm/subdev/fb/tu102.o
nvkm-y += nvkm/subdev/fb/ga100.o
nvkm-y += nvkm/subdev/fb/ga102.o
nvkm-y += nvkm/subdev/fb/gh100.o
nvkm-y += nvkm/subdev/fb/gb100.o
nvkm-y += nvkm/subdev/fb/gb202.o
nvkm-y += nvkm/subdev/fb/r535.o
nvkm-y += nvkm/subdev/fb/ram.o
nvkm-y += nvkm/subdev/fb/ramnv04.o
nvkm-y += nvkm/subdev/fb/ramnv10.o
nvkm-y += nvkm/subdev/fb/ramnv1a.o
nvkm-y += nvkm/subdev/fb/ramnv20.o
nvkm-y += nvkm/subdev/fb/ramnv40.o
nvkm-y += nvkm/subdev/fb/ramnv41.o
nvkm-y += nvkm/subdev/fb/ramnv44.o
nvkm-y += nvkm/subdev/fb/ramnv49.o
nvkm-y += nvkm/subdev/fb/ramnv4e.o
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/ramgp102.o
nvkm-y += nvkm/subdev/fb/sddr2.o
nvkm-y += nvkm/subdev/fb/sddr3.o
nvkm-y += nvkm/subdev/fb/gddr3.o
nvkm-y += nvkm/subdev/fb/gddr5.o
@@ -0,0 +1,302 @@
/*
* Copyright 2012 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"
#include "ram.h"
#include <core/memory.h>
#include <core/option.h>
#include <subdev/bios.h>
#include <subdev/bios/M0203.h>
#include <engine/gr.h>
#include <engine/mpeg.h>
void
nvkm_fb_tile_fini(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile)
{
fb->func->tile.fini(fb, region, tile);
}
void
nvkm_fb_tile_init(struct nvkm_fb *fb, int region, u32 addr, u32 size,
u32 pitch, u32 flags, struct nvkm_fb_tile *tile)
{
fb->func->tile.init(fb, region, addr, size, pitch, flags, tile);
}
void
nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile)
{
struct nvkm_device *device = fb->subdev.device;
if (fb->func->tile.prog) {
fb->func->tile.prog(fb, region, tile);
if (device->gr)
nvkm_engine_tile(&device->gr->engine, region);
if (device->mpeg)
nvkm_engine_tile(device->mpeg, region);
}
}
static void
nvkm_fb_sysmem_flush_page_init(struct nvkm_device *device)
{
struct nvkm_fb *fb = device->fb;
if (fb->func->sysmem.flush_page_init)
fb->func->sysmem.flush_page_init(fb);
}
int
nvkm_fb_bios_memtype(struct nvkm_bios *bios)
{
struct nvkm_subdev *subdev = &bios->subdev;
struct nvkm_device *device = subdev->device;
const u8 ramcfg = (nvkm_rd32(device, 0x101000) & 0x0000003c) >> 2;
struct nvbios_M0203E M0203E;
u8 ver, hdr;
if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) {
switch (M0203E.type) {
case M0203E_TYPE_DDR2 : return NVKM_RAM_TYPE_DDR2;
case M0203E_TYPE_DDR3 : return NVKM_RAM_TYPE_DDR3;
case M0203E_TYPE_GDDR3 : return NVKM_RAM_TYPE_GDDR3;
case M0203E_TYPE_GDDR5 : return NVKM_RAM_TYPE_GDDR5;
case M0203E_TYPE_GDDR5X: return NVKM_RAM_TYPE_GDDR5X;
case M0203E_TYPE_GDDR6 : return NVKM_RAM_TYPE_GDDR6;
case M0203E_TYPE_HBM2 : return NVKM_RAM_TYPE_HBM2;
default:
nvkm_warn(subdev, "M0203E type %02x\n", M0203E.type);
return NVKM_RAM_TYPE_UNKNOWN;
}
}
nvkm_warn(subdev, "M0203E not matched!\n");
return NVKM_RAM_TYPE_UNKNOWN;
}
static void
nvkm_fb_intr(struct nvkm_subdev *subdev)
{
struct nvkm_fb *fb = nvkm_fb(subdev);
if (fb->func->intr)
fb->func->intr(fb);
}
static int
nvkm_fb_oneinit(struct nvkm_subdev *subdev)
{
struct nvkm_fb *fb = nvkm_fb(subdev);
u32 tags = 0;
if (fb->func->ram_new) {
int ret = fb->func->ram_new(fb, &fb->ram);
if (ret) {
nvkm_error(subdev, "vram setup failed, %d\n", ret);
return ret;
}
}
if (fb->func->oneinit) {
int ret = fb->func->oneinit(fb);
if (ret)
return ret;
}
/* Initialise compression tag allocator.
*
* LTC oneinit() will override this on Fermi and newer.
*/
if (fb->func->tags) {
tags = fb->func->tags(fb);
nvkm_debug(subdev, "%d comptags\n", tags);
}
return nvkm_mm_init(&fb->tags.mm, 0, 0, tags, 1);
}
int
nvkm_fb_mem_unlock(struct nvkm_fb *fb)
{
struct nvkm_subdev *subdev = &fb->subdev;
int ret;
if (!fb->func->vpr.scrub_required)
return 0;
ret = nvkm_subdev_oneinit(subdev);
if (ret)
return ret;
if (!fb->func->vpr.scrub_required(fb)) {
nvkm_debug(subdev, "VPR not locked\n");
return 0;
}
nvkm_debug(subdev, "VPR locked, running scrubber binary\n");
if (!fb->vpr_scrubber.fw.img) {
nvkm_warn(subdev, "VPR locked, but no scrubber binary!\n");
return 0;
}
ret = fb->func->vpr.scrub(fb);
if (ret) {
nvkm_error(subdev, "VPR scrubber binary failed\n");
return ret;
}
if (fb->func->vpr.scrub_required(fb)) {
nvkm_error(subdev, "VPR still locked after scrub!\n");
return -EIO;
}
nvkm_debug(subdev, "VPR scrubber binary successful\n");
return 0;
}
u64
nvkm_fb_vidmem_size(struct nvkm_device *device)
{
struct nvkm_fb *fb = device->fb;
if (fb && fb->func->vidmem.size)
return fb->func->vidmem.size(fb);
WARN_ON(1);
return 0;
}
static int
nvkm_fb_init(struct nvkm_subdev *subdev)
{
struct nvkm_fb *fb = nvkm_fb(subdev);
int ret, i;
if (fb->ram) {
ret = nvkm_ram_init(fb->ram);
if (ret)
return ret;
}
for (i = 0; i < fb->tile.regions; i++)
fb->func->tile.prog(fb, i, &fb->tile.region[i]);
nvkm_fb_sysmem_flush_page_init(subdev->device);
if (fb->func->init)
fb->func->init(fb);
if (fb->func->init_remapper)
fb->func->init_remapper(fb);
if (fb->func->init_page) {
ret = fb->func->init_page(fb);
if (WARN_ON(ret))
return ret;
}
if (fb->func->init_unkn)
fb->func->init_unkn(fb);
return 0;
}
static int
nvkm_fb_preinit(struct nvkm_subdev *subdev)
{
nvkm_fb_sysmem_flush_page_init(subdev->device);
return 0;
}
static void *
nvkm_fb_dtor(struct nvkm_subdev *subdev)
{
struct nvkm_fb *fb = nvkm_fb(subdev);
int i;
nvkm_memory_unref(&fb->mmu_wr);
nvkm_memory_unref(&fb->mmu_rd);
for (i = 0; i < fb->tile.regions; i++)
fb->func->tile.fini(fb, i, &fb->tile.region[i]);
nvkm_mm_fini(&fb->tags.mm);
mutex_destroy(&fb->tags.mutex);
nvkm_ram_del(&fb->ram);
nvkm_falcon_fw_dtor(&fb->vpr_scrubber);
if (fb->sysmem.flush_page) {
dma_unmap_page(subdev->device->dev, fb->sysmem.flush_page_addr,
PAGE_SIZE, DMA_BIDIRECTIONAL);
__free_page(fb->sysmem.flush_page);
}
if (fb->func->dtor)
return fb->func->dtor(fb);
return fb;
}
static const struct nvkm_subdev_func
nvkm_fb = {
.dtor = nvkm_fb_dtor,
.preinit = nvkm_fb_preinit,
.oneinit = nvkm_fb_oneinit,
.init = nvkm_fb_init,
.intr = nvkm_fb_intr,
};
int
nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_fb *fb)
{
nvkm_subdev_ctor(&nvkm_fb, device, type, inst, &fb->subdev);
fb->func = func;
fb->tile.regions = fb->func->tile.regions;
fb->page = nvkm_longopt(device->cfgopt, "NvFbBigPage", fb->func->default_bigpage);
mutex_init(&fb->tags.mutex);
if (func->sysmem.flush_page_init) {
fb->sysmem.flush_page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
if (!fb->sysmem.flush_page)
return -ENOMEM;
fb->sysmem.flush_page_addr = dma_map_page(device->dev, fb->sysmem.flush_page,
0, PAGE_SIZE, DMA_BIDIRECTIONAL);
if (dma_mapping_error(device->dev, fb->sysmem.flush_page_addr))
return -EFAULT;
}
return 0;
}
int
nvkm_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
if (!(*pfb = kzalloc_obj(**pfb)))
return -ENOMEM;
return nvkm_fb_ctor(func, device, type, inst, *pfb);
}
@@ -0,0 +1,38 @@
/*
* Copyright 2012 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 "nv50.h"
#include "ram.h"
static const struct nv50_fb_func
g84_fb = {
.ram_new = nv50_ram_new,
.tags = nv20_fb_tags,
.trap = 0x001d07ff,
};
int
g84_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nv50_fb_new_(&g84_fb, device, type, inst, pfb);
}
@@ -0,0 +1,47 @@
/*
* Copyright 2021 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.
*/
#include "gf100.h"
#include "ram.h"
#include <subdev/gsp.h>
static const struct nvkm_fb_func
ga100_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gm200_fb_init,
.init_page = gv100_fb_init_page,
.init_unkn = gp100_fb_init_unkn,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.vidmem.size = gp102_fb_vidmem_size,
.ram_new = gp102_ram_new,
.default_bigpage = 16,
};
int
ga100_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
if (nvkm_gsp_rm(device->gsp))
return r535_fb_new(&ga100_fb, device, type, inst, pfb);
return gf100_fb_new_(&ga100_fb, device, type, inst, pfb);
}
@@ -0,0 +1,73 @@
/*
* Copyright 2021 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.
*/
#include "gf100.h"
#include "ram.h"
#include <subdev/gsp.h>
#include <engine/nvdec.h>
u64
ga102_fb_vidmem_size(struct nvkm_fb *fb)
{
return (u64)nvkm_rd32(fb->subdev.device, 0x1183a4) << 20;
}
static int
ga102_fb_oneinit(struct nvkm_fb *fb)
{
struct nvkm_subdev *subdev = &fb->subdev;
nvkm_falcon_fw_ctor_hs_v2(&ga102_flcn_fw, "mem-unlock", subdev, "nvdec/scrubber",
0, &subdev->device->nvdec[0]->falcon, &fb->vpr_scrubber);
return gf100_fb_oneinit(fb);
}
static const struct nvkm_fb_func
ga102_fb = {
.dtor = gf100_fb_dtor,
.oneinit = ga102_fb_oneinit,
.init = gm200_fb_init,
.init_page = gv100_fb_init_page,
.init_unkn = gp100_fb_init_unkn,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.vidmem.size = ga102_fb_vidmem_size,
.ram_new = gp102_ram_new,
.default_bigpage = 16,
.vpr.scrub_required = tu102_fb_vpr_scrub_required,
.vpr.scrub = gp102_fb_vpr_scrub,
};
int
ga102_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
if (nvkm_gsp_rm(device->gsp))
return r535_fb_new(&ga102_fb, device, type, inst, pfb);
return gf100_fb_new_(&ga102_fb, device, type, inst, pfb);
}
MODULE_FIRMWARE("nvidia/ga102/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/ga103/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/ga104/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/ga106/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/ga107/nvdec/scrubber.bin");
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
*/
#include "priv.h"
#include <nvhw/drf.h>
#include <nvhw/ref/gb100/dev_hshub_base.h>
static void
gb100_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
{
const u32 addr_hi = upper_32_bits(fb->sysmem.flush_page_addr);
const u32 addr_lo = lower_32_bits(fb->sysmem.flush_page_addr);
const u32 hshub = DRF_LO(NV_PFB_HSHUB0);
struct nvkm_device *device = fb->subdev.device;
// Ensure that the address is within hardware limits
WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(52));
nvkm_wr32(device, hshub + NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI, addr_hi);
nvkm_wr32(device, hshub + NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO, addr_lo);
nvkm_wr32(device, hshub + NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI, addr_hi);
nvkm_wr32(device, hshub + NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO, addr_lo);
}
static const struct nvkm_fb_func
gb100_fb = {
.sysmem.flush_page_init = gb100_fb_sysmem_flush_page_init,
.vidmem.size = ga102_fb_vidmem_size,
};
int
gb100_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return r535_fb_new(&gb100_fb, device, type, inst, pfb);
}
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
*/
#include "priv.h"
#include <nvhw/drf.h>
#include <nvhw/ref/gb10b/dev_fbhub.h>
static void
gb202_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
{
struct nvkm_device *device = fb->subdev.device;
const u64 addr = fb->sysmem.flush_page_addr;
// Ensure that the address is within hardware limits
WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(52));
nvkm_wr32(device, NV_PFB_FBHUB0_PCIE_FLUSH_SYSMEM_ADDR_HI, upper_32_bits(addr));
nvkm_wr32(device, NV_PFB_FBHUB0_PCIE_FLUSH_SYSMEM_ADDR_LO, lower_32_bits(addr));
}
static const struct nvkm_fb_func
gb202_fb = {
.sysmem.flush_page_init = gb202_fb_sysmem_flush_page_init,
.vidmem.size = ga102_fb_vidmem_size,
};
int
gb202_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return r535_fb_new(&gb202_fb, device, type, inst, pfb);
}
@@ -0,0 +1,119 @@
/*
* 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 <bskeggs@redhat.com>
* Roy Spliet <rspliet@eclipso.eu>
*/
#include "ram.h"
struct ramxlat {
int id;
u8 enc;
};
static inline int
ramxlat(const struct ramxlat *xlat, int id)
{
while (xlat->id >= 0) {
if (xlat->id == id)
return xlat->enc;
xlat++;
}
return -EINVAL;
}
static const struct ramxlat
ramgddr3_cl_lo[] = {
{ 5, 5 }, { 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 }, { 12, 8 },
/* the below are mentioned in some, but not all, gddr3 docs */
{ 13, 9 }, { 14, 6 },
/* XXX: Per Samsung docs, are these used? They overlap with Qimonda */
/* { 4, 4 }, { 5, 5 }, { 6, 6 }, { 12, 8 }, { 13, 9 }, { 14, 10 },
* { 15, 11 }, */
{ -1 }
};
static const struct ramxlat
ramgddr3_cl_hi[] = {
{ 10, 2 }, { 11, 3 }, { 12, 4 }, { 13, 5 }, { 14, 6 }, { 15, 7 },
{ 16, 0 }, { 17, 1 },
{ -1 }
};
static const struct ramxlat
ramgddr3_wr_lo[] = {
{ 5, 2 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 7 },
{ 11, 0 }, { 13 , 1 },
/* the below are mentioned in some, but not all, gddr3 docs */
{ 4, 0 }, { 6, 3 }, { 12, 1 },
{ -1 }
};
int
nvkm_gddr3_calc(struct nvkm_ram *ram)
{
int CL, WR, CWL, DLL = 0, ODT = 0, RON, hi;
switch (ram->next->bios.timing_ver) {
case 0x10:
CWL = ram->next->bios.timing_10_CWL;
CL = ram->next->bios.timing_10_CL;
WR = ram->next->bios.timing_10_WR;
DLL = !ram->next->bios.ramcfg_DLLoff;
ODT = ram->next->bios.timing_10_ODT;
RON = ram->next->bios.ramcfg_RON;
break;
case 0x20:
CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
/* XXX: Get these values from the VBIOS instead */
DLL = !(ram->mr[1] & 0x1);
RON = !((ram->mr[1] & 0x300) >> 8);
break;
default:
return -ENOSYS;
}
if (ram->next->bios.timing_ver == 0x20 ||
ram->next->bios.ramcfg_timing == 0xff) {
ODT = (ram->mr[1] & 0xc) >> 2;
}
hi = ram->mr[2] & 0x1;
CL = ramxlat(hi ? ramgddr3_cl_hi : ramgddr3_cl_lo, CL);
WR = ramxlat(ramgddr3_wr_lo, WR);
if (CL < 0 || CWL < 1 || CWL > 7 || WR < 0)
return -EINVAL;
ram->mr[0] &= ~0xf74;
ram->mr[0] |= (CWL & 0x07) << 9;
ram->mr[0] |= (CL & 0x07) << 4;
ram->mr[0] |= (CL & 0x08) >> 1;
ram->mr[1] &= ~0x3fc;
ram->mr[1] |= (ODT & 0x03) << 2;
ram->mr[1] |= (RON & 0x03) << 8;
ram->mr[1] |= (WR & 0x03) << 4;
ram->mr[1] |= (WR & 0x04) << 5;
ram->mr[1] |= !DLL << 6;
return 0;
}
@@ -0,0 +1,121 @@
/*
* 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 <bskeggs@redhat.com>
*/
#include "ram.h"
/* binary driver only executes this path if the condition (a) is true
* for any configuration (combination of rammap+ramcfg+timing) that
* can be reached on a given card. for now, we will execute the branch
* unconditionally in the hope that a "false everywhere" in the bios
* tables doesn't actually mean "don't touch this".
*/
#define NOTE00(a) 1
int
nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts)
{
int pd, lf, xd, vh, vr, vo, l3;
int WL, CL, WR, at[2], dt, ds;
int rq = ram->freq < 1000000; /* XXX */
xd = !ram->next->bios.ramcfg_DLLoff;
switch (ram->next->bios.ramcfg_ver) {
case 0x11:
pd = ram->next->bios.ramcfg_11_01_80;
lf = ram->next->bios.ramcfg_11_01_40;
vh = ram->next->bios.ramcfg_11_02_10;
vr = ram->next->bios.ramcfg_11_02_04;
vo = ram->next->bios.ramcfg_11_06;
l3 = !ram->next->bios.ramcfg_11_07_02;
break;
default:
return -ENOSYS;
}
switch (ram->next->bios.timing_ver) {
case 0x20:
WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
CL = (ram->next->bios.timing[1] & 0x0000001f);
WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
at[0] = ram->next->bios.timing_20_2e_c0;
at[1] = ram->next->bios.timing_20_2e_30;
dt = ram->next->bios.timing_20_2e_03;
ds = ram->next->bios.timing_20_2f_03;
break;
default:
return -ENOSYS;
}
if (WL < 1 || WL > 7 || CL < 5 || CL > 36 || WR < 4 || WR > 35)
return -EINVAL;
CL -= 5;
WR -= 4;
ram->mr[0] &= ~0xf7f;
ram->mr[0] |= (WR & 0x0f) << 8;
ram->mr[0] |= (CL & 0x0f) << 3;
ram->mr[0] |= (WL & 0x07) << 0;
ram->mr[1] &= ~0x0bf;
ram->mr[1] |= (xd & 0x01) << 7;
ram->mr[1] |= (at[0] & 0x03) << 4;
ram->mr[1] |= (dt & 0x03) << 2;
ram->mr[1] |= (ds & 0x03) << 0;
/* this seems wrong, alternate field used for the broadcast
* on nuts vs non-nuts configs.. meh, it matches for now.
*/
ram->mr1_nuts = ram->mr[1];
if (nuts) {
ram->mr[1] &= ~0x030;
ram->mr[1] |= (at[1] & 0x03) << 4;
}
ram->mr[3] &= ~0x020;
ram->mr[3] |= (rq & 0x01) << 5;
ram->mr[5] &= ~0x004;
ram->mr[5] |= (l3 << 2);
if (!vo)
vo = (ram->mr[6] & 0xff0) >> 4;
if (ram->mr[6] & 0x001)
pd = 1; /* binary driver does this.. bug? */
ram->mr[6] &= ~0xff1;
ram->mr[6] |= (vo & 0xff) << 4;
ram->mr[6] |= (pd & 0x01) << 0;
if (NOTE00(vr)) {
ram->mr[7] &= ~0x300;
ram->mr[7] |= (vr & 0x03) << 8;
}
ram->mr[7] &= ~0x088;
ram->mr[7] |= (vh & 0x01) << 7;
ram->mr[7] |= (lf & 0x01) << 3;
ram->mr[8] &= ~0x003;
ram->mr[8] |= (WR & 0x10) >> 3;
ram->mr[8] |= (CL & 0x10) >> 4;
return 0;
}
@@ -0,0 +1,139 @@
/*
* Copyright 2012 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 "gf100.h"
#include "ram.h"
#include <core/memory.h>
#include <core/option.h>
#include <subdev/therm.h>
void
gf100_fb_intr(struct nvkm_fb *base)
{
struct gf100_fb *fb = gf100_fb(base);
struct nvkm_subdev *subdev = &fb->base.subdev;
struct nvkm_device *device = subdev->device;
u32 intr = nvkm_rd32(device, 0x000100);
if (intr & 0x08000000)
nvkm_debug(subdev, "PFFB intr\n");
if (intr & 0x00002000)
nvkm_debug(subdev, "PBFB intr\n");
}
int
gf100_fb_oneinit(struct nvkm_fb *base)
{
struct gf100_fb *fb = gf100_fb(base);
struct nvkm_device *device = fb->base.subdev.device;
int ret, size = 1 << (fb->base.page ? fb->base.page : 17);
size = nvkm_longopt(device->cfgopt, "MmuDebugBufferSize", size);
size = max(size, 0x1000);
ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000,
true, &fb->base.mmu_rd);
if (ret)
return ret;
ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000,
true, &fb->base.mmu_wr);
if (ret)
return ret;
return 0;
}
int
gf100_fb_init_page(struct nvkm_fb *fb)
{
struct nvkm_device *device = fb->subdev.device;
switch (fb->page) {
case 16: nvkm_mask(device, 0x100c80, 0x00000001, 0x00000001); break;
case 17: nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); break;
default:
return -EINVAL;
}
return 0;
}
void
gf100_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
{
// Ensure that the address can actually fit in the register
WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(40));
nvkm_wr32(fb->subdev.device, 0x100c10, fb->sysmem.flush_page_addr >> 8);
}
void
gf100_fb_init(struct nvkm_fb *base)
{
struct gf100_fb *fb = gf100_fb(base);
struct nvkm_device *device = fb->base.subdev.device;
if (base->func->clkgate_pack) {
nvkm_therm_clkgate_init(device->therm,
base->func->clkgate_pack);
}
}
void *
gf100_fb_dtor(struct nvkm_fb *base)
{
struct gf100_fb *fb = gf100_fb(base);
return fb;
}
int
gf100_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
struct gf100_fb *fb;
if (!(fb = kzalloc_obj(*fb)))
return -ENOMEM;
nvkm_fb_ctor(func, device, type, inst, &fb->base);
*pfb = &fb->base;
return 0;
}
static const struct nvkm_fb_func
gf100_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gf100_fb_init,
.init_page = gf100_fb_init_page,
.intr = gf100_fb_intr,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gf100_ram_new,
.default_bigpage = 17,
};
int
gf100_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gf100_fb, device, type, inst, pfb);
}
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_RAM_NVC0_H__
#define __NVKM_RAM_NVC0_H__
#define gf100_fb(p) container_of((p), struct gf100_fb, base)
#include "priv.h"
struct gf100_fb {
struct nvkm_fb base;
};
int gf100_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_fb **);
void *gf100_fb_dtor(struct nvkm_fb *);
void gf100_fb_init(struct nvkm_fb *);
void gf100_fb_intr(struct nvkm_fb *);
void gm200_fb_init(struct nvkm_fb *base);
#endif
@@ -0,0 +1,43 @@
/*
* 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,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gf108_ram_new,
.default_bigpage = 17,
};
int
gf108_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gf108_fb, device, type, inst, pfb);
}
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
*/
#include "priv.h"
#include <nvhw/drf.h>
#include <nvhw/ref/gh100/dev_fb.h>
static void
gh100_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
{
const u64 addr = fb->sysmem.flush_page_addr >> NV_PFB_NISO_FLUSH_SYSMEM_ADDR_SHIFT;
struct nvkm_device *device = fb->subdev.device;
// Ensure that the address is within hardware limits
WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(52));
nvkm_wr32(device, NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI, upper_32_bits(addr));
nvkm_wr32(device, NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_LO, lower_32_bits(addr));
}
static const struct nvkm_fb_func
gh100_fb = {
.sysmem.flush_page_init = gh100_fb_sysmem_flush_page_init,
.vidmem.size = ga102_fb_vidmem_size,
};
int
gh100_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return r535_fb_new(&gh100_fb, device, type, inst, pfb);
}
@@ -0,0 +1,90 @@
/*
* Copyright 2012 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
* Lyude Paul
*/
#include "gk104.h"
#include "gf100.h"
#include "ram.h"
/*
*******************************************************************************
* PGRAPH registers for clockgating
*******************************************************************************
*/
const struct nvkm_therm_clkgate_init
gk104_fb_clkgate_blcg_init_unk_0[] = {
{ 0x100d10, 1, 0x0000c244 },
{ 0x100d30, 1, 0x0000c242 },
{ 0x100d3c, 1, 0x00000242 },
{ 0x100d48, 1, 0x00000242 },
{ 0x100d1c, 1, 0x00000042 },
{}
};
const struct nvkm_therm_clkgate_init
gk104_fb_clkgate_blcg_init_vm_0[] = {
{ 0x100c98, 1, 0x00000242 },
{}
};
const struct nvkm_therm_clkgate_init
gk104_fb_clkgate_blcg_init_main_0[] = {
{ 0x10f000, 1, 0x00000042 },
{ 0x17e030, 1, 0x00000044 },
{ 0x17e040, 1, 0x00000044 },
{}
};
const struct nvkm_therm_clkgate_init
gk104_fb_clkgate_blcg_init_bcast_0[] = {
{ 0x17ea60, 4, 0x00000044 },
{}
};
static const struct nvkm_therm_clkgate_pack
gk104_fb_clkgate_pack[] = {
{ gk104_fb_clkgate_blcg_init_unk_0 },
{ gk104_fb_clkgate_blcg_init_vm_0 },
{ gk104_fb_clkgate_blcg_init_main_0 },
{ gk104_fb_clkgate_blcg_init_bcast_0 },
{}
};
static const struct nvkm_fb_func
gk104_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gf100_fb_init,
.init_page = gf100_fb_init_page,
.intr = gf100_fb_intr,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gk104_ram_new,
.default_bigpage = 17,
.clkgate_pack = gk104_fb_clkgate_pack,
};
int
gk104_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gk104_fb, device, type, inst, pfb);
}
@@ -0,0 +1,35 @@
/*
* Copyright 2018 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: Lyude Paul
*/
#ifndef __GK104_FB_H__
#define __GK104_FB_H__
#include <subdev/therm.h>
extern const struct nvkm_therm_clkgate_init gk104_fb_clkgate_blcg_init_unk_0[];
extern const struct nvkm_therm_clkgate_init gk104_fb_clkgate_blcg_init_vm_0[];
extern const struct nvkm_therm_clkgate_init gk104_fb_clkgate_blcg_init_main_0[];
extern const struct nvkm_therm_clkgate_init gk104_fb_clkgate_blcg_init_bcast_0[];
#endif
@@ -0,0 +1,72 @@
/*
* 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: Lyude Paul
*/
#include "gf100.h"
#include "gk104.h"
#include "ram.h"
#include <subdev/therm.h>
#include <subdev/fb.h>
/*
*******************************************************************************
* PGRAPH registers for clockgating
*******************************************************************************
*/
static const struct nvkm_therm_clkgate_init
gk110_fb_clkgate_blcg_init_unk_0[] = {
{ 0x100d10, 1, 0x0000c242 },
{ 0x100d30, 1, 0x0000c242 },
{ 0x100d3c, 1, 0x00000242 },
{ 0x100d48, 1, 0x0000c242 },
{ 0x100d1c, 1, 0x00000042 },
{}
};
static const struct nvkm_therm_clkgate_pack
gk110_fb_clkgate_pack[] = {
{ gk110_fb_clkgate_blcg_init_unk_0 },
{ gk104_fb_clkgate_blcg_init_vm_0 },
{ gk104_fb_clkgate_blcg_init_main_0 },
{ gk104_fb_clkgate_blcg_init_bcast_0 },
{}
};
static const struct nvkm_fb_func
gk110_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gf100_fb_init,
.init_page = gf100_fb_init_page,
.intr = gf100_fb_intr,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gk104_ram_new,
.default_bigpage = 17,
.clkgate_pack = gk110_fb_clkgate_pack,
};
int
gk110_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gk110_fb, device, type, inst, pfb);
}
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
*
* 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "priv.h"
#include "gf100.h"
/* GK20A's FB is similar to GF100's, but without the ability to allocate VRAM */
static const struct nvkm_fb_func
gk20a_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gf100_fb_init,
.init_page = gf100_fb_init_page,
.intr = gf100_fb_intr,
.default_bigpage = 17,
};
int
gk20a_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gk20a_fb, device, type, inst, pfb);
}
@@ -0,0 +1,43 @@
/*
* Copyright 2012 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 "gf100.h"
#include "ram.h"
static const struct nvkm_fb_func
gm107_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gf100_fb_init,
.init_page = gf100_fb_init_page,
.intr = gf100_fb_intr,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gm107_ram_new,
.default_bigpage = 17,
};
int
gm107_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gm107_fb, device, type, inst, pfb);
}
@@ -0,0 +1,71 @@
/*
* Copyright 2012 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 "gf100.h"
#include "ram.h"
#include <core/memory.h>
int
gm200_fb_init_page(struct nvkm_fb *fb)
{
struct nvkm_device *device = fb->subdev.device;
switch (fb->page) {
case 16: nvkm_mask(device, 0x100c80, 0x00001801, 0x00001001); break;
case 17: nvkm_mask(device, 0x100c80, 0x00001801, 0x00000000); break;
case 0: nvkm_mask(device, 0x100c80, 0x00001800, 0x00001800); break;
default:
return -EINVAL;
}
return 0;
}
void
gm200_fb_init(struct nvkm_fb *base)
{
struct gf100_fb *fb = gf100_fb(base);
struct nvkm_device *device = fb->base.subdev.device;
nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(fb->base.mmu_wr) >> 8);
nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(fb->base.mmu_rd) >> 8);
nvkm_mask(device, 0x100cc4, 0x00060000,
min(nvkm_memory_size(fb->base.mmu_rd) >> 16, (u64)2) << 17);
}
static const struct nvkm_fb_func
gm200_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gm200_fb_init,
.init_page = gm200_fb_init_page,
.intr = gf100_fb_intr,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gm200_ram_new,
.default_bigpage = 0 /* per-instance. */,
};
int
gm200_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gm200_fb, device, type, inst, pfb);
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
*
* 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "priv.h"
#include "gf100.h"
/* GM20B's FB is similar to GM200, but without the ability to allocate VRAM */
static const struct nvkm_fb_func
gm20b_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gm200_fb_init,
.init_page = gm200_fb_init_page,
.intr = gf100_fb_intr,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.default_bigpage = 0 /* per-instance. */,
};
int
gm20b_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gm20b_fb, device, type, inst, pfb);
}
@@ -0,0 +1,63 @@
/*
* Copyright 2016 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"
#include <core/memory.h>
void
gp100_fb_init_unkn(struct nvkm_fb *base)
{
struct nvkm_device *device = gf100_fb(base)->base.subdev.device;
nvkm_wr32(device, 0x1fac80, nvkm_rd32(device, 0x100c80));
nvkm_wr32(device, 0x1facc4, nvkm_rd32(device, 0x100cc4));
nvkm_wr32(device, 0x1facc8, nvkm_rd32(device, 0x100cc8));
nvkm_wr32(device, 0x1faccc, nvkm_rd32(device, 0x100ccc));
}
void
gp100_fb_init_remapper(struct nvkm_fb *fb)
{
struct nvkm_device *device = fb->subdev.device;
/* Disable address remapper. */
nvkm_mask(device, 0x100c14, 0x00040000, 0x00000000);
}
static const struct nvkm_fb_func
gp100_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gm200_fb_init,
.init_remapper = gp100_fb_init_remapper,
.init_page = gm200_fb_init_page,
.init_unkn = gp100_fb_init_unkn,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.ram_new = gp100_ram_new,
};
int
gp100_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gp100_fb, device, type, inst, pfb);
}
@@ -0,0 +1,92 @@
/*
* Copyright 2016 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"
#include <engine/nvdec.h>
int
gp102_fb_vpr_scrub(struct nvkm_fb *fb)
{
return nvkm_falcon_fw_boot(&fb->vpr_scrubber, &fb->subdev, true, NULL, NULL, 0, 0x00000000);
}
bool
gp102_fb_vpr_scrub_required(struct nvkm_fb *fb)
{
struct nvkm_device *device = fb->subdev.device;
nvkm_wr32(device, 0x100cd0, 0x2);
return (nvkm_rd32(device, 0x100cd0) & 0x00000010) != 0;
}
u64
gp102_fb_vidmem_size(struct nvkm_fb *fb)
{
const u32 data = nvkm_rd32(fb->subdev.device, 0x100ce0);
const u32 lmag = (data & 0x000003f0) >> 4;
const u32 lsca = (data & 0x0000000f);
const u64 size = (u64)lmag << (lsca + 20);
if (data & 0x40000000)
return size / 16 * 15;
return size;
}
int
gp102_fb_oneinit(struct nvkm_fb *fb)
{
struct nvkm_subdev *subdev = &fb->subdev;
nvkm_falcon_fw_ctor_hs(&gm200_flcn_fw, "mem-unlock", subdev, NULL, "nvdec/scrubber",
0, &subdev->device->nvdec[0]->falcon, &fb->vpr_scrubber);
return gf100_fb_oneinit(fb);
}
static const struct nvkm_fb_func
gp102_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gp102_fb_oneinit,
.init = gm200_fb_init,
.init_remapper = gp100_fb_init_remapper,
.init_page = gm200_fb_init_page,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.vidmem.size = gp102_fb_vidmem_size,
.vpr.scrub_required = gp102_fb_vpr_scrub_required,
.vpr.scrub = gp102_fb_vpr_scrub,
.ram_new = gp102_ram_new,
};
int
gp102_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gp102_fb, device, type, inst, pfb);
}
MODULE_FIRMWARE("nvidia/gp102/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp104/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp106/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp107/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp108/nvdec/scrubber.bin");
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
*
* 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "gf100.h"
static const struct nvkm_fb_func
gp10b_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gf100_fb_oneinit,
.init = gm200_fb_init,
.init_page = gm200_fb_init_page,
.intr = gf100_fb_intr,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
};
int
gp10b_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gp10b_fb, device, type, inst, pfb);
}
@@ -0,0 +1,38 @@
/*
* Copyright 2012 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 "nv50.h"
#include "ram.h"
static const struct nv50_fb_func
gt215_fb = {
.ram_new = gt215_ram_new,
.tags = nv20_fb_tags,
.trap = 0x000d0fff,
};
int
gt215_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nv50_fb_new_(&gt215_fb, device, type, inst, pfb);
}
@@ -0,0 +1,52 @@
/*
* Copyright 2018 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.
*/
#include "gf100.h"
#include "ram.h"
int
gv100_fb_init_page(struct nvkm_fb *fb)
{
return (fb->page == 16) ? 0 : -EINVAL;
}
static const struct nvkm_fb_func
gv100_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gp102_fb_oneinit,
.init = gm200_fb_init,
.init_page = gv100_fb_init_page,
.init_unkn = gp100_fb_init_unkn,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.vidmem.size = gp102_fb_vidmem_size,
.vpr.scrub_required = gp102_fb_vpr_scrub_required,
.vpr.scrub = gp102_fb_vpr_scrub,
.ram_new = gp102_ram_new,
.default_bigpage = 16,
};
int
gv100_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return gf100_fb_new_(&gv100_fb, device, type, inst, pfb);
}
MODULE_FIRMWARE("nvidia/gv100/nvdec/scrubber.bin");
@@ -0,0 +1,37 @@
/*
* Copyright 2012 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 "nv50.h"
#include "ram.h"
static const struct nv50_fb_func
mcp77_fb = {
.ram_new = mcp77_ram_new,
.trap = 0x001d07ff,
};
int
mcp77_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nv50_fb_new_(&mcp77_fb, device, type, inst, pfb);
}
@@ -0,0 +1,37 @@
/*
* Copyright 2012 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 "nv50.h"
#include "ram.h"
static const struct nv50_fb_func
mcp89_fb = {
.ram_new = mcp77_ram_new,
.trap = 0x089d1fff,
};
int
mcp89_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nv50_fb_new_(&mcp89_fb, device, type, inst, pfb);
}
@@ -0,0 +1,50 @@
/*
* Copyright 2012 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"
#include "ram.h"
#include "regsnv04.h"
static void
nv04_fb_init(struct nvkm_fb *fb)
{
struct nvkm_device *device = fb->subdev.device;
/* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows
* nvidia reading PFB_CFG_0, then writing back its original value.
* (which was 0x701114 in this case)
*/
nvkm_wr32(device, NV04_PFB_CFG0, 0x1114);
}
static const struct nvkm_fb_func
nv04_fb = {
.init = nv04_fb_init,
.ram_new = nv04_ram_new,
};
int
nv04_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv04_fb, device, type, inst, pfb);
}
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
void
nv10_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nvkm_fb_tile *tile)
{
tile->addr = 0x80000000 | addr;
tile->limit = max(1u, addr + size) - 1;
tile->pitch = pitch;
}
void
nv10_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile)
{
tile->addr = 0;
tile->limit = 0;
tile->pitch = 0;
tile->zcomp = 0;
}
void
nv10_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile)
{
struct nvkm_device *device = fb->subdev.device;
nvkm_wr32(device, 0x100244 + (i * 0x10), tile->limit);
nvkm_wr32(device, 0x100248 + (i * 0x10), tile->pitch);
nvkm_wr32(device, 0x100240 + (i * 0x10), tile->addr);
nvkm_rd32(device, 0x100240 + (i * 0x10));
}
static const struct nvkm_fb_func
nv10_fb = {
.tile.regions = 8,
.tile.init = nv10_fb_tile_init,
.tile.fini = nv10_fb_tile_fini,
.tile.prog = nv10_fb_tile_prog,
.ram_new = nv10_ram_new,
};
int
nv10_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv10_fb, device, type, inst, pfb);
}
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
static const struct nvkm_fb_func
nv1a_fb = {
.tile.regions = 8,
.tile.init = nv10_fb_tile_init,
.tile.fini = nv10_fb_tile_fini,
.tile.prog = nv10_fb_tile_prog,
.ram_new = nv1a_ram_new,
};
int
nv1a_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv1a_fb, device, type, inst, pfb);
}
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
void
nv20_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nvkm_fb_tile *tile)
{
tile->addr = 0x00000001 | addr;
tile->limit = max(1u, addr + size) - 1;
tile->pitch = pitch;
if (flags & 4) {
fb->func->tile.comp(fb, i, size, flags, tile);
tile->addr |= 2;
}
}
static void
nv20_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags,
struct nvkm_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / fb->ram->parts, 0x40);
if (!nvkm_mm_head(&fb->tags.mm, 0, 1, tags, tags, 1, &tile->tag)) {
if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
else tile->zcomp = 0x04000000; /* Z24S8 */
tile->zcomp |= tile->tag->offset;
tile->zcomp |= 0x80000000; /* enable */
#ifdef __BIG_ENDIAN
tile->zcomp |= 0x08000000;
#endif
}
}
void
nv20_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile)
{
tile->addr = 0;
tile->limit = 0;
tile->pitch = 0;
tile->zcomp = 0;
nvkm_mm_free(&fb->tags.mm, &tile->tag);
}
void
nv20_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile)
{
struct nvkm_device *device = fb->subdev.device;
nvkm_wr32(device, 0x100244 + (i * 0x10), tile->limit);
nvkm_wr32(device, 0x100248 + (i * 0x10), tile->pitch);
nvkm_wr32(device, 0x100240 + (i * 0x10), tile->addr);
nvkm_rd32(device, 0x100240 + (i * 0x10));
nvkm_wr32(device, 0x100300 + (i * 0x04), tile->zcomp);
}
u32
nv20_fb_tags(struct nvkm_fb *fb)
{
const u32 tags = nvkm_rd32(fb->subdev.device, 0x100320);
return tags ? tags + 1 : 0;
}
static const struct nvkm_fb_func
nv20_fb = {
.tags = nv20_fb_tags,
.tile.regions = 8,
.tile.init = nv20_fb_tile_init,
.tile.comp = nv20_fb_tile_comp,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv20_fb_tile_prog,
.ram_new = nv20_ram_new,
};
int
nv20_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv20_fb, device, type, inst, pfb);
}
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
static void
nv25_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags,
struct nvkm_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / fb->ram->parts, 0x40);
if (!nvkm_mm_head(&fb->tags.mm, 0, 1, tags, tags, 1, &tile->tag)) {
if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
else tile->zcomp = 0x00200000; /* Z24S8 */
tile->zcomp |= tile->tag->offset;
#ifdef __BIG_ENDIAN
tile->zcomp |= 0x01000000;
#endif
}
}
static const struct nvkm_fb_func
nv25_fb = {
.tags = nv20_fb_tags,
.tile.regions = 8,
.tile.init = nv20_fb_tile_init,
.tile.comp = nv25_fb_tile_comp,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv20_fb_tile_prog,
.ram_new = nv20_ram_new,
};
int
nv25_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv25_fb, device, type, inst, pfb);
}
@@ -0,0 +1,133 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
void
nv30_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nvkm_fb_tile *tile)
{
/* for performance, select alternate bank offset for zeta */
if (!(flags & 4)) {
tile->addr = (0 << 4);
} else {
if (fb->func->tile.comp) /* z compression */
fb->func->tile.comp(fb, i, size, flags, tile);
tile->addr = (1 << 4);
}
tile->addr |= 0x00000001; /* enable */
tile->addr |= addr;
tile->limit = max(1u, addr + size) - 1;
tile->pitch = pitch;
}
static void
nv30_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags,
struct nvkm_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / fb->ram->parts, 0x40);
if (!nvkm_mm_head(&fb->tags.mm, 0, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
else tile->zcomp |= 0x02000000; /* Z24S8 */
tile->zcomp |= ((tile->tag->offset ) >> 6);
tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 12;
#ifdef __BIG_ENDIAN
tile->zcomp |= 0x10000000;
#endif
}
}
static int
calc_bias(struct nvkm_fb *fb, int k, int i, int j)
{
struct nvkm_device *device = fb->subdev.device;
int b = (device->chipset > 0x30 ?
nvkm_rd32(device, 0x122c + 0x10 * k + 0x4 * j) >>
(4 * (i ^ 1)) :
0) & 0xf;
return 2 * (b & 0x8 ? b - 0x10 : b);
}
static int
calc_ref(struct nvkm_fb *fb, int l, int k, int i)
{
int j, x = 0;
for (j = 0; j < 4; j++) {
int m = (l >> (8 * i) & 0xff) + calc_bias(fb, k, i, j);
x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j);
}
return x;
}
void
nv30_fb_init(struct nvkm_fb *fb)
{
struct nvkm_device *device = fb->subdev.device;
int i, j;
/* Init the memory timing regs at 0x10037c/0x1003ac */
if (device->chipset == 0x30 ||
device->chipset == 0x31 ||
device->chipset == 0x35) {
/* Related to ROP count */
int n = (device->chipset == 0x31 ? 2 : 4);
int l = nvkm_rd32(device, 0x1003d0);
for (i = 0; i < n; i++) {
for (j = 0; j < 3; j++)
nvkm_wr32(device, 0x10037c + 0xc * i + 0x4 * j,
calc_ref(fb, l, 0, j));
for (j = 0; j < 2; j++)
nvkm_wr32(device, 0x1003ac + 0x8 * i + 0x4 * j,
calc_ref(fb, l, 1, j));
}
}
}
static const struct nvkm_fb_func
nv30_fb = {
.tags = nv20_fb_tags,
.init = nv30_fb_init,
.tile.regions = 8,
.tile.init = nv30_fb_tile_init,
.tile.comp = nv30_fb_tile_comp,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv20_fb_tile_prog,
.ram_new = nv20_ram_new,
};
int
nv30_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv30_fb, device, type, inst, pfb);
}
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
static void
nv35_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags,
struct nvkm_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / fb->ram->parts, 0x40);
if (!nvkm_mm_head(&fb->tags.mm, 0, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
else tile->zcomp |= 0x08000000; /* Z24S8 */
tile->zcomp |= ((tile->tag->offset ) >> 6);
tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 13;
#ifdef __BIG_ENDIAN
tile->zcomp |= 0x40000000;
#endif
}
}
static const struct nvkm_fb_func
nv35_fb = {
.tags = nv20_fb_tags,
.init = nv30_fb_init,
.tile.regions = 8,
.tile.init = nv30_fb_tile_init,
.tile.comp = nv35_fb_tile_comp,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv20_fb_tile_prog,
.ram_new = nv20_ram_new,
};
int
nv35_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv35_fb, device, type, inst, pfb);
}
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
static void
nv36_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags,
struct nvkm_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / fb->ram->parts, 0x40);
if (!nvkm_mm_head(&fb->tags.mm, 0, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
else tile->zcomp |= 0x20000000; /* Z24S8 */
tile->zcomp |= ((tile->tag->offset ) >> 6);
tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 14;
#ifdef __BIG_ENDIAN
tile->zcomp |= 0x80000000;
#endif
}
}
static const struct nvkm_fb_func
nv36_fb = {
.tags = nv20_fb_tags,
.init = nv30_fb_init,
.tile.regions = 8,
.tile.init = nv30_fb_tile_init,
.tile.comp = nv36_fb_tile_comp,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv20_fb_tile_prog,
.ram_new = nv20_ram_new,
};
int
nv36_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv36_fb, device, type, inst, pfb);
}
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
void
nv40_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags,
struct nvkm_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x80);
u32 tags = round_up(tiles / fb->ram->parts, 0x100);
if ( (flags & 2) &&
!nvkm_mm_head(&fb->tags.mm, 0, 1, tags, tags, 1, &tile->tag)) {
tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */
tile->zcomp |= ((tile->tag->offset ) >> 8);
tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13;
#ifdef __BIG_ENDIAN
tile->zcomp |= 0x40000000;
#endif
}
}
static void
nv40_fb_init(struct nvkm_fb *fb)
{
nvkm_mask(fb->subdev.device, 0x10033c, 0x00008000, 0x00000000);
}
static const struct nvkm_fb_func
nv40_fb = {
.tags = nv20_fb_tags,
.init = nv40_fb_init,
.tile.regions = 8,
.tile.init = nv30_fb_tile_init,
.tile.comp = nv40_fb_tile_comp,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv20_fb_tile_prog,
.ram_new = nv40_ram_new,
};
int
nv40_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv40_fb, device, type, inst, pfb);
}
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
void
nv41_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile)
{
struct nvkm_device *device = fb->subdev.device;
nvkm_wr32(device, 0x100604 + (i * 0x10), tile->limit);
nvkm_wr32(device, 0x100608 + (i * 0x10), tile->pitch);
nvkm_wr32(device, 0x100600 + (i * 0x10), tile->addr);
nvkm_rd32(device, 0x100600 + (i * 0x10));
nvkm_wr32(device, 0x100700 + (i * 0x04), tile->zcomp);
}
void
nv41_fb_init(struct nvkm_fb *fb)
{
nvkm_wr32(fb->subdev.device, 0x100800, 0x00000001);
}
static const struct nvkm_fb_func
nv41_fb = {
.tags = nv20_fb_tags,
.init = nv41_fb_init,
.tile.regions = 12,
.tile.init = nv30_fb_tile_init,
.tile.comp = nv40_fb_tile_comp,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv41_fb_tile_prog,
.ram_new = nv41_ram_new,
};
int
nv41_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv41_fb, device, type, inst, pfb);
}
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
static void
nv44_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nvkm_fb_tile *tile)
{
tile->addr = 0x00000001; /* mode = vram */
tile->addr |= addr;
tile->limit = max(1u, addr + size) - 1;
tile->pitch = pitch;
}
void
nv44_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile)
{
struct nvkm_device *device = fb->subdev.device;
nvkm_wr32(device, 0x100604 + (i * 0x10), tile->limit);
nvkm_wr32(device, 0x100608 + (i * 0x10), tile->pitch);
nvkm_wr32(device, 0x100600 + (i * 0x10), tile->addr);
nvkm_rd32(device, 0x100600 + (i * 0x10));
}
void
nv44_fb_init(struct nvkm_fb *fb)
{
struct nvkm_device *device = fb->subdev.device;
nvkm_wr32(device, 0x100850, 0x80000000);
nvkm_wr32(device, 0x100800, 0x00000001);
}
static const struct nvkm_fb_func
nv44_fb = {
.init = nv44_fb_init,
.tile.regions = 12,
.tile.init = nv44_fb_tile_init,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv44_fb_tile_prog,
.ram_new = nv44_ram_new,
};
int
nv44_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv44_fb, device, type, inst, pfb);
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
void
nv46_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nvkm_fb_tile *tile)
{
/* for performance, select alternate bank offset for zeta */
if (!(flags & 4)) tile->addr = (0 << 3);
else tile->addr = (1 << 3);
tile->addr |= 0x00000001; /* mode = vram */
tile->addr |= addr;
tile->limit = max(1u, addr + size) - 1;
tile->pitch = pitch;
}
static const struct nvkm_fb_func
nv46_fb = {
.init = nv44_fb_init,
.tile.regions = 15,
.tile.init = nv46_fb_tile_init,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv44_fb_tile_prog,
.ram_new = nv44_ram_new,
};
int
nv46_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv46_fb, device, type, inst, pfb);
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
static const struct nvkm_fb_func
nv47_fb = {
.tags = nv20_fb_tags,
.init = nv41_fb_init,
.tile.regions = 15,
.tile.init = nv30_fb_tile_init,
.tile.comp = nv40_fb_tile_comp,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv41_fb_tile_prog,
.ram_new = nv41_ram_new,
};
int
nv47_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv47_fb, device, type, inst, pfb);
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
static const struct nvkm_fb_func
nv49_fb = {
.tags = nv20_fb_tags,
.init = nv41_fb_init,
.tile.regions = 15,
.tile.init = nv30_fb_tile_init,
.tile.comp = nv40_fb_tile_comp,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv41_fb_tile_prog,
.ram_new = nv49_ram_new,
};
int
nv49_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv49_fb, device, type, inst, pfb);
}
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "priv.h"
#include "ram.h"
static const struct nvkm_fb_func
nv4e_fb = {
.init = nv44_fb_init,
.tile.regions = 12,
.tile.init = nv46_fb_tile_init,
.tile.fini = nv20_fb_tile_fini,
.tile.prog = nv44_fb_tile_prog,
.ram_new = nv44_ram_new,
};
int
nv4e_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nvkm_fb_new_(&nv4e_fb, device, type, inst, pfb);
}
@@ -0,0 +1,266 @@
/*
* Copyright 2012 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 "nv50.h"
#include "ram.h"
#include <core/client.h>
#include <core/enum.h>
#include <engine/fifo.h>
static int
nv50_fb_ram_new(struct nvkm_fb *base, struct nvkm_ram **pram)
{
struct nv50_fb *fb = nv50_fb(base);
return fb->func->ram_new(&fb->base, pram);
}
static const struct nvkm_enum vm_dispatch_subclients[] = {
{ 0x00000000, "GRCTX" },
{ 0x00000001, "NOTIFY" },
{ 0x00000002, "QUERY" },
{ 0x00000003, "COND" },
{ 0x00000004, "M2M_IN" },
{ 0x00000005, "M2M_OUT" },
{ 0x00000006, "M2M_NOTIFY" },
{}
};
static const struct nvkm_enum vm_ccache_subclients[] = {
{ 0x00000000, "CB" },
{ 0x00000001, "TIC" },
{ 0x00000002, "TSC" },
{}
};
static const struct nvkm_enum vm_prop_subclients[] = {
{ 0x00000000, "RT0" },
{ 0x00000001, "RT1" },
{ 0x00000002, "RT2" },
{ 0x00000003, "RT3" },
{ 0x00000004, "RT4" },
{ 0x00000005, "RT5" },
{ 0x00000006, "RT6" },
{ 0x00000007, "RT7" },
{ 0x00000008, "ZETA" },
{ 0x00000009, "LOCAL" },
{ 0x0000000a, "GLOBAL" },
{ 0x0000000b, "STACK" },
{ 0x0000000c, "DST2D" },
{}
};
static const struct nvkm_enum vm_pfifo_subclients[] = {
{ 0x00000000, "PUSHBUF" },
{ 0x00000001, "SEMAPHORE" },
{}
};
static const struct nvkm_enum vm_bar_subclients[] = {
{ 0x00000000, "FB" },
{ 0x00000001, "IN" },
{}
};
static const struct nvkm_enum vm_client[] = {
{ 0x00000000, "STRMOUT" },
{ 0x00000003, "DISPATCH", vm_dispatch_subclients },
{ 0x00000004, "PFIFO_WRITE" },
{ 0x00000005, "CCACHE", vm_ccache_subclients },
{ 0x00000006, "PMSPPP" },
{ 0x00000007, "CLIPID" },
{ 0x00000008, "PFIFO_READ" },
{ 0x00000009, "VFETCH" },
{ 0x0000000a, "TEXTURE" },
{ 0x0000000b, "PROP", vm_prop_subclients },
{ 0x0000000c, "PVP" },
{ 0x0000000d, "PBSP" },
{ 0x0000000e, "PCRYPT" },
{ 0x0000000f, "PCOUNTER" },
{ 0x00000011, "PDAEMON" },
{}
};
static const struct nvkm_enum vm_engine[] = {
{ 0x00000000, "PGRAPH" },
{ 0x00000001, "PVP" },
{ 0x00000004, "PEEPHOLE" },
{ 0x00000005, "PFIFO", vm_pfifo_subclients },
{ 0x00000006, "BAR", vm_bar_subclients },
{ 0x00000008, "PMSPPP" },
{ 0x00000008, "PMPEG" },
{ 0x00000009, "PBSP" },
{ 0x0000000a, "PCRYPT" },
{ 0x0000000b, "PCOUNTER" },
{ 0x0000000c, "SEMAPHORE_BG" },
{ 0x0000000d, "PCE0" },
{ 0x0000000e, "PMU" },
{}
};
static const struct nvkm_enum vm_fault[] = {
{ 0x00000000, "PT_NOT_PRESENT" },
{ 0x00000001, "PT_TOO_SHORT" },
{ 0x00000002, "PAGE_NOT_PRESENT" },
{ 0x00000003, "PAGE_SYSTEM_ONLY" },
{ 0x00000004, "PAGE_READ_ONLY" },
{ 0x00000006, "NULL_DMAOBJ" },
{ 0x00000007, "WRONG_MEMTYPE" },
{ 0x0000000b, "VRAM_LIMIT" },
{ 0x0000000f, "DMAOBJ_LIMIT" },
{}
};
static void
nv50_fb_intr(struct nvkm_fb *base)
{
struct nv50_fb *fb = nv50_fb(base);
struct nvkm_subdev *subdev = &fb->base.subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_chan *chan;
const struct nvkm_enum *en, *re, *cl, *sc;
u32 trap[6], idx, inst;
u8 st0, st1, st2, st3;
unsigned long flags;
int i;
idx = nvkm_rd32(device, 0x100c90);
if (!(idx & 0x80000000))
return;
idx &= 0x00ffffff;
for (i = 0; i < 6; i++) {
nvkm_wr32(device, 0x100c90, idx | i << 24);
trap[i] = nvkm_rd32(device, 0x100c94);
}
nvkm_wr32(device, 0x100c90, idx | 0x80000000);
/* decode status bits into something more useful */
if (device->chipset < 0xa3 ||
device->chipset == 0xaa || device->chipset == 0xac) {
st0 = (trap[0] & 0x0000000f) >> 0;
st1 = (trap[0] & 0x000000f0) >> 4;
st2 = (trap[0] & 0x00000f00) >> 8;
st3 = (trap[0] & 0x0000f000) >> 12;
} else {
st0 = (trap[0] & 0x000000ff) >> 0;
st1 = (trap[0] & 0x0000ff00) >> 8;
st2 = (trap[0] & 0x00ff0000) >> 16;
st3 = (trap[0] & 0xff000000) >> 24;
}
inst = ((trap[2] << 16) | trap[1]) << 12;
en = nvkm_enum_find(vm_engine, st0);
re = nvkm_enum_find(vm_fault , st1);
cl = nvkm_enum_find(vm_client, st2);
if (cl && cl->data) sc = nvkm_enum_find(cl->data, st3);
else if (en && en->data) sc = nvkm_enum_find(en->data, st3);
else sc = NULL;
chan = nvkm_chan_get_inst(&device->fifo->engine, inst, &flags);
nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel %d [%08x %s] "
"engine %02x [%s] client %02x [%s] "
"subclient %02x [%s] reason %08x [%s]\n",
(trap[5] & 0x00000100) ? "read" : "write",
trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff,
chan ? chan->id : -1, inst,
chan ? chan->name : "unknown",
st0, en ? en->name : "",
st2, cl ? cl->name : "", st3, sc ? sc->name : "",
st1, re ? re->name : "");
nvkm_chan_put(&chan, flags);
}
static void
nv50_fb_init(struct nvkm_fb *base)
{
struct nv50_fb *fb = nv50_fb(base);
struct nvkm_device *device = fb->base.subdev.device;
/* This is needed to get meaningful information from 100c90
* on traps. No idea what these values mean exactly. */
nvkm_wr32(device, 0x100c90, fb->func->trap);
}
static u32
nv50_fb_tags(struct nvkm_fb *base)
{
struct nv50_fb *fb = nv50_fb(base);
if (fb->func->tags)
return fb->func->tags(&fb->base);
return 0;
}
static void
nv50_fb_sysmem_flush_page_init(struct nvkm_fb *fb)
{
// Ensure that the address can actually fit in the register
WARN_ON(fb->sysmem.flush_page_addr > DMA_BIT_MASK(40));
nvkm_wr32(fb->subdev.device, 0x100c08, fb->sysmem.flush_page_addr >> 8);
}
static void *
nv50_fb_dtor(struct nvkm_fb *base)
{
struct nv50_fb *fb = nv50_fb(base);
return fb;
}
static const struct nvkm_fb_func
nv50_fb_ = {
.dtor = nv50_fb_dtor,
.tags = nv50_fb_tags,
.init = nv50_fb_init,
.intr = nv50_fb_intr,
.sysmem.flush_page_init = nv50_fb_sysmem_flush_page_init,
.ram_new = nv50_fb_ram_new,
};
int
nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
struct nv50_fb *fb;
if (!(fb = kzalloc_obj(*fb)))
return -ENOMEM;
nvkm_fb_ctor(&nv50_fb_, device, type, inst, &fb->base);
fb->func = func;
*pfb = &fb->base;
return 0;
}
static const struct nv50_fb_func
nv50_fb = {
.ram_new = nv50_ram_new,
.tags = nv20_fb_tags,
.trap = 0x000707ff,
};
int
nv50_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
return nv50_fb_new_(&nv50_fb, device, type, inst, pfb);
}
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_FB_NV50_H__
#define __NVKM_FB_NV50_H__
#define nv50_fb(p) container_of((p), struct nv50_fb, base)
#include "priv.h"
struct nv50_fb {
const struct nv50_fb_func *func;
struct nvkm_fb base;
};
struct nv50_fb_func {
int (*ram_new)(struct nvkm_fb *, struct nvkm_ram **);
u32 (*tags)(struct nvkm_fb *);
u32 trap;
};
int nv50_fb_new_(const struct nv50_fb_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_fb **pfb);
#endif
@@ -0,0 +1,103 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_FB_PRIV_H__
#define __NVKM_FB_PRIV_H__
#define nvkm_fb(p) container_of((p), struct nvkm_fb, subdev)
#include <subdev/fb.h>
#include <subdev/therm.h>
struct nvkm_bios;
int r535_fb_new(const struct nvkm_fb_func *,
struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **);
struct nvkm_fb_func {
void *(*dtor)(struct nvkm_fb *);
u32 (*tags)(struct nvkm_fb *);
int (*oneinit)(struct nvkm_fb *);
void (*init)(struct nvkm_fb *);
void (*init_remapper)(struct nvkm_fb *);
int (*init_page)(struct nvkm_fb *);
void (*init_unkn)(struct nvkm_fb *);
void (*intr)(struct nvkm_fb *);
struct nvkm_fb_func_sysmem {
void (*flush_page_init)(struct nvkm_fb *);
} sysmem;
struct nvkm_fb_func_vidmem {
u64 (*size)(struct nvkm_fb *);
} vidmem;
struct {
bool (*scrub_required)(struct nvkm_fb *);
int (*scrub)(struct nvkm_fb *);
} vpr;
struct {
int regions;
void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nvkm_fb_tile *);
void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags,
struct nvkm_fb_tile *);
void (*fini)(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
void (*prog)(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
} tile;
int (*ram_new)(struct nvkm_fb *, struct nvkm_ram **);
u8 default_bigpage;
const struct nvkm_therm_clkgate_pack *clkgate_pack;
};
int nvkm_fb_ctor(const struct nvkm_fb_func *, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_fb *);
int nvkm_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_fb **);
int nvkm_fb_bios_memtype(struct nvkm_bios *);
void nv10_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nvkm_fb_tile *);
void nv10_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
void nv10_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
u32 nv20_fb_tags(struct nvkm_fb *);
void nv20_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nvkm_fb_tile *);
void nv20_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
void nv20_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
void nv30_fb_init(struct nvkm_fb *);
void nv30_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nvkm_fb_tile *);
void nv40_fb_tile_comp(struct nvkm_fb *, int i, u32 size, u32 flags,
struct nvkm_fb_tile *);
void nv41_fb_init(struct nvkm_fb *);
void nv41_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
void nv44_fb_init(struct nvkm_fb *);
void nv44_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
u32 pitch, u32 flags, struct nvkm_fb_tile *);
int gf100_fb_oneinit(struct nvkm_fb *);
int gf100_fb_init_page(struct nvkm_fb *);
void gf100_fb_sysmem_flush_page_init(struct nvkm_fb *);
int gm200_fb_init_page(struct nvkm_fb *);
void gp100_fb_init_remapper(struct nvkm_fb *);
void gp100_fb_init_unkn(struct nvkm_fb *);
int gp102_fb_oneinit(struct nvkm_fb *);
u64 gp102_fb_vidmem_size(struct nvkm_fb *);
bool gp102_fb_vpr_scrub_required(struct nvkm_fb *);
int gp102_fb_vpr_scrub(struct nvkm_fb *);
int gv100_fb_init_page(struct nvkm_fb *);
bool tu102_fb_vpr_scrub_required(struct nvkm_fb *);
u64 ga102_fb_vidmem_size(struct nvkm_fb *);
#endif
@@ -0,0 +1,87 @@
/*
* Copyright 2023 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.
*/
#include "priv.h"
#include "ram.h"
#include <subdev/gsp.h>
static const struct nvkm_ram_func
r535_fb_ram = {
};
static int
r535_fb_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_gsp *gsp = fb->subdev.device->gsp;
struct nvkm_ram *ram;
int ret;
if (!(ram = *pram = kzalloc_obj(*ram)))
return -ENOMEM;
ram->func = &r535_fb_ram;
ram->fb = fb;
ram->type = NVKM_RAM_TYPE_UNKNOWN; /*TODO: pull this from GSP. */
ram->size = gsp->fb.size;
ram->stolen = false;
mutex_init(&ram->mutex);
for (int i = 0; i < gsp->fb.region_nr; i++) {
ret = nvkm_mm_init(&ram->vram, NVKM_RAM_MM_NORMAL,
gsp->fb.region[i].addr >> NVKM_RAM_MM_SHIFT,
gsp->fb.region[i].size >> NVKM_RAM_MM_SHIFT,
1);
if (ret)
return ret;
}
return 0;
}
static void *
r535_fb_dtor(struct nvkm_fb *fb)
{
kfree(fb->func);
return fb;
}
int
r535_fb_new(const struct nvkm_fb_func *hw,
struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
struct nvkm_fb_func *rm;
int ret;
if (!(rm = kzalloc_obj(*rm)))
return -ENOMEM;
rm->dtor = r535_fb_dtor;
rm->sysmem.flush_page_init = hw->sysmem.flush_page_init;
rm->vidmem.size = hw->vidmem.size;
rm->ram_new = r535_fb_ram_new;
ret = nvkm_fb_new_(rm, device, type, inst, pfb);
if (ret)
kfree(rm);
return ret;
}
@@ -0,0 +1,263 @@
/*
* Copyright 2015 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>
*/
#define nvkm_vram(p) container_of((p), struct nvkm_vram, memory)
#include "ram.h"
#include <core/memory.h>
#include <subdev/instmem.h>
#include <subdev/mmu.h>
struct nvkm_vram {
struct nvkm_memory memory;
struct nvkm_ram *ram;
u8 page;
struct nvkm_mm_node *mn;
};
static int
nvkm_vram_kmap(struct nvkm_memory *memory, struct nvkm_memory **pmemory)
{
return nvkm_instobj_wrap(nvkm_vram(memory)->ram->fb->subdev.device, memory, pmemory);
}
static int
nvkm_vram_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm,
struct nvkm_vma *vma, void *argv, u32 argc)
{
struct nvkm_vram *vram = nvkm_vram(memory);
struct nvkm_vmm_map map = {
.memory = &vram->memory,
.offset = offset,
.mem = vram->mn,
};
return nvkm_vmm_map(vmm, vma, argv, argc, &map);
}
static u64
nvkm_vram_size(struct nvkm_memory *memory)
{
return (u64)nvkm_mm_size(nvkm_vram(memory)->mn) << NVKM_RAM_MM_SHIFT;
}
static u64
nvkm_vram_addr(struct nvkm_memory *memory)
{
struct nvkm_vram *vram = nvkm_vram(memory);
if (!nvkm_mm_contiguous(vram->mn))
return ~0ULL;
return (u64)nvkm_mm_addr(vram->mn) << NVKM_RAM_MM_SHIFT;
}
static u8
nvkm_vram_page(struct nvkm_memory *memory)
{
return nvkm_vram(memory)->page;
}
static enum nvkm_memory_target
nvkm_vram_target(struct nvkm_memory *memory)
{
return NVKM_MEM_TARGET_VRAM;
}
static void *
nvkm_vram_dtor(struct nvkm_memory *memory)
{
struct nvkm_vram *vram = nvkm_vram(memory);
struct nvkm_mm_node *next = vram->mn;
struct nvkm_mm_node *node;
if (next) {
if (likely(next->nl_entry.next)){
mutex_lock(&vram->ram->mutex);
while ((node = next)) {
next = node->next;
nvkm_mm_free(&vram->ram->vram, &node);
}
mutex_unlock(&vram->ram->mutex);
} else {
kfree(vram->mn);
}
}
return vram;
}
static const struct nvkm_memory_func
nvkm_vram = {
.dtor = nvkm_vram_dtor,
.target = nvkm_vram_target,
.page = nvkm_vram_page,
.addr = nvkm_vram_addr,
.size = nvkm_vram_size,
.map = nvkm_vram_map,
.kmap = nvkm_vram_kmap,
};
int
nvkm_ram_wrap(struct nvkm_device *device, u64 addr, u64 size,
struct nvkm_memory **pmemory)
{
struct nvkm_ram *ram;
struct nvkm_vram *vram;
if (!device->fb || !(ram = device->fb->ram))
return -ENODEV;
ram = device->fb->ram;
if (!(vram = kzalloc_obj(*vram)))
return -ENOMEM;
nvkm_memory_ctor(&nvkm_vram, &vram->memory);
vram->ram = ram;
vram->page = NVKM_RAM_MM_SHIFT;
*pmemory = &vram->memory;
vram->mn = kzalloc_obj(*vram->mn);
if (!vram->mn)
return -ENOMEM;
vram->mn->offset = addr >> NVKM_RAM_MM_SHIFT;
vram->mn->length = size >> NVKM_RAM_MM_SHIFT;
return 0;
}
int
nvkm_ram_get(struct nvkm_device *device, u8 heap, u8 type, u8 rpage, u64 size,
bool contig, bool back, struct nvkm_memory **pmemory)
{
struct nvkm_ram *ram;
struct nvkm_mm *mm;
struct nvkm_mm_node **node, *r;
struct nvkm_vram *vram;
u8 page = max(rpage, (u8)NVKM_RAM_MM_SHIFT);
u32 align = (1 << page) >> NVKM_RAM_MM_SHIFT;
u32 max = ALIGN(size, 1 << page) >> NVKM_RAM_MM_SHIFT;
u32 min = contig ? max : align;
int ret;
if (!device->fb || !(ram = device->fb->ram))
return -ENODEV;
ram = device->fb->ram;
mm = &ram->vram;
if (!(vram = kzalloc_obj(*vram)))
return -ENOMEM;
nvkm_memory_ctor(&nvkm_vram, &vram->memory);
vram->ram = ram;
vram->page = page;
*pmemory = &vram->memory;
mutex_lock(&ram->mutex);
node = &vram->mn;
do {
if (back)
ret = nvkm_mm_tail(mm, heap, type, max, min, align, &r);
else
ret = nvkm_mm_head(mm, heap, type, max, min, align, &r);
if (ret) {
mutex_unlock(&ram->mutex);
nvkm_memory_unref(pmemory);
return ret;
}
*node = r;
node = &r->next;
max -= r->length;
} while (max);
mutex_unlock(&ram->mutex);
return 0;
}
int
nvkm_ram_init(struct nvkm_ram *ram)
{
if (ram->func->init)
return ram->func->init(ram);
return 0;
}
void
nvkm_ram_del(struct nvkm_ram **pram)
{
struct nvkm_ram *ram = *pram;
if (ram && !WARN_ON(!ram->func)) {
if (ram->func->dtor)
*pram = ram->func->dtor(ram);
nvkm_mm_fini(&ram->vram);
mutex_destroy(&ram->mutex);
kfree(*pram);
*pram = NULL;
}
}
int
nvkm_ram_ctor(const struct nvkm_ram_func *func, struct nvkm_fb *fb,
enum nvkm_ram_type type, u64 size, struct nvkm_ram *ram)
{
static const char *name[] = {
[NVKM_RAM_TYPE_UNKNOWN] = "of unknown memory type",
[NVKM_RAM_TYPE_STOLEN ] = "stolen system memory",
[NVKM_RAM_TYPE_SGRAM ] = "SGRAM",
[NVKM_RAM_TYPE_SDRAM ] = "SDRAM",
[NVKM_RAM_TYPE_DDR1 ] = "DDR1",
[NVKM_RAM_TYPE_DDR2 ] = "DDR2",
[NVKM_RAM_TYPE_DDR3 ] = "DDR3",
[NVKM_RAM_TYPE_GDDR2 ] = "GDDR2",
[NVKM_RAM_TYPE_GDDR3 ] = "GDDR3",
[NVKM_RAM_TYPE_GDDR4 ] = "GDDR4",
[NVKM_RAM_TYPE_GDDR5 ] = "GDDR5",
[NVKM_RAM_TYPE_GDDR5X ] = "GDDR5X",
[NVKM_RAM_TYPE_GDDR6 ] = "GDDR6",
[NVKM_RAM_TYPE_HBM2 ] = "HBM2",
};
struct nvkm_subdev *subdev = &fb->subdev;
int ret;
nvkm_info(subdev, "%d MiB %s\n", (int)(size >> 20), name[type]);
ram->func = func;
ram->fb = fb;
ram->type = type;
ram->size = size;
mutex_init(&ram->mutex);
if (!nvkm_mm_initialised(&ram->vram)) {
ret = nvkm_mm_init(&ram->vram, NVKM_RAM_MM_NORMAL, 0,
size >> NVKM_RAM_MM_SHIFT, 1);
if (ret)
return ret;
}
return 0;
}
int
nvkm_ram_new_(const struct nvkm_ram_func *func, struct nvkm_fb *fb,
enum nvkm_ram_type type, u64 size, struct nvkm_ram **pram)
{
if (!(*pram = kzalloc_obj(**pram)))
return -ENOMEM;
return nvkm_ram_ctor(func, fb, type, size, *pram);
}
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_FB_RAM_PRIV_H__
#define __NVKM_FB_RAM_PRIV_H__
#include "priv.h"
int nvkm_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *,
enum nvkm_ram_type, u64 size, struct nvkm_ram *);
int nvkm_ram_new_(const struct nvkm_ram_func *, struct nvkm_fb *,
enum nvkm_ram_type, u64 size, struct nvkm_ram **);
void nvkm_ram_del(struct nvkm_ram **);
int nvkm_ram_init(struct nvkm_ram *);
extern const struct nvkm_ram_func nv04_ram_func;
int nv50_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *,
struct nvkm_ram *);
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 *,
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_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 *);
u32 gm200_ram_probe_fbp_amount(const struct nvkm_ram_func *, u32,
struct nvkm_device *, int, int *);
int gp100_ram_init(struct nvkm_ram *);
/* RAM type-specific MR calculation routines */
int nvkm_sddr2_calc(struct nvkm_ram *);
int nvkm_sddr3_calc(struct nvkm_ram *);
int nvkm_gddr3_calc(struct nvkm_ram *);
int nvkm_gddr5_calc(struct nvkm_ram *, bool nuts);
int nv04_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int nv10_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int nv1a_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int nv20_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int nv40_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int nv41_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int nv44_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int nv49_ram_new(struct nvkm_fb *, struct nvkm_ram **);
int nv4e_ram_new(struct nvkm_fb *, struct nvkm_ram **);
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 **);
int gp102_ram_new(struct nvkm_fb *, struct nvkm_ram **);
#endif
@@ -0,0 +1,178 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_FBRAM_FUC_H__
#define __NVKM_FBRAM_FUC_H__
#include <subdev/fb.h>
#include <subdev/pmu.h>
struct ramfuc {
struct nvkm_memx *memx;
struct nvkm_fb *fb;
int sequence;
};
struct ramfuc_reg {
int sequence;
bool force;
u32 addr;
u32 stride; /* in bytes */
u32 mask;
u32 data;
};
static inline struct ramfuc_reg
ramfuc_stride(u32 addr, u32 stride, u32 mask)
{
return (struct ramfuc_reg) {
.sequence = 0,
.addr = addr,
.stride = stride,
.mask = mask,
.data = 0xdeadbeef,
};
}
static inline struct ramfuc_reg
ramfuc_reg2(u32 addr1, u32 addr2)
{
return (struct ramfuc_reg) {
.sequence = 0,
.addr = addr1,
.stride = addr2 - addr1,
.mask = 0x3,
.data = 0xdeadbeef,
};
}
static noinline struct ramfuc_reg
ramfuc_reg(u32 addr)
{
return (struct ramfuc_reg) {
.sequence = 0,
.addr = addr,
.stride = 0,
.mask = 0x1,
.data = 0xdeadbeef,
};
}
static inline int
ramfuc_init(struct ramfuc *ram, struct nvkm_fb *fb)
{
int ret = nvkm_memx_init(fb->subdev.device->pmu, &ram->memx);
if (ret)
return ret;
ram->sequence++;
ram->fb = fb;
return 0;
}
static inline int
ramfuc_exec(struct ramfuc *ram, bool exec)
{
int ret = 0;
if (ram->fb) {
ret = nvkm_memx_fini(&ram->memx, exec);
ram->fb = NULL;
}
return ret;
}
static inline u32
ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg)
{
struct nvkm_device *device = ram->fb->subdev.device;
if (reg->sequence != ram->sequence)
reg->data = nvkm_rd32(device, reg->addr);
return reg->data;
}
static inline void
ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data)
{
unsigned int mask, off = 0;
reg->sequence = ram->sequence;
reg->data = data;
for (mask = reg->mask; mask > 0; mask = (mask & ~1) >> 1) {
if (mask & 1)
nvkm_memx_wr32(ram->memx, reg->addr+off, reg->data);
off += reg->stride;
}
}
static inline void
ramfuc_nuke(struct ramfuc *ram, struct ramfuc_reg *reg)
{
reg->force = true;
}
static inline u32
ramfuc_mask(struct ramfuc *ram, struct ramfuc_reg *reg, u32 mask, u32 data)
{
u32 temp = ramfuc_rd32(ram, reg);
if (temp != ((temp & ~mask) | data) || reg->force) {
ramfuc_wr32(ram, reg, (temp & ~mask) | data);
reg->force = false;
}
return temp;
}
static inline void
ramfuc_wait(struct ramfuc *ram, u32 addr, u32 mask, u32 data, u32 nsec)
{
nvkm_memx_wait(ram->memx, addr, mask, data, nsec);
}
static inline void
ramfuc_nsec(struct ramfuc *ram, u32 nsec)
{
nvkm_memx_nsec(ram->memx, nsec);
}
static inline void
ramfuc_wait_vblank(struct ramfuc *ram)
{
nvkm_memx_wait_vblank(ram->memx);
}
static inline void
ramfuc_train(struct ramfuc *ram)
{
nvkm_memx_train(ram->memx);
}
static inline int
ramfuc_train_result(struct nvkm_fb *fb, u32 *result, u32 rsize)
{
return nvkm_memx_train_result(fb->subdev.device->pmu, result, rsize);
}
static inline void
ramfuc_block(struct ramfuc *ram)
{
nvkm_memx_block(ram->memx);
}
static inline void
ramfuc_unblock(struct ramfuc *ram)
{
nvkm_memx_unblock(ram->memx);
}
#define ram_init(s,p) ramfuc_init(&(s)->base, (p))
#define ram_exec(s,e) ramfuc_exec(&(s)->base, (e))
#define ram_have(s,r) ((s)->r_##r.addr != 0x000000)
#define ram_rd32(s,r) ramfuc_rd32(&(s)->base, &(s)->r_##r)
#define ram_wr32(s,r,d) ramfuc_wr32(&(s)->base, &(s)->r_##r, (d))
#define ram_nuke(s,r) ramfuc_nuke(&(s)->base, &(s)->r_##r)
#define ram_mask(s,r,m,d) ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d))
#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n))
#define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n))
#define ram_wait_vblank(s) ramfuc_wait_vblank(&(s)->base)
#define ram_train(s) ramfuc_train(&(s)->base)
#define ram_train_result(s,r,l) ramfuc_train_result((s), (r), (l))
#define ram_block(s) ramfuc_block(&(s)->base)
#define ram_unblock(s) ramfuc_unblock(&(s)->base)
#endif
@@ -0,0 +1,672 @@
/*
* 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 gf100_ram(p) container_of((p), struct gf100_ram, base)
#include "ram.h"
#include "ramfuc.h"
#include <core/option.h>
#include <subdev/bios.h>
#include <subdev/bios/pll.h>
#include <subdev/bios/rammap.h>
#include <subdev/bios/timing.h>
#include <subdev/clk.h>
#include <subdev/clk/pll.h>
struct gf100_ramfuc {
struct ramfuc base;
struct ramfuc_reg r_0x10fe20;
struct ramfuc_reg r_0x10fe24;
struct ramfuc_reg r_0x137320;
struct ramfuc_reg r_0x137330;
struct ramfuc_reg r_0x132000;
struct ramfuc_reg r_0x132004;
struct ramfuc_reg r_0x132100;
struct ramfuc_reg r_0x137390;
struct ramfuc_reg r_0x10f290;
struct ramfuc_reg r_0x10f294;
struct ramfuc_reg r_0x10f298;
struct ramfuc_reg r_0x10f29c;
struct ramfuc_reg r_0x10f2a0;
struct ramfuc_reg r_0x10f300;
struct ramfuc_reg r_0x10f338;
struct ramfuc_reg r_0x10f340;
struct ramfuc_reg r_0x10f344;
struct ramfuc_reg r_0x10f348;
struct ramfuc_reg r_0x10f910;
struct ramfuc_reg r_0x10f914;
struct ramfuc_reg r_0x100b0c;
struct ramfuc_reg r_0x10f050;
struct ramfuc_reg r_0x10f090;
struct ramfuc_reg r_0x10f200;
struct ramfuc_reg r_0x10f210;
struct ramfuc_reg r_0x10f310;
struct ramfuc_reg r_0x10f314;
struct ramfuc_reg r_0x10f610;
struct ramfuc_reg r_0x10f614;
struct ramfuc_reg r_0x10f800;
struct ramfuc_reg r_0x10f808;
struct ramfuc_reg r_0x10f824;
struct ramfuc_reg r_0x10f830;
struct ramfuc_reg r_0x10f988;
struct ramfuc_reg r_0x10f98c;
struct ramfuc_reg r_0x10f990;
struct ramfuc_reg r_0x10f998;
struct ramfuc_reg r_0x10f9b0;
struct ramfuc_reg r_0x10f9b4;
struct ramfuc_reg r_0x10fb04;
struct ramfuc_reg r_0x10fb08;
struct ramfuc_reg r_0x137300;
struct ramfuc_reg r_0x137310;
struct ramfuc_reg r_0x137360;
struct ramfuc_reg r_0x1373ec;
struct ramfuc_reg r_0x1373f0;
struct ramfuc_reg r_0x1373f8;
struct ramfuc_reg r_0x61c140;
struct ramfuc_reg r_0x611200;
struct ramfuc_reg r_0x13d8f4;
};
struct gf100_ram {
struct nvkm_ram base;
struct gf100_ramfuc fuc;
struct nvbios_pll refpll;
struct nvbios_pll mempll;
};
static void
gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic)
{
struct gf100_ram *ram = container_of(fuc, typeof(*ram), fuc);
struct nvkm_fb *fb = ram->base.fb;
struct nvkm_device *device = fb->subdev.device;
u32 part = nvkm_rd32(device, 0x022438), i;
u32 mask = nvkm_rd32(device, 0x022554);
u32 addr = 0x110974;
ram_wr32(fuc, 0x10f910, magic);
ram_wr32(fuc, 0x10f914, magic);
for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) {
if (mask & (1 << i))
continue;
ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
}
}
int
gf100_ram_calc(struct nvkm_ram *base, u32 freq)
{
struct gf100_ram *ram = gf100_ram(base);
struct gf100_ramfuc *fuc = &ram->fuc;
struct nvkm_subdev *subdev = &ram->base.fb->subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_clk *clk = device->clk;
struct nvkm_bios *bios = device->bios;
struct nvbios_ramcfg cfg;
u8 ver, cnt, len, strap;
struct {
u32 data;
u8 size;
} rammap, ramcfg, timing;
int ref, div, out;
int from, mode;
int N1, M1, P;
int ret;
/* lookup memory config data relevant to the target frequency */
rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
&cnt, &ramcfg.size, &cfg);
if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
nvkm_error(subdev, "invalid/missing rammap entry\n");
return -EINVAL;
}
/* locate specific data set for the attached memory */
strap = nvbios_ramcfg_index(subdev);
if (strap >= cnt) {
nvkm_error(subdev, "invalid ramcfg strap\n");
return -EINVAL;
}
ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
nvkm_error(subdev, "invalid/missing ramcfg entry\n");
return -EINVAL;
}
/* lookup memory timings, if bios says they're present */
strap = nvbios_rd08(bios, ramcfg.data + 0x01);
if (strap != 0xff) {
timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
&cnt, &len);
if (!timing.data || ver != 0x10 || timing.size < 0x19) {
nvkm_error(subdev, "invalid/missing timing entry\n");
return -EINVAL;
}
} else {
timing.data = 0;
}
ret = ram_init(fuc, ram->base.fb);
if (ret)
return ret;
/* determine current mclk configuration */
from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */
/* determine target mclk configuration */
if (!(ram_rd32(fuc, 0x137300) & 0x00000100))
ref = nvkm_clk_read(clk, nv_clk_src_sppll0);
else
ref = nvkm_clk_read(clk, nv_clk_src_sppll1);
div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2;
out = (ref * 2) / (div + 2);
mode = freq != out;
ram_mask(fuc, 0x137360, 0x00000002, 0x00000000);
if ((ram_rd32(fuc, 0x132000) & 0x00000002) || 0 /*XXX*/) {
ram_nuke(fuc, 0x132000);
ram_mask(fuc, 0x132000, 0x00000002, 0x00000002);
ram_mask(fuc, 0x132000, 0x00000002, 0x00000000);
}
if (mode == 1) {
ram_nuke(fuc, 0x10fe20);
ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000002);
ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000000);
}
// 0x00020034 // 0x0000000a
ram_wr32(fuc, 0x132100, 0x00000001);
if (mode == 1 && from == 0) {
/* calculate refpll */
ret = gt215_pll_calc(subdev, &ram->refpll, ram->mempll.refclk,
&N1, NULL, &M1, &P);
if (ret <= 0) {
nvkm_error(subdev, "unable to calc refpll\n");
return ret ? ret : -ERANGE;
}
ram_wr32(fuc, 0x10fe20, 0x20010000);
ram_wr32(fuc, 0x137320, 0x00000003);
ram_wr32(fuc, 0x137330, 0x81200006);
ram_wr32(fuc, 0x10fe24, (P << 16) | (N1 << 8) | M1);
ram_wr32(fuc, 0x10fe20, 0x20010001);
ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
/* calculate mempll */
ret = gt215_pll_calc(subdev, &ram->mempll, freq,
&N1, NULL, &M1, &P);
if (ret <= 0) {
nvkm_error(subdev, "unable to calc refpll\n");
return ret ? ret : -ERANGE;
}
ram_wr32(fuc, 0x10fe20, 0x20010005);
ram_wr32(fuc, 0x132004, (P << 16) | (N1 << 8) | M1);
ram_wr32(fuc, 0x132000, 0x18010101);
ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
} else
if (mode == 0) {
ram_wr32(fuc, 0x137300, 0x00000003);
}
if (from == 0) {
ram_nuke(fuc, 0x10fb04);
ram_mask(fuc, 0x10fb04, 0x0000ffff, 0x00000000);
ram_nuke(fuc, 0x10fb08);
ram_mask(fuc, 0x10fb08, 0x0000ffff, 0x00000000);
ram_wr32(fuc, 0x10f988, 0x2004ff00);
ram_wr32(fuc, 0x10f98c, 0x003fc040);
ram_wr32(fuc, 0x10f990, 0x20012001);
ram_wr32(fuc, 0x10f998, 0x00011a00);
ram_wr32(fuc, 0x13d8f4, 0x00000000);
} else {
ram_wr32(fuc, 0x10f988, 0x20010000);
ram_wr32(fuc, 0x10f98c, 0x00000000);
ram_wr32(fuc, 0x10f990, 0x20012001);
ram_wr32(fuc, 0x10f998, 0x00010a00);
}
if (from == 0) {
// 0x00020039 // 0x000000ba
}
// 0x0002003a // 0x00000002
ram_wr32(fuc, 0x100b0c, 0x00080012);
// 0x00030014 // 0x00000000 // 0x02b5f070
// 0x00030014 // 0x00010000 // 0x02b5f070
ram_wr32(fuc, 0x611200, 0x00003300);
// 0x00020034 // 0x0000000a
// 0x00030020 // 0x00000001 // 0x00000000
ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
ram_wr32(fuc, 0x10f210, 0x00000000);
ram_nsec(fuc, 1000);
if (mode == 0)
gf100_ram_train(fuc, 0x000c1001);
ram_wr32(fuc, 0x10f310, 0x00000001);
ram_nsec(fuc, 1000);
ram_wr32(fuc, 0x10f090, 0x00000061);
ram_wr32(fuc, 0x10f090, 0xc000007f);
ram_nsec(fuc, 1000);
if (from == 0) {
ram_wr32(fuc, 0x10f824, 0x00007fd4);
} else {
ram_wr32(fuc, 0x1373ec, 0x00020404);
}
if (mode == 0) {
ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000);
ram_wr32(fuc, 0x10f830, 0x41500010);
ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
ram_mask(fuc, 0x132100, 0x00000100, 0x00000100);
ram_wr32(fuc, 0x10f050, 0xff000090);
ram_wr32(fuc, 0x1373ec, 0x00020f0f);
ram_wr32(fuc, 0x1373f0, 0x00000003);
ram_wr32(fuc, 0x137310, 0x81201616);
ram_wr32(fuc, 0x132100, 0x00000001);
// 0x00020039 // 0x000000ba
ram_wr32(fuc, 0x10f830, 0x00300017);
ram_wr32(fuc, 0x1373f0, 0x00000001);
ram_wr32(fuc, 0x10f824, 0x00007e77);
ram_wr32(fuc, 0x132000, 0x18030001);
ram_wr32(fuc, 0x10f090, 0x4000007e);
ram_nsec(fuc, 2000);
ram_wr32(fuc, 0x10f314, 0x00000001);
ram_wr32(fuc, 0x10f210, 0x80000000);
ram_wr32(fuc, 0x10f338, 0x00300220);
ram_wr32(fuc, 0x10f300, 0x0000011d);
ram_nsec(fuc, 1000);
ram_wr32(fuc, 0x10f290, 0x02060505);
ram_wr32(fuc, 0x10f294, 0x34208288);
ram_wr32(fuc, 0x10f298, 0x44050411);
ram_wr32(fuc, 0x10f29c, 0x0000114c);
ram_wr32(fuc, 0x10f2a0, 0x42e10069);
ram_wr32(fuc, 0x10f614, 0x40044f77);
ram_wr32(fuc, 0x10f610, 0x40044f77);
ram_wr32(fuc, 0x10f344, 0x00600009);
ram_nsec(fuc, 1000);
ram_wr32(fuc, 0x10f348, 0x00700008);
ram_wr32(fuc, 0x61c140, 0x19240000);
ram_wr32(fuc, 0x10f830, 0x00300017);
gf100_ram_train(fuc, 0x80021001);
gf100_ram_train(fuc, 0x80081001);
ram_wr32(fuc, 0x10f340, 0x00500004);
ram_nsec(fuc, 1000);
ram_wr32(fuc, 0x10f830, 0x01300017);
ram_wr32(fuc, 0x10f830, 0x00300017);
// 0x00030020 // 0x00000000 // 0x00000000
// 0x00020034 // 0x0000000b
ram_wr32(fuc, 0x100b0c, 0x00080028);
ram_wr32(fuc, 0x611200, 0x00003330);
} else {
ram_wr32(fuc, 0x10f800, 0x00001800);
ram_wr32(fuc, 0x13d8f4, 0x00000000);
ram_wr32(fuc, 0x1373ec, 0x00020404);
ram_wr32(fuc, 0x1373f0, 0x00000003);
ram_wr32(fuc, 0x10f830, 0x40700010);
ram_wr32(fuc, 0x10f830, 0x40500010);
ram_wr32(fuc, 0x13d8f4, 0x00000000);
ram_wr32(fuc, 0x1373f8, 0x00000000);
ram_wr32(fuc, 0x132100, 0x00000101);
ram_wr32(fuc, 0x137310, 0x89201616);
ram_wr32(fuc, 0x10f050, 0xff000090);
ram_wr32(fuc, 0x1373ec, 0x00030404);
ram_wr32(fuc, 0x1373f0, 0x00000002);
// 0x00020039 // 0x00000011
ram_wr32(fuc, 0x132100, 0x00000001);
ram_wr32(fuc, 0x1373f8, 0x00002000);
ram_nsec(fuc, 2000);
ram_wr32(fuc, 0x10f808, 0x7aaa0050);
ram_wr32(fuc, 0x10f830, 0x00500010);
ram_wr32(fuc, 0x10f200, 0x00ce1000);
ram_wr32(fuc, 0x10f090, 0x4000007e);
ram_nsec(fuc, 2000);
ram_wr32(fuc, 0x10f314, 0x00000001);
ram_wr32(fuc, 0x10f210, 0x80000000);
ram_wr32(fuc, 0x10f338, 0x00300200);
ram_wr32(fuc, 0x10f300, 0x0000084d);
ram_nsec(fuc, 1000);
ram_wr32(fuc, 0x10f290, 0x0b343825);
ram_wr32(fuc, 0x10f294, 0x3483028e);
ram_wr32(fuc, 0x10f298, 0x440c0600);
ram_wr32(fuc, 0x10f29c, 0x0000214c);
ram_wr32(fuc, 0x10f2a0, 0x42e20069);
ram_wr32(fuc, 0x10f200, 0x00ce0000);
ram_wr32(fuc, 0x10f614, 0x60044e77);
ram_wr32(fuc, 0x10f610, 0x60044e77);
ram_wr32(fuc, 0x10f340, 0x00500000);
ram_nsec(fuc, 1000);
ram_wr32(fuc, 0x10f344, 0x00600228);
ram_nsec(fuc, 1000);
ram_wr32(fuc, 0x10f348, 0x00700000);
ram_wr32(fuc, 0x13d8f4, 0x00000000);
ram_wr32(fuc, 0x61c140, 0x09a40000);
gf100_ram_train(fuc, 0x800e1008);
ram_nsec(fuc, 1000);
ram_wr32(fuc, 0x10f800, 0x00001804);
// 0x00030020 // 0x00000000 // 0x00000000
// 0x00020034 // 0x0000000b
ram_wr32(fuc, 0x13d8f4, 0x00000000);
ram_wr32(fuc, 0x100b0c, 0x00080028);
ram_wr32(fuc, 0x611200, 0x00003330);
ram_nsec(fuc, 100000);
ram_wr32(fuc, 0x10f9b0, 0x05313f41);
ram_wr32(fuc, 0x10f9b4, 0x00002f50);
gf100_ram_train(fuc, 0x010c1001);
}
ram_mask(fuc, 0x10f200, 0x00000800, 0x00000800);
// 0x00020016 // 0x00000000
if (mode == 0)
ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
return 0;
}
int
gf100_ram_prog(struct nvkm_ram *base)
{
struct gf100_ram *ram = gf100_ram(base);
struct nvkm_device *device = ram->base.fb->subdev.device;
ram_exec(&ram->fuc, nvkm_boolopt(device->cfgopt, "NvMemExec", true));
return 0;
}
void
gf100_ram_tidy(struct nvkm_ram *base)
{
struct gf100_ram *ram = gf100_ram(base);
ram_exec(&ram->fuc, false);
}
int
gf100_ram_init(struct nvkm_ram *base)
{
static const u8 train0[] = {
0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc,
0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
};
static const u32 train1[] = {
0x00000000, 0xffffffff,
0x55555555, 0xaaaaaaaa,
0x33333333, 0xcccccccc,
0xf0f0f0f0, 0x0f0f0f0f,
0x00ff00ff, 0xff00ff00,
0x0000ffff, 0xffff0000,
};
struct gf100_ram *ram = gf100_ram(base);
struct nvkm_device *device = ram->base.fb->subdev.device;
int i;
switch (ram->base.type) {
case NVKM_RAM_TYPE_GDDR5:
break;
default:
return 0;
}
/* prepare for ddr link training, and load training patterns */
for (i = 0; i < 0x30; i++) {
nvkm_wr32(device, 0x10f968, 0x00000000 | (i << 8));
nvkm_wr32(device, 0x10f96c, 0x00000000 | (i << 8));
nvkm_wr32(device, 0x10f920, 0x00000100 | train0[i % 12]);
nvkm_wr32(device, 0x10f924, 0x00000100 | train0[i % 12]);
nvkm_wr32(device, 0x10f918, train1[i % 12]);
nvkm_wr32(device, 0x10f91c, train1[i % 12]);
nvkm_wr32(device, 0x10f920, 0x00000000 | train0[i % 12]);
nvkm_wr32(device, 0x10f924, 0x00000000 | train0[i % 12]);
nvkm_wr32(device, 0x10f918, train1[i % 12]);
nvkm_wr32(device, 0x10f91c, train1[i % 12]);
}
return 0;
}
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,
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 */
enum nvkm_ram_type type = nvkm_fb_bios_memtype(bios);
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);
}
}
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, ram);
if (ret)
return ret;
nvkm_mm_fini(&ram->vram);
/* 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, NVKM_RAM_MM_NORMAL,
rsvd_head >> NVKM_RAM_MM_SHIFT,
(lower - rsvd_head) >> NVKM_RAM_MM_SHIFT, 1);
if (ret)
return ret;
/* 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, NVKM_RAM_MM_MIXED,
ubase >> NVKM_RAM_MM_SHIFT,
(usize - rsvd_tail) >> NVKM_RAM_MM_SHIFT, 1);
if (ret)
return ret;
} else {
/* GPUs without mixed-memory are a lot nicer... */
ret = nvkm_mm_init(&ram->vram, NVKM_RAM_MM_NORMAL,
rsvd_head >> NVKM_RAM_MM_SHIFT,
(total - rsvd_head - rsvd_tail) >>
NVKM_RAM_MM_SHIFT, 1);
if (ret)
return ret;
}
return 0;
}
int
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;
struct gf100_ram *ram;
int ret;
if (!(ram = kzalloc_obj(*ram)))
return -ENOMEM;
*pram = &ram->base;
ret = gf100_ram_ctor(func, fb, &ram->base);
if (ret)
return ret;
ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll);
if (ret) {
nvkm_error(subdev, "mclk refpll data not found\n");
return ret;
}
ret = nvbios_pll_parse(bios, 0x04, &ram->mempll);
if (ret) {
nvkm_error(subdev, "mclk pll data not found\n");
return ret;
}
ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20);
ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24);
ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
ram->fuc.r_0x137330 = ramfuc_reg(0x137330);
ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
ram->fuc.r_0x132100 = ramfuc_reg(0x132100);
ram->fuc.r_0x137390 = ramfuc_reg(0x137390);
ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300);
ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338);
ram->fuc.r_0x10f340 = ramfuc_reg(0x10f340);
ram->fuc.r_0x10f344 = ramfuc_reg(0x10f344);
ram->fuc.r_0x10f348 = ramfuc_reg(0x10f348);
ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
ram->fuc.r_0x100b0c = ramfuc_reg(0x100b0c);
ram->fuc.r_0x10f050 = ramfuc_reg(0x10f050);
ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
ram->fuc.r_0x10f988 = ramfuc_reg(0x10f988);
ram->fuc.r_0x10f98c = ramfuc_reg(0x10f98c);
ram->fuc.r_0x10f990 = ramfuc_reg(0x10f990);
ram->fuc.r_0x10f998 = ramfuc_reg(0x10f998);
ram->fuc.r_0x10f9b0 = ramfuc_reg(0x10f9b0);
ram->fuc.r_0x10f9b4 = ramfuc_reg(0x10f9b4);
ram->fuc.r_0x10fb04 = ramfuc_reg(0x10fb04);
ram->fuc.r_0x10fb08 = ramfuc_reg(0x10fb08);
ram->fuc.r_0x137310 = ramfuc_reg(0x137300);
ram->fuc.r_0x137310 = ramfuc_reg(0x137310);
ram->fuc.r_0x137360 = ramfuc_reg(0x137360);
ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
ram->fuc.r_0x1373f8 = ramfuc_reg(0x1373f8);
ram->fuc.r_0x61c140 = ramfuc_reg(0x61c140);
ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4);
return 0;
}
static const struct nvkm_ram_func
gf100_ram = {
.upper = 0x0200000000ULL,
.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,
.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);
}
@@ -0,0 +1,60 @@
/*
* 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 = 0x0200000000ULL,
.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,
.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);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,51 @@
/*
* 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 "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 = 0x1000000000ULL,
.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,
.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_new_(&gm107_ram, fb, pram);
}
@@ -0,0 +1,66 @@
/*
* 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 = 0x1000000000ULL,
.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,
.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);
}
@@ -0,0 +1,99 @@
/*
* 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 "ram.h"
#include <subdev/bios.h>
#include <subdev/bios/init.h>
#include <subdev/bios/rammap.h>
int
gp100_ram_init(struct nvkm_ram *ram)
{
struct nvkm_subdev *subdev = &ram->fb->subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_bios *bios = device->bios;
u8 ver, hdr, cnt, len, snr, ssz;
u32 data;
int i;
/* run a bunch of tables from rammap table. there's actually
* individual pointers for each rammap entry too, but, nvidia
* seem to just run the last two entries' scripts early on in
* their init, and never again.. we'll just run 'em all once
* for now.
*
* i strongly suspect that each script is for a separate mode
* (likely selected by 0x9a065c's lower bits?), and the
* binary driver skips the one that's already been setup by
* the init tables.
*/
data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
if (!data || hdr < 0x15)
return -EINVAL;
cnt = nvbios_rd08(bios, data + 0x14); /* guess at count */
data = nvbios_rd32(bios, data + 0x10); /* guess u32... */
if (cnt) {
u32 save = nvkm_rd32(device, 0x9a065c) & 0x000000f0;
for (i = 0; i < cnt; i++, data += 4) {
if (i != save >> 4) {
nvkm_mask(device, 0x9a065c, 0x000000f0, i << 4);
nvbios_init(subdev, nvbios_rd32(bios, data));
}
}
nvkm_mask(device, 0x9a065c, 0x000000f0, save);
}
nvkm_mask(device, 0x9a0584, 0x11000000, 0x00000000);
nvkm_wr32(device, 0x10ecc0, 0xffffffff);
nvkm_mask(device, 0x9a0160, 0x00000010, 0x00000010);
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 = {
.upper = 0x1000000000ULL,
.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,
};
int
gp100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_ram *ram;
if (!(ram = *pram = kzalloc_obj(*ram)))
return -ENOMEM;
return gf100_ram_ctor(&gp100_ram, fb, ram);
}
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
#include "ram.h"
#include <subdev/bios.h>
static const struct nvkm_ram_func
gp102_ram = {
.init = gp100_ram_init,
};
int
gp102_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
enum nvkm_ram_type type = nvkm_fb_bios_memtype(fb->subdev.device->bios);
const u32 rsvd_head = ( 256 * 1024); /* vga memory */
const u32 rsvd_tail = (1024 * 1024); /* vbios etc */
u64 size = fb->func->vidmem.size(fb);
int ret;
ret = nvkm_ram_new_(&gp102_ram, fb, type, size, pram);
if (ret)
return ret;
nvkm_mm_fini(&(*pram)->vram);
return nvkm_mm_init(&(*pram)->vram, NVKM_RAM_MM_NORMAL,
rsvd_head >> NVKM_RAM_MM_SHIFT,
(size - rsvd_head - rsvd_tail) >> NVKM_RAM_MM_SHIFT,
1);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,86 @@
/*
* 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 mcp77_ram(p) container_of((p), struct mcp77_ram, base)
#include "ram.h"
struct mcp77_ram {
struct nvkm_ram base;
u64 poller_base;
};
static int
mcp77_ram_init(struct nvkm_ram *base)
{
struct mcp77_ram *ram = mcp77_ram(base);
struct nvkm_device *device = ram->base.fb->subdev.device;
u32 dniso = ((ram->base.size - (ram->poller_base + 0x00)) >> 5) - 1;
u32 hostnb = ((ram->base.size - (ram->poller_base + 0x20)) >> 5) - 1;
u32 flush = ((ram->base.size - (ram->poller_base + 0x40)) >> 5) - 1;
/* Enable NISO poller for various clients and set their associated
* read address, only for MCP77/78 and MCP79/7A. (fd#27501)
*/
nvkm_wr32(device, 0x100c18, dniso);
nvkm_mask(device, 0x100c14, 0x00000000, 0x00000001);
nvkm_wr32(device, 0x100c1c, hostnb);
nvkm_mask(device, 0x100c14, 0x00000000, 0x00000002);
nvkm_wr32(device, 0x100c24, flush);
nvkm_mask(device, 0x100c14, 0x00000000, 0x00010000);
return 0;
}
static const struct nvkm_ram_func
mcp77_ram_func = {
.init = mcp77_ram_init,
};
int
mcp77_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_device *device = fb->subdev.device;
u32 rsvd_head = ( 256 * 1024); /* vga memory */
u32 rsvd_tail = (1024 * 1024) + 0x1000; /* vbios etc + poller mem */
u64 base = (u64)nvkm_rd32(device, 0x100e10) << 12;
u64 size = (u64)nvkm_rd32(device, 0x100e14) << 12;
struct mcp77_ram *ram;
int ret;
if (!(ram = kzalloc_obj(*ram)))
return -ENOMEM;
*pram = &ram->base;
ret = nvkm_ram_ctor(&mcp77_ram_func, fb, NVKM_RAM_TYPE_STOLEN,
size, &ram->base);
if (ret)
return ret;
ram->poller_base = size - rsvd_tail;
ram->base.stolen = base;
nvkm_mm_fini(&ram->base.vram);
return nvkm_mm_init(&ram->base.vram, NVKM_RAM_MM_NORMAL,
rsvd_head >> NVKM_RAM_MM_SHIFT,
(size - rsvd_head - rsvd_tail) >>
NVKM_RAM_MM_SHIFT, 1);
}
@@ -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 "ram.h"
#include "regsnv04.h"
const struct nvkm_ram_func
nv04_ram_func = {
};
int
nv04_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_device *device = fb->subdev.device;
u32 boot0 = nvkm_rd32(device, NV04_PFB_BOOT_0);
u64 size;
enum nvkm_ram_type type;
if (boot0 & 0x00000100) {
size = ((boot0 >> 12) & 0xf) * 2 + 2;
size *= 1024 * 1024;
} else {
switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
size = 32 * 1024 * 1024;
break;
case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
size = 16 * 1024 * 1024;
break;
case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
size = 8 * 1024 * 1024;
break;
case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
size = 4 * 1024 * 1024;
break;
}
}
if ((boot0 & 0x00000038) <= 0x10)
type = NVKM_RAM_TYPE_SGRAM;
else
type = NVKM_RAM_TYPE_SDRAM;
return nvkm_ram_new_(&nv04_ram_func, fb, type, size, pram);
}
@@ -0,0 +1,40 @@
/*
* 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 "ram.h"
int
nv10_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_device *device = fb->subdev.device;
u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000;
u32 cfg0 = nvkm_rd32(device, 0x100200);
enum nvkm_ram_type type;
if (cfg0 & 0x00000001)
type = NVKM_RAM_TYPE_DDR1;
else
type = NVKM_RAM_TYPE_SDRAM;
return nvkm_ram_new_(&nv04_ram_func, fb, type, size, pram);
}
@@ -0,0 +1,56 @@
/*
* 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 "ram.h"
int
nv1a_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct pci_dev *bridge;
u32 mem, mib;
int domain = 0;
struct pci_dev *pdev = NULL;
if (dev_is_pci(fb->subdev.device->dev))
pdev = to_pci_dev(fb->subdev.device->dev);
if (pdev)
domain = pci_domain_nr(pdev->bus);
bridge = pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 1));
if (!bridge) {
nvkm_error(&fb->subdev, "no bridge device\n");
return -ENODEV;
}
if (fb->subdev.device->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;
}
return nvkm_ram_new_(&nv04_ram_func, fb, NVKM_RAM_TYPE_STOLEN,
mib * 1024 * 1024, pram);
}
@@ -0,0 +1,48 @@
/*
* 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 "ram.h"
int
nv20_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_device *device = fb->subdev.device;
u32 pbus1218 = nvkm_rd32(device, 0x001218);
u32 size = (nvkm_rd32(device, 0x10020c) & 0xff000000);
enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN;
int ret;
switch (pbus1218 & 0x00000300) {
case 0x00000000: type = NVKM_RAM_TYPE_SDRAM; break;
case 0x00000100: type = NVKM_RAM_TYPE_DDR1 ; break;
case 0x00000200: type = NVKM_RAM_TYPE_GDDR3; break;
case 0x00000300: type = NVKM_RAM_TYPE_GDDR2; break;
}
ret = nvkm_ram_new_(&nv04_ram_func, fb, type, size, pram);
if (ret)
return ret;
(*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1;
return 0;
}
@@ -0,0 +1,223 @@
/*
* 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 "ramnv40.h"
#include <subdev/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/init.h>
#include <subdev/bios/pll.h>
#include <subdev/clk/pll.h>
#include <subdev/timer.h>
static int
nv40_ram_calc(struct nvkm_ram *base, u32 freq)
{
struct nv40_ram *ram = nv40_ram(base);
struct nvkm_subdev *subdev = &ram->base.fb->subdev;
struct nvkm_bios *bios = subdev->device->bios;
struct nvbios_pll pll;
int N1, M1, N2, M2;
int log2P, ret;
ret = nvbios_pll_parse(bios, 0x04, &pll);
if (ret) {
nvkm_error(subdev, "mclk pll data not found\n");
return ret;
}
ret = nv04_pll_calc(subdev, &pll, freq, &N1, &M1, &N2, &M2, &log2P);
if (ret < 0)
return ret;
ram->ctrl = 0x80000000 | (log2P << 16);
ram->ctrl |= min(pll.bias_p + log2P, (int)pll.max_p) << 20;
if (N2 == M2) {
ram->ctrl |= 0x00000100;
ram->coef = (N1 << 8) | M1;
} else {
ram->ctrl |= 0x40000000;
ram->coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
}
return 0;
}
static int
nv40_ram_prog(struct nvkm_ram *base)
{
struct nv40_ram *ram = nv40_ram(base);
struct nvkm_subdev *subdev = &ram->base.fb->subdev;
struct nvkm_device *device = subdev->device;
struct nvkm_bios *bios = device->bios;
struct bit_entry M;
u32 crtc_mask = 0;
u8 sr1[2];
int i;
/* determine which CRTCs are active, fetch VGA_SR1 for each */
for (i = 0; i < 2; i++) {
u32 vbl = nvkm_rd32(device, 0x600808 + (i * 0x2000));
u32 cnt = 0;
do {
if (vbl != nvkm_rd32(device, 0x600808 + (i * 0x2000))) {
nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
sr1[i] = nvkm_rd08(device, 0x0c03c5 + (i * 0x2000));
if (!(sr1[i] & 0x20))
crtc_mask |= (1 << i);
break;
}
udelay(1);
} while (cnt++ < 32);
}
/* wait for vblank start on active crtcs, disable memory access */
for (i = 0; i < 2; i++) {
if (!(crtc_mask & (1 << i)))
continue;
nvkm_msec(device, 2000,
u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000));
if (!(tmp & 0x00010000))
break;
);
nvkm_msec(device, 2000,
u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000));
if ( (tmp & 0x00010000))
break;
);
nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
}
/* prepare ram for reclocking */
nvkm_wr32(device, 0x1002d4, 0x00000001); /* precharge */
nvkm_wr32(device, 0x1002d0, 0x00000001); /* refresh */
nvkm_wr32(device, 0x1002d0, 0x00000001); /* refresh */
nvkm_mask(device, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
nvkm_wr32(device, 0x1002dc, 0x00000001); /* enable self-refresh */
/* change the PLL of each memory partition */
nvkm_mask(device, 0x00c040, 0x0000c000, 0x00000000);
switch (device->chipset) {
case 0x40:
case 0x45:
case 0x41:
case 0x42:
case 0x47:
nvkm_mask(device, 0x004044, 0xc0771100, ram->ctrl);
nvkm_mask(device, 0x00402c, 0xc0771100, ram->ctrl);
nvkm_wr32(device, 0x004048, ram->coef);
nvkm_wr32(device, 0x004030, ram->coef);
fallthrough;
case 0x43:
case 0x49:
case 0x4b:
nvkm_mask(device, 0x004038, 0xc0771100, ram->ctrl);
nvkm_wr32(device, 0x00403c, ram->coef);
fallthrough;
default:
nvkm_mask(device, 0x004020, 0xc0771100, ram->ctrl);
nvkm_wr32(device, 0x004024, ram->coef);
break;
}
udelay(100);
nvkm_mask(device, 0x00c040, 0x0000c000, 0x0000c000);
/* re-enable normal operation of memory controller */
nvkm_wr32(device, 0x1002dc, 0x00000000);
nvkm_mask(device, 0x100210, 0x80000000, 0x80000000);
udelay(100);
/* execute memory reset script from vbios */
if (!bit_entry(bios, 'M', &M))
nvbios_init(subdev, nvbios_rd16(bios, M.offset + 0x00));
/* make sure we're in vblank (hopefully the same one as before), and
* then re-enable crtc memory access
*/
for (i = 0; i < 2; i++) {
if (!(crtc_mask & (1 << i)))
continue;
nvkm_msec(device, 2000,
u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000));
if ( (tmp & 0x00010000))
break;
);
nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01);
nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i]);
}
return 0;
}
static void
nv40_ram_tidy(struct nvkm_ram *base)
{
}
static const struct nvkm_ram_func
nv40_ram_func = {
.calc = nv40_ram_calc,
.prog = nv40_ram_prog,
.tidy = nv40_ram_tidy,
};
int
nv40_ram_new_(struct nvkm_fb *fb, enum nvkm_ram_type type, u64 size,
struct nvkm_ram **pram)
{
struct nv40_ram *ram;
if (!(ram = kzalloc_obj(*ram)))
return -ENOMEM;
*pram = &ram->base;
return nvkm_ram_ctor(&nv40_ram_func, fb, type, size, &ram->base);
}
int
nv40_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_device *device = fb->subdev.device;
u32 pbus1218 = nvkm_rd32(device, 0x001218);
u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000;
enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN;
int ret;
switch (pbus1218 & 0x00000300) {
case 0x00000000: type = NVKM_RAM_TYPE_SDRAM; break;
case 0x00000100: type = NVKM_RAM_TYPE_DDR1 ; break;
case 0x00000200: type = NVKM_RAM_TYPE_GDDR3; break;
case 0x00000300: type = NVKM_RAM_TYPE_DDR2 ; break;
}
ret = nv40_ram_new_(fb, type, size, pram);
if (ret)
return ret;
(*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1;
return 0;
}
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NV40_FB_RAM_H__
#define __NV40_FB_RAM_H__
#define nv40_ram(p) container_of((p), struct nv40_ram, base)
#include "ram.h"
struct nv40_ram {
struct nvkm_ram base;
u32 ctrl;
u32 coef;
};
int nv40_ram_new_(struct nvkm_fb *fb, enum nvkm_ram_type, u64,
struct nvkm_ram **);
#endif
@@ -0,0 +1,48 @@
/*
* 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 "ramnv40.h"
int
nv41_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_device *device = fb->subdev.device;
u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000;
u32 fb474 = nvkm_rd32(device, 0x100474);
enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN;
int ret;
if (fb474 & 0x00000004)
type = NVKM_RAM_TYPE_GDDR3;
if (fb474 & 0x00000002)
type = NVKM_RAM_TYPE_DDR2;
if (fb474 & 0x00000001)
type = NVKM_RAM_TYPE_DDR1;
ret = nv40_ram_new_(fb, type, size, pram);
if (ret)
return ret;
(*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1;
return 0;
}
@@ -0,0 +1,42 @@
/*
* 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 "ramnv40.h"
int
nv44_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_device *device = fb->subdev.device;
u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000;
u32 fb474 = nvkm_rd32(device, 0x100474);
enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN;
if (fb474 & 0x00000004)
type = NVKM_RAM_TYPE_GDDR3;
if (fb474 & 0x00000002)
type = NVKM_RAM_TYPE_DDR2;
if (fb474 & 0x00000001)
type = NVKM_RAM_TYPE_DDR1;
return nv40_ram_new_(fb, type, size, pram);
}
@@ -0,0 +1,48 @@
/*
* 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 "ramnv40.h"
int
nv49_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_device *device = fb->subdev.device;
u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000;
u32 fb914 = nvkm_rd32(device, 0x100914);
enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN;
int ret;
switch (fb914 & 0x00000003) {
case 0x00000000: type = NVKM_RAM_TYPE_DDR1 ; break;
case 0x00000001: type = NVKM_RAM_TYPE_DDR2 ; break;
case 0x00000002: type = NVKM_RAM_TYPE_GDDR3; break;
case 0x00000003: break;
}
ret = nv40_ram_new_(fb, type, size, pram);
if (ret)
return ret;
(*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1;
return 0;
}
@@ -0,0 +1,33 @@
/*
* 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 "ram.h"
int
nv4e_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nvkm_device *device = fb->subdev.device;
u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000;
return nvkm_ram_new_(&nv04_ram_func, fb, NVKM_RAM_TYPE_UNKNOWN,
size, pram);
}
@@ -0,0 +1,641 @@
/*
* 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 nv50_ram(p) container_of((p), struct nv50_ram, base)
#include "ram.h"
#include "ramseq.h"
#include "nv50.h"
#include <core/option.h>
#include <subdev/bios.h>
#include <subdev/bios/perf.h>
#include <subdev/bios/pll.h>
#include <subdev/bios/rammap.h>
#include <subdev/bios/timing.h>
#include <subdev/clk/pll.h>
#include <subdev/gpio.h>
struct nv50_ramseq {
struct hwsq base;
struct hwsq_reg r_0x002504;
struct hwsq_reg r_0x004008;
struct hwsq_reg r_0x00400c;
struct hwsq_reg r_0x00c040;
struct hwsq_reg r_0x100200;
struct hwsq_reg r_0x100210;
struct hwsq_reg r_0x10021c;
struct hwsq_reg r_0x1002d0;
struct hwsq_reg r_0x1002d4;
struct hwsq_reg r_0x1002dc;
struct hwsq_reg r_0x10053c;
struct hwsq_reg r_0x1005a0;
struct hwsq_reg r_0x1005a4;
struct hwsq_reg r_0x100710;
struct hwsq_reg r_0x100714;
struct hwsq_reg r_0x100718;
struct hwsq_reg r_0x10071c;
struct hwsq_reg r_0x100da0;
struct hwsq_reg r_0x100e20;
struct hwsq_reg r_0x100e24;
struct hwsq_reg r_0x611200;
struct hwsq_reg r_timing[9];
struct hwsq_reg r_mr[4];
struct hwsq_reg r_gpio[4];
};
struct nv50_ram {
struct nvkm_ram base;
struct nv50_ramseq hwsq;
};
#define T(t) cfg->timing_10_##t
static int
nv50_ram_timing_calc(struct nv50_ram *ram, u32 *timing)
{
struct nvbios_ramcfg *cfg = &ram->base.target.bios;
struct nvkm_subdev *subdev = &ram->base.fb->subdev;
struct nvkm_device *device = subdev->device;
u32 cur2, cur4, cur7, cur8;
u8 unkt3b;
cur2 = nvkm_rd32(device, 0x100228);
cur4 = nvkm_rd32(device, 0x100230);
cur7 = nvkm_rd32(device, 0x10023c);
cur8 = nvkm_rd32(device, 0x100240);
switch ((!T(CWL)) * ram->base.type) {
case NVKM_RAM_TYPE_DDR2:
T(CWL) = T(CL) - 1;
break;
case NVKM_RAM_TYPE_GDDR3:
T(CWL) = ((cur2 & 0xff000000) >> 24) + 1;
break;
}
/* XXX: N=1 is not proper statistics */
if (device->chipset == 0xa0) {
unkt3b = 0x19 + ram->base.next->bios.rammap_00_16_40;
timing[6] = (0x2d + T(CL) - T(CWL) +
ram->base.next->bios.rammap_00_16_40) << 16 |
T(CWL) << 8 |
(0x2f + T(CL) - T(CWL));
} else {
unkt3b = 0x16;
timing[6] = (0x2b + T(CL) - T(CWL)) << 16 |
max_t(s8, T(CWL) - 2, 1) << 8 |
(0x2e + T(CL) - T(CWL));
}
timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC));
timing[1] = (T(WR) + 1 + T(CWL)) << 24 |
max_t(u8, T(18), 1) << 16 |
(T(WTR) + 1 + T(CWL)) << 8 |
(3 + T(CL) - T(CWL));
timing[2] = (T(CWL) - 1) << 24 |
(T(RRD) << 16) |
(T(RCDWR) << 8) |
T(RCDRD);
timing[3] = (unkt3b - 2 + T(CL)) << 24 |
unkt3b << 16 |
(T(CL) - 1) << 8 |
(T(CL) - 1);
timing[4] = (cur4 & 0xffff0000) |
T(13) << 8 |
T(13);
timing[5] = T(RFC) << 24 |
max_t(u8, T(RCDRD), T(RCDWR)) << 16 |
T(RP);
/* Timing 6 is already done above */
timing[7] = (cur7 & 0xff00ffff) | (T(CL) - 1) << 16;
timing[8] = (cur8 & 0xffffff00);
/* XXX: P.version == 1 only has DDR2 and GDDR3? */
if (ram->base.type == NVKM_RAM_TYPE_DDR2) {
timing[5] |= (T(CL) + 3) << 8;
timing[8] |= (T(CL) - 4);
} else
if (ram->base.type == NVKM_RAM_TYPE_GDDR3) {
timing[5] |= (T(CL) + 2) << 8;
timing[8] |= (T(CL) - 2);
}
nvkm_debug(subdev, " 220: %08x %08x %08x %08x\n",
timing[0], timing[1], timing[2], timing[3]);
nvkm_debug(subdev, " 230: %08x %08x %08x %08x\n",
timing[4], timing[5], timing[6], timing[7]);
nvkm_debug(subdev, " 240: %08x\n", timing[8]);
return 0;
}
static int
nv50_ram_timing_read(struct nv50_ram *ram, u32 *timing)
{
unsigned int i;
struct nvbios_ramcfg *cfg = &ram->base.target.bios;
struct nvkm_subdev *subdev = &ram->base.fb->subdev;
struct nvkm_device *device = subdev->device;
for (i = 0; i <= 8; i++)
timing[i] = nvkm_rd32(device, 0x100220 + (i * 4));
/* Derive the bare minimum for the MR calculation to succeed */
cfg->timing_ver = 0x10;
T(CL) = (timing[3] & 0xff) + 1;
switch (ram->base.type) {
case NVKM_RAM_TYPE_DDR2:
T(CWL) = T(CL) - 1;
break;
case NVKM_RAM_TYPE_GDDR3:
T(CWL) = ((timing[2] & 0xff000000) >> 24) + 1;
break;
default:
return -ENOSYS;
}
T(WR) = ((timing[1] >> 24) & 0xff) - 1 - T(CWL);
return 0;
}
#undef T
static void
nvkm_sddr2_dll_reset(struct nv50_ramseq *hwsq)
{
ram_mask(hwsq, mr[0], 0x100, 0x100);
ram_mask(hwsq, mr[0], 0x100, 0x000);
ram_nsec(hwsq, 24000);
}
static void
nv50_ram_gpio(struct nv50_ramseq *hwsq, u8 tag, u32 val)
{
struct nvkm_gpio *gpio = hwsq->base.subdev->device->gpio;
struct dcb_gpio_func func;
u32 reg, sh, gpio_val;
int ret;
if (nvkm_gpio_get(gpio, 0, tag, DCB_GPIO_UNUSED) != val) {
ret = nvkm_gpio_find(gpio, 0, tag, DCB_GPIO_UNUSED, &func);
if (ret)
return;
reg = func.line >> 3;
sh = (func.line & 0x7) << 2;
gpio_val = ram_rd32(hwsq, gpio[reg]);
if (gpio_val & (8 << sh))
val = !val;
if (!(func.log[1] & 1))
val = !val;
ram_mask(hwsq, gpio[reg], (0x3 << sh), ((val | 0x2) << sh));
ram_nsec(hwsq, 20000);
}
}
static int
nv50_ram_calc(struct nvkm_ram *base, u32 freq)
{
struct nv50_ram *ram = nv50_ram(base);
struct nv50_ramseq *hwsq = &ram->hwsq;
struct nvkm_subdev *subdev = &ram->base.fb->subdev;
struct nvkm_bios *bios = subdev->device->bios;
struct nvbios_perfE perfE;
struct nvbios_pll mpll;
struct nvkm_ram_data *next;
u8 ver, hdr, cnt, len, strap, size;
u32 data;
u32 r100da0, r004008, unk710, unk714, unk718, unk71c;
int N1, M1, N2, M2, P;
int ret, i;
u32 timing[9];
next = &ram->base.target;
next->freq = freq;
ram->base.next = next;
/* lookup closest matching performance table entry for frequency */
i = 0;
do {
data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt,
&size, &perfE);
if (!data || (ver < 0x25 || ver >= 0x40) ||
(size < 2)) {
nvkm_error(subdev, "invalid/missing perftab entry\n");
return -EINVAL;
}
} while (perfE.memory < freq);
nvbios_rammapEp_from_perf(bios, data, hdr, &next->bios);
/* locate specific data set for the attached memory */
strap = nvbios_ramcfg_index(subdev);
if (strap >= cnt) {
nvkm_error(subdev, "invalid ramcfg strap\n");
return -EINVAL;
}
data = nvbios_rammapSp_from_perf(bios, data + hdr, size, strap,
&next->bios);
if (!data) {
nvkm_error(subdev, "invalid/missing rammap entry ");
return -EINVAL;
}
/* lookup memory timings, if bios says they're present */
if (next->bios.ramcfg_timing != 0xff) {
data = nvbios_timingEp(bios, next->bios.ramcfg_timing,
&ver, &hdr, &cnt, &len, &next->bios);
if (!data || ver != 0x10 || hdr < 0x12) {
nvkm_error(subdev, "invalid/missing timing entry "
"%02x %04x %02x %02x\n",
strap, data, ver, hdr);
return -EINVAL;
}
nv50_ram_timing_calc(ram, timing);
} else {
nv50_ram_timing_read(ram, timing);
}
ret = ram_init(hwsq, subdev);
if (ret)
return ret;
/* Determine ram-specific MR values */
ram->base.mr[0] = ram_rd32(hwsq, mr[0]);
ram->base.mr[1] = ram_rd32(hwsq, mr[1]);
ram->base.mr[2] = ram_rd32(hwsq, mr[2]);
switch (ram->base.type) {
case NVKM_RAM_TYPE_GDDR3:
ret = nvkm_gddr3_calc(&ram->base);
break;
default:
ret = -ENOSYS;
break;
}
if (ret) {
nvkm_error(subdev, "Could not calculate MR\n");
return ret;
}
if (subdev->device->chipset <= 0x96 && !next->bios.ramcfg_00_03_02)
ram_mask(hwsq, 0x100710, 0x00000200, 0x00000000);
/* Always disable this bit during reclock */
ram_mask(hwsq, 0x100200, 0x00000800, 0x00000000);
ram_wait_vblank(hwsq);
ram_wr32(hwsq, 0x611200, 0x00003300);
ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */
ram_nsec(hwsq, 8000);
ram_setf(hwsq, 0x10, 0x00); /* disable fb */
ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
ram_nsec(hwsq, 2000);
if (next->bios.timing_10_ODT)
nv50_ram_gpio(hwsq, 0x2e, 1);
ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */
ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
ram_wr32(hwsq, 0x100210, 0x00000000); /* disable auto-refresh */
ram_wr32(hwsq, 0x1002dc, 0x00000001); /* enable self-refresh */
ret = nvbios_pll_parse(bios, 0x004008, &mpll);
mpll.vco2.max_freq = 0;
if (ret >= 0) {
ret = nv04_pll_calc(subdev, &mpll, freq,
&N1, &M1, &N2, &M2, &P);
if (ret <= 0)
ret = -EINVAL;
}
if (ret < 0)
return ret;
/* XXX: 750MHz seems rather arbitrary */
if (freq <= 750000) {
r100da0 = 0x00000010;
r004008 = 0x90000000;
} else {
r100da0 = 0x00000000;
r004008 = 0x80000000;
}
r004008 |= (mpll.bias_p << 19) | (P << 22) | (P << 16);
ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000);
/* XXX: Is rammap_00_16_40 the DLL bit we've seen in GT215? Why does
* it have a different rammap bit from DLLoff? */
ram_mask(hwsq, 0x004008, 0x00004200, 0x00000200 |
next->bios.rammap_00_16_40 << 14);
ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1);
ram_mask(hwsq, 0x004008, 0x91ff0000, r004008);
/* XXX: GDDR3 only? */
if (subdev->device->chipset >= 0x92)
ram_wr32(hwsq, 0x100da0, r100da0);
nv50_ram_gpio(hwsq, 0x18, !next->bios.ramcfg_FBVDDQ);
ram_nsec(hwsq, 64000); /*XXX*/
ram_nsec(hwsq, 32000); /*XXX*/
ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000);
ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */
ram_wr32(hwsq, 0x1002d4, 0x00000001); /* disable self-refresh */
ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */
ram_nsec(hwsq, 12000);
switch (ram->base.type) {
case NVKM_RAM_TYPE_DDR2:
ram_nuke(hwsq, mr[0]); /* force update */
ram_mask(hwsq, mr[0], 0x000, 0x000);
break;
case NVKM_RAM_TYPE_GDDR3:
ram_nuke(hwsq, mr[1]); /* force update */
ram_wr32(hwsq, mr[1], ram->base.mr[1]);
ram_nuke(hwsq, mr[0]); /* force update */
ram_wr32(hwsq, mr[0], ram->base.mr[0]);
break;
default:
break;
}
ram_mask(hwsq, timing[3], 0xffffffff, timing[3]);
ram_mask(hwsq, timing[1], 0xffffffff, timing[1]);
ram_mask(hwsq, timing[6], 0xffffffff, timing[6]);
ram_mask(hwsq, timing[7], 0xffffffff, timing[7]);
ram_mask(hwsq, timing[8], 0xffffffff, timing[8]);
ram_mask(hwsq, timing[0], 0xffffffff, timing[0]);
ram_mask(hwsq, timing[2], 0xffffffff, timing[2]);
ram_mask(hwsq, timing[4], 0xffffffff, timing[4]);
ram_mask(hwsq, timing[5], 0xffffffff, timing[5]);
if (!next->bios.ramcfg_00_03_02)
ram_mask(hwsq, 0x10021c, 0x00010000, 0x00000000);
ram_mask(hwsq, 0x100200, 0x00001000, !next->bios.ramcfg_00_04_02 << 12);
/* XXX: A lot of this could be "chipset"/"ram type" specific stuff */
unk710 = ram_rd32(hwsq, 0x100710) & ~0x00000100;
unk714 = ram_rd32(hwsq, 0x100714) & ~0xf0000020;
unk718 = ram_rd32(hwsq, 0x100718) & ~0x00000100;
unk71c = ram_rd32(hwsq, 0x10071c) & ~0x00000100;
if (subdev->device->chipset <= 0x96) {
unk710 &= ~0x0000006e;
unk714 &= ~0x00000100;
if (!next->bios.ramcfg_00_03_08)
unk710 |= 0x00000060;
if (!next->bios.ramcfg_FBVDDQ)
unk714 |= 0x00000100;
if ( next->bios.ramcfg_00_04_04)
unk710 |= 0x0000000e;
} else {
unk710 &= ~0x00000001;
if (!next->bios.ramcfg_00_03_08)
unk710 |= 0x00000001;
}
if ( next->bios.ramcfg_00_03_01)
unk71c |= 0x00000100;
if ( next->bios.ramcfg_00_03_02)
unk710 |= 0x00000100;
if (!next->bios.ramcfg_00_03_08)
unk714 |= 0x00000020;
if ( next->bios.ramcfg_00_04_04)
unk714 |= 0x70000000;
if ( next->bios.ramcfg_00_04_20)
unk718 |= 0x00000100;
ram_mask(hwsq, 0x100714, 0xffffffff, unk714);
ram_mask(hwsq, 0x10071c, 0xffffffff, unk71c);
ram_mask(hwsq, 0x100718, 0xffffffff, unk718);
ram_mask(hwsq, 0x100710, 0xffffffff, unk710);
/* XXX: G94 does not even test these regs in trace. Harmless we do it,
* but why is it omitted? */
if (next->bios.rammap_00_16_20) {
ram_wr32(hwsq, 0x1005a0, next->bios.ramcfg_00_07 << 16 |
next->bios.ramcfg_00_06 << 8 |
next->bios.ramcfg_00_05);
ram_wr32(hwsq, 0x1005a4, next->bios.ramcfg_00_09 << 8 |
next->bios.ramcfg_00_08);
ram_mask(hwsq, 0x10053c, 0x00001000, 0x00000000);
} else {
ram_mask(hwsq, 0x10053c, 0x00001000, 0x00001000);
}
ram_mask(hwsq, mr[1], 0xffffffff, ram->base.mr[1]);
if (!next->bios.timing_10_ODT)
nv50_ram_gpio(hwsq, 0x2e, 0);
/* Reset DLL */
if (!next->bios.ramcfg_DLLoff)
nvkm_sddr2_dll_reset(hwsq);
ram_setf(hwsq, 0x10, 0x01); /* enable fb */
ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
ram_wr32(hwsq, 0x611200, 0x00003330);
ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */
if (next->bios.rammap_00_17_02)
ram_mask(hwsq, 0x100200, 0x00000800, 0x00000800);
if (!next->bios.rammap_00_16_40)
ram_mask(hwsq, 0x004008, 0x00004000, 0x00000000);
if (next->bios.ramcfg_00_03_02)
ram_mask(hwsq, 0x10021c, 0x00010000, 0x00010000);
if (subdev->device->chipset <= 0x96 && next->bios.ramcfg_00_03_02)
ram_mask(hwsq, 0x100710, 0x00000200, 0x00000200);
return 0;
}
static int
nv50_ram_prog(struct nvkm_ram *base)
{
struct nv50_ram *ram = nv50_ram(base);
struct nvkm_device *device = ram->base.fb->subdev.device;
ram_exec(&ram->hwsq, nvkm_boolopt(device->cfgopt, "NvMemExec", true));
return 0;
}
static void
nv50_ram_tidy(struct nvkm_ram *base)
{
struct nv50_ram *ram = nv50_ram(base);
ram_exec(&ram->hwsq, false);
}
static const struct nvkm_ram_func
nv50_ram_func = {
.calc = nv50_ram_calc,
.prog = nv50_ram_prog,
.tidy = nv50_ram_tidy,
};
static u32
nv50_fb_vram_rblock(struct nvkm_ram *ram)
{
struct nvkm_subdev *subdev = &ram->fb->subdev;
struct nvkm_device *device = subdev->device;
int colbits, rowbitsa, rowbitsb, banks;
u64 rowsize, predicted;
u32 r0, r4, rt, rblock_size;
r0 = nvkm_rd32(device, 0x100200);
r4 = nvkm_rd32(device, 0x100204);
rt = nvkm_rd32(device, 0x100250);
nvkm_debug(subdev, "memcfg %08x %08x %08x %08x\n",
r0, r4, rt, nvkm_rd32(device, 0x001540));
colbits = (r4 & 0x0000f000) >> 12;
rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
rowsize = ram->parts * banks * (1 << colbits) * 8;
predicted = rowsize << rowbitsa;
if (r0 & 0x00000004)
predicted += rowsize << rowbitsb;
if (predicted != ram->size) {
nvkm_warn(subdev, "memory controller reports %d MiB VRAM\n",
(u32)(ram->size >> 20));
}
rblock_size = rowsize;
if (rt & 1)
rblock_size *= 3;
nvkm_debug(subdev, "rblock %d bytes\n", rblock_size);
return rblock_size;
}
int
nv50_ram_ctor(const struct nvkm_ram_func *func,
struct nvkm_fb *fb, struct nvkm_ram *ram)
{
struct nvkm_device *device = fb->subdev.device;
struct nvkm_bios *bios = device->bios;
const u32 rsvd_head = ( 256 * 1024); /* vga memory */
const u32 rsvd_tail = (1024 * 1024); /* vbios etc */
u64 size = nvkm_rd32(device, 0x10020c);
enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN;
int ret;
switch (nvkm_rd32(device, 0x100714) & 0x00000007) {
case 0: type = NVKM_RAM_TYPE_DDR1; break;
case 1:
if (nvkm_fb_bios_memtype(bios) == NVKM_RAM_TYPE_DDR3)
type = NVKM_RAM_TYPE_DDR3;
else
type = NVKM_RAM_TYPE_DDR2;
break;
case 2: type = NVKM_RAM_TYPE_GDDR3; break;
case 3: type = NVKM_RAM_TYPE_GDDR4; break;
case 4: type = NVKM_RAM_TYPE_GDDR5; break;
default:
break;
}
size = (size & 0x000000ff) << 32 | (size & 0xffffff00);
ret = nvkm_ram_ctor(func, fb, type, size, ram);
if (ret)
return ret;
ram->part_mask = (nvkm_rd32(device, 0x001540) & 0x00ff0000) >> 16;
ram->parts = hweight8(ram->part_mask);
ram->ranks = (nvkm_rd32(device, 0x100200) & 0x4) ? 2 : 1;
nvkm_mm_fini(&ram->vram);
return nvkm_mm_init(&ram->vram, NVKM_RAM_MM_NORMAL,
rsvd_head >> NVKM_RAM_MM_SHIFT,
(size - rsvd_head - rsvd_tail) >> NVKM_RAM_MM_SHIFT,
nv50_fb_vram_rblock(ram) >> NVKM_RAM_MM_SHIFT);
}
int
nv50_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{
struct nv50_ram *ram;
int ret, i;
if (!(ram = kzalloc_obj(*ram)))
return -ENOMEM;
*pram = &ram->base;
ret = nv50_ram_ctor(&nv50_ram_func, fb, &ram->base);
if (ret)
return ret;
ram->hwsq.r_0x002504 = hwsq_reg(0x002504);
ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040);
ram->hwsq.r_0x004008 = hwsq_reg(0x004008);
ram->hwsq.r_0x00400c = hwsq_reg(0x00400c);
ram->hwsq.r_0x100200 = hwsq_reg(0x100200);
ram->hwsq.r_0x100210 = hwsq_reg(0x100210);
ram->hwsq.r_0x10021c = hwsq_reg(0x10021c);
ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0);
ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4);
ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc);
ram->hwsq.r_0x10053c = hwsq_reg(0x10053c);
ram->hwsq.r_0x1005a0 = hwsq_reg(0x1005a0);
ram->hwsq.r_0x1005a4 = hwsq_reg(0x1005a4);
ram->hwsq.r_0x100710 = hwsq_reg(0x100710);
ram->hwsq.r_0x100714 = hwsq_reg(0x100714);
ram->hwsq.r_0x100718 = hwsq_reg(0x100718);
ram->hwsq.r_0x10071c = hwsq_reg(0x10071c);
ram->hwsq.r_0x100da0 = hwsq_stride(0x100da0, 4, ram->base.part_mask);
ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20);
ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24);
ram->hwsq.r_0x611200 = hwsq_reg(0x611200);
for (i = 0; i < 9; i++)
ram->hwsq.r_timing[i] = hwsq_reg(0x100220 + (i * 0x04));
if (ram->base.ranks > 1) {
ram->hwsq.r_mr[0] = hwsq_reg2(0x1002c0, 0x1002c8);
ram->hwsq.r_mr[1] = hwsq_reg2(0x1002c4, 0x1002cc);
ram->hwsq.r_mr[2] = hwsq_reg2(0x1002e0, 0x1002e8);
ram->hwsq.r_mr[3] = hwsq_reg2(0x1002e4, 0x1002ec);
} else {
ram->hwsq.r_mr[0] = hwsq_reg(0x1002c0);
ram->hwsq.r_mr[1] = hwsq_reg(0x1002c4);
ram->hwsq.r_mr[2] = hwsq_reg(0x1002e0);
ram->hwsq.r_mr[3] = hwsq_reg(0x1002e4);
}
ram->hwsq.r_gpio[0] = hwsq_reg(0x00e104);
ram->hwsq.r_gpio[1] = hwsq_reg(0x00e108);
ram->hwsq.r_gpio[2] = hwsq_reg(0x00e120);
ram->hwsq.r_gpio[3] = hwsq_reg(0x00e124);
return 0;
}
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_FBRAM_SEQ_H__
#define __NVKM_FBRAM_SEQ_H__
#include <subdev/bus/hwsq.h>
#define ram_init(s,p) hwsq_init(&(s)->base, (p))
#define ram_exec(s,e) hwsq_exec(&(s)->base, (e))
#define ram_have(s,r) ((s)->r_##r.addr != 0x000000)
#define ram_rd32(s,r) hwsq_rd32(&(s)->base, &(s)->r_##r)
#define ram_wr32(s,r,d) hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
#define ram_nuke(s,r) hwsq_nuke(&(s)->base, &(s)->r_##r)
#define ram_mask(s,r,m,d) hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
#define ram_setf(s,f,d) hwsq_setf(&(s)->base, (f), (d))
#define ram_wait(s,f,d) hwsq_wait(&(s)->base, (f), (d))
#define ram_wait_vblank(s) hwsq_wait_vblank(&(s)->base)
#define ram_nsec(s,n) hwsq_nsec(&(s)->base, (n))
#endif
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_FB_REGS_04_H__
#define __NVKM_FB_REGS_04_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
#endif
@@ -0,0 +1,100 @@
/*
* Copyright 2014 Roy Spliet
*
* 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: Roy Spliet <rspliet@eclipso.eu>
* Ben Skeggs
*/
#include "priv.h"
#include "ram.h"
struct ramxlat {
int id;
u8 enc;
};
static inline int
ramxlat(const struct ramxlat *xlat, int id)
{
while (xlat->id >= 0) {
if (xlat->id == id)
return xlat->enc;
xlat++;
}
return -EINVAL;
}
static const struct ramxlat
ramddr2_cl[] = {
{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 },
/* The following are available in some, but not all DDR2 docs */
{ 7, 7 },
{ -1 }
};
static const struct ramxlat
ramddr2_wr[] = {
{ 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 },
/* The following are available in some, but not all DDR2 docs */
{ 7, 6 },
{ -1 }
};
int
nvkm_sddr2_calc(struct nvkm_ram *ram)
{
int CL, WR, DLL = 0, ODT = 0;
switch (ram->next->bios.timing_ver) {
case 0x10:
CL = ram->next->bios.timing_10_CL;
WR = ram->next->bios.timing_10_WR;
DLL = !ram->next->bios.ramcfg_DLLoff;
ODT = ram->next->bios.timing_10_ODT & 3;
break;
case 0x20:
CL = (ram->next->bios.timing[1] & 0x0000001f);
WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
break;
default:
return -ENOSYS;
}
if (ram->next->bios.timing_ver == 0x20 ||
ram->next->bios.ramcfg_timing == 0xff) {
ODT = (ram->mr[1] & 0x004) >> 2 |
(ram->mr[1] & 0x040) >> 5;
}
CL = ramxlat(ramddr2_cl, CL);
WR = ramxlat(ramddr2_wr, WR);
if (CL < 0 || WR < 0)
return -EINVAL;
ram->mr[0] &= ~0xf70;
ram->mr[0] |= (WR & 0x07) << 9;
ram->mr[0] |= (CL & 0x07) << 4;
ram->mr[1] &= ~0x045;
ram->mr[1] |= (ODT & 0x1) << 2;
ram->mr[1] |= (ODT & 0x2) << 5;
ram->mr[1] |= !DLL;
return 0;
}
@@ -0,0 +1,120 @@
/*
* 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 <bskeggs@redhat.com>
* Roy Spliet <rspliet@eclipso.eu>
*/
#include "priv.h"
#include "ram.h"
struct ramxlat {
int id;
u8 enc;
};
static inline int
ramxlat(const struct ramxlat *xlat, int id)
{
while (xlat->id >= 0) {
if (xlat->id == id)
return xlat->enc;
xlat++;
}
return -EINVAL;
}
static const struct ramxlat
ramddr3_cl[] = {
{ 5, 2 }, { 6, 4 }, { 7, 6 }, { 8, 8 }, { 9, 10 }, { 10, 12 },
{ 11, 14 },
/* the below are mentioned in some, but not all, ddr3 docs */
{ 12, 1 }, { 13, 3 }, { 14, 5 },
{ -1 }
};
static const struct ramxlat
ramddr3_wr[] = {
{ 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 },
/* the below are mentioned in some, but not all, ddr3 docs */
{ 14, 7 }, { 15, 7 }, { 16, 0 },
{ -1 }
};
static const struct ramxlat
ramddr3_cwl[] = {
{ 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 },
/* the below are mentioned in some, but not all, ddr3 docs */
{ 9, 4 }, { 10, 5 },
{ -1 }
};
int
nvkm_sddr3_calc(struct nvkm_ram *ram)
{
int CWL, CL, WR, DLL = 0, ODT = 0;
DLL = !ram->next->bios.ramcfg_DLLoff;
switch (ram->next->bios.timing_ver) {
case 0x10:
if (ram->next->bios.timing_hdr < 0x17) {
/* XXX: NV50: Get CWL from the timing register */
return -ENOSYS;
}
CWL = ram->next->bios.timing_10_CWL;
CL = ram->next->bios.timing_10_CL;
WR = ram->next->bios.timing_10_WR;
ODT = ram->next->bios.timing_10_ODT;
break;
case 0x20:
CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
/* XXX: Get these values from the VBIOS instead */
ODT = (ram->mr[1] & 0x004) >> 2 |
(ram->mr[1] & 0x040) >> 5 |
(ram->mr[1] & 0x200) >> 7;
break;
default:
return -ENOSYS;
}
CWL = ramxlat(ramddr3_cwl, CWL);
CL = ramxlat(ramddr3_cl, CL);
WR = ramxlat(ramddr3_wr, WR);
if (CL < 0 || CWL < 0 || WR < 0)
return -EINVAL;
ram->mr[0] &= ~0xf74;
ram->mr[0] |= (WR & 0x07) << 9;
ram->mr[0] |= (CL & 0x0e) << 3;
ram->mr[0] |= (CL & 0x01) << 2;
ram->mr[1] &= ~0x245;
ram->mr[1] |= (ODT & 0x1) << 2;
ram->mr[1] |= (ODT & 0x2) << 5;
ram->mr[1] |= (ODT & 0x4) << 7;
ram->mr[1] |= !DLL;
ram->mr[2] &= ~0x038;
ram->mr[2] |= (CWL & 0x07) << 3;
return 0;
}
@@ -0,0 +1,61 @@
/*
* Copyright 2018 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.
*/
#include "gf100.h"
#include "ram.h"
#include <subdev/gsp.h>
bool
tu102_fb_vpr_scrub_required(struct nvkm_fb *fb)
{
return (nvkm_rd32(fb->subdev.device, 0x1fa80c) & 0x00000010) != 0;
}
static const struct nvkm_fb_func
tu102_fb = {
.dtor = gf100_fb_dtor,
.oneinit = gp102_fb_oneinit,
.init = gm200_fb_init,
.init_page = gv100_fb_init_page,
.init_unkn = gp100_fb_init_unkn,
.sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
.vidmem.size = gp102_fb_vidmem_size,
.vpr.scrub_required = tu102_fb_vpr_scrub_required,
.vpr.scrub = gp102_fb_vpr_scrub,
.ram_new = gp102_ram_new,
.default_bigpage = 16,
};
int
tu102_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
{
if (nvkm_gsp_rm(device->gsp))
return r535_fb_new(&tu102_fb, device, type, inst, pfb);
return gf100_fb_new_(&tu102_fb, device, type, inst, pfb);
}
MODULE_FIRMWARE("nvidia/tu102/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/tu104/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/tu106/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/tu116/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/tu117/nvdec/scrubber.bin");