aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c275
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h4
2 files changed, 158 insertions, 121 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 773d9cbe19df..8dbeeea91872 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -65,195 +65,232 @@ static bool nv_cksum(const uint8_t *data, unsigned int length)
65} 65}
66 66
67static int 67static int
68score_vbios(struct drm_device *dev, const uint8_t *data, const bool writeable) 68score_vbios(struct nvbios *bios, const bool writeable)
69{ 69{
70 if (!(data[0] == 0x55 && data[1] == 0xAA)) { 70 if (!bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) {
71 NV_TRACEWARN(dev, "... BIOS signature not found\n"); 71 NV_TRACEWARN(bios->dev, "... BIOS signature not found\n");
72 return 0; 72 return 0;
73 } 73 }
74 74
75 if (nv_cksum(data, data[2] * 512)) { 75 if (nv_cksum(bios->data, bios->data[2] * 512)) {
76 NV_TRACEWARN(dev, "... BIOS checksum invalid\n"); 76 NV_TRACEWARN(bios->dev, "... BIOS checksum invalid\n");
77 /* if a ro image is somewhat bad, it's probably all rubbish */ 77 /* if a ro image is somewhat bad, it's probably all rubbish */
78 return writeable ? 2 : 1; 78 return writeable ? 2 : 1;
79 } else 79 }
80 NV_TRACE(dev, "... appears to be valid\n");
81 80
81 NV_TRACE(bios->dev, "... appears to be valid\n");
82 return 3; 82 return 3;
83} 83}
84 84
85static void load_vbios_prom(struct drm_device *dev, uint8_t *data) 85static void
86bios_shadow_prom(struct nvbios *bios)
86{ 87{
88 struct drm_device *dev = bios->dev;
87 struct drm_nouveau_private *dev_priv = dev->dev_private; 89 struct drm_nouveau_private *dev_priv = dev->dev_private;
88 uint32_t pci_nv_20, save_pci_nv_20; 90 u32 pcireg, access;
89 int pcir_ptr; 91 u16 pcir;
90 int i; 92 int i;
91 93
94 /* enable access to rom */
92 if (dev_priv->card_type >= NV_50) 95 if (dev_priv->card_type >= NV_50)
93 pci_nv_20 = 0x88050; 96 pcireg = 0x088050;
94 else 97 else
95 pci_nv_20 = NV_PBUS_PCI_NV_20; 98 pcireg = NV_PBUS_PCI_NV_20;
99 access = nv_mask(dev, pcireg, 0x00000001, 0x00000000);
96 100
97 /* enable ROM access */ 101 /* bail if no rom signature, with a workaround for a PROM reading
98 save_pci_nv_20 = nvReadMC(dev, pci_nv_20); 102 * issue on some chipsets. the first read after a period of
99 nvWriteMC(dev, pci_nv_20, 103 * inactivity returns the wrong result, so retry the first header
100 save_pci_nv_20 & ~NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED); 104 * byte a few times before giving up as a workaround
105 */
106 i = 16;
107 do {
108 if (nv_rd08(dev, NV_PROM_OFFSET + 0) == 0x55)
109 break;
110 } while (i--);
101 111
102 /* bail if no rom signature */ 112 if (!i || nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
103 if (nv_rd08(dev, NV_PROM_OFFSET) != 0x55 ||
104 nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
105 goto out; 113 goto out;
106 114
107 /* additional check (see note below) - read PCI record header */ 115 /* additional check (see note below) - read PCI record header */
108 pcir_ptr = nv_rd08(dev, NV_PROM_OFFSET + 0x18) | 116 pcir = nv_rd08(dev, NV_PROM_OFFSET + 0x18) |
109 nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8; 117 nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8;
110 if (nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr) != 'P' || 118 if (nv_rd08(dev, NV_PROM_OFFSET + pcir + 0) != 'P' ||
111 nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 1) != 'C' || 119 nv_rd08(dev, NV_PROM_OFFSET + pcir + 1) != 'C' ||
112 nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 2) != 'I' || 120 nv_rd08(dev, NV_PROM_OFFSET + pcir + 2) != 'I' ||
113 nv_rd08(dev, NV_PROM_OFFSET + pcir_ptr + 3) != 'R') 121 nv_rd08(dev, NV_PROM_OFFSET + pcir + 3) != 'R')
114 goto out; 122 goto out;
115 123
116 /* on some 6600GT/6800LE prom reads are messed up. nvclock alleges a 124 /* read entire bios image to system memory */
117 * a good read may be obtained by waiting or re-reading (cargocult: 5x) 125 bios->length = nv_rd08(dev, NV_PROM_OFFSET + 2) * 512;
118 * each byte. we'll hope pramin has something usable instead 126 bios->data = kmalloc(bios->length, GFP_KERNEL);
119 */ 127 if (bios->data) {
120 for (i = 0; i < NV_PROM_SIZE; i++) 128 for (i = 0; i < bios->length; i++)
121 data[i] = nv_rd08(dev, NV_PROM_OFFSET + i); 129 bios->data[i] = nv_rd08(dev, NV_PROM_OFFSET + i);
130 }
122 131
123out: 132out:
124 /* disable ROM access */ 133 /* disable access to rom */
125 nvWriteMC(dev, pci_nv_20, 134 nv_wr32(dev, pcireg, access);
126 save_pci_nv_20 | NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
127} 135}
128 136
129static void load_vbios_pramin(struct drm_device *dev, uint8_t *data) 137static void
138bios_shadow_pramin(struct nvbios *bios)
130{ 139{
140 struct drm_device *dev = bios->dev;
131 struct drm_nouveau_private *dev_priv = dev->dev_private; 141 struct drm_nouveau_private *dev_priv = dev->dev_private;
132 uint32_t old_bar0_pramin = 0; 142 u32 bar0 = 0;
133 int i; 143 int i;
134 144
135 if (dev_priv->card_type >= NV_50) { 145 if (dev_priv->card_type >= NV_50) {
136 u64 addr = (u64)(nv_rd32(dev, 0x619f04) & 0xffffff00) << 8; 146 u64 addr = (u64)(nv_rd32(dev, 0x619f04) & 0xffffff00) << 8;
137 if (!addr) { 147 if (!addr) {
138 addr = (u64)nv_rd32(dev, 0x1700) << 16; 148 addr = (u64)nv_rd32(dev, 0x001700) << 16;
139 addr += 0xf0000; 149 addr += 0xf0000;
140 } 150 }
141 151
142 old_bar0_pramin = nv_rd32(dev, 0x1700); 152 bar0 = nv_mask(dev, 0x001700, 0xffffffff, addr >> 16);
143 nv_wr32(dev, 0x1700, addr >> 16);
144 } 153 }
145 154
146 /* bail if no rom signature */ 155 /* bail if no rom signature */
147 if (nv_rd08(dev, NV_PRAMIN_OFFSET) != 0x55 || 156 if (nv_rd08(dev, NV_PRAMIN_OFFSET + 0) != 0x55 ||
148 nv_rd08(dev, NV_PRAMIN_OFFSET + 1) != 0xaa) 157 nv_rd08(dev, NV_PRAMIN_OFFSET + 1) != 0xaa)
149 goto out; 158 goto out;
150 159
151 for (i = 0; i < NV_PROM_SIZE; i++) 160 bios->length = nv_rd08(dev, NV_PRAMIN_OFFSET + 2) * 512;
152 data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i); 161 bios->data = kmalloc(bios->length, GFP_KERNEL);
162 if (bios->data) {
163 for (i = 0; i < bios->length; i++)
164 bios->data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i);
165 }
153 166
154out: 167out:
155 if (dev_priv->card_type >= NV_50) 168 if (dev_priv->card_type >= NV_50)
156 nv_wr32(dev, 0x1700, old_bar0_pramin); 169 nv_wr32(dev, 0x001700, bar0);
157} 170}
158 171
159static void load_vbios_pci(struct drm_device *dev, uint8_t *data) 172static void
173bios_shadow_pci(struct nvbios *bios)
174{
175 struct pci_dev *pdev = bios->dev->pdev;
176 size_t length;
177
178 if (!pci_enable_rom(pdev)) {
179 void __iomem *rom = pci_map_rom(pdev, &length);
180 if (rom) {
181 bios->data = kmalloc(length, GFP_KERNEL);
182 if (bios->data) {
183 memcpy_fromio(bios->data, rom, length);
184 bios->length = length;
185 }
186 pci_unmap_rom(pdev, rom);
187 }
188
189 pci_disable_rom(pdev);
190 }
191}
192
193static void
194bios_shadow_acpi(struct nvbios *bios)
160{ 195{
161 void __iomem *rom = NULL; 196 struct pci_dev *pdev = bios->dev->pdev;
162 size_t rom_len; 197 int ptr, len, ret;
163 int ret; 198 u8 data[3];
164 199
165 ret = pci_enable_rom(dev->pdev); 200 if (!nouveau_acpi_rom_supported(pdev))
166 if (ret)
167 return; 201 return;
168 202
169 rom = pci_map_rom(dev->pdev, &rom_len); 203 ret = nouveau_acpi_get_bios_chunk(data, 0, sizeof(data));
170 if (!rom) 204 if (ret != sizeof(data))
171 goto out; 205 return;
172 memcpy_fromio(data, rom, rom_len);
173 pci_unmap_rom(dev->pdev, rom);
174 206
175out: 207 bios->length = min(data[2] * 512, 65536);
176 pci_disable_rom(dev->pdev); 208 bios->data = kmalloc(bios->length, GFP_KERNEL);
177} 209 if (!bios->data)
210 return;
178 211
179static void load_vbios_acpi(struct drm_device *dev, uint8_t *data) 212 len = bios->length;
180{ 213 ptr = 0;
181 int i; 214 while (len) {
182 int ret; 215 int size = (len > ROM_BIOS_PAGE) ? ROM_BIOS_PAGE : len;
183 int size = 64 * 1024;
184 216
185 if (!nouveau_acpi_rom_supported(dev->pdev)) 217 ret = nouveau_acpi_get_bios_chunk(bios->data, ptr, size);
186 return; 218 if (ret != size) {
219 kfree(bios->data);
220 bios->data = NULL;
221 return;
222 }
187 223
188 for (i = 0; i < (size / ROM_BIOS_PAGE); i++) { 224 len -= size;
189 ret = nouveau_acpi_get_bios_chunk(data, 225 ptr += size;
190 (i * ROM_BIOS_PAGE),
191 ROM_BIOS_PAGE);
192 if (ret <= 0)
193 break;
194 } 226 }
195 return;
196} 227}
197 228
198struct methods { 229struct methods {
199 const char desc[8]; 230 const char desc[8];
200 void (*loadbios)(struct drm_device *, uint8_t *); 231 void (*shadow)(struct nvbios *);
201 const bool rw; 232 const bool rw;
233 int score;
234 u32 size;
235 u8 *data;
202}; 236};
203 237
204static struct methods shadow_methods[] = { 238static bool
205 { "PRAMIN", load_vbios_pramin, true }, 239bios_shadow(struct drm_device *dev)
206 { "PROM", load_vbios_prom, false }, 240{
207 { "ACPI", load_vbios_acpi, true }, 241 struct methods shadow_methods[] = {
208 { "PCIROM", load_vbios_pci, true }, 242 { "PRAMIN", bios_shadow_pramin, true, 0, 0, NULL },
209}; 243 { "PROM", bios_shadow_prom, false, 0, 0, NULL },
210#define NUM_SHADOW_METHODS ARRAY_SIZE(shadow_methods) 244 { "ACPI", bios_shadow_acpi, true, 0, 0, NULL },
211 245 { "PCIROM", bios_shadow_pci, true, 0, 0, NULL },
212static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) 246 {}
213{ 247 };
214 struct methods *methods = shadow_methods; 248 struct drm_nouveau_private *dev_priv = dev->dev_private;
215 int testscore = 3; 249 struct nvbios *bios = &dev_priv->vbios;
216 int scores[NUM_SHADOW_METHODS], i; 250 struct methods *mthd, *best;
217 251
218 if (nouveau_vbios) { 252 if (nouveau_vbios) {
219 for (i = 0; i < NUM_SHADOW_METHODS; i++) 253 mthd = shadow_methods;
220 if (!strcasecmp(nouveau_vbios, methods[i].desc)) 254 do {
221 break; 255 if (strcasecmp(nouveau_vbios, mthd->desc))
222 256 continue;
223 if (i < NUM_SHADOW_METHODS) { 257 NV_INFO(dev, "VBIOS source: %s\n", mthd->desc);
224 NV_INFO(dev, "Attempting to use BIOS image from %s\n",
225 methods[i].desc);
226 258
227 methods[i].loadbios(dev, data); 259 mthd->shadow(bios);
228 if (score_vbios(dev, data, methods[i].rw)) 260 mthd->score = score_vbios(bios, mthd->rw);
261 if (mthd->score)
229 return true; 262 return true;
230 } 263 } while ((++mthd)->shadow);
231 264
232 NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios); 265 NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
233 } 266 }
234 267
235 for (i = 0; i < NUM_SHADOW_METHODS; i++) { 268 mthd = shadow_methods;
236 NV_TRACE(dev, "Attempting to load BIOS image from %s\n", 269 do {
237 methods[i].desc); 270 NV_TRACE(dev, "Checking %s for VBIOS\n", mthd->desc);
238 data[0] = data[1] = 0; /* avoid reuse of previous image */ 271 mthd->shadow(bios);
239 methods[i].loadbios(dev, data); 272 mthd->score = score_vbios(bios, mthd->rw);
240 scores[i] = score_vbios(dev, data, methods[i].rw); 273 mthd->size = bios->length;
241 if (scores[i] == testscore) 274 mthd->data = bios->data;
242 return true; 275 } while (mthd->score != 3 && (++mthd)->shadow);
243 } 276
244 277 mthd = shadow_methods;
245 while (--testscore > 0) { 278 best = mthd;
246 for (i = 0; i < NUM_SHADOW_METHODS; i++) { 279 do {
247 if (scores[i] == testscore) { 280 if (mthd->score > best->score) {
248 NV_TRACE(dev, "Using BIOS image from %s\n", 281 kfree(best->data);
249 methods[i].desc); 282 best = mthd;
250 methods[i].loadbios(dev, data);
251 return true;
252 }
253 } 283 }
284 } while ((++mthd)->shadow);
285
286 if (best->score) {
287 NV_TRACE(dev, "Using VBIOS from %s\n", best->desc);
288 bios->length = best->size;
289 bios->data = best->data;
290 return true;
254 } 291 }
255 292
256 NV_ERROR(dev, "No valid BIOS image found\n"); 293 NV_ERROR(dev, "No valid VBIOS image found\n");
257 return false; 294 return false;
258} 295}
259 296
@@ -6334,11 +6371,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
6334 spin_lock_init(&bios->lock); 6371 spin_lock_init(&bios->lock);
6335 bios->dev = dev; 6372 bios->dev = dev;
6336 6373
6337 if (!NVShadowVBIOS(dev, bios->data)) 6374 return bios_shadow(dev);
6338 return false;
6339
6340 bios->length = NV_PROM_SIZE;
6341 return true;
6342} 6375}
6343 6376
6344static int nouveau_parse_vbios_struct(struct drm_device *dev) 6377static int nouveau_parse_vbios_struct(struct drm_device *dev)
@@ -6498,6 +6531,10 @@ nouveau_bios_init(struct drm_device *dev)
6498void 6531void
6499nouveau_bios_takedown(struct drm_device *dev) 6532nouveau_bios_takedown(struct drm_device *dev)
6500{ 6533{
6534 struct drm_nouveau_private *dev_priv = dev->dev_private;
6535
6501 nouveau_mxm_fini(dev); 6536 nouveau_mxm_fini(dev);
6502 nouveau_i2c_fini(dev); 6537 nouveau_i2c_fini(dev);
6538
6539 kfree(dev_priv->vbios.data);
6503} 6540}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index 0fc4e21c748b..1f3233df00e6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -211,6 +211,8 @@ struct nvbios {
211 NVBIOS_BIT 211 NVBIOS_BIT
212 } type; 212 } type;
213 uint16_t offset; 213 uint16_t offset;
214 uint32_t length;
215 uint8_t *data;
214 216
215 uint8_t chip_version; 217 uint8_t chip_version;
216 218
@@ -221,8 +223,6 @@ struct nvbios {
221 223
222 spinlock_t lock; 224 spinlock_t lock;
223 225
224 uint8_t data[NV_PROM_SIZE];
225 unsigned int length;
226 bool execute; 226 bool execute;
227 227
228 uint8_t major_version; 228 uint8_t major_version;