Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nvc0.c
Go to the documentation of this file.
1 /*
2  * Copyright 2012 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 
25 #include <subdev/fb.h>
26 #include <subdev/bios.h>
27 
28 struct nvc0_fb_priv {
29  struct nouveau_fb base;
30  struct page *r100c10_page;
32 };
33 
34 /* 0 = unsupported
35  * 1 = non-compressed
36  * 3 = compressed
37  */
38 static const u8 types[256] = {
39  1, 1, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0,
40  0, 1, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0,
41  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
42  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3,
43  3, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
44  0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
46  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
47  0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 1, 1, 1, 1, 0,
48  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49  0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0,
50  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
51  3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3,
52  3, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 3,
53  3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0,
54  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0
55 };
56 
57 static bool
58 nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
59 {
60  u8 memtype = (tile_flags & 0x0000ff00) >> 8;
61  return likely((types[memtype] == 1));
62 }
63 
64 static int
65 nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
66  u32 memtype, struct nouveau_mem **pmem)
67 {
68  struct nouveau_mm *mm = &pfb->vram;
69  struct nouveau_mm_node *r;
70  struct nouveau_mem *mem;
71  int type = (memtype & 0x0ff);
72  int back = (memtype & 0x800);
73  int ret;
74 
75  size >>= 12;
76  align >>= 12;
77  ncmin >>= 12;
78  if (!ncmin)
79  ncmin = size;
80 
81  mem = kzalloc(sizeof(*mem), GFP_KERNEL);
82  if (!mem)
83  return -ENOMEM;
84 
85  INIT_LIST_HEAD(&mem->regions);
86  mem->memtype = type;
87  mem->size = size;
88 
89  mutex_lock(&mm->mutex);
90  do {
91  if (back)
92  ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
93  else
94  ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
95  if (ret) {
96  mutex_unlock(&mm->mutex);
97  pfb->ram.put(pfb, &mem);
98  return ret;
99  }
100 
101  list_add_tail(&r->rl_entry, &mem->regions);
102  size -= r->length;
103  } while (size);
104  mutex_unlock(&mm->mutex);
105 
106  r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
107  mem->offset = (u64)r->offset << 12;
108  *pmem = mem;
109  return 0;
110 }
111 
112 static int
113 nvc0_fb_init(struct nouveau_object *object)
114 {
115  struct nvc0_fb_priv *priv = (void *)object;
116  int ret;
117 
118  ret = nouveau_fb_init(&priv->base);
119  if (ret)
120  return ret;
121 
122  nv_wr32(priv, 0x100c10, priv->r100c10 >> 8);
123  return 0;
124 }
125 
126 static void
127 nvc0_fb_dtor(struct nouveau_object *object)
128 {
129  struct nouveau_device *device = nv_device(object);
130  struct nvc0_fb_priv *priv = (void *)object;
131 
132  if (priv->r100c10_page) {
133  pci_unmap_page(device->pdev, priv->r100c10, PAGE_SIZE,
135  __free_page(priv->r100c10_page);
136  }
137 
138  nouveau_fb_destroy(&priv->base);
139 }
140 
141 static int
142 nvc0_vram_detect(struct nvc0_fb_priv *priv)
143 {
144  struct nouveau_bios *bios = nouveau_bios(priv);
145  struct nouveau_fb *pfb = &priv->base;
146  const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
147  const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
148  u32 parts = nv_rd32(priv, 0x022438);
149  u32 pmask = nv_rd32(priv, 0x022554);
150  u32 bsize = nv_rd32(priv, 0x10f20c);
151  u32 offset, length;
152  bool uniform = true;
153  int ret, part;
154 
155  nv_debug(priv, "0x100800: 0x%08x\n", nv_rd32(priv, 0x100800));
156  nv_debug(priv, "parts 0x%08x mask 0x%08x\n", parts, pmask);
157 
158  priv->base.ram.type = nouveau_fb_bios_memtype(bios);
159  priv->base.ram.ranks = (nv_rd32(priv, 0x10f200) & 0x00000004) ? 2 : 1;
160 
161  /* read amount of vram attached to each memory controller */
162  for (part = 0; part < parts; part++) {
163  if (!(pmask & (1 << part))) {
164  u32 psize = nv_rd32(priv, 0x11020c + (part * 0x1000));
165  if (psize != bsize) {
166  if (psize < bsize)
167  bsize = psize;
168  uniform = false;
169  }
170 
171  nv_debug(priv, "%d: mem_amount 0x%08x\n", part, psize);
172  priv->base.ram.size += (u64)psize << 20;
173  }
174  }
175 
176  /* if all controllers have the same amount attached, there's no holes */
177  if (uniform) {
178  offset = rsvd_head;
179  length = (priv->base.ram.size >> 12) - rsvd_head - rsvd_tail;
180  return nouveau_mm_init(&pfb->vram, offset, length, 1);
181  }
182 
183  /* otherwise, address lowest common amount from 0GiB */
184  ret = nouveau_mm_init(&pfb->vram, rsvd_head, (bsize << 8) * parts, 1);
185  if (ret)
186  return ret;
187 
188  /* and the rest starting from (8GiB + common_size) */
189  offset = (0x0200000000ULL >> 12) + (bsize << 8);
190  length = (priv->base.ram.size >> 12) - (bsize << 8) - rsvd_tail;
191 
192  ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
193  if (ret) {
194  nouveau_mm_fini(&pfb->vram);
195  return ret;
196  }
197 
198  return 0;
199 }
200 
201 static int
202 nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
203  struct nouveau_oclass *oclass, void *data, u32 size,
204  struct nouveau_object **pobject)
205 {
206  struct nouveau_device *device = nv_device(parent);
207  struct nvc0_fb_priv *priv;
208  int ret;
209 
210  ret = nouveau_fb_create(parent, engine, oclass, &priv);
211  *pobject = nv_object(priv);
212  if (ret)
213  return ret;
214 
215  priv->base.memtype_valid = nvc0_fb_memtype_valid;
216  priv->base.ram.get = nvc0_fb_vram_new;
217  priv->base.ram.put = nv50_fb_vram_del;
218 
219  ret = nvc0_vram_detect(priv);
220  if (ret)
221  return ret;
222 
224  if (!priv->r100c10_page)
225  return -ENOMEM;
226 
227  priv->r100c10 = pci_map_page(device->pdev, priv->r100c10_page, 0,
229  if (pci_dma_mapping_error(device->pdev, priv->r100c10))
230  return -EFAULT;
231 
232  return nouveau_fb_created(&priv->base);
233 }
234 
235 
236 struct nouveau_oclass
238  .handle = NV_SUBDEV(FB, 0xc0),
239  .ofuncs = &(struct nouveau_ofuncs) {
240  .ctor = nvc0_fb_ctor,
241  .dtor = nvc0_fb_dtor,
242  .init = nvc0_fb_init,
243  .fini = _nouveau_fb_fini,
244  },
245 };