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/clients/drm_client_setup.h> 16 #include <drm/drm_atomic_helper.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 .major = 1, 88 .minor = 0, 89 }; 90 91 /* ----------------------------------------------------------------------------- 92 * Platform driver 93 */ 94 95 static void rzg2l_du_remove(struct platform_device *pdev) 96 { 97 struct rzg2l_du_device *rcdu = platform_get_drvdata(pdev); 98 struct drm_device *ddev = &rcdu->ddev; 99 100 drm_dev_unregister(ddev); 101 drm_atomic_helper_shutdown(ddev); 102 103 drm_kms_helper_poll_fini(ddev); 104 } 105 106 static void rzg2l_du_shutdown(struct platform_device *pdev) 107 { 108 struct rzg2l_du_device *rcdu = platform_get_drvdata(pdev); 109 110 drm_atomic_helper_shutdown(&rcdu->ddev); 111 } 112 113 static int rzg2l_du_probe(struct platform_device *pdev) 114 { 115 struct rzg2l_du_device *rcdu; 116 int ret; 117 118 if (drm_firmware_drivers_only()) 119 return -ENODEV; 120 121 /* Allocate and initialize the RZ/G2L device structure. */ 122 rcdu = devm_drm_dev_alloc(&pdev->dev, &rzg2l_du_driver, 123 struct rzg2l_du_device, ddev); 124 if (IS_ERR(rcdu)) 125 return PTR_ERR(rcdu); 126 127 rcdu->dev = &pdev->dev; 128 rcdu->info = of_device_get_match_data(rcdu->dev); 129 130 platform_set_drvdata(pdev, rcdu); 131 132 /* I/O resources */ 133 rcdu->mmio = devm_platform_ioremap_resource(pdev, 0); 134 if (IS_ERR(rcdu->mmio)) 135 return PTR_ERR(rcdu->mmio); 136 137 ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 138 if (ret) 139 return ret; 140 141 /* DRM/KMS objects */ 142 ret = rzg2l_du_modeset_init(rcdu); 143 if (ret < 0) { 144 /* 145 * Don't use dev_err_probe(), as it would overwrite the probe 146 * deferral reason recorded in rzg2l_du_modeset_init(). 147 */ 148 if (ret != -EPROBE_DEFER) 149 dev_err(&pdev->dev, 150 "failed to initialize DRM/KMS (%d)\n", ret); 151 goto error; 152 } 153 154 /* 155 * Register the DRM device with the core and the connectors with 156 * sysfs. 157 */ 158 ret = drm_dev_register(&rcdu->ddev, 0); 159 if (ret) 160 goto error; 161 162 drm_info(&rcdu->ddev, "Device %s probed\n", dev_name(&pdev->dev)); 163 164 drm_client_setup(&rcdu->ddev, NULL); 165 166 return 0; 167 168 error: 169 drm_kms_helper_poll_fini(&rcdu->ddev); 170 return ret; 171 } 172 173 static struct platform_driver rzg2l_du_platform_driver = { 174 .probe = rzg2l_du_probe, 175 .remove = rzg2l_du_remove, 176 .shutdown = rzg2l_du_shutdown, 177 .driver = { 178 .name = "rzg2l-du", 179 .of_match_table = rzg2l_du_of_table, 180 }, 181 }; 182 183 module_platform_driver(rzg2l_du_platform_driver); 184 185 MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); 186 MODULE_DESCRIPTION("Renesas RZ/G2L Display Unit DRM Driver"); 187 MODULE_LICENSE("GPL"); 188