drivers/staging/media/av7110/av7110_hw.c

Source file repositories/reference/linux-study-clean/drivers/staging/media/av7110/av7110_hw.c

File Facts

System
Linux kernel
Corpus path
drivers/staging/media/av7110/av7110_hw.c
Extension
.c
Size
29943 bytes
Lines
1146
Domain
Driver Families
Bucket
drivers/staging
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 (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
			pr_err("%s(): timeout at block %d\n", __func__, i);
			return -ETIMEDOUT;
		}
		dprintk(4, "writing DRAM block %d\n", i);
		mwdebi(av7110, DEBISWAB, bootblock,
		       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
		bootblock ^= 0x1400;
		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
		base += AV7110_BOOT_MAX_SIZE;
	}

	if (rest > 0) {
		if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
			pr_err("%s(): timeout at last block\n", __func__);
			return -ETIMEDOUT;
		}
		if (rest > 4)
			mwdebi(av7110, DEBISWAB, bootblock,
			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
		else
			mwdebi(av7110, DEBISWAB, bootblock,
			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);

		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
	}
	if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
		pr_err("%s(): timeout after last block\n", __func__);
		return -ETIMEDOUT;
	}
	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
	iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
	if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
		pr_err("%s(): final handshake timeout\n", __func__);
		return -ETIMEDOUT;
	}
	return 0;
}

/* we cannot write av7110 DRAM directly, so load a bootloader into
 * the DPRAM which implements a simple boot protocol
 */
int av7110_bootarm(struct av7110 *av7110)
{
	const struct firmware *fw;
	const char *fw_name = "av7110/bootcode.bin";
	struct saa7146_dev *dev = av7110->dev;
	u32 ret;
	int i;

	dprintk(4, "%p\n", av7110);

	av7110->arm_ready = 0;

	saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO);

	/* Disable DEBI and GPIO irq */
	SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19);
	SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03);

	/* enable DEBI */
	saa7146_write(av7110->dev, MC1, 0x08800880);
	saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
	saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));

	/* test DEBI */
	iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
	/* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
	iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);

	ret = irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4);
	if (ret != 0x10325476) {
		pr_err("debi test in %s() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
		       __func__, ret, 0x10325476);
		return -1;
	}
	for (i = 0; i < 8192; i += 4)
		iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4);
	dprintk(2, "debi test OK\n");

	/* boot */
	dprintk(1, "load boot code\n");
	saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO);
	//saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
	//saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);

Annotation

Implementation Notes