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