Merge series "Add driver for dvfsrc, support for active state of scpsys" from Henry Chen <henryc.chen@mediatek.com>:
This series is based on v5.10-rc1. The patchsets add support for MediaTek hardware module named DVFSRC (dynamic voltage and frequency scaling resource collector). The DVFSRC is a HW module which is used to collect all the requests from both software and hardware and turn into the decision of minimum operating voltage and minimum DRAM frequency to fulfill those requests. So, This series is to implement the dvfsrc driver to collect all the requests of operating voltage or DRAM bandwidth from other device drivers likes GPU/Camera through 3 frameworks basically: 1. interconnect framework: to aggregate the bandwidth requirements from different clients [1] https://patchwork.kernel.org/cover/10766329/ There has a hw module "DRAM scheduler", which used to control the throughput. The DVFSRC will collect forecast data of dram bandwidth from SW consumers(camera/gpu...), and according the forecast to change the DRAM frequency 2. Regualtor framework: to handle the operating voltage requirement from user or cosumer which not belong any power domain Changes in V6: * Remove the performace state support, because the request from consumer can be replaced by using interconnect and regulator framework. * Update the DT patches and convert them to DT schema. (Georgi) * Modify the comment format and coding style. (Mark) Changes in V5: * Support more platform mt6873/mt8192 * Drop the compatible and interconnect provider node and make the parent node an interconnect provider. (Rob/Georgi) * Make modification of interconnect driver from coding suggestion. (Georgi) * Move interconnect diagram into the commit text of patch. (Georgi) * Register the interconnect provider as a platform sub-device. (Georgi) Changes in V4: * Add acked TAG on dt-bindings patches. (Rob) * Declaration of emi_icc_aggregate since the prototype of aggregate function has changed meanwhile. (Georgi) * Used emi_icc_remove instead of icc_provider_del on probe. (Georgi) * Add dvfsrc regulator driver into series. * Bug fixed of mt8183_get_current_level. * Add mutex protection for pstate operation on dvfsrc_set_performance. Changes in V3: * Remove RFC from the subject prefix of the series * Combine dt-binding patch and move interconnect dt-binding document into dvfsrc. (Rob) * Remove unused header, add unit descirption to the bandwidth, rename compatible name on interconnect driver. (Georgi) * Fixed some coding style: check flow, naming, used readx_poll_timeout on dvfsrc driver. (Ryan) * Rename interconnect driver mt8183.c to mtk-emi.c * Rename interconnect header mtk,mt8183.h to mtk,emi.h * mtk-scpsys.c: Add opp table check first to avoid OF runtime parse failed Changes in RFC V2: * Remove the DT property dram_type. (Rob) * Used generic dts property 'opp-level' to get the performace state. (Stephen) * Remove unecessary dependency config on Kconfig. (Stephen) * Remove unused header file, fixed some coding style issue, typo, error handling on dvfsrc driver. (Nicolas/Stephen) * Remove irq handler on dvfsrc driver. (Stephen) * Remove init table on dvfsrc driver, combine hw init on trustzone. * Add interconnect support of mt8183 to aggregate the emi bandwidth. (Georgi) V5: https://patchwork.kernel.org/project/linux-mediatek/list/?series=348065 V4: https://lore.kernel.org/patchwork/cover/1209284/ V3: https://patchwork.kernel.org/cover/11118867/ RFC V2: https://lore.kernel.org/patchwork/patch/1068113/ RFC V1: https://lore.kernel.org/patchwork/cover/1028535/ _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
This commit is contained in:
commit
f45c522cf8
|
@ -785,6 +785,16 @@ config REGULATOR_MT6397
|
|||
This driver supports the control of different power rails of device
|
||||
through regulator interface.
|
||||
|
||||
config REGULATOR_MTK_DVFSRC
|
||||
tristate "MediaTek DVFSRC regulator driver"
|
||||
depends on MTK_DVFSRC
|
||||
help
|
||||
Say y here to control regulator by DVFSRC (dynamic voltage
|
||||
and frequency scaling resource collector).
|
||||
This driver supports to control regulators via the DVFSRC
|
||||
of Mediatek. It allows for voting on regulator state
|
||||
between multiple users.
|
||||
|
||||
config REGULATOR_PALMAS
|
||||
tristate "TI Palmas PMIC Regulators"
|
||||
depends on MFD_PALMAS
|
||||
|
|
|
@ -95,6 +95,7 @@ obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o
|
|||
obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (c) 2020 MediaTek Inc.
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/soc/mediatek/mtk_dvfsrc.h>
|
||||
|
||||
#define DVFSRC_ID_VCORE 0
|
||||
#define DVFSRC_ID_VSCP 1
|
||||
|
||||
#define MT_DVFSRC_REGULAR(match, _name, _volt_table) \
|
||||
[DVFSRC_ID_##_name] = { \
|
||||
.desc = { \
|
||||
.name = match, \
|
||||
.of_match = of_match_ptr(match), \
|
||||
.ops = &dvfsrc_vcore_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = DVFSRC_ID_##_name, \
|
||||
.owner = THIS_MODULE, \
|
||||
.n_voltages = ARRAY_SIZE(_volt_table), \
|
||||
.volt_table = _volt_table, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/*
|
||||
* DVFSRC regulators' information
|
||||
*
|
||||
* @desc: standard fields of regulator description.
|
||||
* @voltage_selector: Selector used for get_voltage_sel() and
|
||||
* set_voltage_sel() callbacks
|
||||
*/
|
||||
|
||||
struct dvfsrc_regulator {
|
||||
struct regulator_desc desc;
|
||||
};
|
||||
|
||||
/*
|
||||
* MTK DVFSRC regulators' init data
|
||||
*
|
||||
* @size: num of regulators
|
||||
* @regulator_info: regulator info.
|
||||
*/
|
||||
struct dvfsrc_regulator_init_data {
|
||||
u32 size;
|
||||
struct dvfsrc_regulator *regulator_info;
|
||||
};
|
||||
|
||||
static inline struct device *to_dvfsrc_dev(struct regulator_dev *rdev)
|
||||
{
|
||||
return rdev_get_dev(rdev)->parent;
|
||||
}
|
||||
|
||||
static int dvfsrc_set_voltage_sel(struct regulator_dev *rdev,
|
||||
unsigned int selector)
|
||||
{
|
||||
struct device *dvfsrc_dev = to_dvfsrc_dev(rdev);
|
||||
int id = rdev_get_id(rdev);
|
||||
|
||||
if (id == DVFSRC_ID_VCORE)
|
||||
mtk_dvfsrc_send_request(dvfsrc_dev,
|
||||
MTK_DVFSRC_CMD_VCORE_REQUEST,
|
||||
selector);
|
||||
else if (id == DVFSRC_ID_VSCP)
|
||||
mtk_dvfsrc_send_request(dvfsrc_dev,
|
||||
MTK_DVFSRC_CMD_VSCP_REQUEST,
|
||||
selector);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvfsrc_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
struct device *dvfsrc_dev = to_dvfsrc_dev(rdev);
|
||||
int id = rdev_get_id(rdev);
|
||||
int val, ret;
|
||||
|
||||
if (id == DVFSRC_ID_VCORE)
|
||||
ret = mtk_dvfsrc_query_info(dvfsrc_dev,
|
||||
MTK_DVFSRC_CMD_VCORE_LEVEL_QUERY,
|
||||
&val);
|
||||
else if (id == DVFSRC_ID_VSCP)
|
||||
ret = mtk_dvfsrc_query_info(dvfsrc_dev,
|
||||
MTK_DVFSRC_CMD_VSCP_LEVEL_QUERY,
|
||||
&val);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const struct regulator_ops dvfsrc_vcore_ops = {
|
||||
.list_voltage = regulator_list_voltage_table,
|
||||
.get_voltage_sel = dvfsrc_get_voltage_sel,
|
||||
.set_voltage_sel = dvfsrc_set_voltage_sel,
|
||||
};
|
||||
|
||||
static const unsigned int mt8183_voltages[] = {
|
||||
725000,
|
||||
800000,
|
||||
};
|
||||
|
||||
static struct dvfsrc_regulator mt8183_regulators[] = {
|
||||
MT_DVFSRC_REGULAR("dvfsrc-vcore", VCORE,
|
||||
mt8183_voltages),
|
||||
};
|
||||
|
||||
static const struct dvfsrc_regulator_init_data regulator_mt8183_data = {
|
||||
.size = ARRAY_SIZE(mt8183_regulators),
|
||||
.regulator_info = &mt8183_regulators[0],
|
||||
};
|
||||
|
||||
static const unsigned int mt6873_voltages[] = {
|
||||
575000,
|
||||
600000,
|
||||
650000,
|
||||
725000,
|
||||
};
|
||||
|
||||
static struct dvfsrc_regulator mt6873_regulators[] = {
|
||||
MT_DVFSRC_REGULAR("dvfsrc-vcore", VCORE,
|
||||
mt6873_voltages),
|
||||
MT_DVFSRC_REGULAR("dvfsrc-vscp", VSCP,
|
||||
mt6873_voltages),
|
||||
};
|
||||
|
||||
static const struct dvfsrc_regulator_init_data regulator_mt6873_data = {
|
||||
.size = ARRAY_SIZE(mt6873_regulators),
|
||||
.regulator_info = &mt6873_regulators[0],
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_dvfsrc_regulator_match[] = {
|
||||
{
|
||||
.compatible = "mediatek,mt8183-dvfsrc",
|
||||
.data = ®ulator_mt8183_data,
|
||||
}, {
|
||||
.compatible = "mediatek,mt8192-dvfsrc",
|
||||
.data = ®ulator_mt6873_data,
|
||||
}, {
|
||||
.compatible = "mediatek,mt6873-dvfsrc",
|
||||
.data = ®ulator_mt6873_data,
|
||||
}, {
|
||||
/* sentinel */
|
||||
},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtk_dvfsrc_regulator_match);
|
||||
|
||||
static int dvfsrc_vcore_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct regulator_config config = { };
|
||||
struct regulator_dev *rdev;
|
||||
const struct dvfsrc_regulator_init_data *regulator_init_data;
|
||||
struct dvfsrc_regulator *mt_regulators;
|
||||
int i;
|
||||
|
||||
match = of_match_node(mtk_dvfsrc_regulator_match, dev->parent->of_node);
|
||||
|
||||
if (!match) {
|
||||
dev_err(dev, "invalid compatible string\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
regulator_init_data = match->data;
|
||||
|
||||
mt_regulators = regulator_init_data->regulator_info;
|
||||
for (i = 0; i < regulator_init_data->size; i++) {
|
||||
config.dev = dev->parent;
|
||||
config.driver_data = (mt_regulators + i);
|
||||
rdev = devm_regulator_register(dev->parent,
|
||||
&(mt_regulators + i)->desc,
|
||||
&config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(dev, "failed to register %s\n",
|
||||
(mt_regulators + i)->desc.name);
|
||||
return PTR_ERR(rdev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mtk_dvfsrc_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "mtk-dvfsrc-regulator",
|
||||
},
|
||||
.probe = dvfsrc_vcore_regulator_probe,
|
||||
};
|
||||
|
||||
static int __init mtk_dvfsrc_regulator_init(void)
|
||||
{
|
||||
return platform_driver_register(&mtk_dvfsrc_regulator_driver);
|
||||
}
|
||||
subsys_initcall(mtk_dvfsrc_regulator_init);
|
||||
|
||||
static void __exit mtk_dvfsrc_regulator_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mtk_dvfsrc_regulator_driver);
|
||||
}
|
||||
module_exit(mtk_dvfsrc_regulator_exit);
|
||||
|
||||
MODULE_AUTHOR("Arvin wang <arvin.wang@mediatek.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
Loading…
Reference in New Issue