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