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

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c
Extension
.c
Size
5933 bytes
Lines
234
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 nv40_clk {
	struct nvkm_clk base;
	u32 ctrl;
	u32 npll_ctrl;
	u32 npll_coef;
	u32 spll;
};

static u32
read_pll_1(struct nv40_clk *clk, u32 reg)
{
	struct nvkm_device *device = clk->base.subdev.device;
	u32 ctrl = nvkm_rd32(device, reg + 0x00);
	int P = (ctrl & 0x00070000) >> 16;
	int N = (ctrl & 0x0000ff00) >> 8;
	int M = (ctrl & 0x000000ff) >> 0;
	u32 ref = 27000, khz = 0;

	if (ctrl & 0x80000000)
		khz = ref * N / M;

	return khz >> P;
}

static u32
read_pll_2(struct nv40_clk *clk, u32 reg)
{
	struct nvkm_device *device = clk->base.subdev.device;
	u32 ctrl = nvkm_rd32(device, reg + 0x00);
	u32 coef = nvkm_rd32(device, reg + 0x04);
	int N2 = (coef & 0xff000000) >> 24;
	int M2 = (coef & 0x00ff0000) >> 16;
	int N1 = (coef & 0x0000ff00) >> 8;
	int M1 = (coef & 0x000000ff) >> 0;
	int P = (ctrl & 0x00070000) >> 16;
	u32 ref = 27000, khz = 0;

	if ((ctrl & 0x80000000) && M1) {
		khz = ref * N1 / M1;
		if ((ctrl & 0x40000100) == 0x40000000) {
			if (M2)
				khz = khz * N2 / M2;
			else
				khz = 0;
		}
	}

	return khz >> P;
}

static u32
read_clk(struct nv40_clk *clk, u32 src)
{
	switch (src) {
	case 3:
		return read_pll_2(clk, 0x004000);
	case 2:
		return read_pll_1(clk, 0x004008);
	default:
		break;
	}

	return 0;
}

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

	switch (src) {
	case nv_clk_src_crystal:
		return device->crystal;
	case nv_clk_src_href:
		return 100000; /*XXX: PCIE/AGP differ*/
	case nv_clk_src_core:
		return read_clk(clk, (mast & 0x00000003) >> 0);
	case nv_clk_src_shader:
		return read_clk(clk, (mast & 0x00000030) >> 4);
	case nv_clk_src_mem:
		return read_pll_2(clk, 0x4020);
	default:
		break;
	}

	nvkm_debug(subdev, "unknown clock source %d %08x\n", src, mast);
	return -EINVAL;

Annotation

Implementation Notes