drivers/i3c/master/mipi-i3c-hci/ext_caps.c

Source file repositories/reference/linux-study-clean/drivers/i3c/master/mipi-i3c-hci/ext_caps.c

File Facts

System
Linux kernel
Corpus path
drivers/i3c/master/mipi-i3c-hci/ext_caps.c
Extension
.c
Size
8942 bytes
Lines
308
Domain
Driver Families
Bucket
drivers/i3c
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 hci_ext_caps {
	u8  id;
	u16 min_length;
	int (*parser)(struct i3c_hci *hci, void __iomem *base);
};

#define EXT_CAP(_id, _highest_mandatory_reg_offset, _parser) \
	{ .id = (_id), .parser = (_parser), \
	  .min_length = (_highest_mandatory_reg_offset)/4 + 1 }

static const struct hci_ext_caps ext_capabilities[] = {
	EXT_CAP(0x01, 0x0c, hci_extcap_hardware_id),
	EXT_CAP(0x02, 0x04, hci_extcap_master_config),
	EXT_CAP(0x03, 0x04, hci_extcap_multi_bus),
	EXT_CAP(0x04, 0x24, hci_extcap_xfer_modes),
	EXT_CAP(0x05, 0x08, hci_extcap_auto_command),
	EXT_CAP(0x08, 0x40, hci_extcap_xfer_rates),
	EXT_CAP(0x0c, 0x10, hci_extcap_debug),
	EXT_CAP(0x0d, 0x0c, hci_extcap_scheduled_cmd),
	EXT_CAP(0x0e, 0x80, hci_extcap_non_curr_master), /* TODO confirm size */
	EXT_CAP(0x0f, 0x04, hci_extcap_ccc_resp_conf),
	EXT_CAP(0x10, 0x08, hci_extcap_global_DAT),
	EXT_CAP(0x9d, 0x04,	hci_extcap_multilane),
	EXT_CAP(0x9e, 0x04, hci_extcap_ncm_multilane),
};

static int hci_extcap_vendor_NXP(struct i3c_hci *hci, void __iomem *base)
{
	hci->vendor_data = (__force void *)base;
	dev_dbg(&hci->master.dev, "Build Date Info = %#x\n", readl(base + 1 * 4));
	/* reset the FPGA */
	writel(0xdeadbeef, base + 1*4);
	return 0;
}

struct hci_ext_cap_vendor_specific {
	u32 vendor;
	u8  cap;
	u16 min_length;
	int (*parser)(struct i3c_hci *hci, void __iomem *base);
};

#define EXT_CAP_VENDOR(_vendor, _cap, _highest_mandatory_reg_offset) \
	{ .vendor = (MIPI_VENDOR_##_vendor), .cap = (_cap), \
	  .parser = (hci_extcap_vendor_##_vendor), \
	  .min_length = (_highest_mandatory_reg_offset)/4 + 1 }

static const struct hci_ext_cap_vendor_specific vendor_ext_caps[] = {
	EXT_CAP_VENDOR(NXP, 0xc0, 0x20),
};

static int hci_extcap_vendor_specific(struct i3c_hci *hci, void __iomem *base,
				      u32 cap_id, u32 cap_length)
{
	const struct hci_ext_cap_vendor_specific *vendor_cap_entry;
	int i;

	vendor_cap_entry = NULL;
	for (i = 0; i < ARRAY_SIZE(vendor_ext_caps); i++) {
		if (vendor_ext_caps[i].vendor == hci->vendor_mipi_id &&
		    vendor_ext_caps[i].cap == cap_id) {
			vendor_cap_entry = &vendor_ext_caps[i];
			break;
		}
	}

	if (!vendor_cap_entry) {
		dev_dbg(&hci->master.dev, "unknown ext_cap 0x%02x for vendor 0x%02x\n",
			cap_id, hci->vendor_mipi_id);
		return 0;
	}
	if (cap_length < vendor_cap_entry->min_length) {
		dev_err(&hci->master.dev,
			"ext_cap 0x%02x has size %d (expecting >= %d)\n",
			cap_id, cap_length, vendor_cap_entry->min_length);
		return -EINVAL;
	}
	return vendor_cap_entry->parser(hci, base);
}

int i3c_hci_parse_ext_caps(struct i3c_hci *hci)
{
	void __iomem *curr_cap = hci->EXTCAPS_regs;
	void __iomem *end = curr_cap + 0x1000; /* some arbitrary limit */
	u32 cap_header, cap_id, cap_length;
	const struct hci_ext_caps *cap_entry;
	int i, err = 0;

	if (!curr_cap)
		return 0;

Annotation

Implementation Notes