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

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c
Extension
.c
Size
11171 bytes
Lines
423
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 mcp77_clk {
	struct nvkm_clk base;
	enum nv_clk_src csrc, ssrc, vsrc;
	u32 cctrl, sctrl;
	u32 ccoef, scoef;
	u32 cpost, spost;
	u32 vdiv;
};

static u32
read_div(struct mcp77_clk *clk)
{
	struct nvkm_device *device = clk->base.subdev.device;
	return nvkm_rd32(device, 0x004600);
}

static u32
read_pll(struct mcp77_clk *clk, u32 base)
{
	struct nvkm_device *device = clk->base.subdev.device;
	u32 ctrl = nvkm_rd32(device, base + 0);
	u32 coef = nvkm_rd32(device, base + 4);
	u32 ref = nvkm_clk_read(&clk->base, nv_clk_src_href);
	u32 post_div = 0;
	u32 clock = 0;
	int N1, M1;

	switch (base){
	case 0x4020:
		post_div = 1 << ((nvkm_rd32(device, 0x4070) & 0x000f0000) >> 16);
		break;
	case 0x4028:
		post_div = (nvkm_rd32(device, 0x4040) & 0x000f0000) >> 16;
		break;
	default:
		break;
	}

	N1 = (coef & 0x0000ff00) >> 8;
	M1 = (coef & 0x000000ff);
	if ((ctrl & 0x80000000) && M1) {
		clock = ref * N1 / M1;
		clock = clock / post_div;
	}

	return clock;
}

static int
mcp77_clk_read(struct nvkm_clk *base, enum nv_clk_src src)
{
	struct mcp77_clk *clk = mcp77_clk(base);
	struct nvkm_subdev *subdev = &clk->base.subdev;
	struct nvkm_device *device = subdev->device;
	u32 mast = nvkm_rd32(device, 0x00c054);
	u32 P = 0;

	switch (src) {
	case nv_clk_src_crystal:
		return device->crystal;
	case nv_clk_src_href:
		return 100000; /* PCIE reference clock */
	case nv_clk_src_hclkm4:
		return nvkm_clk_read(&clk->base, nv_clk_src_href) * 4;
	case nv_clk_src_hclkm2d3:
		return nvkm_clk_read(&clk->base, nv_clk_src_href) * 2 / 3;
	case nv_clk_src_host:
		switch (mast & 0x000c0000) {
		case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm2d3);
		case 0x00040000: break;
		case 0x00080000: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm4);
		case 0x000c0000: return nvkm_clk_read(&clk->base, nv_clk_src_cclk);
		}
		break;
	case nv_clk_src_core:
		P = (nvkm_rd32(device, 0x004028) & 0x00070000) >> 16;

		switch (mast & 0x00000003) {
		case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P;
		case 0x00000001: return 0;
		case 0x00000002: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm4) >> P;
		case 0x00000003: return read_pll(clk, 0x004028) >> P;
		}
		break;
	case nv_clk_src_cclk:
		if ((mast & 0x03000000) != 0x03000000)
			return nvkm_clk_read(&clk->base, nv_clk_src_core);

		if ((mast & 0x00000200) == 0x00000000)
			return nvkm_clk_read(&clk->base, nv_clk_src_core);

Annotation

Implementation Notes