Home | History | Annotate | Line # | Download | only in dispnv04
hw.h revision 1.2
      1 /*	$NetBSD: hw.h,v 1.2 2018/08/27 04:58:29 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2008 Stuart Bennett
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     20  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     21  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  */
     24 
     25 #ifndef __NOUVEAU_HW_H__
     26 #define __NOUVEAU_HW_H__
     27 
     28 #include <drm/drmP.h>
     29 #include "disp.h"
     30 #include "nvreg.h"
     31 
     32 #include <subdev/bios/pll.h>
     33 
     34 #define MASK(field) ( \
     35 	(0xffffffff >> (31 - ((1 ? field) - (0 ? field)))) << (0 ? field))
     36 
     37 #define XLATE(src, srclowbit, outfield) ( \
     38 	(((src) >> (srclowbit)) << (0 ? outfield)) & MASK(outfield))
     39 
     40 void NVWriteVgaSeq(struct drm_device *, int head, uint8_t index, uint8_t value);
     41 uint8_t NVReadVgaSeq(struct drm_device *, int head, uint8_t index);
     42 void NVWriteVgaGr(struct drm_device *, int head, uint8_t index, uint8_t value);
     43 uint8_t NVReadVgaGr(struct drm_device *, int head, uint8_t index);
     44 void NVSetOwner(struct drm_device *, int owner);
     45 void NVBlankScreen(struct drm_device *, int head, bool blank);
     46 int nouveau_hw_get_pllvals(struct drm_device *, enum nvbios_pll_type plltype,
     47 			   struct nvkm_pll_vals *pllvals);
     48 int nouveau_hw_pllvals_to_clk(struct nvkm_pll_vals *pllvals);
     49 int nouveau_hw_get_clock(struct drm_device *, enum nvbios_pll_type plltype);
     50 void nouveau_hw_save_vga_fonts(struct drm_device *, bool save);
     51 void nouveau_hw_save_state(struct drm_device *, int head,
     52 			   struct nv04_mode_state *state);
     53 void nouveau_hw_load_state(struct drm_device *, int head,
     54 			   struct nv04_mode_state *state);
     55 void nouveau_hw_load_state_palette(struct drm_device *, int head,
     56 				   struct nv04_mode_state *state);
     57 
     58 /* nouveau_calc.c */
     59 extern void nouveau_calc_arb(struct drm_device *, int vclk, int bpp,
     60 			     int *burst, int *lwm);
     61 
     62 static inline uint32_t NVReadCRTC(struct drm_device *dev,
     63 					int head, uint32_t reg)
     64 {
     65 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
     66 	uint32_t val;
     67 	if (head)
     68 		reg += NV_PCRTC0_SIZE;
     69 	val = nvif_rd32(device, reg);
     70 	return val;
     71 }
     72 
     73 static inline void NVWriteCRTC(struct drm_device *dev,
     74 					int head, uint32_t reg, uint32_t val)
     75 {
     76 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
     77 	if (head)
     78 		reg += NV_PCRTC0_SIZE;
     79 	nvif_wr32(device, reg, val);
     80 }
     81 
     82 static inline uint32_t NVReadRAMDAC(struct drm_device *dev,
     83 					int head, uint32_t reg)
     84 {
     85 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
     86 	uint32_t val;
     87 	if (head)
     88 		reg += NV_PRAMDAC0_SIZE;
     89 	val = nvif_rd32(device, reg);
     90 	return val;
     91 }
     92 
     93 static inline void NVWriteRAMDAC(struct drm_device *dev,
     94 					int head, uint32_t reg, uint32_t val)
     95 {
     96 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
     97 	if (head)
     98 		reg += NV_PRAMDAC0_SIZE;
     99 	nvif_wr32(device, reg, val);
    100 }
    101 
    102 static inline uint8_t nv_read_tmds(struct drm_device *dev,
    103 					int or, int dl, uint8_t address)
    104 {
    105 	int ramdac = (or & DCB_OUTPUT_C) >> 2;
    106 
    107 	NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8,
    108 	NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE | address);
    109 	return NVReadRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8);
    110 }
    111 
    112 static inline void nv_write_tmds(struct drm_device *dev,
    113 					int or, int dl, uint8_t address,
    114 					uint8_t data)
    115 {
    116 	int ramdac = (or & DCB_OUTPUT_C) >> 2;
    117 
    118 	NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8, data);
    119 	NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8, address);
    120 }
    121 
    122 static inline void NVWriteVgaCrtc(struct drm_device *dev,
    123 					int head, uint8_t index, uint8_t value)
    124 {
    125 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
    126 	nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
    127 	nvif_wr08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value);
    128 }
    129 
    130 static inline uint8_t NVReadVgaCrtc(struct drm_device *dev,
    131 					int head, uint8_t index)
    132 {
    133 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
    134 	uint8_t val;
    135 	nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
    136 	val = nvif_rd08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE);
    137 	return val;
    138 }
    139 
    140 /* CR57 and CR58 are a fun pair of regs. CR57 provides an index (0-0xf) for CR58
    141  * I suspect they in fact do nothing, but are merely a way to carry useful
    142  * per-head variables around
    143  *
    144  * Known uses:
    145  * CR57		CR58
    146  * 0x00		index to the appropriate dcb entry (or 7f for inactive)
    147  * 0x02		dcb entry's "or" value (or 00 for inactive)
    148  * 0x03		bit0 set for dual link (LVDS, possibly elsewhere too)
    149  * 0x08 or 0x09	pxclk in MHz
    150  * 0x0f		laptop panel info -	low nibble for PEXTDEV_BOOT_0 strap
    151  * 					high nibble for xlat strap value
    152  */
    153 
    154 static inline void
    155 NVWriteVgaCrtc5758(struct drm_device *dev, int head, uint8_t index, uint8_t value)
    156 {
    157 	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
    158 	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_58, value);
    159 }
    160 
    161 static inline uint8_t NVReadVgaCrtc5758(struct drm_device *dev, int head, uint8_t index)
    162 {
    163 	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
    164 	return NVReadVgaCrtc(dev, head, NV_CIO_CRE_58);
    165 }
    166 
    167 static inline uint8_t NVReadPRMVIO(struct drm_device *dev,
    168 					int head, uint32_t reg)
    169 {
    170 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
    171 	struct nouveau_drm *drm = nouveau_drm(dev);
    172 	uint8_t val;
    173 
    174 	/* Only NV4x have two pvio ranges; other twoHeads cards MUST call
    175 	 * NVSetOwner for the relevant head to be programmed */
    176 	if (head && drm->device.info.family == NV_DEVICE_INFO_V0_CURIE)
    177 		reg += NV_PRMVIO_SIZE;
    178 
    179 	val = nvif_rd08(device, reg);
    180 	return val;
    181 }
    182 
    183 static inline void NVWritePRMVIO(struct drm_device *dev,
    184 					int head, uint32_t reg, uint8_t value)
    185 {
    186 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
    187 	struct nouveau_drm *drm = nouveau_drm(dev);
    188 
    189 	/* Only NV4x have two pvio ranges; other twoHeads cards MUST call
    190 	 * NVSetOwner for the relevant head to be programmed */
    191 	if (head && drm->device.info.family == NV_DEVICE_INFO_V0_CURIE)
    192 		reg += NV_PRMVIO_SIZE;
    193 
    194 	nvif_wr08(device, reg, value);
    195 }
    196 
    197 static inline void NVSetEnablePalette(struct drm_device *dev, int head, bool enable)
    198 {
    199 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
    200 	nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
    201 	nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20);
    202 }
    203 
    204 static inline bool NVGetEnablePalette(struct drm_device *dev, int head)
    205 {
    206 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
    207 	nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
    208 	return !(nvif_rd08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20);
    209 }
    210 
    211 static inline void NVWriteVgaAttr(struct drm_device *dev,
    212 					int head, uint8_t index, uint8_t value)
    213 {
    214 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
    215 	if (NVGetEnablePalette(dev, head))
    216 		index &= ~0x20;
    217 	else
    218 		index |= 0x20;
    219 
    220 	nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
    221 	nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
    222 	nvif_wr08(device, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value);
    223 }
    224 
    225 static inline uint8_t NVReadVgaAttr(struct drm_device *dev,
    226 					int head, uint8_t index)
    227 {
    228 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
    229 	uint8_t val;
    230 	if (NVGetEnablePalette(dev, head))
    231 		index &= ~0x20;
    232 	else
    233 		index |= 0x20;
    234 
    235 	nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
    236 	nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
    237 	val = nvif_rd08(device, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE);
    238 	return val;
    239 }
    240 
    241 static inline void NVVgaSeqReset(struct drm_device *dev, int head, bool start)
    242 {
    243 	NVWriteVgaSeq(dev, head, NV_VIO_SR_RESET_INDEX, start ? 0x1 : 0x3);
    244 }
    245 
    246 static inline void NVVgaProtect(struct drm_device *dev, int head, bool protect)
    247 {
    248 	uint8_t seq1 = NVReadVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX);
    249 
    250 	if (protect) {
    251 		NVVgaSeqReset(dev, head, true);
    252 		NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 | 0x20);
    253 	} else {
    254 		/* Reenable sequencer, then turn on screen */
    255 		NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 & ~0x20);   /* reenable display */
    256 		NVVgaSeqReset(dev, head, false);
    257 	}
    258 	NVSetEnablePalette(dev, head, protect);
    259 }
    260 
    261 static inline bool
    262 nv_heads_tied(struct drm_device *dev)
    263 {
    264 	struct nvif_object *device = &nouveau_drm(dev)->device.object;
    265 	struct nouveau_drm *drm = nouveau_drm(dev);
    266 
    267 	if (drm->device.info.chipset == 0x11)
    268 		return !!(nvif_rd32(device, NV_PBUS_DEBUG_1) & (1 << 28));
    269 
    270 	return NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44) & 0x4;
    271 }
    272 
    273 /* makes cr0-7 on the specified head read-only */
    274 static inline bool
    275 nv_lock_vga_crtc_base(struct drm_device *dev, int head, bool lock)
    276 {
    277 	uint8_t cr11 = NVReadVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX);
    278 	bool waslocked = cr11 & 0x80;
    279 
    280 	if (lock)
    281 		cr11 |= 0x80;
    282 	else
    283 		cr11 &= ~0x80;
    284 	NVWriteVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX, cr11);
    285 
    286 	return waslocked;
    287 }
    288 
    289 static inline void
    290 nv_lock_vga_crtc_shadow(struct drm_device *dev, int head, int lock)
    291 {
    292 	/* shadow lock: connects 0x60?3d? regs to "real" 0x3d? regs
    293 	 * bit7: unlocks HDT, HBS, HBE, HRS, HRE, HEB
    294 	 * bit6: seems to have some effect on CR09 (double scan, VBS_9)
    295 	 * bit5: unlocks HDE
    296 	 * bit4: unlocks VDE
    297 	 * bit3: unlocks VDT, OVL, VRS, ?VRE?, VBS, VBE, LSR, EBR
    298 	 * bit2: same as bit 1 of 0x60?804
    299 	 * bit0: same as bit 0 of 0x60?804
    300 	 */
    301 
    302 	uint8_t cr21 = lock;
    303 
    304 	if (lock < 0)
    305 		/* 0xfa is generic "unlock all" mask */
    306 		cr21 = NVReadVgaCrtc(dev, head, NV_CIO_CRE_21) | 0xfa;
    307 
    308 	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_21, cr21);
    309 }
    310 
    311 /* renders the extended crtc regs (cr19+) on all crtcs impervious:
    312  * immutable and unreadable
    313  */
    314 static inline bool
    315 NVLockVgaCrtcs(struct drm_device *dev, bool lock)
    316 {
    317 	struct nouveau_drm *drm = nouveau_drm(dev);
    318 	bool waslocked = !NVReadVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX);
    319 
    320 	NVWriteVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX,
    321 		       lock ? NV_CIO_SR_LOCK_VALUE : NV_CIO_SR_UNLOCK_RW_VALUE);
    322 	/* NV11 has independently lockable extended crtcs, except when tied */
    323 	if (drm->device.info.chipset == 0x11 && !nv_heads_tied(dev))
    324 		NVWriteVgaCrtc(dev, 1, NV_CIO_SR_LOCK_INDEX,
    325 			       lock ? NV_CIO_SR_LOCK_VALUE :
    326 				      NV_CIO_SR_UNLOCK_RW_VALUE);
    327 
    328 	return waslocked;
    329 }
    330 
    331 /* nv04 cursor max dimensions of 32x32 (A1R5G5B5) */
    332 #define NV04_CURSOR_SIZE 32
    333 /* limit nv10 cursors to 64x64 (ARGB8) (we could go to 64x255) */
    334 #define NV10_CURSOR_SIZE 64
    335 
    336 static inline int nv_cursor_width(struct drm_device *dev)
    337 {
    338 	struct nouveau_drm *drm = nouveau_drm(dev);
    339 
    340 	return drm->device.info.family >= NV_DEVICE_INFO_V0_CELSIUS ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE;
    341 }
    342 
    343 static inline void
    344 nv_fix_nv40_hw_cursor(struct drm_device *dev, int head)
    345 {
    346 	/* on some nv40 (such as the "true" (in the NV_PFB_BOOT_0 sense) nv40,
    347 	 * the gf6800gt) a hardware bug requires a write to PRAMDAC_CURSOR_POS
    348 	 * for changes to the CRTC CURCTL regs to take effect, whether changing
    349 	 * the pixmap location, or just showing/hiding the cursor
    350 	 */
    351 	uint32_t curpos = NVReadRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS);
    352 	NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos);
    353 }
    354 
    355 static inline void
    356 nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
    357 {
    358 	struct nouveau_drm *drm = nouveau_drm(dev);
    359 
    360 	NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
    361 
    362 	if (drm->device.info.family == NV_DEVICE_INFO_V0_TNT) {
    363 		/*
    364 		 * Hilarious, the 24th bit doesn't want to stick to
    365 		 * PCRTC_START...
    366 		 */
    367 		int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX);
    368 
    369 		NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX,
    370 			       (cre_heb & ~0x40) | ((offset >> 18) & 0x40));
    371 	}
    372 }
    373 
    374 static inline void
    375 nv_show_cursor(struct drm_device *dev, int head, bool show)
    376 {
    377 	struct nouveau_drm *drm = nouveau_drm(dev);
    378 	uint8_t *curctl1 =
    379 		&nv04_display(dev)->mode_reg.crtc_reg[head].CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX];
    380 
    381 	if (show)
    382 		*curctl1 |= MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
    383 	else
    384 		*curctl1 &= ~MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
    385 	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HCUR_ADDR1_INDEX, *curctl1);
    386 
    387 	if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE)
    388 		nv_fix_nv40_hw_cursor(dev, head);
    389 }
    390 
    391 static inline uint32_t
    392 nv_pitch_align(struct drm_device *dev, uint32_t width, int bpp)
    393 {
    394 	struct nouveau_drm *drm = nouveau_drm(dev);
    395 	int mask;
    396 
    397 	if (bpp == 15)
    398 		bpp = 16;
    399 	if (bpp == 24)
    400 		bpp = 8;
    401 
    402 	/* Alignment requirements taken from the Haiku driver */
    403 	if (drm->device.info.family == NV_DEVICE_INFO_V0_TNT)
    404 		mask = 128 / bpp - 1;
    405 	else
    406 		mask = 512 / bpp - 1;
    407 
    408 	return (width + mask) & ~mask;
    409 }
    410 
    411 #endif	/* __NOUVEAU_HW_H__ */
    412