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

zynqmp_dpsub.c (7365B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * ZynqMP DisplayPort Subsystem Driver
      4 *
      5 * Copyright (C) 2017 - 2020 Xilinx, Inc.
      6 *
      7 * Authors:
      8 * - Hyun Woo Kwon <hyun.kwon@xilinx.com>
      9 * - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
     10 */
     11
     12#include <linux/clk.h>
     13#include <linux/dma-mapping.h>
     14#include <linux/module.h>
     15#include <linux/of_reserved_mem.h>
     16#include <linux/platform_device.h>
     17#include <linux/pm_runtime.h>
     18
     19#include <drm/drm_atomic_helper.h>
     20#include <drm/drm_device.h>
     21#include <drm/drm_drv.h>
     22#include <drm/drm_fb_helper.h>
     23#include <drm/drm_fourcc.h>
     24#include <drm/drm_gem_cma_helper.h>
     25#include <drm/drm_gem_framebuffer_helper.h>
     26#include <drm/drm_managed.h>
     27#include <drm/drm_mode_config.h>
     28#include <drm/drm_module.h>
     29#include <drm/drm_probe_helper.h>
     30#include <drm/drm_vblank.h>
     31
     32#include "zynqmp_disp.h"
     33#include "zynqmp_dp.h"
     34#include "zynqmp_dpsub.h"
     35
     36/* -----------------------------------------------------------------------------
     37 * Dumb Buffer & Framebuffer Allocation
     38 */
     39
     40static int zynqmp_dpsub_dumb_create(struct drm_file *file_priv,
     41				    struct drm_device *drm,
     42				    struct drm_mode_create_dumb *args)
     43{
     44	struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
     45	unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
     46
     47	/* Enforce the alignment constraints of the DMA engine. */
     48	args->pitch = ALIGN(pitch, dpsub->dma_align);
     49
     50	return drm_gem_cma_dumb_create_internal(file_priv, drm, args);
     51}
     52
     53static struct drm_framebuffer *
     54zynqmp_dpsub_fb_create(struct drm_device *drm, struct drm_file *file_priv,
     55		       const struct drm_mode_fb_cmd2 *mode_cmd)
     56{
     57	struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
     58	struct drm_mode_fb_cmd2 cmd = *mode_cmd;
     59	unsigned int i;
     60
     61	/* Enforce the alignment constraints of the DMA engine. */
     62	for (i = 0; i < ARRAY_SIZE(cmd.pitches); ++i)
     63		cmd.pitches[i] = ALIGN(cmd.pitches[i], dpsub->dma_align);
     64
     65	return drm_gem_fb_create(drm, file_priv, &cmd);
     66}
     67
     68static const struct drm_mode_config_funcs zynqmp_dpsub_mode_config_funcs = {
     69	.fb_create		= zynqmp_dpsub_fb_create,
     70	.atomic_check		= drm_atomic_helper_check,
     71	.atomic_commit		= drm_atomic_helper_commit,
     72};
     73
     74/* -----------------------------------------------------------------------------
     75 * DRM/KMS Driver
     76 */
     77
     78DEFINE_DRM_GEM_CMA_FOPS(zynqmp_dpsub_drm_fops);
     79
     80static const struct drm_driver zynqmp_dpsub_drm_driver = {
     81	.driver_features		= DRIVER_MODESET | DRIVER_GEM |
     82					  DRIVER_ATOMIC,
     83
     84	DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(zynqmp_dpsub_dumb_create),
     85
     86	.fops				= &zynqmp_dpsub_drm_fops,
     87
     88	.name				= "zynqmp-dpsub",
     89	.desc				= "Xilinx DisplayPort Subsystem Driver",
     90	.date				= "20130509",
     91	.major				= 1,
     92	.minor				= 0,
     93};
     94
     95static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
     96{
     97	struct drm_device *drm = &dpsub->drm;
     98	int ret;
     99
    100	/* Initialize mode config, vblank and the KMS poll helper. */
    101	ret = drmm_mode_config_init(drm);
    102	if (ret < 0)
    103		return ret;
    104
    105	drm->mode_config.funcs = &zynqmp_dpsub_mode_config_funcs;
    106	drm->mode_config.min_width = 0;
    107	drm->mode_config.min_height = 0;
    108	drm->mode_config.max_width = ZYNQMP_DISP_MAX_WIDTH;
    109	drm->mode_config.max_height = ZYNQMP_DISP_MAX_HEIGHT;
    110
    111	ret = drm_vblank_init(drm, 1);
    112	if (ret)
    113		return ret;
    114
    115	drm_kms_helper_poll_init(drm);
    116
    117	/*
    118	 * Initialize the DISP and DP components. This will creates planes,
    119	 * CRTC, encoder and connector. The DISP should be initialized first as
    120	 * the DP encoder needs the CRTC.
    121	 */
    122	ret = zynqmp_disp_drm_init(dpsub);
    123	if (ret)
    124		goto err_poll_fini;
    125
    126	ret = zynqmp_dp_drm_init(dpsub);
    127	if (ret)
    128		goto err_poll_fini;
    129
    130	/* Reset all components and register the DRM device. */
    131	drm_mode_config_reset(drm);
    132
    133	ret = drm_dev_register(drm, 0);
    134	if (ret < 0)
    135		goto err_poll_fini;
    136
    137	/* Initialize fbdev generic emulation. */
    138	drm_fbdev_generic_setup(drm, 24);
    139
    140	return 0;
    141
    142err_poll_fini:
    143	drm_kms_helper_poll_fini(drm);
    144	return ret;
    145}
    146
    147/* -----------------------------------------------------------------------------
    148 * Power Management
    149 */
    150
    151static int __maybe_unused zynqmp_dpsub_suspend(struct device *dev)
    152{
    153	struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev);
    154
    155	return drm_mode_config_helper_suspend(&dpsub->drm);
    156}
    157
    158static int __maybe_unused zynqmp_dpsub_resume(struct device *dev)
    159{
    160	struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev);
    161
    162	return drm_mode_config_helper_resume(&dpsub->drm);
    163}
    164
    165static const struct dev_pm_ops zynqmp_dpsub_pm_ops = {
    166	SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dpsub_suspend, zynqmp_dpsub_resume)
    167};
    168
    169/* -----------------------------------------------------------------------------
    170 * Probe & Remove
    171 */
    172
    173static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub)
    174{
    175	int ret;
    176
    177	dpsub->apb_clk = devm_clk_get(dpsub->dev, "dp_apb_clk");
    178	if (IS_ERR(dpsub->apb_clk))
    179		return PTR_ERR(dpsub->apb_clk);
    180
    181	ret = clk_prepare_enable(dpsub->apb_clk);
    182	if (ret) {
    183		dev_err(dpsub->dev, "failed to enable the APB clock\n");
    184		return ret;
    185	}
    186
    187	return 0;
    188}
    189
    190static int zynqmp_dpsub_probe(struct platform_device *pdev)
    191{
    192	struct zynqmp_dpsub *dpsub;
    193	int ret;
    194
    195	/* Allocate private data. */
    196	dpsub = devm_drm_dev_alloc(&pdev->dev, &zynqmp_dpsub_drm_driver,
    197				   struct zynqmp_dpsub, drm);
    198	if (IS_ERR(dpsub))
    199		return PTR_ERR(dpsub);
    200
    201	dpsub->dev = &pdev->dev;
    202	platform_set_drvdata(pdev, dpsub);
    203
    204	dma_set_mask(dpsub->dev, DMA_BIT_MASK(ZYNQMP_DISP_MAX_DMA_BIT));
    205
    206	/* Try the reserved memory. Proceed if there's none. */
    207	of_reserved_mem_device_init(&pdev->dev);
    208
    209	ret = zynqmp_dpsub_init_clocks(dpsub);
    210	if (ret < 0)
    211		goto err_mem;
    212
    213	pm_runtime_enable(&pdev->dev);
    214
    215	/*
    216	 * DP should be probed first so that the zynqmp_disp can set the output
    217	 * format accordingly.
    218	 */
    219	ret = zynqmp_dp_probe(dpsub, &dpsub->drm);
    220	if (ret)
    221		goto err_pm;
    222
    223	ret = zynqmp_disp_probe(dpsub, &dpsub->drm);
    224	if (ret)
    225		goto err_dp;
    226
    227	ret = zynqmp_dpsub_drm_init(dpsub);
    228	if (ret)
    229		goto err_disp;
    230
    231	dev_info(&pdev->dev, "ZynqMP DisplayPort Subsystem driver probed");
    232
    233	return 0;
    234
    235err_disp:
    236	zynqmp_disp_remove(dpsub);
    237err_dp:
    238	zynqmp_dp_remove(dpsub);
    239err_pm:
    240	pm_runtime_disable(&pdev->dev);
    241	clk_disable_unprepare(dpsub->apb_clk);
    242err_mem:
    243	of_reserved_mem_device_release(&pdev->dev);
    244	return ret;
    245}
    246
    247static int zynqmp_dpsub_remove(struct platform_device *pdev)
    248{
    249	struct zynqmp_dpsub *dpsub = platform_get_drvdata(pdev);
    250	struct drm_device *drm = &dpsub->drm;
    251
    252	drm_dev_unregister(drm);
    253	drm_atomic_helper_shutdown(drm);
    254	drm_kms_helper_poll_fini(drm);
    255
    256	zynqmp_disp_remove(dpsub);
    257	zynqmp_dp_remove(dpsub);
    258
    259	pm_runtime_disable(&pdev->dev);
    260	clk_disable_unprepare(dpsub->apb_clk);
    261	of_reserved_mem_device_release(&pdev->dev);
    262
    263	return 0;
    264}
    265
    266static void zynqmp_dpsub_shutdown(struct platform_device *pdev)
    267{
    268	struct zynqmp_dpsub *dpsub = platform_get_drvdata(pdev);
    269
    270	drm_atomic_helper_shutdown(&dpsub->drm);
    271}
    272
    273static const struct of_device_id zynqmp_dpsub_of_match[] = {
    274	{ .compatible = "xlnx,zynqmp-dpsub-1.7", },
    275	{ /* end of table */ },
    276};
    277MODULE_DEVICE_TABLE(of, zynqmp_dpsub_of_match);
    278
    279static struct platform_driver zynqmp_dpsub_driver = {
    280	.probe			= zynqmp_dpsub_probe,
    281	.remove			= zynqmp_dpsub_remove,
    282	.shutdown		= zynqmp_dpsub_shutdown,
    283	.driver			= {
    284		.name		= "zynqmp-dpsub",
    285		.pm		= &zynqmp_dpsub_pm_ops,
    286		.of_match_table	= zynqmp_dpsub_of_match,
    287	},
    288};
    289
    290drm_module_platform_driver(zynqmp_dpsub_driver);
    291
    292MODULE_AUTHOR("Xilinx, Inc.");
    293MODULE_DESCRIPTION("ZynqMP DP Subsystem Driver");
    294MODULE_LICENSE("GPL v2");