blob: 84aa71c471280539588f9a0d8f780f9e92de8537 [file] [log] [blame]
Ben Skeggs861d2102012-07-11 19:05:01 +10001/*
2 * Copyright (C) 2010 Francisco Jerez.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
Ben Skeggs6ee73862009-12-11 19:24:15 +100026
Ben Skeggs861d2102012-07-11 19:05:01 +100027#include <subdev/fb.h>
28
29struct nv40_fb_priv {
30 struct nouveau_fb base;
31};
32
33static inline int
34nv44_graph_class(struct nouveau_device *device)
Francisco Jerez0d87c102009-12-16 12:12:27 +010035{
Ben Skeggs861d2102012-07-11 19:05:01 +100036 if ((device->chipset & 0xf0) == 0x60)
37 return 1;
Francisco Jerez0d87c102009-12-16 12:12:27 +010038
Ben Skeggs861d2102012-07-11 19:05:01 +100039 return !(0x0baf & (1 << (device->chipset & 0x0f)));
Francisco Jerez0d87c102009-12-16 12:12:27 +010040}
41
Ben Skeggs79487582011-01-11 14:52:40 +100042static void
Ben Skeggs861d2102012-07-11 19:05:01 +100043nv40_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
Ben Skeggs79487582011-01-11 14:52:40 +100044{
Ben Skeggs861d2102012-07-11 19:05:01 +100045 nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
46 nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
47 nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
48}
Ben Skeggs79487582011-01-11 14:52:40 +100049
Ben Skeggs861d2102012-07-11 19:05:01 +100050static void
51nv40_fb_init_gart(struct nv40_fb_priv *priv)
52{
53#if 0
54 struct nouveau_gpuobj *gart = ndev->gart_info.sg_ctxdma;
55
56 if (ndev->gart_info.type != NOUVEAU_GART_HW) {
57#endif
58 nv_wr32(priv, 0x100800, 0x00000001);
59#if 0
Ben Skeggs79487582011-01-11 14:52:40 +100060 return;
61 }
62
Ben Skeggs861d2102012-07-11 19:05:01 +100063 nv_wr32(ndev, 0x100800, gart->pinst | 0x00000002);
64 nv_mask(ndev, 0x10008c, 0x00000100, 0x00000100);
65 nv_wr32(ndev, 0x100820, 0x00000000);
66#endif
Ben Skeggs79487582011-01-11 14:52:40 +100067}
68
69static void
Ben Skeggs861d2102012-07-11 19:05:01 +100070nv44_fb_init_gart(struct nv40_fb_priv *priv)
Ben Skeggs79487582011-01-11 14:52:40 +100071{
Ben Skeggs861d2102012-07-11 19:05:01 +100072#if 0
73 struct nouveau_gpuobj *gart = ndev->gart_info.sg_ctxdma;
Ben Skeggs79487582011-01-11 14:52:40 +100074 u32 vinst;
75
Ben Skeggs861d2102012-07-11 19:05:01 +100076 if (ndev->gart_info.type != NOUVEAU_GART_HW) {
77#endif
78 nv_wr32(priv, 0x100850, 0x80000000);
79 nv_wr32(priv, 0x100800, 0x00000001);
80#if 0
Ben Skeggs79487582011-01-11 14:52:40 +100081 return;
82 }
83
84 /* calculate vram address of this PRAMIN block, object
85 * must be allocated on 512KiB alignment, and not exceed
86 * a total size of 512KiB for this to work correctly
87 */
Ben Skeggs861d2102012-07-11 19:05:01 +100088 vinst = nv_rd32(ndev, 0x10020c);
Ben Skeggs79487582011-01-11 14:52:40 +100089 vinst -= ((gart->pinst >> 19) + 1) << 19;
90
Ben Skeggs861d2102012-07-11 19:05:01 +100091 nv_wr32(ndev, 0x100850, 0x80000000);
92 nv_wr32(ndev, 0x100818, ndev->gart_info.dummy.addr);
Ben Skeggs79487582011-01-11 14:52:40 +100093
Ben Skeggs861d2102012-07-11 19:05:01 +100094 nv_wr32(ndev, 0x100804, ndev->gart_info.aper_size);
95 nv_wr32(ndev, 0x100850, 0x00008000);
96 nv_mask(ndev, 0x10008c, 0x00000200, 0x00000200);
97 nv_wr32(ndev, 0x100820, 0x00000000);
98 nv_wr32(ndev, 0x10082c, 0x00000001);
99 nv_wr32(ndev, 0x100800, vinst | 0x00000010);
100#endif
Ben Skeggs79487582011-01-11 14:52:40 +1000101}
102
Ben Skeggs861d2102012-07-11 19:05:01 +1000103static int
104nv40_fb_init(struct nouveau_object *object)
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000105{
Ben Skeggs861d2102012-07-11 19:05:01 +1000106 struct nv40_fb_priv *priv = (void *)object;
107 int ret;
108
109 ret = nouveau_fb_init(&priv->base);
110 if (ret)
111 return ret;
112
113 switch (nv_device(priv)->chipset) {
114 case 0x40:
115 case 0x45:
116 nv_mask(priv, 0x10033c, 0x00008000, 0x00000000);
117 break;
118 default:
119 if (nv44_graph_class(nv_device(priv)))
120 nv44_fb_init_gart(priv);
121 else
122 nv40_fb_init_gart(priv);
123 break;
124 }
125
126 return 0;
127}
128
129static int
130nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
131 struct nouveau_oclass *oclass, void *data, u32 size,
132 struct nouveau_object **pobject)
133{
134 struct nouveau_device *device = nv_device(parent);
135 struct nv40_fb_priv *priv;
136 int ret;
137
138 ret = nouveau_fb_create(parent, engine, oclass, &priv);
139 *pobject = nv_object(priv);
140 if (ret)
141 return ret;
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000142
143 /* 0x001218 is actually present on a few other NV4X I looked at,
144 * and even contains sane values matching 0x100474. From looking
145 * at various vbios images however, this isn't the case everywhere.
146 * So, I chose to use the same regs I've seen NVIDIA reading around
147 * the memory detection, hopefully that'll get us the right numbers
148 */
Ben Skeggs861d2102012-07-11 19:05:01 +1000149 if (device->chipset == 0x40) {
150 u32 pbus1218 = nv_rd32(priv, 0x001218);
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000151 switch (pbus1218 & 0x00000300) {
Ben Skeggs861d2102012-07-11 19:05:01 +1000152 case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_SDRAM; break;
153 case 0x00000100: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
154 case 0x00000200: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
155 case 0x00000300: priv->base.ram.type = NV_MEM_TYPE_DDR2; break;
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000156 }
157 } else
Ben Skeggs861d2102012-07-11 19:05:01 +1000158 if (device->chipset == 0x49 || device->chipset == 0x4b) {
159 u32 pfb914 = nv_rd32(priv, 0x100914);
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000160 switch (pfb914 & 0x00000003) {
Ben Skeggs861d2102012-07-11 19:05:01 +1000161 case 0x00000000: priv->base.ram.type = NV_MEM_TYPE_DDR1; break;
162 case 0x00000001: priv->base.ram.type = NV_MEM_TYPE_DDR2; break;
163 case 0x00000002: priv->base.ram.type = NV_MEM_TYPE_GDDR3; break;
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000164 case 0x00000003: break;
165 }
166 } else
Ben Skeggs861d2102012-07-11 19:05:01 +1000167 if (device->chipset != 0x4e) {
168 u32 pfb474 = nv_rd32(priv, 0x100474);
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000169 if (pfb474 & 0x00000004)
Ben Skeggs861d2102012-07-11 19:05:01 +1000170 priv->base.ram.type = NV_MEM_TYPE_GDDR3;
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000171 if (pfb474 & 0x00000002)
Ben Skeggs861d2102012-07-11 19:05:01 +1000172 priv->base.ram.type = NV_MEM_TYPE_DDR2;
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000173 if (pfb474 & 0x00000001)
Ben Skeggs861d2102012-07-11 19:05:01 +1000174 priv->base.ram.type = NV_MEM_TYPE_DDR1;
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000175 } else {
Ben Skeggs861d2102012-07-11 19:05:01 +1000176 priv->base.ram.type = NV_MEM_TYPE_STOLEN;
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000177 }
178
Ben Skeggs861d2102012-07-11 19:05:01 +1000179 priv->base.ram.size = nv_rd32(priv, 0x10020c) & 0xff000000;
Ben Skeggsff92a6c2011-12-12 23:03:14 +1000180
Ben Skeggs861d2102012-07-11 19:05:01 +1000181 priv->base.memtype_valid = nv04_fb_memtype_valid;
182 switch (device->chipset) {
Ben Skeggs6ee73862009-12-11 19:24:15 +1000183 case 0x40:
184 case 0x45:
Ben Skeggs861d2102012-07-11 19:05:01 +1000185 priv->base.tile.regions = 8;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000186 break;
Ben Skeggs861d2102012-07-11 19:05:01 +1000187 case 0x46:
188 case 0x47:
189 case 0x49:
190 case 0x4b:
191 case 0x4c:
192 priv->base.tile.regions = 15;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000193 break;
194 default:
Ben Skeggs861d2102012-07-11 19:05:01 +1000195 priv->base.tile.regions = 12;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000196 break;
197 }
Ben Skeggs861d2102012-07-11 19:05:01 +1000198 priv->base.tile.init = nv30_fb_tile_init;
199 priv->base.tile.fini = nv30_fb_tile_fini;
200 if (device->chipset == 0x40)
201 priv->base.tile.prog = nv10_fb_tile_prog;
202 else
203 priv->base.tile.prog = nv40_fb_tile_prog;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000204
Ben Skeggs861d2102012-07-11 19:05:01 +1000205 return nouveau_fb_created(&priv->base);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000206}
207
Ben Skeggs861d2102012-07-11 19:05:01 +1000208
209struct nouveau_oclass
210nv40_fb_oclass = {
211 .handle = NV_SUBDEV(FB, 0x40),
212 .ofuncs = &(struct nouveau_ofuncs) {
213 .ctor = nv40_fb_ctor,
214 .dtor = _nouveau_fb_dtor,
215 .init = nv40_fb_init,
216 .fini = _nouveau_fb_fini,
217 },
218};