18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2008 Stuart Bennett
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178c2ecf20Sopenharmony_ci * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
188c2ecf20Sopenharmony_ci * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
198c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
208c2ecf20Sopenharmony_ci * SOFTWARE.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#ifndef __NOUVEAU_HW_H__
248c2ecf20Sopenharmony_ci#define __NOUVEAU_HW_H__
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "disp.h"
278c2ecf20Sopenharmony_ci#include "nvreg.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <subdev/bios/pll.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define MASK(field) ( \
328c2ecf20Sopenharmony_ci	(0xffffffff >> (31 - ((1 ? field) - (0 ? field)))) << (0 ? field))
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define XLATE(src, srclowbit, outfield) ( \
358c2ecf20Sopenharmony_ci	(((src) >> (srclowbit)) << (0 ? outfield)) & MASK(outfield))
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_civoid NVWriteVgaSeq(struct drm_device *, int head, uint8_t index, uint8_t value);
388c2ecf20Sopenharmony_ciuint8_t NVReadVgaSeq(struct drm_device *, int head, uint8_t index);
398c2ecf20Sopenharmony_civoid NVWriteVgaGr(struct drm_device *, int head, uint8_t index, uint8_t value);
408c2ecf20Sopenharmony_ciuint8_t NVReadVgaGr(struct drm_device *, int head, uint8_t index);
418c2ecf20Sopenharmony_civoid NVSetOwner(struct drm_device *, int owner);
428c2ecf20Sopenharmony_civoid NVBlankScreen(struct drm_device *, int head, bool blank);
438c2ecf20Sopenharmony_ciint nouveau_hw_get_pllvals(struct drm_device *, enum nvbios_pll_type plltype,
448c2ecf20Sopenharmony_ci			   struct nvkm_pll_vals *pllvals);
458c2ecf20Sopenharmony_ciint nouveau_hw_pllvals_to_clk(struct nvkm_pll_vals *pllvals);
468c2ecf20Sopenharmony_ciint nouveau_hw_get_clock(struct drm_device *, enum nvbios_pll_type plltype);
478c2ecf20Sopenharmony_civoid nouveau_hw_save_vga_fonts(struct drm_device *, bool save);
488c2ecf20Sopenharmony_civoid nouveau_hw_save_state(struct drm_device *, int head,
498c2ecf20Sopenharmony_ci			   struct nv04_mode_state *state);
508c2ecf20Sopenharmony_civoid nouveau_hw_load_state(struct drm_device *, int head,
518c2ecf20Sopenharmony_ci			   struct nv04_mode_state *state);
528c2ecf20Sopenharmony_civoid nouveau_hw_load_state_palette(struct drm_device *, int head,
538c2ecf20Sopenharmony_ci				   struct nv04_mode_state *state);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* nouveau_calc.c */
568c2ecf20Sopenharmony_ciextern void nouveau_calc_arb(struct drm_device *, int vclk, int bpp,
578c2ecf20Sopenharmony_ci			     int *burst, int *lwm);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline uint32_t NVReadCRTC(struct drm_device *dev,
608c2ecf20Sopenharmony_ci					int head, uint32_t reg)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
638c2ecf20Sopenharmony_ci	uint32_t val;
648c2ecf20Sopenharmony_ci	if (head)
658c2ecf20Sopenharmony_ci		reg += NV_PCRTC0_SIZE;
668c2ecf20Sopenharmony_ci	val = nvif_rd32(device, reg);
678c2ecf20Sopenharmony_ci	return val;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline void NVWriteCRTC(struct drm_device *dev,
718c2ecf20Sopenharmony_ci					int head, uint32_t reg, uint32_t val)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
748c2ecf20Sopenharmony_ci	if (head)
758c2ecf20Sopenharmony_ci		reg += NV_PCRTC0_SIZE;
768c2ecf20Sopenharmony_ci	nvif_wr32(device, reg, val);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic inline uint32_t NVReadRAMDAC(struct drm_device *dev,
808c2ecf20Sopenharmony_ci					int head, uint32_t reg)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
838c2ecf20Sopenharmony_ci	uint32_t val;
848c2ecf20Sopenharmony_ci	if (head)
858c2ecf20Sopenharmony_ci		reg += NV_PRAMDAC0_SIZE;
868c2ecf20Sopenharmony_ci	val = nvif_rd32(device, reg);
878c2ecf20Sopenharmony_ci	return val;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic inline void NVWriteRAMDAC(struct drm_device *dev,
918c2ecf20Sopenharmony_ci					int head, uint32_t reg, uint32_t val)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
948c2ecf20Sopenharmony_ci	if (head)
958c2ecf20Sopenharmony_ci		reg += NV_PRAMDAC0_SIZE;
968c2ecf20Sopenharmony_ci	nvif_wr32(device, reg, val);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic inline uint8_t nv_read_tmds(struct drm_device *dev,
1008c2ecf20Sopenharmony_ci					int or, int dl, uint8_t address)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	int ramdac = (or & DCB_OUTPUT_C) >> 2;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8,
1058c2ecf20Sopenharmony_ci	NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE | address);
1068c2ecf20Sopenharmony_ci	return NVReadRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic inline void nv_write_tmds(struct drm_device *dev,
1108c2ecf20Sopenharmony_ci					int or, int dl, uint8_t address,
1118c2ecf20Sopenharmony_ci					uint8_t data)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	int ramdac = (or & DCB_OUTPUT_C) >> 2;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_DATA + dl * 8, data);
1168c2ecf20Sopenharmony_ci	NVWriteRAMDAC(dev, ramdac, NV_PRAMDAC_FP_TMDS_CONTROL + dl * 8, address);
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic inline void NVWriteVgaCrtc(struct drm_device *dev,
1208c2ecf20Sopenharmony_ci					int head, uint8_t index, uint8_t value)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
1238c2ecf20Sopenharmony_ci	nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
1248c2ecf20Sopenharmony_ci	nvif_wr08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic inline uint8_t NVReadVgaCrtc(struct drm_device *dev,
1288c2ecf20Sopenharmony_ci					int head, uint8_t index)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
1318c2ecf20Sopenharmony_ci	uint8_t val;
1328c2ecf20Sopenharmony_ci	nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index);
1338c2ecf20Sopenharmony_ci	val = nvif_rd08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE);
1348c2ecf20Sopenharmony_ci	return val;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* CR57 and CR58 are a fun pair of regs. CR57 provides an index (0-0xf) for CR58
1388c2ecf20Sopenharmony_ci * I suspect they in fact do nothing, but are merely a way to carry useful
1398c2ecf20Sopenharmony_ci * per-head variables around
1408c2ecf20Sopenharmony_ci *
1418c2ecf20Sopenharmony_ci * Known uses:
1428c2ecf20Sopenharmony_ci * CR57		CR58
1438c2ecf20Sopenharmony_ci * 0x00		index to the appropriate dcb entry (or 7f for inactive)
1448c2ecf20Sopenharmony_ci * 0x02		dcb entry's "or" value (or 00 for inactive)
1458c2ecf20Sopenharmony_ci * 0x03		bit0 set for dual link (LVDS, possibly elsewhere too)
1468c2ecf20Sopenharmony_ci * 0x08 or 0x09	pxclk in MHz
1478c2ecf20Sopenharmony_ci * 0x0f		laptop panel info -	low nibble for PEXTDEV_BOOT_0 strap
1488c2ecf20Sopenharmony_ci * 					high nibble for xlat strap value
1498c2ecf20Sopenharmony_ci */
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic inline void
1528c2ecf20Sopenharmony_ciNVWriteVgaCrtc5758(struct drm_device *dev, int head, uint8_t index, uint8_t value)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
1558c2ecf20Sopenharmony_ci	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_58, value);
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic inline uint8_t NVReadVgaCrtc5758(struct drm_device *dev, int head, uint8_t index)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_57, index);
1618c2ecf20Sopenharmony_ci	return NVReadVgaCrtc(dev, head, NV_CIO_CRE_58);
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic inline uint8_t NVReadPRMVIO(struct drm_device *dev,
1658c2ecf20Sopenharmony_ci					int head, uint32_t reg)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
1688c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
1698c2ecf20Sopenharmony_ci	uint8_t val;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* Only NV4x have two pvio ranges; other twoHeads cards MUST call
1728c2ecf20Sopenharmony_ci	 * NVSetOwner for the relevant head to be programmed */
1738c2ecf20Sopenharmony_ci	if (head && drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE)
1748c2ecf20Sopenharmony_ci		reg += NV_PRMVIO_SIZE;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	val = nvif_rd08(device, reg);
1778c2ecf20Sopenharmony_ci	return val;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic inline void NVWritePRMVIO(struct drm_device *dev,
1818c2ecf20Sopenharmony_ci					int head, uint32_t reg, uint8_t value)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
1848c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* Only NV4x have two pvio ranges; other twoHeads cards MUST call
1878c2ecf20Sopenharmony_ci	 * NVSetOwner for the relevant head to be programmed */
1888c2ecf20Sopenharmony_ci	if (head && drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE)
1898c2ecf20Sopenharmony_ci		reg += NV_PRMVIO_SIZE;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	nvif_wr08(device, reg, value);
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic inline void NVSetEnablePalette(struct drm_device *dev, int head, bool enable)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
1978c2ecf20Sopenharmony_ci	nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
1988c2ecf20Sopenharmony_ci	nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic inline bool NVGetEnablePalette(struct drm_device *dev, int head)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
2048c2ecf20Sopenharmony_ci	nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
2058c2ecf20Sopenharmony_ci	return !(nvif_rd08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic inline void NVWriteVgaAttr(struct drm_device *dev,
2098c2ecf20Sopenharmony_ci					int head, uint8_t index, uint8_t value)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
2128c2ecf20Sopenharmony_ci	if (NVGetEnablePalette(dev, head))
2138c2ecf20Sopenharmony_ci		index &= ~0x20;
2148c2ecf20Sopenharmony_ci	else
2158c2ecf20Sopenharmony_ci		index |= 0x20;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
2188c2ecf20Sopenharmony_ci	nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
2198c2ecf20Sopenharmony_ci	nvif_wr08(device, NV_PRMCIO_AR__WRITE + head * NV_PRMCIO_SIZE, value);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic inline uint8_t NVReadVgaAttr(struct drm_device *dev,
2238c2ecf20Sopenharmony_ci					int head, uint8_t index)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
2268c2ecf20Sopenharmony_ci	uint8_t val;
2278c2ecf20Sopenharmony_ci	if (NVGetEnablePalette(dev, head))
2288c2ecf20Sopenharmony_ci		index &= ~0x20;
2298c2ecf20Sopenharmony_ci	else
2308c2ecf20Sopenharmony_ci		index |= 0x20;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE);
2338c2ecf20Sopenharmony_ci	nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, index);
2348c2ecf20Sopenharmony_ci	val = nvif_rd08(device, NV_PRMCIO_AR__READ + head * NV_PRMCIO_SIZE);
2358c2ecf20Sopenharmony_ci	return val;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic inline void NVVgaSeqReset(struct drm_device *dev, int head, bool start)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	NVWriteVgaSeq(dev, head, NV_VIO_SR_RESET_INDEX, start ? 0x1 : 0x3);
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic inline void NVVgaProtect(struct drm_device *dev, int head, bool protect)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	uint8_t seq1 = NVReadVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (protect) {
2488c2ecf20Sopenharmony_ci		NVVgaSeqReset(dev, head, true);
2498c2ecf20Sopenharmony_ci		NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 | 0x20);
2508c2ecf20Sopenharmony_ci	} else {
2518c2ecf20Sopenharmony_ci		/* Reenable sequencer, then turn on screen */
2528c2ecf20Sopenharmony_ci		NVWriteVgaSeq(dev, head, NV_VIO_SR_CLOCK_INDEX, seq1 & ~0x20);   /* reenable display */
2538c2ecf20Sopenharmony_ci		NVVgaSeqReset(dev, head, false);
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci	NVSetEnablePalette(dev, head, protect);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic inline bool
2598c2ecf20Sopenharmony_cinv_heads_tied(struct drm_device *dev)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
2628c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (drm->client.device.info.chipset == 0x11)
2658c2ecf20Sopenharmony_ci		return !!(nvif_rd32(device, NV_PBUS_DEBUG_1) & (1 << 28));
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44) & 0x4;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci/* makes cr0-7 on the specified head read-only */
2718c2ecf20Sopenharmony_cistatic inline bool
2728c2ecf20Sopenharmony_cinv_lock_vga_crtc_base(struct drm_device *dev, int head, bool lock)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	uint8_t cr11 = NVReadVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX);
2758c2ecf20Sopenharmony_ci	bool waslocked = cr11 & 0x80;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (lock)
2788c2ecf20Sopenharmony_ci		cr11 |= 0x80;
2798c2ecf20Sopenharmony_ci	else
2808c2ecf20Sopenharmony_ci		cr11 &= ~0x80;
2818c2ecf20Sopenharmony_ci	NVWriteVgaCrtc(dev, head, NV_CIO_CR_VRE_INDEX, cr11);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return waslocked;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic inline void
2878c2ecf20Sopenharmony_cinv_lock_vga_crtc_shadow(struct drm_device *dev, int head, int lock)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	/* shadow lock: connects 0x60?3d? regs to "real" 0x3d? regs
2908c2ecf20Sopenharmony_ci	 * bit7: unlocks HDT, HBS, HBE, HRS, HRE, HEB
2918c2ecf20Sopenharmony_ci	 * bit6: seems to have some effect on CR09 (double scan, VBS_9)
2928c2ecf20Sopenharmony_ci	 * bit5: unlocks HDE
2938c2ecf20Sopenharmony_ci	 * bit4: unlocks VDE
2948c2ecf20Sopenharmony_ci	 * bit3: unlocks VDT, OVL, VRS, ?VRE?, VBS, VBE, LSR, EBR
2958c2ecf20Sopenharmony_ci	 * bit2: same as bit 1 of 0x60?804
2968c2ecf20Sopenharmony_ci	 * bit0: same as bit 0 of 0x60?804
2978c2ecf20Sopenharmony_ci	 */
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	uint8_t cr21 = lock;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (lock < 0)
3028c2ecf20Sopenharmony_ci		/* 0xfa is generic "unlock all" mask */
3038c2ecf20Sopenharmony_ci		cr21 = NVReadVgaCrtc(dev, head, NV_CIO_CRE_21) | 0xfa;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_21, cr21);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci/* renders the extended crtc regs (cr19+) on all crtcs impervious:
3098c2ecf20Sopenharmony_ci * immutable and unreadable
3108c2ecf20Sopenharmony_ci */
3118c2ecf20Sopenharmony_cistatic inline bool
3128c2ecf20Sopenharmony_ciNVLockVgaCrtcs(struct drm_device *dev, bool lock)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
3158c2ecf20Sopenharmony_ci	bool waslocked = !NVReadVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	NVWriteVgaCrtc(dev, 0, NV_CIO_SR_LOCK_INDEX,
3188c2ecf20Sopenharmony_ci		       lock ? NV_CIO_SR_LOCK_VALUE : NV_CIO_SR_UNLOCK_RW_VALUE);
3198c2ecf20Sopenharmony_ci	/* NV11 has independently lockable extended crtcs, except when tied */
3208c2ecf20Sopenharmony_ci	if (drm->client.device.info.chipset == 0x11 && !nv_heads_tied(dev))
3218c2ecf20Sopenharmony_ci		NVWriteVgaCrtc(dev, 1, NV_CIO_SR_LOCK_INDEX,
3228c2ecf20Sopenharmony_ci			       lock ? NV_CIO_SR_LOCK_VALUE :
3238c2ecf20Sopenharmony_ci				      NV_CIO_SR_UNLOCK_RW_VALUE);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	return waslocked;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/* nv04 cursor max dimensions of 32x32 (A1R5G5B5) */
3298c2ecf20Sopenharmony_ci#define NV04_CURSOR_SIZE 32
3308c2ecf20Sopenharmony_ci/* limit nv10 cursors to 64x64 (ARGB8) (we could go to 64x255) */
3318c2ecf20Sopenharmony_ci#define NV10_CURSOR_SIZE 64
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic inline int nv_cursor_width(struct drm_device *dev)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	return drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS ? NV10_CURSOR_SIZE : NV04_CURSOR_SIZE;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic inline void
3418c2ecf20Sopenharmony_cinv_fix_nv40_hw_cursor(struct drm_device *dev, int head)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	/* on some nv40 (such as the "true" (in the NV_PFB_BOOT_0 sense) nv40,
3448c2ecf20Sopenharmony_ci	 * the gf6800gt) a hardware bug requires a write to PRAMDAC_CURSOR_POS
3458c2ecf20Sopenharmony_ci	 * for changes to the CRTC CURCTL regs to take effect, whether changing
3468c2ecf20Sopenharmony_ci	 * the pixmap location, or just showing/hiding the cursor
3478c2ecf20Sopenharmony_ci	 */
3488c2ecf20Sopenharmony_ci	uint32_t curpos = NVReadRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS);
3498c2ecf20Sopenharmony_ci	NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos);
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic inline void
3538c2ecf20Sopenharmony_cinv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (drm->client.device.info.family == NV_DEVICE_INFO_V0_TNT) {
3608c2ecf20Sopenharmony_ci		/*
3618c2ecf20Sopenharmony_ci		 * Hilarious, the 24th bit doesn't want to stick to
3628c2ecf20Sopenharmony_ci		 * PCRTC_START...
3638c2ecf20Sopenharmony_ci		 */
3648c2ecf20Sopenharmony_ci		int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci		NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX,
3678c2ecf20Sopenharmony_ci			       (cre_heb & ~0x40) | ((offset >> 18) & 0x40));
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic inline void
3728c2ecf20Sopenharmony_cinv_show_cursor(struct drm_device *dev, int head, bool show)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
3758c2ecf20Sopenharmony_ci	uint8_t *curctl1 =
3768c2ecf20Sopenharmony_ci		&nv04_display(dev)->mode_reg.crtc_reg[head].CRTC[NV_CIO_CRE_HCUR_ADDR1_INDEX];
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (show)
3798c2ecf20Sopenharmony_ci		*curctl1 |= MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
3808c2ecf20Sopenharmony_ci	else
3818c2ecf20Sopenharmony_ci		*curctl1 &= ~MASK(NV_CIO_CRE_HCUR_ADDR1_ENABLE);
3828c2ecf20Sopenharmony_ci	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HCUR_ADDR1_INDEX, *curctl1);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE)
3858c2ecf20Sopenharmony_ci		nv_fix_nv40_hw_cursor(dev, head);
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic inline uint32_t
3898c2ecf20Sopenharmony_cinv_pitch_align(struct drm_device *dev, uint32_t width, int bpp)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
3928c2ecf20Sopenharmony_ci	int mask;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if (bpp == 15)
3958c2ecf20Sopenharmony_ci		bpp = 16;
3968c2ecf20Sopenharmony_ci	if (bpp == 24)
3978c2ecf20Sopenharmony_ci		bpp = 8;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	/* Alignment requirements taken from the Haiku driver */
4008c2ecf20Sopenharmony_ci	if (drm->client.device.info.family == NV_DEVICE_INFO_V0_TNT)
4018c2ecf20Sopenharmony_ci		mask = 128 / bpp - 1;
4028c2ecf20Sopenharmony_ci	else
4038c2ecf20Sopenharmony_ci		mask = 512 / bpp - 1;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return (width + mask) & ~mask;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci#endif	/* __NOUVEAU_HW_H__ */
409