162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2008 Stuart Bennett 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1262306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1762306a36Sopenharmony_ci * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 1862306a36Sopenharmony_ci * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 1962306a36Sopenharmony_ci * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2062306a36Sopenharmony_ci * SOFTWARE. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#ifndef __NOUVEAU_HW_H__ 2462306a36Sopenharmony_ci#define __NOUVEAU_HW_H__ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "disp.h" 2762306a36Sopenharmony_ci#include "nvreg.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <subdev/bios/pll.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define MASK(field) ( \ 3262306a36Sopenharmony_ci (0xffffffff >> (31 - ((1 ? field) - (0 ? field)))) << (0 ? field)) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define XLATE(src, srclowbit, outfield) ( \ 3562306a36Sopenharmony_ci (((src) >> (srclowbit)) << (0 ? outfield)) & MASK(outfield)) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_civoid NVWriteVgaSeq(struct drm_device *, int head, uint8_t index, uint8_t value); 3862306a36Sopenharmony_ciuint8_t NVReadVgaSeq(struct drm_device *, int head, uint8_t index); 3962306a36Sopenharmony_civoid NVWriteVgaGr(struct drm_device *, int head, uint8_t index, uint8_t value); 4062306a36Sopenharmony_ciuint8_t NVReadVgaGr(struct drm_device *, int head, uint8_t index); 4162306a36Sopenharmony_civoid NVSetOwner(struct drm_device *, int owner); 4262306a36Sopenharmony_civoid NVBlankScreen(struct drm_device *, int head, bool blank); 4362306a36Sopenharmony_ciint nouveau_hw_get_pllvals(struct drm_device *, enum nvbios_pll_type plltype, 4462306a36Sopenharmony_ci struct nvkm_pll_vals *pllvals); 4562306a36Sopenharmony_ciint nouveau_hw_pllvals_to_clk(struct nvkm_pll_vals *pllvals); 4662306a36Sopenharmony_ciint nouveau_hw_get_clock(struct drm_device *, enum nvbios_pll_type plltype); 4762306a36Sopenharmony_civoid nouveau_hw_save_vga_fonts(struct drm_device *, bool save); 4862306a36Sopenharmony_civoid nouveau_hw_save_state(struct drm_device *, int head, 4962306a36Sopenharmony_ci struct nv04_mode_state *state); 5062306a36Sopenharmony_civoid nouveau_hw_load_state(struct drm_device *, int head, 5162306a36Sopenharmony_ci struct nv04_mode_state *state); 5262306a36Sopenharmony_civoid nouveau_hw_load_state_palette(struct drm_device *, int head, 5362306a36Sopenharmony_ci struct nv04_mode_state *state); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* nouveau_calc.c */ 5662306a36Sopenharmony_ciextern void nouveau_calc_arb(struct drm_device *, int vclk, int bpp, 5762306a36Sopenharmony_ci int *burst, int *lwm); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline uint32_t NVReadCRTC(struct drm_device *dev, 6062306a36Sopenharmony_ci int head, uint32_t reg) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 6362306a36Sopenharmony_ci uint32_t val; 6462306a36Sopenharmony_ci if (head) 6562306a36Sopenharmony_ci reg += NV_PCRTC0_SIZE; 6662306a36Sopenharmony_ci val = nvif_rd32(device, reg); 6762306a36Sopenharmony_ci return val; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic inline void NVWriteCRTC(struct drm_device *dev, 7162306a36Sopenharmony_ci int head, uint32_t reg, uint32_t val) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 7462306a36Sopenharmony_ci if (head) 7562306a36Sopenharmony_ci reg += NV_PCRTC0_SIZE; 7662306a36Sopenharmony_ci nvif_wr32(device, reg, val); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic inline uint32_t NVReadRAMDAC(struct drm_device *dev, 8062306a36Sopenharmony_ci int head, uint32_t reg) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 8362306a36Sopenharmony_ci uint32_t val; 8462306a36Sopenharmony_ci if (head) 8562306a36Sopenharmony_ci reg += NV_PRAMDAC0_SIZE; 8662306a36Sopenharmony_ci val = nvif_rd32(device, reg); 8762306a36Sopenharmony_ci return val; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic inline void NVWriteRAMDAC(struct drm_device *dev, 9162306a36Sopenharmony_ci int head, uint32_t reg, uint32_t val) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 9462306a36Sopenharmony_ci if (head) 9562306a36Sopenharmony_ci reg += NV_PRAMDAC0_SIZE; 9662306a36Sopenharmony_ci nvif_wr32(device, reg, val); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic inline uint8_t nv_read_tmds(struct drm_device *dev, 10062306a36Sopenharmony_ci int or, int dl, uint8_t address) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci int ramdac = (or & DCB_OUTPUT_C) >> 2; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8, 10562306a36Sopenharmony_ci NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE | address); 10662306a36Sopenharmony_ci return NVReadRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic inline void nv_write_tmds(struct drm_device *dev, 11062306a36Sopenharmony_ci int or, int dl, uint8_t address, 11162306a36Sopenharmony_ci uint8_t data) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci int ramdac = (or & DCB_OUTPUT_C) >> 2; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8, data); 11662306a36Sopenharmony_ci NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8, address); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic inline void NVWriteVgaCrtc(struct drm_device *dev, 12062306a36Sopenharmony_ci int head, uint8_t index, uint8_t value) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 12362306a36Sopenharmony_ci nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index); 12462306a36Sopenharmony_ci nvif_wr08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic inline uint8_t NVReadVgaCrtc(struct drm_device *dev, 12862306a36Sopenharmony_ci int head, uint8_t index) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 13162306a36Sopenharmony_ci uint8_t val; 13262306a36Sopenharmony_ci nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index); 13362306a36Sopenharmony_ci val = nvif_rd08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE); 13462306a36Sopenharmony_ci return val; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* CR57 and CR58 are a fun pair of regs. CR57 provides an index (0-0xf) for CR58 13862306a36Sopenharmony_ci * I suspect they in fact do nothing, but are merely a way to carry useful 13962306a36Sopenharmony_ci * per-head variables around 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * Known uses: 14262306a36Sopenharmony_ci * CR57 CR58 14362306a36Sopenharmony_ci * 0x00 index to the appropriate dcb entry (or 7f for inactive) 14462306a36Sopenharmony_ci * 0x02 dcb entry's "or" value (or 00 for inactive) 14562306a36Sopenharmony_ci * 0x03 bit0 set for dual link (LVDS, possibly elsewhere too) 14662306a36Sopenharmony_ci * 0x08 or 0x09 pxclk in MHz 14762306a36Sopenharmony_ci * 0x0f laptop panel info - low nibble for PEXTDEV_BOOT_0 strap 14862306a36Sopenharmony_ci * high nibble for xlat strap value 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic inline void 15262306a36Sopenharmony_ciNVWriteVgaCrtc5758(struct drm_device *dev, int head, uint8_t index, uint8_t value) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index); 15562306a36Sopenharmony_ci NVWriteVgaCrtc(dev, head, NV_CIO_CRE_58, value); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic inline uint8_t NVReadVgaCrtc5758(struct drm_device *dev, int head, uint8_t index) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index); 16162306a36Sopenharmony_ci return NVReadVgaCrtc(dev, head, NV_CIO_CRE_58); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic inline uint8_t NVReadPRMVIO(struct drm_device *dev, 16562306a36Sopenharmony_ci int head, uint32_t reg) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 16862306a36Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(dev); 16962306a36Sopenharmony_ci uint8_t val; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Only NV4x have two pvio ranges; other twoHeads cards MUST call 17262306a36Sopenharmony_ci * NVSetOwner for the relevant head to be programmed */ 17362306a36Sopenharmony_ci if (head && drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE) 17462306a36Sopenharmony_ci reg += NV_PRMVIO_SIZE; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci val = nvif_rd08(device, reg); 17762306a36Sopenharmony_ci return val; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic inline void NVWritePRMVIO(struct drm_device *dev, 18162306a36Sopenharmony_ci int head, uint32_t reg, uint8_t value) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 18462306a36Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(dev); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* Only NV4x have two pvio ranges; other twoHeads cards MUST call 18762306a36Sopenharmony_ci * NVSetOwner for the relevant head to be programmed */ 18862306a36Sopenharmony_ci if (head && drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE) 18962306a36Sopenharmony_ci reg += NV_PRMVIO_SIZE; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci nvif_wr08(device, reg, value); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic inline void NVSetEnablePalette(struct drm_device *dev, int head, bool enable) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 19762306a36Sopenharmony_ci nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); 19862306a36Sopenharmony_ci nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic inline bool NVGetEnablePalette(struct drm_device *dev, int head) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 20462306a36Sopenharmony_ci nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); 20562306a36Sopenharmony_ci return !(nvif_rd08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic inline void NVWriteVgaAttr(struct drm_device *dev, 20962306a36Sopenharmony_ci int head, uint8_t index, uint8_t value) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 21262306a36Sopenharmony_ci if (NVGetEnablePalette(dev, head)) 21362306a36Sopenharmony_ci index &= ~0x20; 21462306a36Sopenharmony_ci else 21562306a36Sopenharmony_ci index |= 0x20; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); 21862306a36Sopenharmony_ci nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index); 21962306a36Sopenharmony_ci nvif_wr08(device, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic inline uint8_t NVReadVgaAttr(struct drm_device *dev, 22362306a36Sopenharmony_ci int head, uint8_t index) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 22662306a36Sopenharmony_ci uint8_t val; 22762306a36Sopenharmony_ci if (NVGetEnablePalette(dev, head)) 22862306a36Sopenharmony_ci index &= ~0x20; 22962306a36Sopenharmony_ci else 23062306a36Sopenharmony_ci index |= 0x20; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); 23362306a36Sopenharmony_ci nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index); 23462306a36Sopenharmony_ci val = nvif_rd08(device, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE); 23562306a36Sopenharmony_ci return val; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic inline void NVVgaSeqReset(struct drm_device *dev, int head, bool start) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci NVWriteVgaSeq(dev, head, NV_VIO_SR_RESET_INDEX, start ? 0x1 : 0x3); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic inline void NVVgaProtect(struct drm_device *dev, int head, bool protect) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci uint8_t seq1 = NVReadVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (protect) { 24862306a36Sopenharmony_ci NVVgaSeqReset(dev, head, true); 24962306a36Sopenharmony_ci NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 | 0x20); 25062306a36Sopenharmony_ci } else { 25162306a36Sopenharmony_ci /* Reenable sequencer, then turn on screen */ 25262306a36Sopenharmony_ci NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 & ~0x20); /* reenable display */ 25362306a36Sopenharmony_ci NVVgaSeqReset(dev, head, false); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci NVSetEnablePalette(dev, head, protect); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic inline bool 25962306a36Sopenharmony_cinv_heads_tied(struct drm_device *dev) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct nvif_object *device = &nouveau_drm(dev)->client.device.object; 26262306a36Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(dev); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (drm->client.device.info.chipset == 0x11) 26562306a36Sopenharmony_ci return !!(nvif_rd32(device, NV_PBUS_DEBUG_1) & (1 << 28)); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44) & 0x4; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/* makes cr0-7 on the specified head read-only */ 27162306a36Sopenharmony_cistatic inline bool 27262306a36Sopenharmony_cinv_lock_vga_crtc_base(struct drm_device *dev, int head, bool lock) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci uint8_t cr11 = NVReadVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX); 27562306a36Sopenharmony_ci bool waslocked = cr11 & 0x80; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (lock) 27862306a36Sopenharmony_ci cr11 |= 0x80; 27962306a36Sopenharmony_ci else 28062306a36Sopenharmony_ci cr11 &= ~0x80; 28162306a36Sopenharmony_ci NVWriteVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX, cr11); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return waslocked; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic inline void 28762306a36Sopenharmony_cinv_lock_vga_crtc_shadow(struct drm_device *dev, int head, int lock) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci /* shadow lock: connects 0x60?3d? regs to "real" 0x3d? regs 29062306a36Sopenharmony_ci * bit7: unlocks HDT, HBS, HBE, HRS, HRE, HEB 29162306a36Sopenharmony_ci * bit6: seems to have some effect on CR09 (double scan, VBS_9) 29262306a36Sopenharmony_ci * bit5: unlocks HDE 29362306a36Sopenharmony_ci * bit4: unlocks VDE 29462306a36Sopenharmony_ci * bit3: unlocks VDT, OVL, VRS, ?VRE?, VBS, VBE, LSR, EBR 29562306a36Sopenharmony_ci * bit2: same as bit 1 of 0x60?804 29662306a36Sopenharmony_ci * bit0: same as bit 0 of 0x60?804 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci uint8_t cr21 = lock; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (lock < 0) 30262306a36Sopenharmony_ci /* 0xfa is generic "unlock all" mask */ 30362306a36Sopenharmony_ci cr21 = NVReadVgaCrtc(dev, head, NV_CIO_CRE_21) | 0xfa; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci NVWriteVgaCrtc(dev, head, NV_CIO_CRE_21, cr21); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* renders the extended crtc regs (cr19+) on all crtcs impervious: 30962306a36Sopenharmony_ci * immutable and unreadable 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_cistatic inline bool 31262306a36Sopenharmony_ciNVLockVgaCrtcs(struct drm_device *dev, bool lock) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(dev); 31562306a36Sopenharmony_ci bool waslocked = !NVReadVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci NVWriteVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX, 31862306a36Sopenharmony_ci lock ? NV_CIO_SR_LOCK_VALUE : NV_CIO_SR_UNLOCK_RW_VALUE); 31962306a36Sopenharmony_ci /* NV11 has independently lockable extended crtcs, except when tied */ 32062306a36Sopenharmony_ci if (drm->client.device.info.chipset == 0x11 && !nv_heads_tied(dev)) 32162306a36Sopenharmony_ci NVWriteVgaCrtc(dev, 1, NV_CIO_SR_LOCK_INDEX, 32262306a36Sopenharmony_ci lock ? NV_CIO_SR_LOCK_VALUE : 32362306a36Sopenharmony_ci NV_CIO_SR_UNLOCK_RW_VALUE); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return waslocked; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/* nv04 cursor max dimensions of 32x32 (A1R5G5B5) */ 32962306a36Sopenharmony_ci#define NV04_CURSOR_SIZE 32 33062306a36Sopenharmony_ci/* limit nv10 cursors to 64x64 (ARGB8) (we could go to 64x255) */ 33162306a36Sopenharmony_ci#define NV10_CURSOR_SIZE 64 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic inline int nv_cursor_width(struct drm_device *dev) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(dev); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic inline void 34162306a36Sopenharmony_cinv_fix_nv40_hw_cursor(struct drm_device *dev, int head) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci /* on some nv40 (such as the "true" (in the NV_PFB_BOOT_0 sense) nv40, 34462306a36Sopenharmony_ci * the gf6800gt) a hardware bug requires a write to PRAMDAC_CURSOR_POS 34562306a36Sopenharmony_ci * for changes to the CRTC CURCTL regs to take effect, whether changing 34662306a36Sopenharmony_ci * the pixmap location, or just showing/hiding the cursor 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci uint32_t curpos = NVReadRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS); 34962306a36Sopenharmony_ci NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic inline void 35362306a36Sopenharmony_cinv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(dev); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci NVWriteCRTC(dev, head, NV_PCRTC_START, offset); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (drm->client.device.info.family == NV_DEVICE_INFO_V0_TNT) { 36062306a36Sopenharmony_ci /* 36162306a36Sopenharmony_ci * Hilarious, the 24th bit doesn't want to stick to 36262306a36Sopenharmony_ci * PCRTC_START... 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ci int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX, 36762306a36Sopenharmony_ci (cre_heb & ~0x40) | ((offset >> 18) & 0x40)); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic inline void 37262306a36Sopenharmony_cinv_show_cursor(struct drm_device *dev, int head, bool show) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(dev); 37562306a36Sopenharmony_ci uint8_t *curctl1 = 37662306a36Sopenharmony_ci &nv04_display(dev)->mode_reg.crtc_reg[head].CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX]; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (show) 37962306a36Sopenharmony_ci *curctl1 |= MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE); 38062306a36Sopenharmony_ci else 38162306a36Sopenharmony_ci *curctl1 &= ~MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE); 38262306a36Sopenharmony_ci NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HCUR_ADDR1_INDEX, *curctl1); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE) 38562306a36Sopenharmony_ci nv_fix_nv40_hw_cursor(dev, head); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic inline uint32_t 38962306a36Sopenharmony_cinv_pitch_align(struct drm_device *dev, uint32_t width, int bpp) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct nouveau_drm *drm = nouveau_drm(dev); 39262306a36Sopenharmony_ci int mask; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (bpp == 15) 39562306a36Sopenharmony_ci bpp = 16; 39662306a36Sopenharmony_ci if (bpp == 24) 39762306a36Sopenharmony_ci bpp = 8; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Alignment requirements taken from the Haiku driver */ 40062306a36Sopenharmony_ci if (drm->client.device.info.family == NV_DEVICE_INFO_V0_TNT) 40162306a36Sopenharmony_ci mask = 128 / bpp - 1; 40262306a36Sopenharmony_ci else 40362306a36Sopenharmony_ci mask = 512 / bpp - 1; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return (width + mask) & ~mask; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci#endif /* __NOUVEAU_HW_H__ */ 409