komeda_drv.c (4530B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved. 4 * Author: James.Qian.Wang <james.qian.wang@arm.com> 5 * 6 */ 7#include <linux/module.h> 8#include <linux/kernel.h> 9#include <linux/platform_device.h> 10#include <linux/component.h> 11#include <linux/pm_runtime.h> 12#include <drm/drm_module.h> 13#include <drm/drm_of.h> 14#include "komeda_dev.h" 15#include "komeda_kms.h" 16 17struct komeda_drv { 18 struct komeda_dev *mdev; 19 struct komeda_kms_dev *kms; 20}; 21 22struct komeda_dev *dev_to_mdev(struct device *dev) 23{ 24 struct komeda_drv *mdrv = dev_get_drvdata(dev); 25 26 return mdrv ? mdrv->mdev : NULL; 27} 28 29static void komeda_unbind(struct device *dev) 30{ 31 struct komeda_drv *mdrv = dev_get_drvdata(dev); 32 33 if (!mdrv) 34 return; 35 36 komeda_kms_detach(mdrv->kms); 37 38 if (pm_runtime_enabled(dev)) 39 pm_runtime_disable(dev); 40 else 41 komeda_dev_suspend(mdrv->mdev); 42 43 komeda_dev_destroy(mdrv->mdev); 44 45 dev_set_drvdata(dev, NULL); 46 devm_kfree(dev, mdrv); 47} 48 49static int komeda_bind(struct device *dev) 50{ 51 struct komeda_drv *mdrv; 52 int err; 53 54 mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL); 55 if (!mdrv) 56 return -ENOMEM; 57 58 mdrv->mdev = komeda_dev_create(dev); 59 if (IS_ERR(mdrv->mdev)) { 60 err = PTR_ERR(mdrv->mdev); 61 goto free_mdrv; 62 } 63 64 pm_runtime_enable(dev); 65 if (!pm_runtime_enabled(dev)) 66 komeda_dev_resume(mdrv->mdev); 67 68 mdrv->kms = komeda_kms_attach(mdrv->mdev); 69 if (IS_ERR(mdrv->kms)) { 70 err = PTR_ERR(mdrv->kms); 71 goto destroy_mdev; 72 } 73 74 dev_set_drvdata(dev, mdrv); 75 76 return 0; 77 78destroy_mdev: 79 if (pm_runtime_enabled(dev)) 80 pm_runtime_disable(dev); 81 else 82 komeda_dev_suspend(mdrv->mdev); 83 84 komeda_dev_destroy(mdrv->mdev); 85 86free_mdrv: 87 devm_kfree(dev, mdrv); 88 return err; 89} 90 91static const struct component_master_ops komeda_master_ops = { 92 .bind = komeda_bind, 93 .unbind = komeda_unbind, 94}; 95 96static void komeda_add_slave(struct device *master, 97 struct component_match **match, 98 struct device_node *np, 99 u32 port, u32 endpoint) 100{ 101 struct device_node *remote; 102 103 remote = of_graph_get_remote_node(np, port, endpoint); 104 if (remote) { 105 drm_of_component_match_add(master, match, component_compare_of, remote); 106 of_node_put(remote); 107 } 108} 109 110static int komeda_platform_probe(struct platform_device *pdev) 111{ 112 struct device *dev = &pdev->dev; 113 struct component_match *match = NULL; 114 struct device_node *child; 115 116 if (!dev->of_node) 117 return -ENODEV; 118 119 for_each_available_child_of_node(dev->of_node, child) { 120 if (of_node_cmp(child->name, "pipeline") != 0) 121 continue; 122 123 /* add connector */ 124 komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT, 0); 125 komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT, 1); 126 } 127 128 return component_master_add_with_match(dev, &komeda_master_ops, match); 129} 130 131static int komeda_platform_remove(struct platform_device *pdev) 132{ 133 component_master_del(&pdev->dev, &komeda_master_ops); 134 return 0; 135} 136 137static const struct of_device_id komeda_of_match[] = { 138 { .compatible = "arm,mali-d71", .data = d71_identify, }, 139 { .compatible = "arm,mali-d32", .data = d71_identify, }, 140 {}, 141}; 142 143MODULE_DEVICE_TABLE(of, komeda_of_match); 144 145static int __maybe_unused komeda_rt_pm_suspend(struct device *dev) 146{ 147 struct komeda_drv *mdrv = dev_get_drvdata(dev); 148 149 return komeda_dev_suspend(mdrv->mdev); 150} 151 152static int __maybe_unused komeda_rt_pm_resume(struct device *dev) 153{ 154 struct komeda_drv *mdrv = dev_get_drvdata(dev); 155 156 return komeda_dev_resume(mdrv->mdev); 157} 158 159static int __maybe_unused komeda_pm_suspend(struct device *dev) 160{ 161 struct komeda_drv *mdrv = dev_get_drvdata(dev); 162 int res; 163 164 res = drm_mode_config_helper_suspend(&mdrv->kms->base); 165 166 if (!pm_runtime_status_suspended(dev)) 167 komeda_dev_suspend(mdrv->mdev); 168 169 return res; 170} 171 172static int __maybe_unused komeda_pm_resume(struct device *dev) 173{ 174 struct komeda_drv *mdrv = dev_get_drvdata(dev); 175 176 if (!pm_runtime_status_suspended(dev)) 177 komeda_dev_resume(mdrv->mdev); 178 179 return drm_mode_config_helper_resume(&mdrv->kms->base); 180} 181 182static const struct dev_pm_ops komeda_pm_ops = { 183 SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume) 184 SET_RUNTIME_PM_OPS(komeda_rt_pm_suspend, komeda_rt_pm_resume, NULL) 185}; 186 187static struct platform_driver komeda_platform_driver = { 188 .probe = komeda_platform_probe, 189 .remove = komeda_platform_remove, 190 .driver = { 191 .name = "komeda", 192 .of_match_table = komeda_of_match, 193 .pm = &komeda_pm_ops, 194 }, 195}; 196 197drm_module_platform_driver(komeda_platform_driver); 198 199MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>"); 200MODULE_DESCRIPTION("Komeda KMS driver"); 201MODULE_LICENSE("GPL v2");