blob: 24c4592136134af4bfc021cb9fde0afe59528bd9 [file] [log] [blame]
Ben Skeggs6ee73862009-12-11 19:24:15 +10001/*
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
Ben Skeggs70790f42012-07-10 17:26:46 +100029#include <subdev/bios/pll.h>
30
Ben Skeggs6ee73862009-12-11 19:24:15 +100031#define MASK(field) ( \
32 (0xffffffff >> (31 - ((1 ? field) - (0 ? field)))) << (0 ? field))
33
34#define XLATE(src, srclowbit, outfield) ( \
35 (((src) >> (srclowbit)) << (0 ? outfield)) & MASK(outfield))
36
37void NVWriteVgaSeq(struct drm_device *, int head, uint8_t index, uint8_t value);
38uint8_t NVReadVgaSeq(struct drm_device *, int head, uint8_t index);
39void NVWriteVgaGr(struct drm_device *, int head, uint8_t index, uint8_t value);
40uint8_t NVReadVgaGr(struct drm_device *, int head, uint8_t index);
41void NVSetOwner(struct drm_device *, int owner);
42void NVBlankScreen(struct drm_device *, int head, bool blank);
Ben Skeggs70790f42012-07-10 17:26:46 +100043int nouveau_hw_get_pllvals(struct drm_device *, enum nvbios_pll_type plltype,
Ben Skeggs6ee73862009-12-11 19:24:15 +100044 struct nouveau_pll_vals *pllvals);
45int nouveau_hw_pllvals_to_clk(struct nouveau_pll_vals *pllvals);
Ben Skeggs70790f42012-07-10 17:26:46 +100046int nouveau_hw_get_clock(struct drm_device *, enum nvbios_pll_type plltype);
Ben Skeggs6ee73862009-12-11 19:24:15 +100047void 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);
Ben Skeggs6ee73862009-12-11 19:24:15 +100058
59static inline uint32_t
60nvReadMC(struct drm_device *dev, uint32_t reg)
61{
62 uint32_t val = nv_rd32(dev, reg);
63 NV_REG_DEBUG(MC, dev, "reg %08x val %08x\n", reg, val);
64 return val;
65}
66
67static inline void
68nvWriteMC(struct drm_device *dev, uint32_t reg, uint32_t val)
69{
70 NV_REG_DEBUG(MC, dev, "reg %08x val %08x\n", reg, val);
71 nv_wr32(dev, reg, val);
72}
73
74static inline uint32_t
75nvReadVIDEO(struct drm_device *dev, uint32_t reg)
76{
77 uint32_t val = nv_rd32(dev, reg);
78 NV_REG_DEBUG(VIDEO, dev, "reg %08x val %08x\n", reg, val);
79 return val;
80}
81
82static inline void
83nvWriteVIDEO(struct drm_device *dev, uint32_t reg, uint32_t val)
84{
85 NV_REG_DEBUG(VIDEO, dev, "reg %08x val %08x\n", reg, val);
86 nv_wr32(dev, reg, val);
87}
88
89static inline uint32_t
90nvReadFB(struct drm_device *dev, uint32_t reg)
91{
92 uint32_t val = nv_rd32(dev, reg);
93 NV_REG_DEBUG(FB, dev, "reg %08x val %08x\n", reg, val);
94 return val;
95}
96
97static inline void
98nvWriteFB(struct drm_device *dev, uint32_t reg, uint32_t val)
99{
100 NV_REG_DEBUG(FB, dev, "reg %08x val %08x\n", reg, val);
101 nv_wr32(dev, reg, val);
102}
103
104static inline uint32_t
105nvReadEXTDEV(struct drm_device *dev, uint32_t reg)
106{
107 uint32_t val = nv_rd32(dev, reg);
108 NV_REG_DEBUG(EXTDEV, dev, "reg %08x val %08x\n", reg, val);
109 return val;
110}
111
112static inline void
113nvWriteEXTDEV(struct drm_device *dev, uint32_t reg, uint32_t val)
114{
115 NV_REG_DEBUG(EXTDEV, dev, "reg %08x val %08x\n", reg, val);
116 nv_wr32(dev, reg, val);
117}
118
119static inline uint32_t NVReadCRTC(struct drm_device *dev,
120 int head, uint32_t reg)
121{
122 uint32_t val;
123 if (head)
124 reg += NV_PCRTC0_SIZE;
125 val = nv_rd32(dev, reg);
126 NV_REG_DEBUG(CRTC, dev, "head %d reg %08x val %08x\n", head, reg, val);
127 return val;
128}
129
130static inline void NVWriteCRTC(struct drm_device *dev,
131 int head, uint32_t reg, uint32_t val)
132{
133 if (head)
134 reg += NV_PCRTC0_SIZE;
135 NV_REG_DEBUG(CRTC, dev, "head %d reg %08x val %08x\n", head, reg, val);
136 nv_wr32(dev, reg, val);
137}
138
139static inline uint32_t NVReadRAMDAC(struct drm_device *dev,
140 int head, uint32_t reg)
141{
142 uint32_t val;
143 if (head)
144 reg += NV_PRAMDAC0_SIZE;
145 val = nv_rd32(dev, reg);
146 NV_REG_DEBUG(RAMDAC, dev, "head %d reg %08x val %08x\n",
147 head, reg, val);
148 return val;
149}
150
151static inline void NVWriteRAMDAC(struct drm_device *dev,
152 int head, uint32_t reg, uint32_t val)
153{
154 if (head)
155 reg += NV_PRAMDAC0_SIZE;
156 NV_REG_DEBUG(RAMDAC, dev, "head %d reg %08x val %08x\n",
157 head, reg, val);
158 nv_wr32(dev, reg, val);
159}
160
161static inline uint8_t nv_read_tmds(struct drm_device *dev,
162 int or, int dl, uint8_t address)
163{
Ben Skeggscb75d972012-07-11 10:44:20 +1000164 int ramdac = (or & DCB_OUTPUT_C) >> 2;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000165
166 NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8,
167 NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE | address);
168 return NVReadRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8);
169}
170
171static inline void nv_write_tmds(struct drm_device *dev,
172 int or, int dl, uint8_t address,
173 uint8_t data)
174{
Ben Skeggscb75d972012-07-11 10:44:20 +1000175 int ramdac = (or & DCB_OUTPUT_C) >> 2;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000176
177 NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8, data);
178 NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8, address);
179}
180
181static inline void NVWriteVgaCrtc(struct drm_device *dev,
182 int head, uint8_t index, uint8_t value)
183{
184 NV_REG_DEBUG(VGACRTC, dev, "head %d index 0x%02x data 0x%02x\n",
185 head, index, value);
186 nv_wr08(dev, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
187 nv_wr08(dev, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value);
188}
189
190static inline uint8_t NVReadVgaCrtc(struct drm_device *dev,
191 int head, uint8_t index)
192{
193 uint8_t val;
194 nv_wr08(dev, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
195 val = nv_rd08(dev, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE);
196 NV_REG_DEBUG(VGACRTC, dev, "head %d index 0x%02x data 0x%02x\n",
197 head, index, val);
198 return val;
199}
200
201/* CR57 and CR58 are a fun pair of regs. CR57 provides an index (0-0xf) for CR58
202 * I suspect they in fact do nothing, but are merely a way to carry useful
203 * per-head variables around
204 *
205 * Known uses:
206 * CR57 CR58
207 * 0x00 index to the appropriate dcb entry (or 7f for inactive)
208 * 0x02 dcb entry's "or" value (or 00 for inactive)
209 * 0x03 bit0 set for dual link (LVDS, possibly elsewhere too)
210 * 0x08 or 0x09 pxclk in MHz
211 * 0x0f laptop panel info - low nibble for PEXTDEV_BOOT_0 strap
212 * high nibble for xlat strap value
213 */
214
215static inline void
216NVWriteVgaCrtc5758(struct drm_device *dev, int head, uint8_t index, uint8_t value)
217{
218 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
219 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_58, value);
220}
221
222static inline uint8_t NVReadVgaCrtc5758(struct drm_device *dev, int head, uint8_t index)
223{
224 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
225 return NVReadVgaCrtc(dev, head, NV_CIO_CRE_58);
226}
227
228static inline uint8_t NVReadPRMVIO(struct drm_device *dev,
229 int head, uint32_t reg)
230{
231 struct drm_nouveau_private *dev_priv = dev->dev_private;
232 uint8_t val;
233
234 /* Only NV4x have two pvio ranges; other twoHeads cards MUST call
235 * NVSetOwner for the relevant head to be programmed */
236 if (head && dev_priv->card_type == NV_40)
237 reg += NV_PRMVIO_SIZE;
238
239 val = nv_rd08(dev, reg);
240 NV_REG_DEBUG(RMVIO, dev, "head %d reg %08x val %02x\n", head, reg, val);
241 return val;
242}
243
244static inline void NVWritePRMVIO(struct drm_device *dev,
245 int head, uint32_t reg, uint8_t value)
246{
247 struct drm_nouveau_private *dev_priv = dev->dev_private;
248
249 /* Only NV4x have two pvio ranges; other twoHeads cards MUST call
250 * NVSetOwner for the relevant head to be programmed */
251 if (head && dev_priv->card_type == NV_40)
252 reg += NV_PRMVIO_SIZE;
253
254 NV_REG_DEBUG(RMVIO, dev, "head %d reg %08x val %02x\n",
255 head, reg, value);
256 nv_wr08(dev, reg, value);
257}
258
259static inline void NVSetEnablePalette(struct drm_device *dev, int head, bool enable)
260{
261 nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
262 nv_wr08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20);
263}
264
265static inline bool NVGetEnablePalette(struct drm_device *dev, int head)
266{
267 nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
268 return !(nv_rd08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20);
269}
270
271static inline void NVWriteVgaAttr(struct drm_device *dev,
272 int head, uint8_t index, uint8_t value)
273{
274 if (NVGetEnablePalette(dev, head))
275 index &= ~0x20;
276 else
277 index |= 0x20;
278
279 nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
280 NV_REG_DEBUG(VGAATTR, dev, "head %d index 0x%02x data 0x%02x\n",
281 head, index, value);
282 nv_wr08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
283 nv_wr08(dev, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value);
284}
285
286static inline uint8_t NVReadVgaAttr(struct drm_device *dev,
287 int head, uint8_t index)
288{
289 uint8_t val;
290 if (NVGetEnablePalette(dev, head))
291 index &= ~0x20;
292 else
293 index |= 0x20;
294
295 nv_rd08(dev, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
296 nv_wr08(dev, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
297 val = nv_rd08(dev, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE);
298 NV_REG_DEBUG(VGAATTR, dev, "head %d index 0x%02x data 0x%02x\n",
299 head, index, val);
300 return val;
301}
302
303static inline void NVVgaSeqReset(struct drm_device *dev, int head, bool start)
304{
305 NVWriteVgaSeq(dev, head, NV_VIO_SR_RESET_INDEX, start ? 0x1 : 0x3);
306}
307
308static inline void NVVgaProtect(struct drm_device *dev, int head, bool protect)
309{
310 uint8_t seq1 = NVReadVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX);
311
312 if (protect) {
313 NVVgaSeqReset(dev, head, true);
314 NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 | 0x20);
315 } else {
316 /* Reenable sequencer, then turn on screen */
317 NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 & ~0x20); /* reenable display */
318 NVVgaSeqReset(dev, head, false);
319 }
320 NVSetEnablePalette(dev, head, protect);
321}
322
323static inline bool
324nv_heads_tied(struct drm_device *dev)
325{
326 struct drm_nouveau_private *dev_priv = dev->dev_private;
327
328 if (dev_priv->chipset == 0x11)
329 return !!(nvReadMC(dev, NV_PBUS_DEBUG_1) & (1 << 28));
330
331 return NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44) & 0x4;
332}
333
334/* makes cr0-7 on the specified head read-only */
335static inline bool
336nv_lock_vga_crtc_base(struct drm_device *dev, int head, bool lock)
337{
338 uint8_t cr11 = NVReadVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX);
339 bool waslocked = cr11 & 0x80;
340
341 if (lock)
342 cr11 |= 0x80;
343 else
344 cr11 &= ~0x80;
345 NVWriteVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX, cr11);
346
347 return waslocked;
348}
349
350static inline void
351nv_lock_vga_crtc_shadow(struct drm_device *dev, int head, int lock)
352{
353 /* shadow lock: connects 0x60?3d? regs to "real" 0x3d? regs
354 * bit7: unlocks HDT, HBS, HBE, HRS, HRE, HEB
355 * bit6: seems to have some effect on CR09 (double scan, VBS_9)
356 * bit5: unlocks HDE
357 * bit4: unlocks VDE
358 * bit3: unlocks VDT, OVL, VRS, ?VRE?, VBS, VBE, LSR, EBR
359 * bit2: same as bit 1 of 0x60?804
360 * bit0: same as bit 0 of 0x60?804
361 */
362
363 uint8_t cr21 = lock;
364
365 if (lock < 0)
366 /* 0xfa is generic "unlock all" mask */
367 cr21 = NVReadVgaCrtc(dev, head, NV_CIO_CRE_21) | 0xfa;
368
369 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_21, cr21);
370}
371
372/* renders the extended crtc regs (cr19+) on all crtcs impervious:
373 * immutable and unreadable
374 */
375static inline bool
376NVLockVgaCrtcs(struct drm_device *dev, bool lock)
377{
378 struct drm_nouveau_private *dev_priv = dev->dev_private;
379 bool waslocked = !NVReadVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX);
380
381 NVWriteVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX,
382 lock ? NV_CIO_SR_LOCK_VALUE : NV_CIO_SR_UNLOCK_RW_VALUE);
383 /* NV11 has independently lockable extended crtcs, except when tied */
384 if (dev_priv->chipset == 0x11 && !nv_heads_tied(dev))
385 NVWriteVgaCrtc(dev, 1, NV_CIO_SR_LOCK_INDEX,
386 lock ? NV_CIO_SR_LOCK_VALUE :
387 NV_CIO_SR_UNLOCK_RW_VALUE);
388
389 return waslocked;
390}
391
392/* nv04 cursor max dimensions of 32x32 (A1R5G5B5) */
393#define NV04_CURSOR_SIZE 32
394/* limit nv10 cursors to 64x64 (ARGB8) (we could go to 64x255) */
395#define NV10_CURSOR_SIZE 64
396
397static inline int nv_cursor_width(struct drm_device *dev)
398{
399 struct drm_nouveau_private *dev_priv = dev->dev_private;
400
401 return dev_priv->card_type >= NV_10 ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE;
402}
403
404static inline void
405nv_fix_nv40_hw_cursor(struct drm_device *dev, int head)
406{
407 /* on some nv40 (such as the "true" (in the NV_PFB_BOOT_0 sense) nv40,
408 * the gf6800gt) a hardware bug requires a write to PRAMDAC_CURSOR_POS
409 * for changes to the CRTC CURCTL regs to take effect, whether changing
410 * the pixmap location, or just showing/hiding the cursor
411 */
412 uint32_t curpos = NVReadRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS);
413 NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos);
414}
415
416static inline void
Francisco Jerez5794b5f2010-10-22 04:39:14 +0200417nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
418{
419 struct drm_nouveau_private *dev_priv = dev->dev_private;
420
421 NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
422
423 if (dev_priv->card_type == NV_04) {
424 /*
425 * Hilarious, the 24th bit doesn't want to stick to
426 * PCRTC_START...
427 */
428 int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX);
429
430 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX,
431 (cre_heb & ~0x40) | ((offset >> 18) & 0x40));
432 }
433}
434
435static inline void
Ben Skeggs6ee73862009-12-11 19:24:15 +1000436nv_show_cursor(struct drm_device *dev, int head, bool show)
437{
438 struct drm_nouveau_private *dev_priv = dev->dev_private;
439 uint8_t *curctl1 =
440 &dev_priv->mode_reg.crtc_reg[head].CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX];
441
442 if (show)
443 *curctl1 |= MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
444 else
445 *curctl1 &= ~MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
446 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HCUR_ADDR1_INDEX, *curctl1);
447
448 if (dev_priv->card_type == NV_40)
449 nv_fix_nv40_hw_cursor(dev, head);
450}
451
452static inline uint32_t
453nv_pitch_align(struct drm_device *dev, uint32_t width, int bpp)
454{
455 struct drm_nouveau_private *dev_priv = dev->dev_private;
456 int mask;
457
458 if (bpp == 15)
459 bpp = 16;
460 if (bpp == 24)
461 bpp = 8;
462
463 /* Alignment requirements taken from the Haiku driver */
464 if (dev_priv->card_type == NV_04)
465 mask = 128 / bpp - 1;
466 else
467 mask = 512 / bpp - 1;
468
469 return (width + mask) & ~mask;
470}
471
472#endif /* __NOUVEAU_HW_H__ */