aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_hw.h
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2009-12-11 04:24:15 -0500
committerDave Airlie <airlied@redhat.com>2009-12-11 06:29:34 -0500
commit6ee738610f41b59733f63718f0bdbcba7d3a3f12 (patch)
treeeccb9f07671998c50a1bc606a54cd6f82ba43e0a /drivers/gpu/drm/nouveau/nouveau_hw.h
parentd1ede145cea25c5b6d2ebb19b167af14e374bb45 (diff)
drm/nouveau: Add DRM driver for NVIDIA GPUs
This adds a drm/kms staging non-API stable driver for GPUs from NVIDIA. This driver is a KMS-based driver and requires a compatible nouveau userspace libdrm and nouveau X.org driver. This driver requires firmware files not available in this kernel tree, interested parties can find them via the nouveau project git archive. This driver is reverse engineered, and is in no way supported by nVidia. Support for nearly the complete range of nvidia hw from nv04->g80 (nv50) is available, and the kms driver should support driving nearly all output types (displayport is under development still) along with supporting suspend/resume. This work is all from the upstream nouveau project found at nouveau.freedesktop.org. The original authors list from nouveau git tree is: Anssi Hannula <anssi.hannula@iki.fi> Ben Skeggs <bskeggs@redhat.com> Francisco Jerez <currojerez@riseup.net> Maarten Maathuis <madman2003@gmail.com> Marcin Koƛcielnicki <koriakin@0x04.net> Matthew Garrett <mjg@redhat.com> Matt Parnell <mparnell@gmail.com> Patrice Mandin <patmandin@gmail.com> Pekka Paalanen <pq@iki.fi> Xavier Chantry <shiningxc@gmail.com> along with project founder Stephane Marchesin <marchesin@icps.u-strasbg.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_hw.h')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hw.h455
1 files changed, 455 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.h b/drivers/gpu/drm/nouveau/nouveau_hw.h
new file mode 100644
index 000000000000..869130f83602
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_hw.h
@@ -0,0 +1,455 @@
1/*
2 * Copyright 2008 Stuart Bennett
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 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23#ifndef __NOUVEAU_HW_H__
24#define __NOUVEAU_HW_H__
25
26#include "drmP.h"
27#include "nouveau_drv.h"
28
29#define MASK(field) ( \
30 (0xffffffff >> (31 - ((1 ? field) - (0 ? field)))) << (0 ? field))
31
32#define XLATE(src, srclowbit, outfield) ( \
33 (((src) >> (srclowbit)) << (0 ? outfield)) & MASK(outfield))
34
35void NVWriteVgaSeq(struct drm_device *, int head, uint8_t index, uint8_t value);
36uint8_t NVReadVgaSeq(struct drm_device *, int head, uint8_t index);
37void NVWriteVgaGr(struct drm_device *, int head, uint8_t index, uint8_t value);
38uint8_t NVReadVgaGr(struct drm_device *, int head, uint8_t index);
39void NVSetOwner(struct drm_device *, int owner);
40void NVBlankScreen(struct drm_device *, int head, bool blank);
41void nouveau_hw_setpll(struct drm_device *, uint32_t reg1,
42 struct nouveau_pll_vals *pv);
43int nouveau_hw_get_pllvals(struct drm_device *, enum pll_types plltype,
44 struct nouveau_pll_vals *pllvals);
45int nouveau_hw_pllvals_to_clk(struct nouveau_pll_vals *pllvals);
46int nouveau_hw_get_clock(struct drm_device *, enum pll_types plltype);
47void nouveau_hw_save_vga_fonts(struct drm_device *, bool save);
48void nouveau_hw_save_state(struct drm_device *, int head,
49 struct nv04_mode_state *state);
50void nouveau_hw_load_state(struct drm_device *, int head,
51 struct nv04_mode_state *state);
52void nouveau_hw_load_state_palette(struct drm_device *, int head,
53 struct nv04_mode_state *state);
54
55/* nouveau_calc.c */
56extern void nouveau_calc_arb(struct drm_device *, int vclk, int bpp,
57 int *burst, int *lwm);
58extern int nouveau_calc_pll_mnp(struct drm_device *, struct pll_lims *pll_lim,
59 int clk, struct nouveau_pll_vals *pv);
60
61static inline uint32_t
62nvReadMC(struct drm_device *dev, uint32_t reg)
63{
64 uint32_t val = nv_rd32(dev, reg);
65 NV_REG_DEBUG(MC, dev, "reg %08x val %08x\n", reg, val);
66 return val;
67}
68
69static inline void
70nvWriteMC(struct drm_device *dev, uint32_t reg, uint32_t val)
71{
72 NV_REG_DEBUG(MC, dev, "reg %08x val %08x\n", reg, val);
73 nv_wr32(dev, reg, val);
74}
75
76static inline uint32_t
77nvReadVIDEO(struct drm_device *dev, uint32_t reg)
78{
79 uint32_t val = nv_rd32(dev, reg);
80 NV_REG_DEBUG(VIDEO, dev, "reg %08x val %08x\n", reg, val);
81 return val;
82}
83
84static inline void
85nvWriteVIDEO(struct drm_device *dev, uint32_t reg, uint32_t val)
86{
87 NV_REG_DEBUG(VIDEO, dev, "reg %08x val %08x\n", reg, val);
88 nv_wr32(dev, reg, val);
89}
90
91static inline uint32_t
92nvReadFB(struct drm_device *dev, uint32_t reg)
93{
94 uint32_t val = nv_rd32(dev, reg);
95 NV_REG_DEBUG(FB, dev, "reg %08x val %08x\n", reg, val);
96 return val;
97}
98
99static inline void
100nvWriteFB(struct drm_device *dev, uint32_t reg, uint32_t val)
101{
102 NV_REG_DEBUG(FB, dev, "reg %08x val %08x\n", reg, val);
103 nv_wr32(dev, reg, val);
104}
105
106static inline uint32_t
107nvReadEXTDEV(struct drm_device *dev, uint32_t reg)
108{
109 uint32_t val = nv_rd32(dev, reg);
110 NV_REG_DEBUG(EXTDEV, dev, "reg %08x val %08x\n", reg, val);
111 return val;
112}
113
114static inline void
115nvWriteEXTDEV(struct drm_device *dev, uint32_t reg, uint32_t val)
116{
117 NV_REG_DEBUG(EXTDEV, dev, "reg %08x val %08x\n", reg, val);
118 nv_wr32(dev, reg, val);
119}
120
121static inline uint32_t NVReadCRTC(struct drm_device *dev,
122 int head, uint32_t reg)
123{
124 uint32_t val;
125 if (head)
126 reg += NV_PCRTC0_SIZE;
127 val = nv_rd32(dev, reg);
128 NV_REG_DEBUG(CRTC, dev, "head %d reg %08x val %08x\n", head, reg, val);
129 return val;
130}
131
132static inline void NVWriteCRTC(struct drm_device *dev,
133 int head, uint32_t reg, uint32_t val)
134{
135 if (head)
136 reg += NV_PCRTC0_SIZE;
137 NV_REG_DEBUG(CRTC, dev, "head %d reg %08x val %08x\n", head, reg, val);
138 nv_wr32(dev, reg, val);
139}
140
141static inline uint32_t NVReadRAMDAC(struct drm_device *dev,
142 int head, uint32_t reg)
143{
144 uint32_t val;
145 if (head)
146 reg += NV_PRAMDAC0_SIZE;
147 val = nv_rd32(dev, reg);
148 NV_REG_DEBUG(RAMDAC, dev, "head %d reg %08x val %08x\n",
149 head, reg, val);
150 return val;
151}
152
153static inline void NVWriteRAMDAC(struct drm_device *dev,
154 int head, uint32_t reg, uint32_t val)
155{
156 if (head)
157 reg += NV_PRAMDAC0_SIZE;
158 NV_REG_DEBUG(RAMDAC, dev, "head %d reg %08x val %08x\n",
159 head, reg, val);
160 nv_wr32(dev, reg, val);
161}
162
163static inline uint8_t nv_read_tmds(struct drm_device *dev,
164 int or, int dl, uint8_t address)
165{
166 int ramdac = (or & OUTPUT_C) >> 2;
167
168 NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8,
169 NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE | address);
170 return NVReadRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8);
171}
172
173static inline void nv_write_tmds(struct drm_device *dev,
174 int or, int dl, uint8_t address,
175 uint8_t data)
176{
177 int ramdac = (or & OUTPUT_C) >> 2;
178
179 NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8, data);
180 NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8, address);
181}
182
183static inline void NVWriteVgaCrtc(struct drm_device *dev,
184 int head, uint8_t index, uint8_t value)
185{
186 NV_REG_DEBUG(VGACRTC, dev, "head %d index 0x%02x data 0x%02x\n",
187 head, index, value);
188 nv_wr08(dev, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
189 nv_wr08(dev, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value);
190}
191
192static inline uint8_t NVReadVgaCrtc(struct drm_device *dev,
193 int head, uint8_t index)
194{
195 uint8_t val;
196 nv_wr08(dev, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
197 val = nv_rd08(dev, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE);
198 NV_REG_DEBUG(VGACRTC, dev, "head %d index 0x%02x data 0x%02x\n",
199 head, index, val);
200 return val;
201}
202
203/* CR57 and CR58 are a fun pair of regs. CR57 provides an index (0-0xf) for CR58
204 * I suspect they in fact do nothing, but are merely a way to carry useful
205 * per-head variables around
206 *
207 * Known uses:
208 * CR57 CR58
209 * 0x00 index to the appropriate dcb entry (or 7f for inactive)
210 * 0x02 dcb entry's "or" value (or 00 for inactive)
211 * 0x03 bit0 set for dual link (LVDS, possibly elsewhere too)
212 * 0x08 or 0x09 pxclk in MHz
213 * 0x0f laptop panel info - low nibble for PEXTDEV_BOOT_0 strap
214 * high nibble for xlat strap value
215 */
216
217static inline void
218NVWriteVgaCrtc5758(struct drm_device *dev, int head, uint8_t index, uint8_t value)
219{
220 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
221 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_58, value);
222}
223
224static inline uint8_t NVReadVgaCrtc5758(struct drm_device *dev, int head, uint8_t index)
225{
226 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
227 return NVReadVgaCrtc(dev, head, NV_CIO_CRE_58);
228}
229
230static inline uint8_t NVReadPRMVIO(struct drm_device *dev,
231 int head, uint32_t reg)
232{
233 struct drm_nouveau_private *dev_priv = dev->dev_private;
234 uint8_t val;
235
236 /* Only NV4x have two pvio ranges; other twoHeads cards MUST call
237 * NVSetOwner for the relevant head to be programmed */
238 if (head && dev_priv->card_type == NV_40)
239 reg += NV_PRMVIO_SIZE;
240
241 val = nv_rd08(dev, reg);
242 NV_REG_DEBUG(RMVIO, dev, "head %d reg %08x val %02x\n", head, reg, val);
243 return val;
244}
245
246static inline void NVWritePRMVIO(struct drm_device *dev,
247 int head, uint32_t reg, uint8_t value)
248{
249 struct drm_nouveau_private *dev_priv = dev->dev_private;
250
251 /* Only NV4x have two pvio ranges; other twoHeads cards MUST call
252 * NVSetOwner for the relevant head to be programmed */
253 if (head && dev_priv->card_type == NV_40)
254 reg += NV_PRMVIO_SIZE;
255
256 NV_REG_DEBUG(RMVIO, dev, "head %d reg %08x val %02x\n",
257 head, reg, value);
258 nv_wr08(dev, reg, value);
259}
260
261static inline void NVSetEnablePalette(struct drm_device *dev, int head, bool enable)
262{
263 nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
264 nv_wr08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20);
265}
266
267static inline bool NVGetEnablePalette(struct drm_device *dev, int head)
268{
269 nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
270 return !(nv_rd08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20);
271}
272
273static inline void NVWriteVgaAttr(struct drm_device *dev,
274 int head, uint8_t index, uint8_t value)
275{
276 if (NVGetEnablePalette(dev, head))
277 index &= ~0x20;
278 else
279 index |= 0x20;
280
281 nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
282 NV_REG_DEBUG(VGAATTR, dev, "head %d index 0x%02x data 0x%02x\n",
283 head, index, value);
284 nv_wr08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
285 nv_wr08(dev, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value);
286}
287
288static inline uint8_t NVReadVgaAttr(struct drm_device *dev,
289 int head, uint8_t index)
290{
291 uint8_t val;
292 if (NVGetEnablePalette(dev, head))
293 index &= ~0x20;
294 else
295 index |= 0x20;
296
297 nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
298 nv_wr08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
299 val = nv_rd08(dev, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE);
300 NV_REG_DEBUG(VGAATTR, dev, "head %d index 0x%02x data 0x%02x\n",
301 head, index, val);
302 return val;
303}
304
305static inline void NVVgaSeqReset(struct drm_device *dev, int head, bool start)
306{
307 NVWriteVgaSeq(dev, head, NV_VIO_SR_RESET_INDEX, start ? 0x1 : 0x3);
308}
309
310static inline void NVVgaProtect(struct drm_device *dev, int head, bool protect)
311{
312 uint8_t seq1 = NVReadVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX);
313
314 if (protect) {
315 NVVgaSeqReset(dev, head, true);
316 NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 | 0x20);
317 } else {
318 /* Reenable sequencer, then turn on screen */
319 NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 & ~0x20); /* reenable display */
320 NVVgaSeqReset(dev, head, false);
321 }
322 NVSetEnablePalette(dev, head, protect);
323}
324
325static inline bool
326nv_heads_tied(struct drm_device *dev)
327{
328 struct drm_nouveau_private *dev_priv = dev->dev_private;
329
330 if (dev_priv->chipset == 0x11)
331 return !!(nvReadMC(dev, NV_PBUS_DEBUG_1) & (1 << 28));
332
333 return NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44) & 0x4;
334}
335
336/* makes cr0-7 on the specified head read-only */
337static inline bool
338nv_lock_vga_crtc_base(struct drm_device *dev, int head, bool lock)
339{
340 uint8_t cr11 = NVReadVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX);
341 bool waslocked = cr11 & 0x80;
342
343 if (lock)
344 cr11 |= 0x80;
345 else
346 cr11 &= ~0x80;
347 NVWriteVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX, cr11);
348
349 return waslocked;
350}
351
352static inline void
353nv_lock_vga_crtc_shadow(struct drm_device *dev, int head, int lock)
354{
355 /* shadow lock: connects 0x60?3d? regs to "real" 0x3d? regs
356 * bit7: unlocks HDT, HBS, HBE, HRS, HRE, HEB
357 * bit6: seems to have some effect on CR09 (double scan, VBS_9)
358 * bit5: unlocks HDE
359 * bit4: unlocks VDE
360 * bit3: unlocks VDT, OVL, VRS, ?VRE?, VBS, VBE, LSR, EBR
361 * bit2: same as bit 1 of 0x60?804
362 * bit0: same as bit 0 of 0x60?804
363 */
364
365 uint8_t cr21 = lock;
366
367 if (lock < 0)
368 /* 0xfa is generic "unlock all" mask */
369 cr21 = NVReadVgaCrtc(dev, head, NV_CIO_CRE_21) | 0xfa;
370
371 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_21, cr21);
372}
373
374/* renders the extended crtc regs (cr19+) on all crtcs impervious:
375 * immutable and unreadable
376 */
377static inline bool
378NVLockVgaCrtcs(struct drm_device *dev, bool lock)
379{
380 struct drm_nouveau_private *dev_priv = dev->dev_private;
381 bool waslocked = !NVReadVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX);
382
383 NVWriteVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX,
384 lock ? NV_CIO_SR_LOCK_VALUE : NV_CIO_SR_UNLOCK_RW_VALUE);
385 /* NV11 has independently lockable extended crtcs, except when tied */
386 if (dev_priv->chipset == 0x11 && !nv_heads_tied(dev))
387 NVWriteVgaCrtc(dev, 1, NV_CIO_SR_LOCK_INDEX,
388 lock ? NV_CIO_SR_LOCK_VALUE :
389 NV_CIO_SR_UNLOCK_RW_VALUE);
390
391 return waslocked;
392}
393
394/* nv04 cursor max dimensions of 32x32 (A1R5G5B5) */
395#define NV04_CURSOR_SIZE 32
396/* limit nv10 cursors to 64x64 (ARGB8) (we could go to 64x255) */
397#define NV10_CURSOR_SIZE 64
398
399static inline int nv_cursor_width(struct drm_device *dev)
400{
401 struct drm_nouveau_private *dev_priv = dev->dev_private;
402
403 return dev_priv->card_type >= NV_10 ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE;
404}
405
406static inline void
407nv_fix_nv40_hw_cursor(struct drm_device *dev, int head)
408{
409 /* on some nv40 (such as the "true" (in the NV_PFB_BOOT_0 sense) nv40,
410 * the gf6800gt) a hardware bug requires a write to PRAMDAC_CURSOR_POS
411 * for changes to the CRTC CURCTL regs to take effect, whether changing
412 * the pixmap location, or just showing/hiding the cursor
413 */
414 uint32_t curpos = NVReadRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS);
415 NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos);
416}
417
418static inline void
419nv_show_cursor(struct drm_device *dev, int head, bool show)
420{
421 struct drm_nouveau_private *dev_priv = dev->dev_private;
422 uint8_t *curctl1 =
423 &dev_priv->mode_reg.crtc_reg[head].CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX];
424
425 if (show)
426 *curctl1 |= MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
427 else
428 *curctl1 &= ~MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
429 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HCUR_ADDR1_INDEX, *curctl1);
430
431 if (dev_priv->card_type == NV_40)
432 nv_fix_nv40_hw_cursor(dev, head);
433}
434
435static inline uint32_t
436nv_pitch_align(struct drm_device *dev, uint32_t width, int bpp)
437{
438 struct drm_nouveau_private *dev_priv = dev->dev_private;
439 int mask;
440
441 if (bpp == 15)
442 bpp = 16;
443 if (bpp == 24)
444 bpp = 8;
445
446 /* Alignment requirements taken from the Haiku driver */
447 if (dev_priv->card_type == NV_04)
448 mask = 128 / bpp - 1;
449 else
450 mask = 512 / bpp - 1;
451
452 return (width + mask) & ~mask;
453}
454
455#endif /* __NOUVEAU_HW_H__ */