Home | History | Annotate | Line # | Download | only in dispnv04
hw.h revision 1.1
      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 
     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 	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 
     71 static 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 
     80 static 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 
     91 static 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 
    100 static 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 
    110 static 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 
    120 static 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 
    128 static 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 
    152 static inline void
    153 NVWriteVgaCrtc5758(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 
    159 static 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 
    165 static 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 
    181 static 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 
    195 static 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 
    202 static 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 
    209 static 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 
    223 static 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 
    239 static 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 
    244 static 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 
    259 static inline bool
    260 nv_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 */
    272 static inline bool
    273 nv_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 
    287 static inline void
    288 nv_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  */
    312 static inline bool
    313 NVLockVgaCrtcs(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 
    334 static 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 
    341 static inline void
    342 nv_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 
    353 static inline void
    354 nv_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 
    372 static inline void
    373 nv_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 
    389 static inline uint32_t
    390 nv_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__ */
    410