drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c
Extension
.c
Size
13297 bytes
Lines
466
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

switch (reg1) {
		case 0x680504:
			shift_c040 += 2; fallthrough;
		case 0x680500:
			shift_c040 += 2; fallthrough;
		case 0x680520:
			shift_c040 += 2; fallthrough;
		case 0x680508:
			shift_c040 += 2;
		}

		savedc040 = nvkm_rd32(device, 0xc040);
		if (shift_c040 != 14)
			nvkm_wr32(device, 0xc040, savedc040 & ~(3 << shift_c040));
	}

	if (oldramdac580 != ramdac580)
		nvkm_wr32(device, 0x680580, ramdac580);

	if (!nv3035)
		nvkm_wr32(device, reg2, pll2);
	nvkm_wr32(device, reg1, pll1);

	if (shift_powerctrl_1 >= 0)
		nvkm_wr32(device, 0x001584, saved_powerctrl_1);
	if (chip_version >= 0x40)
		nvkm_wr32(device, 0xc040, savedc040);
}

void
setPLL_double_lowregs(struct nvkm_devinit *init, u32 NMNMreg,
		      struct nvkm_pll_vals *pv)
{
	/* When setting PLLs, there is a merry game of disabling and enabling
	 * various bits of hardware during the process. This function is a
	 * synthesis of six nv4x traces, nearly each card doing a subtly
	 * different thing. With luck all the necessary bits for each card are
	 * combined herein. Without luck it deviates from each card's formula
	 * so as to not work on any :)
	 */
	struct nvkm_device *device = init->subdev.device;
	uint32_t Preg = NMNMreg - 4;
	bool mpll = Preg == 0x4020;
	uint32_t oldPval = nvkm_rd32(device, Preg);
	uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
	uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
			0xc << 28 | pv->log2P << 16;
	uint32_t saved4600 = 0;
	/* some cards have different maskc040s */
	uint32_t maskc040 = ~(3 << 14), savedc040;
	bool single_stage = !pv->NM2 || pv->N2 == pv->M2;

	if (nvkm_rd32(device, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
		return;

	if (Preg == 0x4000)
		maskc040 = ~0x333;
	if (Preg == 0x4058)
		maskc040 = ~(0xc << 24);

	if (mpll) {
		struct nvbios_pll info;
		uint8_t Pval2;

		if (nvbios_pll_parse(device->bios, Preg, &info))
			return;

		Pval2 = pv->log2P + info.bias_p;
		if (Pval2 > info.max_p)
			Pval2 = info.max_p;
		Pval |= 1 << 28 | Pval2 << 20;

		saved4600 = nvkm_rd32(device, 0x4600);
		nvkm_wr32(device, 0x4600, saved4600 | 8 << 28);
	}
	if (single_stage)
		Pval |= mpll ? 1 << 12 : 1 << 8;

	nvkm_wr32(device, Preg, oldPval | 1 << 28);
	nvkm_wr32(device, Preg, Pval & ~(4 << 28));
	if (mpll) {
		Pval |= 8 << 20;
		nvkm_wr32(device, 0x4020, Pval & ~(0xc << 28));
		nvkm_wr32(device, 0x4038, Pval & ~(0xc << 28));
	}

	savedc040 = nvkm_rd32(device, 0xc040);
	nvkm_wr32(device, 0xc040, savedc040 & maskc040);

	nvkm_wr32(device, NMNMreg, NMNM);

Annotation

Implementation Notes