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