1 // SPDX-License-Identifier: GPL-2.0+
3 * RZ/G2L Display Unit DRM driver
5 * Copyright (C) 2023 Renesas Electronics Corporation
7 * Based on rcar_du_drv.c
10 #include <linux/dma-mapping.h>
11 #include <linux/module.h>
13 #include <linux/platform_device.h>
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>
22 #include "rzg2l_du_drv.h"
23 #include "rzg2l_du_kms.h"
25 /* -----------------------------------------------------------------------------
29 static const struct rzg2l_du_device_info rzg2l_du_r9a07g043u_info
= {
30 .channels_mask
= BIT(0),
32 [RZG2L_DU_OUTPUT_DPAD0
] = {
33 .possible_outputs
= BIT(0),
39 static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info
= {
40 .channels_mask
= BIT(0),
42 [RZG2L_DU_OUTPUT_DSI0
] = {
43 .possible_outputs
= BIT(0),
46 [RZG2L_DU_OUTPUT_DPAD0
] = {
47 .possible_outputs
= BIT(0),
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
},
59 MODULE_DEVICE_TABLE(of
, rzg2l_du_of_table
);
61 const char *rzg2l_du_output_name(enum rzg2l_du_output output
)
63 static const char * const names
[] = {
64 [RZG2L_DU_OUTPUT_DSI0
] = "DSI0",
65 [RZG2L_DU_OUTPUT_DPAD0
] = "DPAD0"
68 if (output
>= ARRAY_SIZE(names
))
74 /* -----------------------------------------------------------------------------
78 DEFINE_DRM_GEM_DMA_FOPS(rzg2l_du_fops
);
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
,
86 .desc
= "Renesas RZ/G2L Display Unit",
92 /* -----------------------------------------------------------------------------
96 static void rzg2l_du_remove(struct platform_device
*pdev
)
98 struct rzg2l_du_device
*rcdu
= platform_get_drvdata(pdev
);
99 struct drm_device
*ddev
= &rcdu
->ddev
;
101 drm_dev_unregister(ddev
);
102 drm_atomic_helper_shutdown(ddev
);
104 drm_kms_helper_poll_fini(ddev
);
107 static void rzg2l_du_shutdown(struct platform_device
*pdev
)
109 struct rzg2l_du_device
*rcdu
= platform_get_drvdata(pdev
);
111 drm_atomic_helper_shutdown(&rcdu
->ddev
);
114 static int rzg2l_du_probe(struct platform_device
*pdev
)
116 struct rzg2l_du_device
*rcdu
;
119 if (drm_firmware_drivers_only())
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
);
126 return PTR_ERR(rcdu
);
128 rcdu
->dev
= &pdev
->dev
;
129 rcdu
->info
= of_device_get_match_data(rcdu
->dev
);
131 platform_set_drvdata(pdev
, rcdu
);
134 rcdu
->mmio
= devm_platform_ioremap_resource(pdev
, 0);
135 if (IS_ERR(rcdu
->mmio
))
136 return PTR_ERR(rcdu
->mmio
);
138 ret
= dma_coerce_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(32));
142 /* DRM/KMS objects */
143 ret
= rzg2l_du_modeset_init(rcdu
);
146 * Don't use dev_err_probe(), as it would overwrite the probe
147 * deferral reason recorded in rzg2l_du_modeset_init().
149 if (ret
!= -EPROBE_DEFER
)
151 "failed to initialize DRM/KMS (%d)\n", ret
);
156 * Register the DRM device with the core and the connectors with
159 ret
= drm_dev_register(&rcdu
->ddev
, 0);
163 drm_info(&rcdu
->ddev
, "Device %s probed\n", dev_name(&pdev
->dev
));
165 drm_client_setup(&rcdu
->ddev
, NULL
);
170 drm_kms_helper_poll_fini(&rcdu
->ddev
);
174 static struct platform_driver rzg2l_du_platform_driver
= {
175 .probe
= rzg2l_du_probe
,
176 .remove
= rzg2l_du_remove
,
177 .shutdown
= rzg2l_du_shutdown
,
180 .of_match_table
= rzg2l_du_of_table
,
184 module_platform_driver(rzg2l_du_platform_driver
);
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");