1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2014 Traphandler
4 * Copyright (C) 2014 Free Electrons
5 * Copyright (C) 2014 Atmel
11 #include <linux/clk.h>
12 #include <linux/irq.h>
13 #include <linux/irqchip.h>
14 #include <linux/mfd/atmel-hlcdc.h>
15 #include <linux/module.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/platform_device.h>
19 #include <drm/clients/drm_client_setup.h>
20 #include <drm/drm_atomic.h>
21 #include <drm/drm_atomic_helper.h>
22 #include <drm/drm_drv.h>
23 #include <drm/drm_fbdev_dma.h>
24 #include <drm/drm_fourcc.h>
25 #include <drm/drm_gem_dma_helper.h>
26 #include <drm/drm_gem_framebuffer_helper.h>
27 #include <drm/drm_module.h>
28 #include <drm/drm_probe_helper.h>
29 #include <drm/drm_vblank.h>
31 #include "atmel_hlcdc_dc.h"
33 #define ATMEL_HLCDC_LAYER_IRQS_OFFSET 8
35 static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9n12_layers[] = {
38 .formats = &atmel_hlcdc_plane_rgb_formats,
41 .type = ATMEL_HLCDC_BASE_LAYER,
52 static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9n12 = {
60 .conflicting_output_formats = true,
61 .nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9n12_layers),
62 .layers = atmel_hlcdc_at91sam9n12_layers,
63 .ops = &atmel_hlcdc_ops,
66 static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = {
69 .formats = &atmel_hlcdc_plane_rgb_formats,
72 .type = ATMEL_HLCDC_BASE_LAYER,
85 .formats = &atmel_hlcdc_plane_rgb_formats,
88 .type = ATMEL_HLCDC_OVERLAY_LAYER,
100 .clut_offset = 0x800,
103 .name = "high-end-overlay",
104 .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
105 .regs_offset = 0x280,
107 .type = ATMEL_HLCDC_OVERLAY_LAYER,
117 .chroma_key_mask = 11,
118 .general_config = 12,
122 .clut_offset = 0x1000,
126 .formats = &atmel_hlcdc_plane_rgb_formats,
127 .regs_offset = 0x340,
129 .type = ATMEL_HLCDC_CURSOR_LAYER,
139 .chroma_key_mask = 8,
142 .clut_offset = 0x1400,
146 static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9x5 = {
154 .conflicting_output_formats = true,
155 .nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9x5_layers),
156 .layers = atmel_hlcdc_at91sam9x5_layers,
157 .ops = &atmel_hlcdc_ops,
160 static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
163 .formats = &atmel_hlcdc_plane_rgb_formats,
166 .type = ATMEL_HLCDC_BASE_LAYER,
175 .clut_offset = 0x600,
179 .formats = &atmel_hlcdc_plane_rgb_formats,
180 .regs_offset = 0x140,
182 .type = ATMEL_HLCDC_OVERLAY_LAYER,
191 .chroma_key_mask = 8,
194 .clut_offset = 0xa00,
198 .formats = &atmel_hlcdc_plane_rgb_formats,
199 .regs_offset = 0x240,
201 .type = ATMEL_HLCDC_OVERLAY_LAYER,
210 .chroma_key_mask = 8,
213 .clut_offset = 0xe00,
216 .name = "high-end-overlay",
217 .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
218 .regs_offset = 0x340,
220 .type = ATMEL_HLCDC_OVERLAY_LAYER,
230 .chroma_key_mask = 11,
231 .general_config = 12,
239 .clut_offset = 0x1200,
243 .formats = &atmel_hlcdc_plane_rgb_formats,
244 .regs_offset = 0x440,
246 .type = ATMEL_HLCDC_CURSOR_LAYER,
257 .chroma_key_mask = 8,
261 .clut_offset = 0x1600,
265 static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = {
273 .conflicting_output_formats = true,
274 .nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d3_layers),
275 .layers = atmel_hlcdc_sama5d3_layers,
276 .ops = &atmel_hlcdc_ops,
279 static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = {
282 .formats = &atmel_hlcdc_plane_rgb_formats,
285 .type = ATMEL_HLCDC_BASE_LAYER,
294 .clut_offset = 0x600,
298 .formats = &atmel_hlcdc_plane_rgb_formats,
299 .regs_offset = 0x140,
301 .type = ATMEL_HLCDC_OVERLAY_LAYER,
310 .chroma_key_mask = 8,
313 .clut_offset = 0xa00,
317 .formats = &atmel_hlcdc_plane_rgb_formats,
318 .regs_offset = 0x240,
320 .type = ATMEL_HLCDC_OVERLAY_LAYER,
329 .chroma_key_mask = 8,
332 .clut_offset = 0xe00,
335 .name = "high-end-overlay",
336 .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
337 .regs_offset = 0x340,
339 .type = ATMEL_HLCDC_OVERLAY_LAYER,
349 .chroma_key_mask = 11,
350 .general_config = 12,
358 .clut_offset = 0x1200,
362 static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d4 = {
370 .nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d4_layers),
371 .layers = atmel_hlcdc_sama5d4_layers,
372 .ops = &atmel_hlcdc_ops,
375 static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sam9x60_layers[] = {
378 .formats = &atmel_hlcdc_plane_rgb_formats,
381 .type = ATMEL_HLCDC_BASE_LAYER,
390 .clut_offset = 0x600,
394 .formats = &atmel_hlcdc_plane_rgb_formats,
395 .regs_offset = 0x160,
397 .type = ATMEL_HLCDC_OVERLAY_LAYER,
406 .chroma_key_mask = 8,
409 .clut_offset = 0xa00,
413 .formats = &atmel_hlcdc_plane_rgb_formats,
414 .regs_offset = 0x260,
416 .type = ATMEL_HLCDC_OVERLAY_LAYER,
425 .chroma_key_mask = 8,
428 .clut_offset = 0xe00,
431 .name = "high-end-overlay",
432 .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
433 .regs_offset = 0x360,
435 .type = ATMEL_HLCDC_OVERLAY_LAYER,
445 .chroma_key_mask = 11,
446 .general_config = 12,
454 .clut_offset = 0x1200,
458 static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sam9x60 = {
466 .fixed_clksrc = true,
467 .nlayers = ARRAY_SIZE(atmel_hlcdc_sam9x60_layers),
468 .layers = atmel_hlcdc_sam9x60_layers,
469 .ops = &atmel_hlcdc_ops,
472 static const struct atmel_hlcdc_layer_desc atmel_xlcdc_sam9x75_layers[] = {
475 .formats = &atmel_hlcdc_plane_rgb_formats,
478 .type = ATMEL_HLCDC_BASE_LAYER,
487 .clut_offset = 0x700,
491 .formats = &atmel_hlcdc_plane_rgb_formats,
492 .regs_offset = 0x160,
494 .type = ATMEL_HLCDC_OVERLAY_LAYER,
503 .chroma_key_mask = 8,
506 .clut_offset = 0xb00,
510 .formats = &atmel_hlcdc_plane_rgb_formats,
511 .regs_offset = 0x260,
513 .type = ATMEL_HLCDC_OVERLAY_LAYER,
522 .chroma_key_mask = 8,
525 .clut_offset = 0xf00,
528 .name = "high-end-overlay",
529 .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
530 .regs_offset = 0x360,
532 .type = ATMEL_HLCDC_OVERLAY_LAYER,
542 .chroma_key_mask = 11,
543 .general_config = 12,
549 .clut_offset = 0x1300,
553 static const struct atmel_hlcdc_dc_desc atmel_xlcdc_dc_sam9x75 = {
561 .fixed_clksrc = true,
563 .nlayers = ARRAY_SIZE(atmel_xlcdc_sam9x75_layers),
564 .layers = atmel_xlcdc_sam9x75_layers,
565 .ops = &atmel_xlcdc_ops,
568 static const struct of_device_id atmel_hlcdc_of_match[] = {
570 .compatible = "atmel,at91sam9n12-hlcdc",
571 .data = &atmel_hlcdc_dc_at91sam9n12,
574 .compatible = "atmel,at91sam9x5-hlcdc",
575 .data = &atmel_hlcdc_dc_at91sam9x5,
578 .compatible = "atmel,sama5d2-hlcdc",
579 .data = &atmel_hlcdc_dc_sama5d4,
582 .compatible = "atmel,sama5d3-hlcdc",
583 .data = &atmel_hlcdc_dc_sama5d3,
586 .compatible = "atmel,sama5d4-hlcdc",
587 .data = &atmel_hlcdc_dc_sama5d4,
590 .compatible = "microchip,sam9x60-hlcdc",
591 .data = &atmel_hlcdc_dc_sam9x60,
594 .compatible = "microchip,sam9x75-xlcdc",
595 .data = &atmel_xlcdc_dc_sam9x75,
599 MODULE_DEVICE_TABLE(of, atmel_hlcdc_of_match);
602 atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
603 const struct drm_display_mode *mode)
605 int vfront_porch = mode->vsync_start - mode->vdisplay;
606 int vback_porch = mode->vtotal - mode->vsync_end;
607 int vsync_len = mode->vsync_end - mode->vsync_start;
608 int hfront_porch = mode->hsync_start - mode->hdisplay;
609 int hback_porch = mode->htotal - mode->hsync_end;
610 int hsync_len = mode->hsync_end - mode->hsync_start;
612 if (hsync_len > dc->desc->max_spw + 1 || hsync_len < 1)
615 if (vsync_len > dc->desc->max_spw + 1 || vsync_len < 1)
618 if (hfront_porch > dc->desc->max_hpw + 1 || hfront_porch < 1 ||
619 hback_porch > dc->desc->max_hpw + 1 || hback_porch < 1 ||
621 return MODE_H_ILLEGAL;
623 if (vfront_porch > dc->desc->max_vpw + 1 || vfront_porch < 1 ||
624 vback_porch > dc->desc->max_vpw || vback_porch < 0 ||
626 return MODE_V_ILLEGAL;
631 static void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
636 if (layer->desc->type == ATMEL_HLCDC_BASE_LAYER ||
637 layer->desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
638 layer->desc->type == ATMEL_HLCDC_CURSOR_LAYER)
639 atmel_hlcdc_plane_irq(atmel_hlcdc_layer_to_plane(layer));
642 static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
644 struct drm_device *dev = data;
645 struct atmel_hlcdc_dc *dc = dev->dev_private;
646 unsigned long status;
647 unsigned int imr, isr;
650 regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_IMR, &imr);
651 regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
656 if (status & ATMEL_HLCDC_SOF)
657 atmel_hlcdc_crtc_irq(dc->crtc);
659 for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
660 if (ATMEL_HLCDC_LAYER_STATUS(i) & status)
661 atmel_hlcdc_layer_irq(dc->layers[i]);
667 static void atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
669 struct atmel_hlcdc_dc *dc = dev->dev_private;
670 unsigned int cfg = 0;
673 /* Enable interrupts on activated layers */
674 for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
676 cfg |= ATMEL_HLCDC_LAYER_STATUS(i);
679 regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, cfg);
682 static void atmel_hlcdc_dc_irq_disable(struct drm_device *dev)
684 struct atmel_hlcdc_dc *dc = dev->dev_private;
687 regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, 0xffffffff);
688 regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
691 static int atmel_hlcdc_dc_irq_install(struct drm_device *dev, unsigned int irq)
695 atmel_hlcdc_dc_irq_disable(dev);
697 ret = devm_request_irq(dev->dev, irq, atmel_hlcdc_dc_irq_handler, 0,
698 dev->driver->name, dev);
702 atmel_hlcdc_dc_irq_postinstall(dev);
707 static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
709 atmel_hlcdc_dc_irq_disable(dev);
712 static const struct drm_mode_config_funcs mode_config_funcs = {
713 .fb_create = drm_gem_fb_create,
714 .atomic_check = drm_atomic_helper_check,
715 .atomic_commit = drm_atomic_helper_commit,
718 static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
720 struct atmel_hlcdc_dc *dc = dev->dev_private;
723 drm_mode_config_init(dev);
725 ret = atmel_hlcdc_create_outputs(dev);
727 dev_err(dev->dev, "failed to create HLCDC outputs: %d\n", ret);
731 ret = atmel_hlcdc_create_planes(dev);
733 dev_err(dev->dev, "failed to create planes: %d\n", ret);
737 ret = atmel_hlcdc_crtc_create(dev);
739 dev_err(dev->dev, "failed to create crtc\n");
743 dev->mode_config.min_width = dc->desc->min_width;
744 dev->mode_config.min_height = dc->desc->min_height;
745 dev->mode_config.max_width = dc->desc->max_width;
746 dev->mode_config.max_height = dc->desc->max_height;
747 dev->mode_config.funcs = &mode_config_funcs;
748 dev->mode_config.async_page_flip = true;
753 static int atmel_hlcdc_dc_load(struct drm_device *dev)
755 struct platform_device *pdev = to_platform_device(dev->dev);
756 const struct of_device_id *match;
757 struct atmel_hlcdc_dc *dc;
760 match = of_match_node(atmel_hlcdc_of_match, dev->dev->parent->of_node);
762 dev_err(&pdev->dev, "invalid compatible string\n");
767 dev_err(&pdev->dev, "invalid hlcdc description\n");
771 dc = devm_kzalloc(dev->dev, sizeof(*dc), GFP_KERNEL);
775 dc->desc = match->data;
776 dc->hlcdc = dev_get_drvdata(dev->dev->parent);
777 dev->dev_private = dc;
779 ret = clk_prepare_enable(dc->hlcdc->periph_clk);
781 dev_err(dev->dev, "failed to enable periph_clk\n");
785 pm_runtime_enable(dev->dev);
787 ret = drm_vblank_init(dev, 1);
789 dev_err(dev->dev, "failed to initialize vblank\n");
790 goto err_periph_clk_disable;
793 ret = atmel_hlcdc_dc_modeset_init(dev);
795 dev_err(dev->dev, "failed to initialize mode setting\n");
796 goto err_periph_clk_disable;
799 drm_mode_config_reset(dev);
801 pm_runtime_get_sync(dev->dev);
802 ret = atmel_hlcdc_dc_irq_install(dev, dc->hlcdc->irq);
803 pm_runtime_put_sync(dev->dev);
805 dev_err(dev->dev, "failed to install IRQ handler\n");
806 goto err_periph_clk_disable;
809 platform_set_drvdata(pdev, dev);
811 drm_kms_helper_poll_init(dev);
815 err_periph_clk_disable:
816 pm_runtime_disable(dev->dev);
817 clk_disable_unprepare(dc->hlcdc->periph_clk);
822 static void atmel_hlcdc_dc_unload(struct drm_device *dev)
824 struct atmel_hlcdc_dc *dc = dev->dev_private;
826 drm_kms_helper_poll_fini(dev);
827 drm_atomic_helper_shutdown(dev);
828 drm_mode_config_cleanup(dev);
830 pm_runtime_get_sync(dev->dev);
831 atmel_hlcdc_dc_irq_uninstall(dev);
832 pm_runtime_put_sync(dev->dev);
834 dev->dev_private = NULL;
836 pm_runtime_disable(dev->dev);
837 clk_disable_unprepare(dc->hlcdc->periph_clk);
840 DEFINE_DRM_GEM_DMA_FOPS(fops);
842 static const struct drm_driver atmel_hlcdc_dc_driver = {
843 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
844 DRM_GEM_DMA_DRIVER_OPS,
845 DRM_FBDEV_DMA_DRIVER_OPS,
847 .name = "atmel-hlcdc",
848 .desc = "Atmel HLCD Controller DRM",
853 static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
855 struct drm_device *ddev;
858 ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev);
860 return PTR_ERR(ddev);
862 ret = atmel_hlcdc_dc_load(ddev);
866 ret = drm_dev_register(ddev, 0);
870 drm_client_setup_with_fourcc(ddev, DRM_FORMAT_RGB888);
875 atmel_hlcdc_dc_unload(ddev);
883 static void atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
885 struct drm_device *ddev = platform_get_drvdata(pdev);
887 drm_dev_unregister(ddev);
888 atmel_hlcdc_dc_unload(ddev);
892 static void atmel_hlcdc_dc_drm_shutdown(struct platform_device *pdev)
894 drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
897 static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
899 struct drm_device *drm_dev = dev_get_drvdata(dev);
900 struct atmel_hlcdc_dc *dc = drm_dev->dev_private;
901 struct regmap *regmap = dc->hlcdc->regmap;
902 struct drm_atomic_state *state;
904 state = drm_atomic_helper_suspend(drm_dev);
906 return PTR_ERR(state);
908 dc->suspend.state = state;
910 regmap_read(regmap, ATMEL_HLCDC_IMR, &dc->suspend.imr);
911 regmap_write(regmap, ATMEL_HLCDC_IDR, dc->suspend.imr);
912 clk_disable_unprepare(dc->hlcdc->periph_clk);
917 static int atmel_hlcdc_dc_drm_resume(struct device *dev)
919 struct drm_device *drm_dev = dev_get_drvdata(dev);
920 struct atmel_hlcdc_dc *dc = drm_dev->dev_private;
922 clk_prepare_enable(dc->hlcdc->periph_clk);
923 regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, dc->suspend.imr);
925 return drm_atomic_helper_resume(drm_dev, dc->suspend.state);
928 static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
929 atmel_hlcdc_dc_drm_suspend,
930 atmel_hlcdc_dc_drm_resume);
932 static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
933 { .compatible = "atmel,hlcdc-display-controller" },
937 static struct platform_driver atmel_hlcdc_dc_platform_driver = {
938 .probe = atmel_hlcdc_dc_drm_probe,
939 .remove = atmel_hlcdc_dc_drm_remove,
940 .shutdown = atmel_hlcdc_dc_drm_shutdown,
942 .name = "atmel-hlcdc-display-controller",
943 .pm = pm_sleep_ptr(&atmel_hlcdc_dc_drm_pm_ops),
944 .of_match_table = atmel_hlcdc_dc_of_match,
947 drm_module_platform_driver(atmel_hlcdc_dc_platform_driver);
951 MODULE_DESCRIPTION("Atmel HLCDC Display Controller DRM Driver");
952 MODULE_LICENSE("GPL");
953 MODULE_ALIAS("platform:atmel-hlcdc-dc");