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