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

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

File Facts

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

struct gf100_clk_info {
	u32 freq;
	u32 ssel;
	u32 mdiv;
	u32 dsrc;
	u32 ddiv;
	u32 coef;
};

struct gf100_clk {
	struct nvkm_clk base;
	struct gf100_clk_info eng[16];
};

static u32 read_div(struct gf100_clk *, int, u32, u32);

static u32
read_vco(struct gf100_clk *clk, u32 dsrc)
{
	struct nvkm_device *device = clk->base.subdev.device;
	u32 ssrc = nvkm_rd32(device, dsrc);
	if (!(ssrc & 0x00000100))
		return nvkm_clk_read(&clk->base, nv_clk_src_sppll0);
	return nvkm_clk_read(&clk->base, nv_clk_src_sppll1);
}

static u32
read_pll(struct gf100_clk *clk, u32 pll)
{
	struct nvkm_device *device = clk->base.subdev.device;
	u32 ctrl = nvkm_rd32(device, pll + 0x00);
	u32 coef = nvkm_rd32(device, pll + 0x04);
	u32 P = (coef & 0x003f0000) >> 16;
	u32 N = (coef & 0x0000ff00) >> 8;
	u32 M = (coef & 0x000000ff) >> 0;
	u32 sclk;

	if (!(ctrl & 0x00000001))
		return 0;

	switch (pll) {
	case 0x00e800:
	case 0x00e820:
		sclk = device->crystal;
		P = 1;
		break;
	case 0x132000:
		sclk = nvkm_clk_read(&clk->base, nv_clk_src_mpllsrc);
		break;
	case 0x132020:
		sclk = nvkm_clk_read(&clk->base, nv_clk_src_mpllsrcref);
		break;
	case 0x137000:
	case 0x137020:
	case 0x137040:
	case 0x1370e0:
		sclk = read_div(clk, (pll & 0xff) / 0x20, 0x137120, 0x137140);
		break;
	default:
		return 0;
	}

	return sclk * N / M / P;
}

static u32
read_div(struct gf100_clk *clk, int doff, u32 dsrc, u32 dctl)
{
	struct nvkm_device *device = clk->base.subdev.device;
	u32 ssrc = nvkm_rd32(device, dsrc + (doff * 4));
	u32 sclk, sctl, sdiv = 2;

	switch (ssrc & 0x00000003) {
	case 0:
		if ((ssrc & 0x00030000) != 0x00030000)
			return device->crystal;
		return 108000;
	case 2:
		return 100000;
	case 3:
		sclk = read_vco(clk, dsrc + (doff * 4));

		/* Memclk has doff of 0 despite its alt. location */
		if (doff <= 2) {
			sctl = nvkm_rd32(device, dctl + (doff * 4));

			if (sctl & 0x80000000) {
				if (ssrc & 0x100)
					sctl >>= 8;

Annotation

Implementation Notes