drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c
Extension
.c
Size
6666 bytes
Lines
246
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

if (cv < 0x17 || cv == 0x1a || cv == 0x20) {
			if (clk > 250000)
				maxM = 6;
			if (clk > 340000)
				maxM = 2;
		} else if (cv < 0x40) {
			if (clk > 150000)
				maxM = 6;
			if (clk > 200000)
				maxM = 4;
			if (clk > 340000)
				maxM = 2;
		}
	}

	P = 1 << maxP;
	if ((clk * P) < minvco) {
		minvco = clk * maxP;
		maxvco = minvco * 2;
	}

	if (clk + clk/200 > maxvco)	/* +0.5% */
		maxvco = clk + clk/200;

	/* NV34 goes maxlog2P->0, NV20 goes 0->maxlog2P */
	for (thisP = minP; thisP <= maxP; thisP++) {
		P = 1 << thisP;
		clkP = clk * P;

		if (clkP < minvco)
			continue;
		if (clkP > maxvco)
			return bestclk;

		for (M = minM; M <= maxM; M++) {
			if (crystal/M < minU)
				return bestclk;
			if (crystal/M > maxU)
				continue;

			/* add crystal/2 to round better */
			N = (clkP * M + crystal/2) / crystal;

			if (N < minN)
				continue;
			if (N > maxN)
				break;

			/* more rounding additions */
			calcclk = ((N * crystal + P/2) / P + M/2) / M;
			delta = abs(calcclk - clk);
			/* we do an exhaustive search rather than terminating
			 * on an optimality condition...
			 */
			if (delta < bestdelta) {
				bestdelta = delta;
				bestclk = calcclk;
				*pN = N;
				*pM = M;
				*pP = thisP;
				if (delta == 0)	/* except this one */
					return bestclk;
			}
		}
	}

	return bestclk;
}

static int
getMNP_double(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk,
	      int *pN1, int *pM1, int *pN2, int *pM2, int *pP)
{
	/* Find M, N and P for a two stage PLL
	 *
	 * Note that some bioses (NV30+) have lookup tables of precomputed MNP
	 * values, but we're too lazy to use those atm
	 *
	 * "clk" parameter in kHz
	 * returns calculated clock
	 */
	int chip_version = subdev->device->bios->version.chip;
	int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq;
	int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq;
	int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq;
	int maxU1 = info->vco1.max_inputfreq, maxU2 = info->vco2.max_inputfreq;
	int minM1 = info->vco1.min_m, maxM1 = info->vco1.max_m;
	int minN1 = info->vco1.min_n, maxN1 = info->vco1.max_n;
	int minM2 = info->vco2.min_m, maxM2 = info->vco2.max_m;
	int minN2 = info->vco2.min_n, maxN2 = info->vco2.max_n;

Annotation

Implementation Notes