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

kirin_drm_drv.c (7668B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Hisilicon Kirin SoCs drm master driver
      4 *
      5 * Copyright (c) 2016 Linaro Limited.
      6 * Copyright (c) 2014-2016 HiSilicon Limited.
      7 *
      8 * Author:
      9 *	Xinliang Liu <z.liuxinliang@hisilicon.com>
     10 *	Xinliang Liu <xinliang.liu@linaro.org>
     11 *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
     12 */
     13
     14#include <linux/of_platform.h>
     15#include <linux/component.h>
     16#include <linux/module.h>
     17#include <linux/of_graph.h>
     18#include <linux/platform_device.h>
     19
     20#include <drm/drm_atomic_helper.h>
     21#include <drm/drm_drv.h>
     22#include <drm/drm_fb_cma_helper.h>
     23#include <drm/drm_fb_helper.h>
     24#include <drm/drm_gem_cma_helper.h>
     25#include <drm/drm_gem_framebuffer_helper.h>
     26#include <drm/drm_module.h>
     27#include <drm/drm_of.h>
     28#include <drm/drm_probe_helper.h>
     29#include <drm/drm_vblank.h>
     30
     31#include "kirin_drm_drv.h"
     32
     33#define KIRIN_MAX_PLANE	2
     34
     35struct kirin_drm_private {
     36	struct kirin_crtc crtc;
     37	struct kirin_plane planes[KIRIN_MAX_PLANE];
     38	void *hw_ctx;
     39};
     40
     41static int kirin_drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
     42			       struct drm_plane *plane,
     43			       const struct kirin_drm_data *driver_data)
     44{
     45	struct device_node *port;
     46	int ret;
     47
     48	/* set crtc port so that
     49	 * drm_of_find_possible_crtcs call works
     50	 */
     51	port = of_get_child_by_name(dev->dev->of_node, "port");
     52	if (!port) {
     53		DRM_ERROR("no port node found in %pOF\n", dev->dev->of_node);
     54		return -EINVAL;
     55	}
     56	of_node_put(port);
     57	crtc->port = port;
     58
     59	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
     60					driver_data->crtc_funcs, NULL);
     61	if (ret) {
     62		DRM_ERROR("failed to init crtc.\n");
     63		return ret;
     64	}
     65
     66	drm_crtc_helper_add(crtc, driver_data->crtc_helper_funcs);
     67
     68	return 0;
     69}
     70
     71static int kirin_drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
     72				enum drm_plane_type type,
     73				const struct kirin_drm_data *data)
     74{
     75	int ret = 0;
     76
     77	ret = drm_universal_plane_init(dev, plane, 1, data->plane_funcs,
     78				       data->channel_formats,
     79				       data->channel_formats_cnt,
     80				       NULL, type, NULL);
     81	if (ret) {
     82		DRM_ERROR("fail to init plane, ch=%d\n", 0);
     83		return ret;
     84	}
     85
     86	drm_plane_helper_add(plane, data->plane_helper_funcs);
     87
     88	return 0;
     89}
     90
     91static void kirin_drm_private_cleanup(struct drm_device *dev)
     92{
     93	struct kirin_drm_private *kirin_priv = dev->dev_private;
     94	struct kirin_drm_data *data;
     95
     96	data = (struct kirin_drm_data *)of_device_get_match_data(dev->dev);
     97	if (data->cleanup_hw_ctx)
     98		data->cleanup_hw_ctx(kirin_priv->hw_ctx);
     99
    100	devm_kfree(dev->dev, kirin_priv);
    101	dev->dev_private = NULL;
    102}
    103
    104static int kirin_drm_private_init(struct drm_device *dev,
    105				  const struct kirin_drm_data *driver_data)
    106{
    107	struct platform_device *pdev = to_platform_device(dev->dev);
    108	struct kirin_drm_private *kirin_priv;
    109	struct drm_plane *prim_plane;
    110	enum drm_plane_type type;
    111	void *ctx;
    112	int ret;
    113	u32 ch;
    114
    115	kirin_priv = devm_kzalloc(dev->dev, sizeof(*kirin_priv), GFP_KERNEL);
    116	if (!kirin_priv) {
    117		DRM_ERROR("failed to alloc kirin_drm_private\n");
    118		return -ENOMEM;
    119	}
    120
    121	ctx = driver_data->alloc_hw_ctx(pdev, &kirin_priv->crtc.base);
    122	if (IS_ERR(ctx)) {
    123		DRM_ERROR("failed to initialize kirin_priv hw ctx\n");
    124		return -EINVAL;
    125	}
    126	kirin_priv->hw_ctx = ctx;
    127
    128	/*
    129	 * plane init
    130	 * TODO: Now only support primary plane, overlay planes
    131	 * need to do.
    132	 */
    133	for (ch = 0; ch < driver_data->num_planes; ch++) {
    134		if (ch == driver_data->prim_plane)
    135			type = DRM_PLANE_TYPE_PRIMARY;
    136		else
    137			type = DRM_PLANE_TYPE_OVERLAY;
    138		ret = kirin_drm_plane_init(dev, &kirin_priv->planes[ch].base,
    139					   type, driver_data);
    140		if (ret)
    141			return ret;
    142		kirin_priv->planes[ch].ch = ch;
    143		kirin_priv->planes[ch].hw_ctx = ctx;
    144	}
    145
    146	/* crtc init */
    147	prim_plane = &kirin_priv->planes[driver_data->prim_plane].base;
    148	ret = kirin_drm_crtc_init(dev, &kirin_priv->crtc.base,
    149				  prim_plane, driver_data);
    150	if (ret)
    151		return ret;
    152	kirin_priv->crtc.hw_ctx = ctx;
    153	dev->dev_private = kirin_priv;
    154
    155	return 0;
    156}
    157
    158static int kirin_drm_kms_init(struct drm_device *dev,
    159			      const struct kirin_drm_data *driver_data)
    160{
    161	int ret;
    162
    163	/* dev->mode_config initialization */
    164	drm_mode_config_init(dev);
    165	dev->mode_config.min_width = 0;
    166	dev->mode_config.min_height = 0;
    167	dev->mode_config.max_width = driver_data->config_max_width;
    168	dev->mode_config.max_height = driver_data->config_max_width;
    169	dev->mode_config.funcs = driver_data->mode_config_funcs;
    170
    171	/* display controller init */
    172	ret = kirin_drm_private_init(dev, driver_data);
    173	if (ret)
    174		goto err_mode_config_cleanup;
    175
    176	/* bind and init sub drivers */
    177	ret = component_bind_all(dev->dev, dev);
    178	if (ret) {
    179		DRM_ERROR("failed to bind all component.\n");
    180		goto err_private_cleanup;
    181	}
    182
    183	/* vblank init */
    184	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
    185	if (ret) {
    186		DRM_ERROR("failed to initialize vblank.\n");
    187		goto err_unbind_all;
    188	}
    189
    190	/* reset all the states of crtc/plane/encoder/connector */
    191	drm_mode_config_reset(dev);
    192
    193	/* init kms poll for handling hpd */
    194	drm_kms_helper_poll_init(dev);
    195
    196	return 0;
    197
    198err_unbind_all:
    199	component_unbind_all(dev->dev, dev);
    200err_private_cleanup:
    201	kirin_drm_private_cleanup(dev);
    202err_mode_config_cleanup:
    203	drm_mode_config_cleanup(dev);
    204	return ret;
    205}
    206
    207static int kirin_drm_kms_cleanup(struct drm_device *dev)
    208{
    209	drm_kms_helper_poll_fini(dev);
    210	kirin_drm_private_cleanup(dev);
    211	drm_mode_config_cleanup(dev);
    212
    213	return 0;
    214}
    215
    216static int kirin_drm_bind(struct device *dev)
    217{
    218	struct kirin_drm_data *driver_data;
    219	struct drm_device *drm_dev;
    220	int ret;
    221
    222	driver_data = (struct kirin_drm_data *)of_device_get_match_data(dev);
    223	if (!driver_data)
    224		return -EINVAL;
    225
    226	drm_dev = drm_dev_alloc(driver_data->driver, dev);
    227	if (IS_ERR(drm_dev))
    228		return PTR_ERR(drm_dev);
    229	dev_set_drvdata(dev, drm_dev);
    230
    231	/* display controller init */
    232	ret = kirin_drm_kms_init(drm_dev, driver_data);
    233	if (ret)
    234		goto err_drm_dev_put;
    235
    236	ret = drm_dev_register(drm_dev, 0);
    237	if (ret)
    238		goto err_kms_cleanup;
    239
    240	drm_fbdev_generic_setup(drm_dev, 32);
    241
    242	return 0;
    243
    244err_kms_cleanup:
    245	kirin_drm_kms_cleanup(drm_dev);
    246err_drm_dev_put:
    247	drm_dev_put(drm_dev);
    248
    249	return ret;
    250}
    251
    252static void kirin_drm_unbind(struct device *dev)
    253{
    254	struct drm_device *drm_dev = dev_get_drvdata(dev);
    255
    256	drm_dev_unregister(drm_dev);
    257	kirin_drm_kms_cleanup(drm_dev);
    258	drm_dev_put(drm_dev);
    259}
    260
    261static const struct component_master_ops kirin_drm_ops = {
    262	.bind = kirin_drm_bind,
    263	.unbind = kirin_drm_unbind,
    264};
    265
    266static int kirin_drm_platform_probe(struct platform_device *pdev)
    267{
    268	struct device *dev = &pdev->dev;
    269	struct device_node *np = dev->of_node;
    270	struct component_match *match = NULL;
    271	struct device_node *remote;
    272
    273	remote = of_graph_get_remote_node(np, 0, 0);
    274	if (!remote)
    275		return -ENODEV;
    276
    277	drm_of_component_match_add(dev, &match, component_compare_of, remote);
    278	of_node_put(remote);
    279
    280	return component_master_add_with_match(dev, &kirin_drm_ops, match);
    281}
    282
    283static int kirin_drm_platform_remove(struct platform_device *pdev)
    284{
    285	component_master_del(&pdev->dev, &kirin_drm_ops);
    286	return 0;
    287}
    288
    289static const struct of_device_id kirin_drm_dt_ids[] = {
    290	{ .compatible = "hisilicon,hi6220-ade",
    291	  .data = &ade_driver_data,
    292	},
    293	{ /* end node */ },
    294};
    295MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids);
    296
    297static struct platform_driver kirin_drm_platform_driver = {
    298	.probe = kirin_drm_platform_probe,
    299	.remove = kirin_drm_platform_remove,
    300	.driver = {
    301		.name = "kirin-drm",
    302		.of_match_table = kirin_drm_dt_ids,
    303	},
    304};
    305
    306drm_module_platform_driver(kirin_drm_platform_driver);
    307
    308MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
    309MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
    310MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
    311MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver");
    312MODULE_LICENSE("GPL v2");