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 17 struct komeda_drv { 18 struct komeda_dev *mdev; 19 struct komeda_kms_dev *kms; 20 }; 21 22 struct 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 29 static 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 49 static 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 78 destroy_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 86 free_mdrv: 87 devm_kfree(dev, mdrv); 88 return err; 89 } 90 91 static const struct component_master_ops komeda_master_ops = { 92 .bind = komeda_bind, 93 .unbind = komeda_unbind, 94 }; 95 96 static 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 110 static 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 131 static int komeda_platform_remove(struct platform_device *pdev) 132 { 133 component_master_del(&pdev->dev, &komeda_master_ops); 134 return 0; 135 } 136 137 static 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 143 MODULE_DEVICE_TABLE(of, komeda_of_match); 144 145 static 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 152 static 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 159 static 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 172 static 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 182 static 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 187 static 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 197 drm_module_platform_driver(komeda_platform_driver); 198 199 MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>"); 200 MODULE_DESCRIPTION("Komeda KMS driver"); 201 MODULE_LICENSE("GPL v2"); 202