cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dp_power.c (9701B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
      4 */
      5
      6#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
      7
      8#include <linux/clk.h>
      9#include <linux/clk-provider.h>
     10#include <linux/regulator/consumer.h>
     11#include <linux/pm_opp.h>
     12#include "dp_power.h"
     13#include "msm_drv.h"
     14
     15struct dp_power_private {
     16	struct dp_parser *parser;
     17	struct platform_device *pdev;
     18	struct device *dev;
     19	struct drm_device *drm_dev;
     20	struct clk *link_clk_src;
     21	struct clk *pixel_provider;
     22	struct clk *link_provider;
     23	struct regulator_bulk_data supplies[DP_DEV_REGULATOR_MAX];
     24
     25	struct dp_power dp_power;
     26};
     27
     28static void dp_power_regulator_disable(struct dp_power_private *power)
     29{
     30	struct regulator_bulk_data *s = power->supplies;
     31	const struct dp_reg_entry *regs = power->parser->regulator_cfg->regs;
     32	int num = power->parser->regulator_cfg->num;
     33	int i;
     34
     35	DBG("");
     36	for (i = num - 1; i >= 0; i--)
     37		if (regs[i].disable_load >= 0)
     38			regulator_set_load(s[i].consumer,
     39					   regs[i].disable_load);
     40
     41	regulator_bulk_disable(num, s);
     42}
     43
     44static int dp_power_regulator_enable(struct dp_power_private *power)
     45{
     46	struct regulator_bulk_data *s = power->supplies;
     47	const struct dp_reg_entry *regs = power->parser->regulator_cfg->regs;
     48	int num = power->parser->regulator_cfg->num;
     49	int ret, i;
     50
     51	DBG("");
     52	for (i = 0; i < num; i++) {
     53		if (regs[i].enable_load >= 0) {
     54			ret = regulator_set_load(s[i].consumer,
     55						 regs[i].enable_load);
     56			if (ret < 0) {
     57				pr_err("regulator %d set op mode failed, %d\n",
     58					i, ret);
     59				goto fail;
     60			}
     61		}
     62	}
     63
     64	ret = regulator_bulk_enable(num, s);
     65	if (ret < 0) {
     66		pr_err("regulator enable failed, %d\n", ret);
     67		goto fail;
     68	}
     69
     70	return 0;
     71
     72fail:
     73	for (i--; i >= 0; i--)
     74		regulator_set_load(s[i].consumer, regs[i].disable_load);
     75	return ret;
     76}
     77
     78static int dp_power_regulator_init(struct dp_power_private *power)
     79{
     80	struct regulator_bulk_data *s = power->supplies;
     81	const struct dp_reg_entry *regs = power->parser->regulator_cfg->regs;
     82	struct platform_device *pdev = power->pdev;
     83	int num = power->parser->regulator_cfg->num;
     84	int i, ret;
     85
     86	for (i = 0; i < num; i++)
     87		s[i].supply = regs[i].name;
     88
     89	ret = devm_regulator_bulk_get(&pdev->dev, num, s);
     90	if (ret < 0) {
     91		pr_err("%s: failed to init regulator, ret=%d\n",
     92						__func__, ret);
     93		return ret;
     94	}
     95
     96	return 0;
     97}
     98
     99static int dp_power_clk_init(struct dp_power_private *power)
    100{
    101	int rc = 0;
    102	struct dss_module_power *core, *ctrl, *stream;
    103	struct device *dev = &power->pdev->dev;
    104
    105	core = &power->parser->mp[DP_CORE_PM];
    106	ctrl = &power->parser->mp[DP_CTRL_PM];
    107	stream = &power->parser->mp[DP_STREAM_PM];
    108
    109	rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk);
    110	if (rc) {
    111		DRM_ERROR("failed to get %s clk. err=%d\n",
    112			dp_parser_pm_name(DP_CORE_PM), rc);
    113		return rc;
    114	}
    115
    116	rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk);
    117	if (rc) {
    118		DRM_ERROR("failed to get %s clk. err=%d\n",
    119			dp_parser_pm_name(DP_CTRL_PM), rc);
    120		msm_dss_put_clk(core->clk_config, core->num_clk);
    121		return -ENODEV;
    122	}
    123
    124	rc = msm_dss_get_clk(dev, stream->clk_config, stream->num_clk);
    125	if (rc) {
    126		DRM_ERROR("failed to get %s clk. err=%d\n",
    127			dp_parser_pm_name(DP_CTRL_PM), rc);
    128		msm_dss_put_clk(core->clk_config, core->num_clk);
    129		return -ENODEV;
    130	}
    131
    132	return 0;
    133}
    134
    135static int dp_power_clk_deinit(struct dp_power_private *power)
    136{
    137	struct dss_module_power *core, *ctrl, *stream;
    138
    139	core = &power->parser->mp[DP_CORE_PM];
    140	ctrl = &power->parser->mp[DP_CTRL_PM];
    141	stream = &power->parser->mp[DP_STREAM_PM];
    142
    143	if (!core || !ctrl || !stream) {
    144		DRM_ERROR("invalid power_data\n");
    145		return -EINVAL;
    146	}
    147
    148	msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk);
    149	msm_dss_put_clk(core->clk_config, core->num_clk);
    150	msm_dss_put_clk(stream->clk_config, stream->num_clk);
    151	return 0;
    152}
    153
    154static int dp_power_clk_set_link_rate(struct dp_power_private *power,
    155			struct dss_clk *clk_arry, int num_clk, int enable)
    156{
    157	u32 rate;
    158	int i, rc = 0;
    159
    160	for (i = 0; i < num_clk; i++) {
    161		if (clk_arry[i].clk) {
    162			if (clk_arry[i].type == DSS_CLK_PCLK) {
    163				if (enable)
    164					rate = clk_arry[i].rate;
    165				else
    166					rate = 0;
    167
    168				rc = dev_pm_opp_set_rate(power->dev, rate);
    169				if (rc)
    170					break;
    171			}
    172
    173		}
    174	}
    175	return rc;
    176}
    177
    178static int dp_power_clk_set_rate(struct dp_power_private *power,
    179		enum dp_pm_type module, bool enable)
    180{
    181	int rc = 0;
    182	struct dss_module_power *mp = &power->parser->mp[module];
    183
    184	if (module == DP_CTRL_PM) {
    185		rc = dp_power_clk_set_link_rate(power, mp->clk_config, mp->num_clk, enable);
    186		if (rc) {
    187			DRM_ERROR("failed to set link clks rate\n");
    188			return rc;
    189		}
    190	} else {
    191
    192		if (enable) {
    193			rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
    194			if (rc) {
    195				DRM_ERROR("failed to set clks rate\n");
    196				return rc;
    197			}
    198		}
    199	}
    200
    201	rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
    202	if (rc) {
    203		DRM_ERROR("failed to %d clks, err: %d\n", enable, rc);
    204		return rc;
    205	}
    206
    207	return 0;
    208}
    209
    210int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
    211{
    212	struct dp_power_private *power;
    213
    214	power = container_of(dp_power, struct dp_power_private, dp_power);
    215
    216	drm_dbg_dp(power->drm_dev,
    217		"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
    218		dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on);
    219
    220	if (pm_type == DP_CORE_PM)
    221		return dp_power->core_clks_on;
    222
    223	if (pm_type == DP_CTRL_PM)
    224		return dp_power->link_clks_on;
    225
    226	if (pm_type == DP_STREAM_PM)
    227		return dp_power->stream_clks_on;
    228
    229	return 0;
    230}
    231
    232int dp_power_clk_enable(struct dp_power *dp_power,
    233		enum dp_pm_type pm_type, bool enable)
    234{
    235	int rc = 0;
    236	struct dp_power_private *power;
    237
    238	power = container_of(dp_power, struct dp_power_private, dp_power);
    239
    240	if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
    241			pm_type != DP_STREAM_PM) {
    242		DRM_ERROR("unsupported power module: %s\n",
    243				dp_parser_pm_name(pm_type));
    244		return -EINVAL;
    245	}
    246
    247	if (enable) {
    248		if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
    249			drm_dbg_dp(power->drm_dev,
    250					"core clks already enabled\n");
    251			return 0;
    252		}
    253
    254		if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
    255			drm_dbg_dp(power->drm_dev,
    256					"links clks already enabled\n");
    257			return 0;
    258		}
    259
    260		if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
    261			drm_dbg_dp(power->drm_dev,
    262					"pixel clks already enabled\n");
    263			return 0;
    264		}
    265
    266		if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
    267			drm_dbg_dp(power->drm_dev,
    268					"Enable core clks before link clks\n");
    269
    270			rc = dp_power_clk_set_rate(power, DP_CORE_PM, enable);
    271			if (rc) {
    272				DRM_ERROR("fail to enable clks: %s. err=%d\n",
    273					dp_parser_pm_name(DP_CORE_PM), rc);
    274				return rc;
    275			}
    276			dp_power->core_clks_on = true;
    277		}
    278	}
    279
    280	rc = dp_power_clk_set_rate(power, pm_type, enable);
    281	if (rc) {
    282		DRM_ERROR("failed to '%s' clks for: %s. err=%d\n",
    283			enable ? "enable" : "disable",
    284			dp_parser_pm_name(pm_type), rc);
    285		return rc;
    286	}
    287
    288	if (pm_type == DP_CORE_PM)
    289		dp_power->core_clks_on = enable;
    290	else if (pm_type == DP_STREAM_PM)
    291		dp_power->stream_clks_on = enable;
    292	else
    293		dp_power->link_clks_on = enable;
    294
    295	drm_dbg_dp(power->drm_dev, "%s clocks for %s\n",
    296			enable ? "enable" : "disable",
    297			dp_parser_pm_name(pm_type));
    298	drm_dbg_dp(power->drm_dev,
    299		"strem_clks:%s link_clks:%s core_clks:%s\n",
    300		dp_power->stream_clks_on ? "on" : "off",
    301		dp_power->link_clks_on ? "on" : "off",
    302		dp_power->core_clks_on ? "on" : "off");
    303
    304	return 0;
    305}
    306
    307int dp_power_client_init(struct dp_power *dp_power)
    308{
    309	int rc = 0;
    310	struct dp_power_private *power;
    311
    312	if (!dp_power) {
    313		DRM_ERROR("invalid power data\n");
    314		return -EINVAL;
    315	}
    316
    317	power = container_of(dp_power, struct dp_power_private, dp_power);
    318
    319	pm_runtime_enable(&power->pdev->dev);
    320
    321	rc = dp_power_regulator_init(power);
    322	if (rc) {
    323		DRM_ERROR("failed to init regulators %d\n", rc);
    324		goto error;
    325	}
    326
    327	rc = dp_power_clk_init(power);
    328	if (rc) {
    329		DRM_ERROR("failed to init clocks %d\n", rc);
    330		goto error;
    331	}
    332	return 0;
    333
    334error:
    335	pm_runtime_disable(&power->pdev->dev);
    336	return rc;
    337}
    338
    339void dp_power_client_deinit(struct dp_power *dp_power)
    340{
    341	struct dp_power_private *power;
    342
    343	if (!dp_power) {
    344		DRM_ERROR("invalid power data\n");
    345		return;
    346	}
    347
    348	power = container_of(dp_power, struct dp_power_private, dp_power);
    349
    350	dp_power_clk_deinit(power);
    351	pm_runtime_disable(&power->pdev->dev);
    352
    353}
    354
    355int dp_power_init(struct dp_power *dp_power, bool flip)
    356{
    357	int rc = 0;
    358	struct dp_power_private *power = NULL;
    359
    360	if (!dp_power) {
    361		DRM_ERROR("invalid power data\n");
    362		return -EINVAL;
    363	}
    364
    365	power = container_of(dp_power, struct dp_power_private, dp_power);
    366
    367	pm_runtime_get_sync(&power->pdev->dev);
    368	rc = dp_power_regulator_enable(power);
    369	if (rc) {
    370		DRM_ERROR("failed to enable regulators, %d\n", rc);
    371		goto exit;
    372	}
    373
    374	rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
    375	if (rc) {
    376		DRM_ERROR("failed to enable DP core clocks, %d\n", rc);
    377		goto err_clk;
    378	}
    379
    380	return 0;
    381
    382err_clk:
    383	dp_power_regulator_disable(power);
    384exit:
    385	pm_runtime_put_sync(&power->pdev->dev);
    386	return rc;
    387}
    388
    389int dp_power_deinit(struct dp_power *dp_power)
    390{
    391	struct dp_power_private *power;
    392
    393	power = container_of(dp_power, struct dp_power_private, dp_power);
    394
    395	dp_power_clk_enable(dp_power, DP_CORE_PM, false);
    396	dp_power_regulator_disable(power);
    397	pm_runtime_put_sync(&power->pdev->dev);
    398	return 0;
    399}
    400
    401struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
    402{
    403	struct dp_power_private *power;
    404	struct dp_power *dp_power;
    405
    406	if (!parser) {
    407		DRM_ERROR("invalid input\n");
    408		return ERR_PTR(-EINVAL);
    409	}
    410
    411	power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL);
    412	if (!power)
    413		return ERR_PTR(-ENOMEM);
    414
    415	power->parser = parser;
    416	power->pdev = parser->pdev;
    417	power->dev = dev;
    418
    419	dp_power = &power->dp_power;
    420
    421	return dp_power;
    422}