forked from Minki/linux
drm/komeda: Build komeda to be a platform module
Implement a simple wrapper for platform module to build komeda to module, Also add a very simple D71 layer code to show how to discover a product. Komeda driver direct bind the product ENTRY function xxx_identity to DT compatible name like: d71_product = { .product_id = MALIDP_D71_PRODUCT_ID, .identify = d71_identify, }, const struct of_device_id komeda_of_match[] = { { .compatible = "arm,mali-d71", .data = &d71_product, }, {}, }; Then when linux found a matched DT node and call driver to probe, we can easily get the of data, and call into the product to do the identify: komeda_bind() { ... product = of_device_get_match_data(dev); product->identify(); ... } Changes in v4: - Replaced kzalloc with devm_kzalloc Changes in v3: - Fixed style problem found by checkpatch.pl --strict. Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com> Acked-by: Liviu Dudau <liviu.dudau@arm.com> Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
This commit is contained in:
parent
df766e4a41
commit
26bd43a759
42
drivers/gpu/drm/arm/display/include/malidp_io.h
Normal file
42
drivers/gpu/drm/arm/display/include/malidp_io.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
|
||||
* Author: James.Qian.Wang <james.qian.wang@arm.com>
|
||||
*
|
||||
*/
|
||||
#ifndef _MALIDP_IO_H_
|
||||
#define _MALIDP_IO_H_
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
static inline u32
|
||||
malidp_read32(u32 __iomem *base, u32 offset)
|
||||
{
|
||||
return readl((base + (offset >> 2)));
|
||||
}
|
||||
|
||||
static inline void
|
||||
malidp_write32(u32 __iomem *base, u32 offset, u32 v)
|
||||
{
|
||||
writel(v, (base + (offset >> 2)));
|
||||
}
|
||||
|
||||
static inline void
|
||||
malidp_write32_mask(u32 __iomem *base, u32 offset, u32 m, u32 v)
|
||||
{
|
||||
u32 tmp = malidp_read32(base, offset);
|
||||
|
||||
tmp &= (~m);
|
||||
malidp_write32(base, offset, v | tmp);
|
||||
}
|
||||
|
||||
static inline void
|
||||
malidp_write_group(u32 __iomem *base, u32 offset, int num, const u32 *values)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
malidp_write32(base, offset + i * 4, values[i]);
|
||||
}
|
||||
|
||||
#endif /*_MALIDP_IO_H_*/
|
@ -5,7 +5,11 @@ ccflags-y := \
|
||||
-I$(src)
|
||||
|
||||
komeda-y := \
|
||||
komeda_drv.o \
|
||||
komeda_dev.o \
|
||||
komeda_pipeline.o \
|
||||
komeda_pipeline.o
|
||||
|
||||
komeda-y += \
|
||||
d71/d71_dev.o
|
||||
|
||||
obj-$(CONFIG_DRM_KOMEDA) += komeda.o
|
||||
|
33
drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
Normal file
33
drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
Normal file
@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
|
||||
* Author: James.Qian.Wang <james.qian.wang@arm.com>
|
||||
*
|
||||
*/
|
||||
#include "malidp_io.h"
|
||||
#include "komeda_dev.h"
|
||||
|
||||
static int d71_enum_resources(struct komeda_dev *mdev)
|
||||
{
|
||||
/* TODO add enum resources */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct komeda_dev_funcs d71_chip_funcs = {
|
||||
.enum_resources = d71_enum_resources,
|
||||
.cleanup = NULL,
|
||||
};
|
||||
|
||||
#define GLB_ARCH_ID 0x000
|
||||
#define GLB_CORE_ID 0x004
|
||||
#define GLB_CORE_INFO 0x008
|
||||
|
||||
struct komeda_dev_funcs *
|
||||
d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip)
|
||||
{
|
||||
chip->arch_id = malidp_read32(reg_base, GLB_ARCH_ID);
|
||||
chip->core_id = malidp_read32(reg_base, GLB_CORE_ID);
|
||||
chip->core_info = malidp_read32(reg_base, GLB_CORE_INFO);
|
||||
|
||||
return &d71_chip_funcs;
|
||||
}
|
@ -92,6 +92,9 @@ komeda_product_match(struct komeda_dev *mdev, u32 target)
|
||||
return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target;
|
||||
}
|
||||
|
||||
struct komeda_dev_funcs *
|
||||
d71_identify(u32 __iomem *reg, struct komeda_chip_info *chip);
|
||||
|
||||
struct komeda_dev *komeda_dev_create(struct device *dev);
|
||||
void komeda_dev_destroy(struct komeda_dev *mdev);
|
||||
|
||||
|
132
drivers/gpu/drm/arm/display/komeda/komeda_drv.c
Normal file
132
drivers/gpu/drm/arm/display/komeda/komeda_drv.c
Normal file
@ -0,0 +1,132 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
|
||||
* Author: James.Qian.Wang <james.qian.wang@arm.com>
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/component.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include "komeda_dev.h"
|
||||
|
||||
struct komeda_drv {
|
||||
struct komeda_dev *mdev;
|
||||
};
|
||||
|
||||
static void komeda_unbind(struct device *dev)
|
||||
{
|
||||
struct komeda_drv *mdrv = dev_get_drvdata(dev);
|
||||
|
||||
if (!mdrv)
|
||||
return;
|
||||
|
||||
komeda_dev_destroy(mdrv->mdev);
|
||||
|
||||
dev_set_drvdata(dev, NULL);
|
||||
devm_kfree(dev, mdrv);
|
||||
}
|
||||
|
||||
static int komeda_bind(struct device *dev)
|
||||
{
|
||||
struct komeda_drv *mdrv;
|
||||
int err;
|
||||
|
||||
mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
|
||||
if (!mdrv)
|
||||
return -ENOMEM;
|
||||
|
||||
mdrv->mdev = komeda_dev_create(dev);
|
||||
if (IS_ERR(mdrv->mdev)) {
|
||||
err = PTR_ERR(mdrv->mdev);
|
||||
goto free_mdrv;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, mdrv);
|
||||
|
||||
return 0;
|
||||
|
||||
free_mdrv:
|
||||
devm_kfree(dev, mdrv);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct component_master_ops komeda_master_ops = {
|
||||
.bind = komeda_bind,
|
||||
.unbind = komeda_unbind,
|
||||
};
|
||||
|
||||
static int compare_of(struct device *dev, void *data)
|
||||
{
|
||||
return dev->of_node == data;
|
||||
}
|
||||
|
||||
static void komeda_add_slave(struct device *master,
|
||||
struct component_match **match,
|
||||
struct device_node *np, int port)
|
||||
{
|
||||
struct device_node *remote;
|
||||
|
||||
remote = of_graph_get_remote_node(np, port, 0);
|
||||
if (remote) {
|
||||
drm_of_component_match_add(master, match, compare_of, remote);
|
||||
of_node_put(remote);
|
||||
}
|
||||
}
|
||||
|
||||
static int komeda_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct component_match *match = NULL;
|
||||
struct device_node *child;
|
||||
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, child) {
|
||||
if (of_node_cmp(child->name, "pipeline") != 0)
|
||||
continue;
|
||||
|
||||
/* add connector */
|
||||
komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT);
|
||||
}
|
||||
|
||||
return component_master_add_with_match(dev, &komeda_master_ops, match);
|
||||
}
|
||||
|
||||
static int komeda_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
component_master_del(&pdev->dev, &komeda_master_ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct komeda_product_data komeda_products[] = {
|
||||
[MALI_D71] = {
|
||||
.product_id = MALIDP_D71_PRODUCT_ID,
|
||||
.identify = d71_identify,
|
||||
},
|
||||
};
|
||||
|
||||
const struct of_device_id komeda_of_match[] = {
|
||||
{ .compatible = "arm,mali-d71", .data = &komeda_products[MALI_D71], },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, komeda_of_match);
|
||||
|
||||
static struct platform_driver komeda_platform_driver = {
|
||||
.probe = komeda_platform_probe,
|
||||
.remove = komeda_platform_remove,
|
||||
.driver = {
|
||||
.name = "komeda",
|
||||
.of_match_table = komeda_of_match,
|
||||
.pm = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(komeda_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>");
|
||||
MODULE_DESCRIPTION("Komeda KMS driver");
|
||||
MODULE_LICENSE("GPL v2");
|
Loading…
Reference in New Issue
Block a user