drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
Extension
.c
Size
5526 bytes
Lines
195
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 g94_i2c_aux {
	struct nvkm_i2c_aux base;
	int ch;
};

static void
g94_i2c_aux_fini(struct g94_i2c_aux *aux)
{
	struct nvkm_device *device = aux->base.pad->i2c->subdev.device;
	nvkm_mask(device, 0x00e4e4 + (aux->ch * 0x50), 0x00310000, 0x00000000);
}

static int
g94_i2c_aux_init(struct g94_i2c_aux *aux)
{
	struct nvkm_device *device = aux->base.pad->i2c->subdev.device;
	const u32 unksel = 1; /* nfi which to use, or if it matters.. */
	const u32 ureq = unksel ? 0x00100000 : 0x00200000;
	const u32 urep = unksel ? 0x01000000 : 0x02000000;
	u32 ctrl, timeout;

	/* wait up to 1ms for any previous transaction to be done... */
	timeout = 1000;
	do {
		ctrl = nvkm_rd32(device, 0x00e4e4 + (aux->ch * 0x50));
		udelay(1);
		if (!timeout--) {
			AUX_ERR(&aux->base, "begin idle timeout %08x", ctrl);
			return -EBUSY;
		}
	} while (ctrl & 0x03010000);

	/* set some magic, and wait up to 1ms for it to appear */
	nvkm_mask(device, 0x00e4e4 + (aux->ch * 0x50), 0x00300000, ureq);
	timeout = 1000;
	do {
		ctrl = nvkm_rd32(device, 0x00e4e4 + (aux->ch * 0x50));
		udelay(1);
		if (!timeout--) {
			AUX_ERR(&aux->base, "magic wait %08x", ctrl);
			g94_i2c_aux_fini(aux);
			return -EBUSY;
		}
	} while ((ctrl & 0x03000000) != urep);

	return 0;
}

int
g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry,
		 u8 type, u32 addr, u8 *data, u8 *size)
{
	struct g94_i2c_aux *aux = g94_i2c_aux(obj);
	struct nvkm_i2c *i2c = aux->base.pad->i2c;
	struct nvkm_device *device = i2c->subdev.device;
	const u32 base = aux->ch * 0x50;
	u32 ctrl, stat, timeout, retries = 0;
	u32 xbuf[4] = {};
	int ret, i;

	AUX_TRACE(&aux->base, "%d: %08x %d", type, addr, *size);

	ret = g94_i2c_aux_init(aux);
	if (ret < 0)
		goto out;

	stat = nvkm_rd32(device, 0x00e4e8 + base);
	if (!(stat & 0x10000000)) {
		AUX_TRACE(&aux->base, "sink not detected");
		ret = -ENXIO;
		goto out;
	}

	nvkm_i2c_aux_autodpcd(i2c, aux->ch, false);

	if (!(type & 1)) {
		memcpy(xbuf, data, *size);
		for (i = 0; i < 16; i += 4) {
			AUX_TRACE(&aux->base, "wr %08x", xbuf[i / 4]);
			nvkm_wr32(device, 0x00e4c0 + base + i, xbuf[i / 4]);
		}
	}

	ctrl  = nvkm_rd32(device, 0x00e4e4 + base);
	ctrl &= ~0x0001f1ff;
	ctrl |= type << 12;
	ctrl |= (*size ? (*size - 1) : 0x00000100);
	nvkm_wr32(device, 0x00e4e0 + base, addr);

	/* (maybe) retry transaction a number of times on failure... */

Annotation

Implementation Notes