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/of.h> 10 #include <linux/platform_device.h> 11 #include <linux/pm_runtime.h> 12 #include <drm/drm_client_setup.h> 13 #include <drm/drm_module.h> 14 #include <drm/drm_of.h> 15 #include "komeda_dev.h" 16 #include "komeda_kms.h" 17 18 struct komeda_drv { 19 struct komeda_dev *mdev; 20 struct komeda_kms_dev *kms; 21 }; 22 23 struct komeda_dev *dev_to_mdev(struct device *dev) 24 { 25 struct komeda_drv *mdrv = dev_get_drvdata(dev); 26 27 return mdrv ? mdrv->mdev : NULL; 28 } 29 30 static void komeda_platform_remove(struct platform_device *pdev) 31 { 32 struct device *dev = &pdev->dev; 33 struct komeda_drv *mdrv = dev_get_drvdata(dev); 34 35 komeda_kms_detach(mdrv->kms); 36 37 if (pm_runtime_enabled(dev)) 38 pm_runtime_disable(dev); 39 else 40 komeda_dev_suspend(mdrv->mdev); 41 42 komeda_dev_destroy(mdrv->mdev); 43 44 dev_set_drvdata(dev, NULL); 45 devm_kfree(dev, mdrv); 46 } 47 48 static void komeda_platform_shutdown(struct platform_device *pdev) 49 { 50 struct device *dev = &pdev->dev; 51 struct komeda_drv *mdrv = dev_get_drvdata(dev); 52 53 komeda_kms_shutdown(mdrv->kms); 54 } 55 56 static int komeda_platform_probe(struct platform_device *pdev) 57 { 58 struct device *dev = &pdev->dev; 59 struct komeda_drv *mdrv; 60 int err; 61 62 err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); 63 if (err) 64 return dev_err_probe(dev, err, "DMA mask error\n"); 65 66 mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL); 67 if (!mdrv) 68 return -ENOMEM; 69 70 mdrv->mdev = komeda_dev_create(dev); 71 if (IS_ERR(mdrv->mdev)) { 72 err = PTR_ERR(mdrv->mdev); 73 goto free_mdrv; 74 } 75 76 pm_runtime_enable(dev); 77 if (!pm_runtime_enabled(dev)) 78 komeda_dev_resume(mdrv->mdev); 79 80 mdrv->kms = komeda_kms_attach(mdrv->mdev); 81 if (IS_ERR(mdrv->kms)) { 82 err = PTR_ERR(mdrv->kms); 83 goto destroy_mdev; 84 } 85 86 dev_set_drvdata(dev, mdrv); 87 drm_client_setup(&mdrv->kms->base, NULL); 88 89 return 0; 90 91 destroy_mdev: 92 if (pm_runtime_enabled(dev)) 93 pm_runtime_disable(dev); 94 else 95 komeda_dev_suspend(mdrv->mdev); 96 97 komeda_dev_destroy(mdrv->mdev); 98 99 free_mdrv: 100 devm_kfree(dev, mdrv); 101 return err; 102 } 103 104 static const struct of_device_id komeda_of_match[] = { 105 { .compatible = "arm,mali-d71", .data = d71_identify, }, 106 { .compatible = "arm,mali-d32", .data = d71_identify, }, 107 {}, 108 }; 109 110 MODULE_DEVICE_TABLE(of, komeda_of_match); 111 112 static int __maybe_unused komeda_rt_pm_suspend(struct device *dev) 113 { 114 struct komeda_drv *mdrv = dev_get_drvdata(dev); 115 116 return komeda_dev_suspend(mdrv->mdev); 117 } 118 119 static int __maybe_unused komeda_rt_pm_resume(struct device *dev) 120 { 121 struct komeda_drv *mdrv = dev_get_drvdata(dev); 122 123 return komeda_dev_resume(mdrv->mdev); 124 } 125 126 static int __maybe_unused komeda_pm_suspend(struct device *dev) 127 { 128 struct komeda_drv *mdrv = dev_get_drvdata(dev); 129 int res; 130 131 res = drm_mode_config_helper_suspend(&mdrv->kms->base); 132 133 if (!pm_runtime_status_suspended(dev)) 134 komeda_dev_suspend(mdrv->mdev); 135 136 return res; 137 } 138 139 static int __maybe_unused komeda_pm_resume(struct device *dev) 140 { 141 struct komeda_drv *mdrv = dev_get_drvdata(dev); 142 143 if (!pm_runtime_status_suspended(dev)) 144 komeda_dev_resume(mdrv->mdev); 145 146 return drm_mode_config_helper_resume(&mdrv->kms->base); 147 } 148 149 static const struct dev_pm_ops komeda_pm_ops = { 150 SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume) 151 SET_RUNTIME_PM_OPS(komeda_rt_pm_suspend, komeda_rt_pm_resume, NULL) 152 }; 153 154 static struct platform_driver komeda_platform_driver = { 155 .probe = komeda_platform_probe, 156 .remove_new = komeda_platform_remove, 157 .shutdown = komeda_platform_shutdown, 158 .driver = { 159 .name = "komeda", 160 .of_match_table = komeda_of_match, 161 .pm = &komeda_pm_ops, 162 }, 163 }; 164 165 drm_module_platform_driver(komeda_platform_driver); 166 167 MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>"); 168 MODULE_DESCRIPTION("Komeda KMS driver"); 169 MODULE_LICENSE("GPL v2"); 170