1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * RZ/G2L Display Unit DRM driver 4 * 5 * Copyright (C) 2023 Renesas Electronics Corporation 6 * 7 * Based on rcar_du_drv.c 8 */ 9 10 #include <linux/dma-mapping.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/platform_device.h> 14 15 #include <drm/drm_atomic_helper.h> 16 #include <drm/drm_drv.h> 17 #include <drm/drm_fbdev_dma.h> 18 #include <drm/drm_gem_dma_helper.h> 19 #include <drm/drm_probe_helper.h> 20 21 #include "rzg2l_du_drv.h" 22 #include "rzg2l_du_kms.h" 23 24 /* ----------------------------------------------------------------------------- 25 * Device Information 26 */ 27 28 static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = { 29 .channels_mask = BIT(0), 30 .routes = { 31 [RZG2L_DU_OUTPUT_DSI0] = { 32 .possible_outputs = BIT(0), 33 .port = 0, 34 }, 35 [RZG2L_DU_OUTPUT_DPAD0] = { 36 .possible_outputs = BIT(0), 37 .port = 1, 38 } 39 } 40 }; 41 42 static const struct of_device_id rzg2l_du_of_table[] = { 43 { .compatible = "renesas,r9a07g044-du", .data = &rzg2l_du_r9a07g044_info }, 44 { /* sentinel */ } 45 }; 46 47 MODULE_DEVICE_TABLE(of, rzg2l_du_of_table); 48 49 const char *rzg2l_du_output_name(enum rzg2l_du_output output) 50 { 51 static const char * const names[] = { 52 [RZG2L_DU_OUTPUT_DSI0] = "DSI0", 53 [RZG2L_DU_OUTPUT_DPAD0] = "DPAD0" 54 }; 55 56 if (output >= ARRAY_SIZE(names)) 57 return "UNKNOWN"; 58 59 return names[output]; 60 } 61 62 /* ----------------------------------------------------------------------------- 63 * DRM operations 64 */ 65 66 DEFINE_DRM_GEM_DMA_FOPS(rzg2l_du_fops); 67 68 static const struct drm_driver rzg2l_du_driver = { 69 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, 70 .dumb_create = rzg2l_du_dumb_create, 71 .fops = &rzg2l_du_fops, 72 .name = "rzg2l-du", 73 .desc = "Renesas RZ/G2L Display Unit", 74 .date = "20230410", 75 .major = 1, 76 .minor = 0, 77 }; 78 79 /* ----------------------------------------------------------------------------- 80 * Platform driver 81 */ 82 83 static void rzg2l_du_remove(struct platform_device *pdev) 84 { 85 struct rzg2l_du_device *rcdu = platform_get_drvdata(pdev); 86 struct drm_device *ddev = &rcdu->ddev; 87 88 drm_dev_unregister(ddev); 89 drm_atomic_helper_shutdown(ddev); 90 91 drm_kms_helper_poll_fini(ddev); 92 } 93 94 static void rzg2l_du_shutdown(struct platform_device *pdev) 95 { 96 struct rzg2l_du_device *rcdu = platform_get_drvdata(pdev); 97 98 drm_atomic_helper_shutdown(&rcdu->ddev); 99 } 100 101 static int rzg2l_du_probe(struct platform_device *pdev) 102 { 103 struct rzg2l_du_device *rcdu; 104 int ret; 105 106 if (drm_firmware_drivers_only()) 107 return -ENODEV; 108 109 /* Allocate and initialize the RZ/G2L device structure. */ 110 rcdu = devm_drm_dev_alloc(&pdev->dev, &rzg2l_du_driver, 111 struct rzg2l_du_device, ddev); 112 if (IS_ERR(rcdu)) 113 return PTR_ERR(rcdu); 114 115 rcdu->dev = &pdev->dev; 116 rcdu->info = of_device_get_match_data(rcdu->dev); 117 118 platform_set_drvdata(pdev, rcdu); 119 120 /* I/O resources */ 121 rcdu->mmio = devm_platform_ioremap_resource(pdev, 0); 122 if (IS_ERR(rcdu->mmio)) 123 return PTR_ERR(rcdu->mmio); 124 125 ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 126 if (ret) 127 return ret; 128 129 /* DRM/KMS objects */ 130 ret = rzg2l_du_modeset_init(rcdu); 131 if (ret < 0) { 132 /* 133 * Don't use dev_err_probe(), as it would overwrite the probe 134 * deferral reason recorded in rzg2l_du_modeset_init(). 135 */ 136 if (ret != -EPROBE_DEFER) 137 dev_err(&pdev->dev, 138 "failed to initialize DRM/KMS (%d)\n", ret); 139 goto error; 140 } 141 142 /* 143 * Register the DRM device with the core and the connectors with 144 * sysfs. 145 */ 146 ret = drm_dev_register(&rcdu->ddev, 0); 147 if (ret) 148 goto error; 149 150 drm_info(&rcdu->ddev, "Device %s probed\n", dev_name(&pdev->dev)); 151 152 drm_fbdev_dma_setup(&rcdu->ddev, 32); 153 154 return 0; 155 156 error: 157 drm_kms_helper_poll_fini(&rcdu->ddev); 158 return ret; 159 } 160 161 static struct platform_driver rzg2l_du_platform_driver = { 162 .probe = rzg2l_du_probe, 163 .remove_new = rzg2l_du_remove, 164 .shutdown = rzg2l_du_shutdown, 165 .driver = { 166 .name = "rzg2l-du", 167 .of_match_table = rzg2l_du_of_table, 168 }, 169 }; 170 171 module_platform_driver(rzg2l_du_platform_driver); 172 173 MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); 174 MODULE_DESCRIPTION("Renesas RZ/G2L Display Unit DRM Driver"); 175 MODULE_LICENSE("GPL"); 176