drivers/interconnect/imx/imx.c

Source file repositories/reference/linux-study-clean/drivers/interconnect/imx/imx.c

File Facts

System
Linux kernel
Corpus path
drivers/interconnect/imx/imx.c
Extension
.c
Size
8920 bytes
Lines
339
Domain
Driver Families
Bucket
drivers/interconnect
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 imx_icc_node {
	const struct imx_icc_node_desc *desc;
	const struct imx_icc_noc_setting *setting;
	struct device *qos_dev;
	struct dev_pm_qos_request qos_req;
	struct imx_icc_provider *imx_provider;
};

static int imx_icc_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
{
	*avg = 0;
	*peak = 0;

	return 0;
}

static int imx_icc_node_set(struct icc_node *node)
{
	struct device *dev = node->provider->dev;
	struct imx_icc_node *node_data = node->data;
	void __iomem *base;
	u32 prio;
	u64 freq;

	if (node_data->setting && node->peak_bw) {
		base = node_data->setting->reg + node_data->imx_provider->noc_base;
		if (node_data->setting->mode == IMX_NOC_MODE_FIXED) {
			prio = node_data->setting->prio_level;
			prio = PRIORITY_COMP_MARK | (prio << 8) | prio;
			writel(prio, base + IMX_NOC_PRIO_REG);
			writel(node_data->setting->mode, base + IMX_NOC_MODE_REG);
			writel(node_data->setting->ext_control, base + IMX_NOC_EXT_CTL_REG);
			dev_dbg(dev, "%s: mode: 0x%x, prio: 0x%x, ext_control: 0x%x\n",
				node_data->desc->name, node_data->setting->mode, prio,
				node_data->setting->ext_control);
		} else if (node_data->setting->mode == IMX_NOC_MODE_UNCONFIGURED) {
			dev_dbg(dev, "%s: mode not unconfigured\n", node_data->desc->name);
		} else {
			dev_info(dev, "%s: mode: %d not supported\n",
				 node_data->desc->name, node_data->setting->mode);
			return -EOPNOTSUPP;
		}
	}

	if (!node_data->qos_dev)
		return 0;

	freq = (node->avg_bw + node->peak_bw) * node_data->desc->adj->bw_mul;
	do_div(freq, node_data->desc->adj->bw_div);
	dev_dbg(dev, "node %s device %s avg_bw %ukBps peak_bw %ukBps min_freq %llukHz\n",
		node->name, dev_name(node_data->qos_dev),
		node->avg_bw, node->peak_bw, freq);

	if (freq > S32_MAX) {
		dev_err(dev, "%s can't request more than S32_MAX freq\n",
				node->name);
		return -ERANGE;
	}

	dev_pm_qos_update_request(&node_data->qos_req, freq);

	return 0;
}

static int imx_icc_set(struct icc_node *src, struct icc_node *dst)
{
	int ret;

	ret = imx_icc_node_set(src);
	if (ret)
		return ret;

	return imx_icc_node_set(dst);
}

/* imx_icc_node_destroy() - Destroy an imx icc_node, including private data */
static void imx_icc_node_destroy(struct icc_node *node)
{
	struct imx_icc_node *node_data = node->data;
	int ret;

	if (dev_pm_qos_request_active(&node_data->qos_req)) {
		ret = dev_pm_qos_remove_request(&node_data->qos_req);
		if (ret)
			dev_warn(node->provider->dev,
				 "failed to remove qos request for %s\n",
				 dev_name(node_data->qos_dev));
	}

	put_device(node_data->qos_dev);

Annotation

Implementation Notes