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

dcss-dev.c (6629B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright 2019 NXP.
      4 */
      5
      6#include <linux/clk.h>
      7#include <linux/of_device.h>
      8#include <linux/of_graph.h>
      9#include <linux/pm_runtime.h>
     10#include <linux/slab.h>
     11#include <drm/drm_bridge_connector.h>
     12#include <drm/drm_device.h>
     13#include <drm/drm_modeset_helper.h>
     14
     15#include "dcss-dev.h"
     16#include "dcss-kms.h"
     17
     18static void dcss_clocks_enable(struct dcss_dev *dcss)
     19{
     20	clk_prepare_enable(dcss->axi_clk);
     21	clk_prepare_enable(dcss->apb_clk);
     22	clk_prepare_enable(dcss->rtrm_clk);
     23	clk_prepare_enable(dcss->dtrc_clk);
     24	clk_prepare_enable(dcss->pix_clk);
     25}
     26
     27static void dcss_clocks_disable(struct dcss_dev *dcss)
     28{
     29	clk_disable_unprepare(dcss->pix_clk);
     30	clk_disable_unprepare(dcss->dtrc_clk);
     31	clk_disable_unprepare(dcss->rtrm_clk);
     32	clk_disable_unprepare(dcss->apb_clk);
     33	clk_disable_unprepare(dcss->axi_clk);
     34}
     35
     36static void dcss_disable_dtg_and_ss_cb(void *data)
     37{
     38	struct dcss_dev *dcss = data;
     39
     40	dcss->disable_callback = NULL;
     41
     42	dcss_ss_shutoff(dcss->ss);
     43	dcss_dtg_shutoff(dcss->dtg);
     44
     45	complete(&dcss->disable_completion);
     46}
     47
     48void dcss_disable_dtg_and_ss(struct dcss_dev *dcss)
     49{
     50	dcss->disable_callback = dcss_disable_dtg_and_ss_cb;
     51}
     52
     53void dcss_enable_dtg_and_ss(struct dcss_dev *dcss)
     54{
     55	if (dcss->disable_callback)
     56		dcss->disable_callback = NULL;
     57
     58	dcss_dtg_enable(dcss->dtg);
     59	dcss_ss_enable(dcss->ss);
     60}
     61
     62static int dcss_submodules_init(struct dcss_dev *dcss)
     63{
     64	int ret = 0;
     65	u32 base_addr = dcss->start_addr;
     66	const struct dcss_type_data *devtype = dcss->devtype;
     67
     68	dcss_clocks_enable(dcss);
     69
     70	ret = dcss_blkctl_init(dcss, base_addr + devtype->blkctl_ofs);
     71	if (ret)
     72		return ret;
     73
     74	ret = dcss_ctxld_init(dcss, base_addr + devtype->ctxld_ofs);
     75	if (ret)
     76		goto ctxld_err;
     77
     78	ret = dcss_dtg_init(dcss, base_addr + devtype->dtg_ofs);
     79	if (ret)
     80		goto dtg_err;
     81
     82	ret = dcss_ss_init(dcss, base_addr + devtype->ss_ofs);
     83	if (ret)
     84		goto ss_err;
     85
     86	ret = dcss_dpr_init(dcss, base_addr + devtype->dpr_ofs);
     87	if (ret)
     88		goto dpr_err;
     89
     90	ret = dcss_scaler_init(dcss, base_addr + devtype->scaler_ofs);
     91	if (ret)
     92		goto scaler_err;
     93
     94	dcss_clocks_disable(dcss);
     95
     96	return 0;
     97
     98scaler_err:
     99	dcss_dpr_exit(dcss->dpr);
    100
    101dpr_err:
    102	dcss_ss_exit(dcss->ss);
    103
    104ss_err:
    105	dcss_dtg_exit(dcss->dtg);
    106
    107dtg_err:
    108	dcss_ctxld_exit(dcss->ctxld);
    109
    110ctxld_err:
    111	dcss_blkctl_exit(dcss->blkctl);
    112
    113	dcss_clocks_disable(dcss);
    114
    115	return ret;
    116}
    117
    118static void dcss_submodules_stop(struct dcss_dev *dcss)
    119{
    120	dcss_clocks_enable(dcss);
    121	dcss_scaler_exit(dcss->scaler);
    122	dcss_dpr_exit(dcss->dpr);
    123	dcss_ss_exit(dcss->ss);
    124	dcss_dtg_exit(dcss->dtg);
    125	dcss_ctxld_exit(dcss->ctxld);
    126	dcss_blkctl_exit(dcss->blkctl);
    127	dcss_clocks_disable(dcss);
    128}
    129
    130static int dcss_clks_init(struct dcss_dev *dcss)
    131{
    132	int i;
    133	struct {
    134		const char *id;
    135		struct clk **clk;
    136	} clks[] = {
    137		{"apb",   &dcss->apb_clk},
    138		{"axi",   &dcss->axi_clk},
    139		{"pix",   &dcss->pix_clk},
    140		{"rtrm",  &dcss->rtrm_clk},
    141		{"dtrc",  &dcss->dtrc_clk},
    142	};
    143
    144	for (i = 0; i < ARRAY_SIZE(clks); i++) {
    145		*clks[i].clk = devm_clk_get(dcss->dev, clks[i].id);
    146		if (IS_ERR(*clks[i].clk)) {
    147			dev_err(dcss->dev, "failed to get %s clock\n",
    148				clks[i].id);
    149			return PTR_ERR(*clks[i].clk);
    150		}
    151	}
    152
    153	return 0;
    154}
    155
    156static void dcss_clks_release(struct dcss_dev *dcss)
    157{
    158	devm_clk_put(dcss->dev, dcss->dtrc_clk);
    159	devm_clk_put(dcss->dev, dcss->rtrm_clk);
    160	devm_clk_put(dcss->dev, dcss->pix_clk);
    161	devm_clk_put(dcss->dev, dcss->axi_clk);
    162	devm_clk_put(dcss->dev, dcss->apb_clk);
    163}
    164
    165struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output)
    166{
    167	struct platform_device *pdev = to_platform_device(dev);
    168	int ret;
    169	struct resource *res;
    170	struct dcss_dev *dcss;
    171	const struct dcss_type_data *devtype;
    172
    173	devtype = of_device_get_match_data(dev);
    174	if (!devtype) {
    175		dev_err(dev, "no device match found\n");
    176		return ERR_PTR(-ENODEV);
    177	}
    178
    179	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    180	if (!res) {
    181		dev_err(dev, "cannot get memory resource\n");
    182		return ERR_PTR(-EINVAL);
    183	}
    184
    185	dcss = kzalloc(sizeof(*dcss), GFP_KERNEL);
    186	if (!dcss)
    187		return ERR_PTR(-ENOMEM);
    188
    189	dcss->dev = dev;
    190	dcss->devtype = devtype;
    191	dcss->hdmi_output = hdmi_output;
    192
    193	ret = dcss_clks_init(dcss);
    194	if (ret) {
    195		dev_err(dev, "clocks initialization failed\n");
    196		goto err;
    197	}
    198
    199	dcss->of_port = of_graph_get_port_by_id(dev->of_node, 0);
    200	if (!dcss->of_port) {
    201		dev_err(dev, "no port@0 node in %s\n", dev->of_node->full_name);
    202		ret = -ENODEV;
    203		goto clks_err;
    204	}
    205
    206	dcss->start_addr = res->start;
    207
    208	ret = dcss_submodules_init(dcss);
    209	if (ret) {
    210		dev_err(dev, "submodules initialization failed\n");
    211		goto clks_err;
    212	}
    213
    214	init_completion(&dcss->disable_completion);
    215
    216	pm_runtime_set_autosuspend_delay(dev, 100);
    217	pm_runtime_use_autosuspend(dev);
    218	pm_runtime_set_suspended(dev);
    219	pm_runtime_allow(dev);
    220	pm_runtime_enable(dev);
    221
    222	return dcss;
    223
    224clks_err:
    225	dcss_clks_release(dcss);
    226
    227err:
    228	kfree(dcss);
    229
    230	return ERR_PTR(ret);
    231}
    232
    233void dcss_dev_destroy(struct dcss_dev *dcss)
    234{
    235	if (!pm_runtime_suspended(dcss->dev)) {
    236		dcss_ctxld_suspend(dcss->ctxld);
    237		dcss_clocks_disable(dcss);
    238	}
    239
    240	pm_runtime_disable(dcss->dev);
    241
    242	dcss_submodules_stop(dcss);
    243
    244	dcss_clks_release(dcss);
    245
    246	kfree(dcss);
    247}
    248
    249#ifdef CONFIG_PM_SLEEP
    250int dcss_dev_suspend(struct device *dev)
    251{
    252	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
    253	struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
    254	struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
    255	int ret;
    256
    257	drm_bridge_connector_disable_hpd(kms->connector);
    258
    259	drm_mode_config_helper_suspend(ddev);
    260
    261	if (pm_runtime_suspended(dev))
    262		return 0;
    263
    264	ret = dcss_ctxld_suspend(dcss->ctxld);
    265	if (ret)
    266		return ret;
    267
    268	dcss_clocks_disable(dcss);
    269
    270	return 0;
    271}
    272
    273int dcss_dev_resume(struct device *dev)
    274{
    275	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
    276	struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
    277	struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
    278
    279	if (pm_runtime_suspended(dev)) {
    280		drm_mode_config_helper_resume(ddev);
    281		return 0;
    282	}
    283
    284	dcss_clocks_enable(dcss);
    285
    286	dcss_blkctl_cfg(dcss->blkctl);
    287
    288	dcss_ctxld_resume(dcss->ctxld);
    289
    290	drm_mode_config_helper_resume(ddev);
    291
    292	drm_bridge_connector_enable_hpd(kms->connector);
    293
    294	return 0;
    295}
    296#endif /* CONFIG_PM_SLEEP */
    297
    298#ifdef CONFIG_PM
    299int dcss_dev_runtime_suspend(struct device *dev)
    300{
    301	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
    302	int ret;
    303
    304	ret = dcss_ctxld_suspend(dcss->ctxld);
    305	if (ret)
    306		return ret;
    307
    308	dcss_clocks_disable(dcss);
    309
    310	return 0;
    311}
    312
    313int dcss_dev_runtime_resume(struct device *dev)
    314{
    315	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
    316
    317	dcss_clocks_enable(dcss);
    318
    319	dcss_blkctl_cfg(dcss->blkctl);
    320
    321	dcss_ctxld_resume(dcss->ctxld);
    322
    323	return 0;
    324}
    325#endif /* CONFIG_PM */