drivers/net/ethernet/mediatek/mtk_wed_mcu.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mediatek/mtk_wed_mcu.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mediatek/mtk_wed_mcu.c
Extension
.c
Size
9567 bytes
Lines
412
Domain
Driver Families
Bucket
drivers/net
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 (!region->shared || !region->consumed) {
				memcpy_toio(region->addr, ptr, length);
				region->consumed = true;
				break;
			}
		}

		if (i == ARRAY_SIZE(mem_region))
			return -EINVAL;
next:
		region_ptr += sizeof(*fw_region);
		ptr += length;
	}

	return 0;
}

static int
mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo)
{
	const struct mtk_wed_fw_trailer *trailer;
	const struct firmware *fw;
	const char *fw_name;
	u32 val, boot_cr;
	int ret, i;

	/* load firmware region metadata */
	for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
		ret = mtk_wed_get_memory_region(wo->hw, mem_region[i].name, &mem_region[i]);
		if (ret)
			return ret;
	}

	/* set dummy cr */
	wed_w32(wo->hw->wed_dev, MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_FWDL,
		wo->hw->index + 1);

	/* load firmware */
	switch (wo->hw->version) {
	case 2:
		if (of_device_is_compatible(wo->hw->node,
					    "mediatek,mt7981-wed"))
			fw_name = MT7981_FIRMWARE_WO;
		else
			fw_name = wo->hw->index ? MT7986_FIRMWARE_WO1
						: MT7986_FIRMWARE_WO0;
		break;
	case 3:
		fw_name = wo->hw->index ? MT7988_FIRMWARE_WO1
					: MT7988_FIRMWARE_WO0;
		break;
	default:
		return -EINVAL;
	}

	ret = request_firmware(&fw, fw_name, wo->hw->dev);
	if (ret)
		return ret;

	trailer = (void *)(fw->data + fw->size -
			   sizeof(struct mtk_wed_fw_trailer));
	dev_info(wo->hw->dev,
		 "MTK WED WO Firmware Version: %.10s, Build Time: %.15s\n",
		 trailer->fw_ver, trailer->build_date);
	dev_info(wo->hw->dev, "MTK WED WO Chip ID %02x Region %d\n",
		 trailer->chip_id, trailer->num_region);

	ret = mtk_wed_mcu_run_firmware(wo, fw);
	if (ret)
		goto out;

	/* set the start address */
	if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index)
		boot_cr = MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR;
	else
		boot_cr = MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
	wo_w32(boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16);
	/* wo firmware reset */
	wo_w32(MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00);

	val = wo_r32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR);

	if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index)
		val |= MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK;
	else
		val |= MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK;
	wo_w32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
out:
	release_firmware(fw);

Annotation

Implementation Notes