Skip to content

Commit

Permalink
drm/hisilicon: Add hisilicon kirin drm master driver
Browse files Browse the repository at this point in the history
Add kirin DRM master driver for hi6220 SoC which used in HiKey board.
Add dumb buffer feature.
Add prime dmabuf feature.

v9: Add OF and ARM64 depends on in Kconfig
v8: None.
v7:
- Add config.mutex protection when accessing mode_config.connector_list.
- Clean up match data getting.
v6: None.
v5: None.
v4: None.
v3:
- Move and rename all the files to kirin sub-directory.
  So that we could separate different seires SoCs' driver.
- Replace drm_platform_init, load, unload implementation.
v2:
- Remove abtraction layer.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
  • Loading branch information
Xinliang Liu committed Apr 29, 2016
1 parent 284aabb commit 23e7b2a
Show file tree
Hide file tree
Showing 8 changed files with 354 additions and 0 deletions.
2 changes: 2 additions & 0 deletions drivers/gpu/drm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,5 @@ source "drivers/gpu/drm/vc4/Kconfig"
source "drivers/gpu/drm/etnaviv/Kconfig"

source "drivers/gpu/drm/arc/Kconfig"

source "drivers/gpu/drm/hisilicon/Kconfig"
1 change: 1 addition & 0 deletions drivers/gpu/drm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,4 @@ obj-y += bridge/
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
obj-$(CONFIG_DRM_ARCPGU)+= arc/
obj-y += hisilicon/
5 changes: 5 additions & 0 deletions drivers/gpu/drm/hisilicon/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# hisilicon drm device configuration.
# Please keep this list sorted alphabetically

source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
5 changes: 5 additions & 0 deletions drivers/gpu/drm/hisilicon/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Makefile for hisilicon drm drivers.
# Please keep this list sorted alphabetically

obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
9 changes: 9 additions & 0 deletions drivers/gpu/drm/hisilicon/kirin/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
config DRM_HISI_KIRIN
tristate "DRM Support for Hisilicon Kirin series SoCs Platform"
depends on DRM && OF && ARM64
select DRM_KMS_HELPER
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
help
Choose this option if you have a hisilicon Kirin chipsets(hi6220).
If M is selected the module will be called kirin-drm.
3 changes: 3 additions & 0 deletions drivers/gpu/drm/hisilicon/kirin/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kirin-drm-y := kirin_drm_drv.o

obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o
309 changes: 309 additions & 0 deletions drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
/*
* Hisilicon Kirin SoCs drm master driver
*
* Copyright (c) 2016 Linaro Limited.
* Copyright (c) 2014-2016 Hisilicon Limited.
*
* Author:
* Xinliang Liu <z.liuxinliang@hisilicon.com>
* Xinliang Liu <xinliang.liu@linaro.org>
* Xinwei Kong <kong.kongxinwei@hisilicon.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/

#include <linux/of_platform.h>
#include <linux/component.h>
#include <linux/of_graph.h>

#include <drm/drmP.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_atomic_helper.h>

#include "kirin_drm_drv.h"

static struct kirin_dc_ops *dc_ops;

static int kirin_drm_kms_cleanup(struct drm_device *dev)
{
dc_ops->cleanup(dev);
drm_mode_config_cleanup(dev);

return 0;
}

static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};

static void kirin_drm_mode_config_init(struct drm_device *dev)
{
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;

dev->mode_config.max_width = 2048;
dev->mode_config.max_height = 2048;

dev->mode_config.funcs = &kirin_drm_mode_config_funcs;
}

static int kirin_drm_kms_init(struct drm_device *dev)
{
int ret;

dev_set_drvdata(dev->dev, dev);

/* dev->mode_config initialization */
drm_mode_config_init(dev);
kirin_drm_mode_config_init(dev);

/* display controller init */
ret = dc_ops->init(dev);
if (ret)
goto err_mode_config_cleanup;

/* bind and init sub drivers */
ret = component_bind_all(dev->dev, dev);
if (ret) {
DRM_ERROR("failed to bind all component.\n");
goto err_dc_cleanup;
}

/* reset all the states of crtc/plane/encoder/connector */
drm_mode_config_reset(dev);

return 0;

err_dc_cleanup:
dc_ops->cleanup(dev);
err_mode_config_cleanup:
drm_mode_config_cleanup(dev);

return ret;
}

static const struct file_operations kirin_drm_fops = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
.unlocked_ioctl = drm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
#endif
.poll = drm_poll,
.read = drm_read,
.llseek = no_llseek,
.mmap = drm_gem_cma_mmap,
};

static int kirin_gem_cma_dumb_create(struct drm_file *file,
struct drm_device *dev,
struct drm_mode_create_dumb *args)
{
return drm_gem_cma_dumb_create_internal(file, dev, args);
}

static struct drm_driver kirin_drm_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC,
.fops = &kirin_drm_fops,
.set_busid = drm_platform_set_busid,

