blob: 4d62a1d957822deb452a0ecd3e43620a879ba258 [file] [log] [blame]
Ben Skeggs8984e042010-11-15 11:48:33 +10001/*
2 * Copyright 2010 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
David Howells760285e2012-10-02 18:01:07 +010025#include <drm/drmP.h>
Ben Skeggs8984e042010-11-15 11:48:33 +100026#include "nouveau_drv.h"
27#include "nouveau_mm.h"
28
Ben Skeggsb5e2f072011-02-14 07:34:55 +100029/* 0 = unsupported
30 * 1 = non-compressed
31 * 3 = compressed
32 */
33static const u8 types[256] = {
34 1, 1, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0,
35 0, 1, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0,
36 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
37 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3,
38 3, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
42 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 1, 1, 1, 1, 0,
43 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
44 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0,
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
Christoph Bumiller12b6d9d2011-10-07 18:10:45 +020046 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3,
Ben Skeggsb5e2f072011-02-14 07:34:55 +100047 3, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 3,
48 3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0,
49 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0
50};
51
Ben Skeggs8984e042010-11-15 11:48:33 +100052bool
53nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags)
54{
Ben Skeggsb5e2f072011-02-14 07:34:55 +100055 u8 memtype = (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) >> 8;
56 return likely((types[memtype] == 1));
Ben Skeggs8984e042010-11-15 11:48:33 +100057}
58
59int
60nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin,
Ben Skeggsd5f42392011-02-10 12:22:52 +100061 u32 type, struct nouveau_mem **pmem)
Ben Skeggs8984e042010-11-15 11:48:33 +100062{
63 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs987eec12011-06-24 10:14:07 +100064 struct nouveau_mm *mm = &dev_priv->engine.vram.mm;
Ben Skeggs8984e042010-11-15 11:48:33 +100065 struct nouveau_mm_node *r;
Ben Skeggsd5f42392011-02-10 12:22:52 +100066 struct nouveau_mem *mem;
Ben Skeggs8984e042010-11-15 11:48:33 +100067 int ret;
68
69 size >>= 12;
70 align >>= 12;
71 ncmin >>= 12;
72
Ben Skeggsd5f42392011-02-10 12:22:52 +100073 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
74 if (!mem)
Ben Skeggs8984e042010-11-15 11:48:33 +100075 return -ENOMEM;
76
Ben Skeggsd5f42392011-02-10 12:22:52 +100077 INIT_LIST_HEAD(&mem->regions);
78 mem->dev = dev_priv->dev;
Ben Skeggs8f7286f2011-02-14 09:57:35 +100079 mem->memtype = (type & 0xff);
Ben Skeggsd5f42392011-02-10 12:22:52 +100080 mem->size = size;
Ben Skeggs8984e042010-11-15 11:48:33 +100081
82 mutex_lock(&mm->mutex);
83 do {
84 ret = nouveau_mm_get(mm, 1, size, ncmin, align, &r);
85 if (ret) {
86 mutex_unlock(&mm->mutex);
Ben Skeggsd5f42392011-02-10 12:22:52 +100087 nv50_vram_del(dev, &mem);
Ben Skeggs8984e042010-11-15 11:48:33 +100088 return ret;
89 }
90
Ben Skeggsd5f42392011-02-10 12:22:52 +100091 list_add_tail(&r->rl_entry, &mem->regions);
Ben Skeggs8984e042010-11-15 11:48:33 +100092 size -= r->length;
93 } while (size);
94 mutex_unlock(&mm->mutex);
95
Ben Skeggsd5f42392011-02-10 12:22:52 +100096 r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
97 mem->offset = (u64)r->offset << 12;
98 *pmem = mem;
Ben Skeggs8984e042010-11-15 11:48:33 +100099 return 0;
100}
101
102int
103nvc0_vram_init(struct drm_device *dev)
104{
105 struct drm_nouveau_private *dev_priv = dev->dev_private;
Ben Skeggs24f246a2011-06-10 13:36:08 +1000106 struct nouveau_vram_engine *vram = &dev_priv->engine.vram;
107 const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
108 const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
Ben Skeggs29181d22012-03-04 15:44:59 +1000109 u32 parts = nv_rd32(dev, 0x022438);
110 u32 pmask = nv_rd32(dev, 0x022554);
Ben Skeggsaa650092011-06-24 12:47:46 +1000111 u32 bsize = nv_rd32(dev, 0x10f20c);
112 u32 offset, length;
113 bool uniform = true;
Ben Skeggsd4547ed2011-10-27 11:26:17 +1000114 int ret, part;
Ben Skeggs8984e042010-11-15 11:48:33 +1000115
Ben Skeggsaa650092011-06-24 12:47:46 +1000116 NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800));
Ben Skeggs29181d22012-03-04 15:44:59 +1000117 NV_DEBUG(dev, "parts 0x%08x mask 0x%08x\n", parts, pmask);
Ben Skeggs24f246a2011-06-10 13:36:08 +1000118
Ben Skeggsf3298532011-12-13 12:46:18 +1000119 dev_priv->vram_type = nouveau_mem_vbios_type(dev);
Ben Skeggs950c44b2012-02-01 09:05:42 +1000120 dev_priv->vram_rank_B = !!(nv_rd32(dev, 0x10f200) & 0x00000004);
Ben Skeggsf3298532011-12-13 12:46:18 +1000121
Ben Skeggsaa650092011-06-24 12:47:46 +1000122 /* read amount of vram attached to each memory controller */
Ben Skeggs29181d22012-03-04 15:44:59 +1000123 for (part = 0; part < parts; part++) {
124 if (!(pmask & (1 << part))) {
125 u32 psize = nv_rd32(dev, 0x11020c + (part * 0x1000));
126 if (psize != bsize) {
127 if (psize < bsize)
128 bsize = psize;
129 uniform = false;
130 }
Ben Skeggsd4547ed2011-10-27 11:26:17 +1000131
Ben Skeggs29181d22012-03-04 15:44:59 +1000132 NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", part, psize);
133 dev_priv->vram_size += (u64)psize << 20;
Ben Skeggsaa650092011-06-24 12:47:46 +1000134 }
Ben Skeggsaa650092011-06-24 12:47:46 +1000135 }
136
137 /* if all controllers have the same amount attached, there's no holes */
138 if (uniform) {
139 offset = rsvd_head;
140 length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail;
141 return nouveau_mm_init(&vram->mm, offset, length, 1);
142 }
143
144 /* otherwise, address lowest common amount from 0GiB */
145 ret = nouveau_mm_init(&vram->mm, rsvd_head, (bsize << 8) * parts, 1);
146 if (ret)
147 return ret;
148
149 /* and the rest starting from (8GiB + common_size) */
150 offset = (0x0200000000ULL >> 12) + (bsize << 8);
151 length = (dev_priv->vram_size >> 12) - (bsize << 8) - rsvd_tail;
152
153 ret = nouveau_mm_init(&vram->mm, offset, length, 0);
154 if (ret) {
155 nouveau_mm_fini(&vram->mm);
156 return ret;
157 }
158
159 return 0;
Ben Skeggs8984e042010-11-15 11:48:33 +1000160}