aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/dispnv04/hw.h
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-03-21 01:45:11 -0400
committerBen Skeggs <bskeggs@redhat.com>2013-04-26 01:37:51 -0400
commit1a6463425552a8b9960e5a19b25421895846925c (patch)
treedda4f2208f78dbc654fbfcecb97575c3cc564a7e /drivers/gpu/drm/nouveau/dispnv04/hw.h
parentb9a3140ce8fcd616b02533fbdef375a87a910daf (diff)
drm/nv04/disp: hide all the cruft away in its own little hole
It'd be pretty awesome if someone would care enough to port this all properly to a class interface, perhaps submitting a command stream to the core via a sw object on PFIFO (emulating how EVO works basically, and also what nvidia have done forever..).. But, this seems unlikely given how old this hardware is now, so, lets just hide it away. There's a heap of other bits and pieces laying around that are still tangled. I'll (re)move them in pieces. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv04/hw.h')
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/hw.h409
1 files changed, 409 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.h b/drivers/gpu/drm/nouveau/dispnv04/hw.h
new file mode 100644
index 000000000000..eeb70d912d99
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/dispnv04/hw.h
@@ -0,0 +1,409 @@
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 <drm/drmP.h>
27#include "disp.h"
28#include "nvreg.h"
29
30#include <subdev/bios/pll.h>
31
32#define MASK(field) ( \
33 (0xffffffff >> (31 - ((1 ? field) - (0 ? field)))) << (0 ? field))
34
35#define XLATE(src, srclowbit, outfield) ( \
36 (((src) >> (srclowbit)) << (0 ? outfield)) & MASK(outfield))
37
38void NVWriteVgaSeq(struct drm_device *, int head, uint8_t index, uint8_t value);
39uint8_t NVReadVgaSeq(struct drm_device *, int head, uint8_t index);
40void NVWriteVgaGr(struct drm_device *, int head, uint8_t index, uint8_t value);
41uint8_t NVReadVgaGr(struct drm_device *, int head, uint8_t index);
42void NVSetOwner(struct drm_device *, int owner);
43void NVBlankScreen(struct drm_device *, int head, bool blank);
44int nouveau_hw_get_pllvals(struct drm_device *, enum nvbios_pll_type plltype,
45 struct nouveau_pll_vals *pllvals);
46int nouveau_hw_pllvals_to_clk(struct nouveau_pll_vals *pllvals);
47int nouveau_hw_get_clock(struct drm_device *, enum nvbios_pll_type plltype);
48void nouveau_hw_save_vga_fonts(struct drm_device *, bool save);
49void nouveau_hw_save_state(struct drm_device *, int head,
50 struct nv04_mode_state *state);
51void nouveau_hw_load_state(struct drm_device *, int head,
52 struct nv04_mode_state *state);
53void nouveau_hw_load_state_palette(struct drm_device *, int head,
54 struct nv04_mode_state *state);
55
56/* nouveau_calc.c */
57extern void nouveau_calc_arb(struct drm_device *, int vclk, int bpp,
58 int *burst, int *lwm);
59
60static inline uint32_t NVReadCRTC(struct drm_device *dev,
61 int head, uint32_t reg)
62{
63 struct nouveau_device *device = nouveau_dev(dev);
64 uint32_t val;
65 if (head)
66 reg += NV_PCRTC0_SIZE;
67 val = nv_rd32(device, reg);
68 return val;
69}
70
71static inline void NVWriteCRTC(struct drm_device *dev,
72 int head, uint32_t reg, uint32_t val)
73{
74 struct nouveau_device *device = nouveau_dev(dev);
75 if (head)
76 reg += NV_PCRTC0_SIZE;
77 nv_wr32(device, reg, val);
78}
79
80static inline uint32_t NVReadRAMDAC(struct drm_device *dev,
81 int head, uint32_t reg)
82{
83 struct nouveau_device *device = nouveau_dev(dev);
84 uint32_t val;
85 if (head)
86 reg += NV_PRAMDAC0_SIZE;
87 val = nv_rd32(device, reg);
88 return val;
89}
90
91static inline void NVWriteRAMDAC(struct drm_device *dev,
92 int head, uint32_t reg, uint32_t val)
93{
94 struct nouveau_device *device = nouveau_dev(dev);
95 if (head)
96 reg += NV_PRAMDAC0_SIZE;
97 nv_wr32(device, reg, val);
98}
99
100static inline uint8_t nv_read_tmds(struct drm_device *dev,
101 int or, int dl, uint8_t address)
102{
103 int ramdac = (or & DCB_OUTPUT_C) >> 2;
104
105 NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8,
106 NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE | address);
107 return NVReadRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8);
108}
109
110static inline void nv_write_tmds(struct drm_device *dev,
111 int or, int dl, uint8_t address,
112 uint8_t data)
113{
114 int ramdac = (or & DCB_OUTPUT_C) >> 2;
115
116 NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8, data);
117 NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8, address);
118}
119
120static inline void NVWriteVgaCrtc(struct drm_device *dev,
121 int head, uint8_t index, uint8_t value)
122{
123 struct nouveau_device *device = nouveau_dev(dev);
124 nv_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
125 nv_wr08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value);
126}
127
128static inline uint8_t NVReadVgaCrtc(struct drm_device *dev,
129 int head, uint8_t index)
130{
131 struct nouveau_device *device = nouveau_dev(dev);
132 uint8_t val;
133 nv_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
134 val = nv_rd08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE);
135 return val;
136}
137
138/* CR57 and CR58 are a fun pair of regs. CR57 provides an index (0-0xf) for CR58
139 * I suspect they in fact do nothing, but are merely a way to carry useful
140 * per-head variables around
141 *
142 * Known uses:
143 * CR57 CR58
144 * 0x00 index to the appropriate dcb entry (or 7f for inactive)
145 * 0x02 dcb entry's "or" value (or 00 for inactive)
146 * 0x03 bit0 set for dual link (LVDS, possibly elsewhere too)
147 * 0x08 or 0x09 pxclk in MHz
148 * 0x0f laptop panel info - low nibble for PEXTDEV_BOOT_0 strap
149 * high nibble for xlat strap value
150 */
151
152static inline void
153NVWriteVgaCrtc5758(struct drm_device *dev, int head, uint8_t index, uint8_t value)
154{
155 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
156 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_58, value);
157}
158
159static inline uint8_t NVReadVgaCrtc5758(struct drm_device *dev, int head, uint8_t index)
160{
161 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
162 return NVReadVgaCrtc(dev, head, NV_CIO_CRE_58);
163}
164
165static inline uint8_t NVReadPRMVIO(struct drm_device *dev,
166 int head, uint32_t reg)
167{
168 struct nouveau_device *device = nouveau_dev(dev);
169 struct nouveau_drm *drm = nouveau_drm(dev);
170 uint8_t val;
171
172 /* Only NV4x have two pvio ranges; other twoHeads cards MUST call
173 * NVSetOwner for the relevant head to be programmed */
174 if (head && nv_device(drm->device)->card_type == NV_40)
175 reg += NV_PRMVIO_SIZE;
176
177 val = nv_rd08(device, reg);
178 return val;
179}
180
181static inline void NVWritePRMVIO(struct drm_device *dev,
182 int head, uint32_t reg, uint8_t value)
183{
184 struct nouveau_device *device = nouveau_dev(dev);
185 struct nouveau_drm *drm = nouveau_drm(dev);
186
187 /* Only NV4x have two pvio ranges; other twoHeads cards MUST call
188 * NVSetOwner for the relevant head to be programmed */
189 if (head && nv_device(drm->device)->card_type == NV_40)
190 reg += NV_PRMVIO_SIZE;
191
192 nv_wr08(device, reg, value);
193}
194
195static inline void NVSetEnablePalette(struct drm_device *dev, int head, bool enable)
196{
197 struct nouveau_device *device = nouveau_dev(dev);
198 nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
199 nv_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20);
200}
201
202static inline bool NVGetEnablePalette(struct drm_device *dev, int head)
203{
204 struct nouveau_device *device = nouveau_dev(dev);
205 nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
206 return !(nv_rd08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20);
207}
208
209static inline void NVWriteVgaAttr(struct drm_device *dev,
210 int head, uint8_t index, uint8_t value)
211{
212 struct nouveau_device *device = nouveau_dev(dev);
213 if (NVGetEnablePalette(dev, head))
214 index &= ~0x20;
215 else
216 index |= 0x20;
217
218 nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
219 nv_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
220 nv_wr08(device, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value);
221}
222
223static inline uint8_t NVReadVgaAttr(struct drm_device *dev,
224 int head, uint8_t index)
225{
226 struct nouveau_device *device = nouveau_dev(dev);
227 uint8_t val;
228 if (NVGetEnablePalette(dev, head))
229 index &= ~0x20;
230 else
231 index |= 0x20;
232
233 nv_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
234 nv_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
235 val = nv_rd08(device, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE);
236 return val;
237}
238
239static inline void NVVgaSeqReset(struct drm_device *dev, int head, bool start)
240{
241 NVWriteVgaSeq(dev, head, NV_VIO_SR_RESET_INDEX, start ? 0x1 : 0x3);
242}
243
244static inline void NVVgaProtect(struct drm_device *dev, int head, bool protect)
245{
246 uint8_t seq1 = NVReadVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX);
247
248 if (protect) {
249 NVVgaSeqReset(dev, head, true);
250 NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 | 0x20);
251 } else {
252 /* Reenable sequencer, then turn on screen */
253 NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 & ~0x20); /* reenable display */
254 NVVgaSeqReset(dev, head, false);
255 }
256 NVSetEnablePalette(dev, head, protect);
257}
258
259static inline bool
260nv_heads_tied(struct drm_device *dev)
261{
262 struct nouveau_device *device = nouveau_dev(dev);
263 struct nouveau_drm *drm = nouveau_drm(dev);
264
265 if (nv_device(drm->device)->chipset == 0x11)
266 return !!(nv_rd32(device, NV_PBUS_DEBUG_1) & (1 << 28));
267
268 return NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44) & 0x4;
269}
270
271/* makes cr0-7 on the specified head read-only */
272static inline bool
273nv_lock_vga_crtc_base(struct drm_device *dev, int head, bool lock)
274{
275 uint8_t cr11 = NVReadVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX);
276 bool waslocked = cr11 & 0x80;
277
278 if (lock)
279 cr11 |= 0x80;
280 else
281 cr11 &= ~0x80;
282 NVWriteVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX, cr11);
283
284 return waslocked;
285}
286
287static inline void
288nv_lock_vga_crtc_shadow(struct drm_device *dev, int head, int lock)
289{
290 /* shadow lock: connects 0x60?3d? regs to "real" 0x3d? regs
291 * bit7: unlocks HDT, HBS, HBE, HRS, HRE, HEB
292 * bit6: seems to have some effect on CR09 (double scan, VBS_9)
293 * bit5: unlocks HDE
294 * bit4: unlocks VDE
295 * bit3: unlocks VDT, OVL, VRS, ?VRE?, VBS, VBE, LSR, EBR
296 * bit2: same as bit 1 of 0x60?804
297 * bit0: same as bit 0 of 0x60?804
298 */
299
300 uint8_t cr21 = lock;
301
302 if (lock < 0)
303 /* 0xfa is generic "unlock all" mask */
304 cr21 = NVReadVgaCrtc(dev, head, NV_CIO_CRE_21) | 0xfa;
305
306 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_21, cr21);
307}
308
309/* renders the extended crtc regs (cr19+) on all crtcs impervious:
310 * immutable and unreadable
311 */
312static inline bool
313NVLockVgaCrtcs(struct drm_device *dev, bool lock)
314{
315 struct nouveau_drm *drm = nouveau_drm(dev);
316 bool waslocked = !NVReadVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX);
317
318 NVWriteVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX,
319 lock ? NV_CIO_SR_LOCK_VALUE : NV_CIO_SR_UNLOCK_RW_VALUE);
320 /* NV11 has independently lockable extended crtcs, except when tied */
321 if (nv_device(drm->device)->chipset == 0x11 && !nv_heads_tied(dev))
322 NVWriteVgaCrtc(dev, 1, NV_CIO_SR_LOCK_INDEX,
323 lock ? NV_CIO_SR_LOCK_VALUE :
324 NV_CIO_SR_UNLOCK_RW_VALUE);
325
326 return waslocked;
327}
328
329/* nv04 cursor max dimensions of 32x32 (A1R5G5B5) */
330#define NV04_CURSOR_SIZE 32
331/* limit nv10 cursors to 64x64 (ARGB8) (we could go to 64x255) */
332#define NV10_CURSOR_SIZE 64
333
334static inline int nv_cursor_width(struct drm_device *dev)
335{
336 struct nouveau_drm *drm = nouveau_drm(dev);
337
338 return nv_device(drm->device)->card_type >= NV_10 ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE;
339}
340
341static inline void
342nv_fix_nv40_hw_cursor(struct drm_device *dev, int head)
343{
344 /* on some nv40 (such as the "true" (in the NV_PFB_BOOT_0 sense) nv40,
345 * the gf6800gt) a hardware bug requires a write to PRAMDAC_CURSOR_POS
346 * for changes to the CRTC CURCTL regs to take effect, whether changing
347 * the pixmap location, or just showing/hiding the cursor
348 */
349 uint32_t curpos = NVReadRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS);
350 NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos);
351}
352
353static inline void
354nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
355{
356 struct nouveau_drm *drm = nouveau_drm(dev);
357
358 NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
359
360 if (nv_device(drm->device)->card_type == NV_04) {
361 /*
362 * Hilarious, the 24th bit doesn't want to stick to
363 * PCRTC_START...
364 */
365 int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX);
366
367 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX,
368 (cre_heb & ~0x40) | ((offset >> 18) & 0x40));
369 }
370}
371
372static inline void
373nv_show_cursor(struct drm_device *dev, int head, bool show)
374{
375 struct nouveau_drm *drm = nouveau_drm(dev);
376 uint8_t *curctl1 =
377 &nv04_display(dev)->mode_reg.crtc_reg[head].CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX];
378
379 if (show)
380 *curctl1 |= MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
381 else
382 *curctl1 &= ~MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
383 NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HCUR_ADDR1_INDEX, *curctl1);
384
385 if (nv_device(drm->device)->card_type == NV_40)
386 nv_fix_nv40_hw_cursor(dev, head);
387}
388
389static inline uint32_t
390nv_pitch_align(struct drm_device *dev, uint32_t width, int bpp)
391{
392 struct nouveau_drm *drm = nouveau_drm(dev);
393 int mask;
394
395 if (bpp == 15)
396 bpp = 16;
397 if (bpp == 24)
398 bpp = 8;
399
400 /* Alignment requirements taken from the Haiku driver */
401 if (nv_device(drm->device)->card_type == NV_04)
402 mask = 128 / bpp - 1;
403 else
404 mask = 512 / bpp - 1;
405
406 return (width + mask) & ~mask;
407}
408
409#endif /* __NOUVEAU_HW_H__ */