1 // SPDX-License-Identifier: GPL-2.0
3 * MediaTek External Memory Interface (EMI) Interconnect driver
5 * Copyright (c) 2021 MediaTek Inc.
6 * Copyright (c) 2024 Collabora Ltd.
7 * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
10 #include <linux/interconnect.h>
11 #include <linux/interconnect-provider.h>
12 #include <linux/module.h>
14 #include <linux/of_platform.h>
15 #include <linux/platform_device.h>
16 #include <linux/soc/mediatek/dvfsrc.h>
20 static int mtk_emi_icc_aggregate(struct icc_node
*node
, u32 tag
, u32 avg_bw
,
21 u32 peak_bw
, u32
*agg_avg
, u32
*agg_peak
)
23 struct mtk_icc_node
*in
= node
->data
;
26 *agg_peak
= max_t(u32
, *agg_peak
, peak_bw
);
28 in
->sum_avg
= *agg_avg
;
29 in
->max_peak
= *agg_peak
;
34 static int mtk_emi_icc_set(struct icc_node
*src
, struct icc_node
*dst
)
36 struct mtk_icc_node
*node
= dst
->data
;
40 if (unlikely(!src
->provider
))
43 dev
= src
->provider
->dev
;
49 ret
= mtk_dvfsrc_send_request(dev
, MTK_DVFSRC_CMD_PEAK_BW
, node
->max_peak
);
51 dev_err(dev
, "Cannot send peak bw request: %d\n", ret
);
55 ret
= mtk_dvfsrc_send_request(dev
, MTK_DVFSRC_CMD_BW
, node
->sum_avg
);
57 dev_err(dev
, "Cannot send bw request: %d\n", ret
);
62 ret
= mtk_dvfsrc_send_request(dev
, MTK_DVFSRC_CMD_HRT_BW
, node
->sum_avg
);
64 dev_err(dev
, "Cannot send HRT bw request: %d\n", ret
);
69 dev_err(src
->provider
->dev
, "Unknown endpoint %u\n", node
->ep
);
76 int mtk_emi_icc_probe(struct platform_device
*pdev
)
78 const struct mtk_icc_desc
*desc
;
79 struct device
*dev
= &pdev
->dev
;
80 struct icc_node
*node
;
81 struct icc_onecell_data
*data
;
82 struct icc_provider
*provider
;
83 struct mtk_icc_node
**mnodes
;
86 desc
= of_device_get_match_data(dev
);
92 provider
= devm_kzalloc(dev
, sizeof(*provider
), GFP_KERNEL
);
96 data
= devm_kzalloc(dev
, struct_size(data
, nodes
, desc
->num_nodes
), GFP_KERNEL
);
100 provider
->dev
= pdev
->dev
.parent
;
101 provider
->set
= mtk_emi_icc_set
;
102 provider
->aggregate
= mtk_emi_icc_aggregate
;
103 provider
->xlate
= of_icc_xlate_onecell
;
104 INIT_LIST_HEAD(&provider
->nodes
);
105 provider
->data
= data
;
107 for (i
= 0; i
< desc
->num_nodes
; i
++) {
111 node
= icc_node_create(mnodes
[i
]->id
);
117 node
->name
= mnodes
[i
]->name
;
118 node
->data
= mnodes
[i
];
119 icc_node_add(node
, provider
);
121 for (j
= 0; j
< mnodes
[i
]->num_links
; j
++)
122 icc_link_create(node
, mnodes
[i
]->links
[j
]);
124 data
->nodes
[i
] = node
;
126 data
->num_nodes
= desc
->num_nodes
;
128 ret
= icc_provider_register(provider
);
132 platform_set_drvdata(pdev
, provider
);
136 icc_nodes_remove(provider
);
139 EXPORT_SYMBOL_GPL(mtk_emi_icc_probe
);
141 void mtk_emi_icc_remove(struct platform_device
*pdev
)
143 struct icc_provider
*provider
= platform_get_drvdata(pdev
);
145 icc_provider_deregister(provider
);
146 icc_nodes_remove(provider
);
148 EXPORT_SYMBOL_GPL(mtk_emi_icc_remove
);
150 MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
151 MODULE_AUTHOR("Henry Chen <henryc.chen@mediatek.com>");
152 MODULE_DESCRIPTION("MediaTek External Memory Interface interconnect driver");
153 MODULE_LICENSE("GPL");