.gem_free_object = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = kirin_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,

.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
.gem_prime_vmap = drm_gem_cma_prime_vmap,
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = drm_gem_cma_prime_mmap,

.name = "kirin",
.desc = "Hisilicon Kirin SoCs' DRM Driver",
.date = "20150718",
.major = 1,
.minor = 0,
};

static int compare_of(struct device *dev, void *data)
{
return dev->of_node == data;
}

static int kirin_drm_connectors_register(struct drm_device *dev)
{
struct drm_connector *connector;
struct drm_connector *failed_connector;
int ret;

mutex_lock(&dev->mode_config.mutex);
drm_for_each_connector(connector, dev) {
ret = drm_connector_register(connector);
if (ret) {
failed_connector = connector;
goto err;
}
}
mutex_unlock(&dev->mode_config.mutex);

return 0;

err:
drm_for_each_connector(connector, dev) {
if (failed_connector == connector)
break;
drm_connector_unregister(connector);
}
mutex_unlock(&dev->mode_config.mutex);

return ret;
}

static int kirin_drm_bind(struct device *dev)
{
struct drm_driver *driver = &kirin_drm_driver;
struct drm_device *drm_dev;
int ret;

drm_dev = drm_dev_alloc(driver, dev);
if (!drm_dev)
return -ENOMEM;

drm_dev->platformdev = to_platform_device(dev);

ret = kirin_drm_kms_init(drm_dev);
if (ret)
goto err_drm_dev_unref;

ret = drm_dev_register(drm_dev, 0);
if (ret)
goto err_kms_cleanup;

/* connectors should be registered after drm device register */
ret = kirin_drm_connectors_register(drm_dev);
if (ret)
goto err_drm_dev_unregister;

DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, drm_dev->primary->index);

return 0;

err_drm_dev_unregister:
drm_dev_unregister(drm_dev);
err_kms_cleanup:
kirin_drm_kms_cleanup(drm_dev);
err_drm_dev_unref:
drm_dev_unref(drm_dev);

return ret;
}

static void kirin_drm_unbind(struct device *dev)
{
drm_put_dev(dev_get_drvdata(dev));
}

static const struct component_master_ops kirin_drm_ops = {
.bind = kirin_drm_bind,
.unbind = kirin_drm_unbind,
};

static struct device_node *kirin_get_remote_node(struct device_node *np)
{
struct device_node *endpoint, *remote;

/* get the first endpoint, in our case only one remote node
* is connected to display controller.
*/
endpoint = of_graph_get_next_endpoint(np, NULL);
if (!endpoint) {
DRM_ERROR("no valid endpoint node\n");
return ERR_PTR(-ENODEV);
}
of_node_put(endpoint);

remote = of_graph_get_remote_port_parent(endpoint);
if (!remote) {
DRM_ERROR("no valid remote node\n");
return ERR_PTR(-ENODEV);
}
of_node_put(remote);

if (!of_device_is_available(remote)) {
DRM_ERROR("not available for remote node\n");
return ERR_PTR(-ENODEV);
}

return remote;
}

static int kirin_drm_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct component_match *match = NULL;
struct device_node *remote;

dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev);
if (!dc_ops) {
DRM_ERROR("failed to get dt id data\n");
return -EINVAL;
}

remote = kirin_get_remote_node(np);
if (IS_ERR(remote))
return PTR_ERR(remote);

component_match_add(dev, &match, compare_of, remote);

return component_master_add_with_match(dev, &kirin_drm_ops, match);

return 0;
}

static int kirin_drm_platform_remove(struct platform_device *pdev)
{
component_master_del(&pdev->dev, &kirin_drm_ops);
dc_ops = NULL;
return 0;
}

static const struct of_device_id kirin_drm_dt_ids[] = {
{ .compatible = "hisilicon,hi6220-ade",
.data = &ade_dc_ops,
},
{ /* end node */ },
};
MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids);

static struct platform_driver kirin_drm_platform_driver = {
.probe = kirin_drm_platform_probe,
.remove = kirin_drm_platform_remove,
.driver = {
.name = "kirin-drm",
.of_match_table = kirin_drm_dt_ids,
},
};

module_platform_driver(kirin_drm_platform_driver);

MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver");
MODULE_LICENSE("GPL v2");
20 changes: 20 additions & 0 deletions drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2016 Linaro Limited.
* Copyright (c) 2014-2016 Hisilicon Limited.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/

#ifndef __KIRIN_DRM_DRV_H__
#define __KIRIN_DRM_DRV_H__

/* display controller init/cleanup ops */
struct kirin_dc_ops {
int (*init)(struct drm_device *dev);
void (*cleanup)(struct drm_device *dev);
};

#endif /* __KIRIN_DRM_DRV_H__ */

0 comments on commit 23e7b2a

Please sign in to comment.