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