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 40void NVWriteVgaSeq(struct drm_device *, int head, uint8_t index, uint8_t value); 41uint8_t NVReadVgaSeq(struct drm_device *, int head, uint8_t index); 42void NVWriteVgaGr(struct drm_device *, int head, uint8_t index, uint8_t value); 43uint8_t NVReadVgaGr(struct drm_device *, int head, uint8_t index); 44void NVSetOwner(struct drm_device *, int owner); 45void NVBlankScreen(struct drm_device *, int head, bool blank); 46int nouveau_hw_get_pllvals(struct drm_device *, enum nvbios_pll_type plltype, 47 struct nvkm_pll_vals *pllvals); 48int nouveau_hw_pllvals_to_clk(struct nvkm_pll_vals *pllvals); 49int nouveau_hw_get_clock(struct drm_device *, enum nvbios_pll_type plltype); 50void nouveau_hw_save_vga_fonts(struct drm_device *, bool save); 51void nouveau_hw_save_state(struct drm_device *, int head, 52 struct nv04_mode_state *state); 53void nouveau_hw_load_state(struct drm_device *, int head, 54 struct nv04_mode_state *state); 55void nouveau_hw_load_state_palette(struct drm_device *, int head, 56 struct nv04_mode_state *state); 57 58/* nouveau_calc.c */ 59extern void nouveau_calc_arb(struct drm_device *, int vclk, int bpp, 60 int *burst, int *lwm); 61 62static 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 73static 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 82static 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 93static 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 102static 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 112static 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 122static 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 130static 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 154static inline void 155NVWriteVgaCrtc5758(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 161static 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 167static 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 183static 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 197static 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 204static 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 211static 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 225static 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 241static 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 246static 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 261static inline bool 262nv_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 */ 274static inline bool 275nv_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 289static inline void 290nv_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 */ 314static inline bool 315NVLockVgaCrtcs(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 336static 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 343static inline void 344nv_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 355static inline void 356nv_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 374static inline void 375nv_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 391static inline uint32_t 392nv_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