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