1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21a396789SBoris Brezillon /*
31a396789SBoris Brezillon * Copyright (C) 2014 Traphandler
41a396789SBoris Brezillon * Copyright (C) 2014 Free Electrons
51a396789SBoris Brezillon * Copyright (C) 2014 Atmel
61a396789SBoris Brezillon *
71a396789SBoris Brezillon * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
81a396789SBoris Brezillon * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
91a396789SBoris Brezillon */
101a396789SBoris Brezillon
111a396789SBoris Brezillon #include <linux/clk.h>
121a396789SBoris Brezillon #include <linux/irq.h>
131a396789SBoris Brezillon #include <linux/irqchip.h>
1471866a56SSam Ravnborg #include <linux/mfd/atmel-hlcdc.h>
151a396789SBoris Brezillon #include <linux/module.h>
161a396789SBoris Brezillon #include <linux/pm_runtime.h>
1771866a56SSam Ravnborg #include <linux/platform_device.h>
1871866a56SSam Ravnborg
1971866a56SSam Ravnborg #include <drm/drm_atomic.h>
2071866a56SSam Ravnborg #include <drm/drm_atomic_helper.h>
2171866a56SSam Ravnborg #include <drm/drm_drv.h>
22b3fec11dSThomas Zimmermann #include <drm/drm_fbdev_dma.h>
234a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
2471866a56SSam Ravnborg #include <drm/drm_gem_framebuffer_helper.h>
25d5410d69SJavier Martinez Canillas #include <drm/drm_module.h>
2671866a56SSam Ravnborg #include <drm/drm_probe_helper.h>
2771866a56SSam Ravnborg #include <drm/drm_vblank.h>
281a396789SBoris Brezillon
291a396789SBoris Brezillon #include "atmel_hlcdc_dc.h"
301a396789SBoris Brezillon
311a396789SBoris Brezillon #define ATMEL_HLCDC_LAYER_IRQS_OFFSET 8
321a396789SBoris Brezillon
336b22cadcSBoris Brezillon static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9n12_layers[] = {
346b22cadcSBoris Brezillon {
356b22cadcSBoris Brezillon .name = "base",
366b22cadcSBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
376b22cadcSBoris Brezillon .regs_offset = 0x40,
386b22cadcSBoris Brezillon .id = 0,
396b22cadcSBoris Brezillon .type = ATMEL_HLCDC_BASE_LAYER,
409a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
416b22cadcSBoris Brezillon .layout = {
426b22cadcSBoris Brezillon .xstride = { 2 },
436b22cadcSBoris Brezillon .default_color = 3,
446b22cadcSBoris Brezillon .general_config = 4,
456b22cadcSBoris Brezillon },
46364a7bf5SPeter Rosin .clut_offset = 0x400,
476b22cadcSBoris Brezillon },
486b22cadcSBoris Brezillon };
496b22cadcSBoris Brezillon
506b22cadcSBoris Brezillon static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9n12 = {
516b22cadcSBoris Brezillon .min_width = 0,
526b22cadcSBoris Brezillon .min_height = 0,
536b22cadcSBoris Brezillon .max_width = 1280,
546b22cadcSBoris Brezillon .max_height = 860,
5579a3fc2dSBoris Brezillon .max_spw = 0x3f,
5679a3fc2dSBoris Brezillon .max_vpw = 0x3f,
5779a3fc2dSBoris Brezillon .max_hpw = 0xff,
58aca63b76SBoris Brezillon .conflicting_output_formats = true,
596b22cadcSBoris Brezillon .nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9n12_layers),
606b22cadcSBoris Brezillon .layers = atmel_hlcdc_at91sam9n12_layers,
616b22cadcSBoris Brezillon };
626b22cadcSBoris Brezillon
63348ef85fSBoris Brezillon static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = {
64348ef85fSBoris Brezillon {
65348ef85fSBoris Brezillon .name = "base",
66348ef85fSBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
67348ef85fSBoris Brezillon .regs_offset = 0x40,
68348ef85fSBoris Brezillon .id = 0,
69348ef85fSBoris Brezillon .type = ATMEL_HLCDC_BASE_LAYER,
709a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
71348ef85fSBoris Brezillon .layout = {
72348ef85fSBoris Brezillon .xstride = { 2 },
73348ef85fSBoris Brezillon .default_color = 3,
74348ef85fSBoris Brezillon .general_config = 4,
75348ef85fSBoris Brezillon .disc_pos = 5,
76348ef85fSBoris Brezillon .disc_size = 6,
77348ef85fSBoris Brezillon },
78364a7bf5SPeter Rosin .clut_offset = 0x400,
79348ef85fSBoris Brezillon },
80348ef85fSBoris Brezillon {
81348ef85fSBoris Brezillon .name = "overlay1",
82348ef85fSBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
83348ef85fSBoris Brezillon .regs_offset = 0x100,
84348ef85fSBoris Brezillon .id = 1,
85348ef85fSBoris Brezillon .type = ATMEL_HLCDC_OVERLAY_LAYER,
869a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
87348ef85fSBoris Brezillon .layout = {
88348ef85fSBoris Brezillon .pos = 2,
89348ef85fSBoris Brezillon .size = 3,
90348ef85fSBoris Brezillon .xstride = { 4 },
91348ef85fSBoris Brezillon .pstride = { 5 },
92348ef85fSBoris Brezillon .default_color = 6,
93348ef85fSBoris Brezillon .chroma_key = 7,
94348ef85fSBoris Brezillon .chroma_key_mask = 8,
95348ef85fSBoris Brezillon .general_config = 9,
96348ef85fSBoris Brezillon },
97364a7bf5SPeter Rosin .clut_offset = 0x800,
98348ef85fSBoris Brezillon },
99348ef85fSBoris Brezillon {
100348ef85fSBoris Brezillon .name = "high-end-overlay",
101348ef85fSBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
102348ef85fSBoris Brezillon .regs_offset = 0x280,
103348ef85fSBoris Brezillon .id = 2,
104348ef85fSBoris Brezillon .type = ATMEL_HLCDC_OVERLAY_LAYER,
1059a45d33cSBoris Brezillon .cfgs_offset = 0x4c,
106348ef85fSBoris Brezillon .layout = {
107348ef85fSBoris Brezillon .pos = 2,
108348ef85fSBoris Brezillon .size = 3,
109348ef85fSBoris Brezillon .memsize = 4,
110348ef85fSBoris Brezillon .xstride = { 5, 7 },
111348ef85fSBoris Brezillon .pstride = { 6, 8 },
112348ef85fSBoris Brezillon .default_color = 9,
113348ef85fSBoris Brezillon .chroma_key = 10,
114348ef85fSBoris Brezillon .chroma_key_mask = 11,
115348ef85fSBoris Brezillon .general_config = 12,
1169a45d33cSBoris Brezillon .scaler_config = 13,
117348ef85fSBoris Brezillon .csc = 14,
118348ef85fSBoris Brezillon },
119364a7bf5SPeter Rosin .clut_offset = 0x1000,
120348ef85fSBoris Brezillon },
121348ef85fSBoris Brezillon {
122348ef85fSBoris Brezillon .name = "cursor",
123348ef85fSBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
124348ef85fSBoris Brezillon .regs_offset = 0x340,
125348ef85fSBoris Brezillon .id = 3,
126348ef85fSBoris Brezillon .type = ATMEL_HLCDC_CURSOR_LAYER,
127348ef85fSBoris Brezillon .max_width = 128,
128348ef85fSBoris Brezillon .max_height = 128,
1299a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
130348ef85fSBoris Brezillon .layout = {
131348ef85fSBoris Brezillon .pos = 2,
132348ef85fSBoris Brezillon .size = 3,
133348ef85fSBoris Brezillon .xstride = { 4 },
134348ef85fSBoris Brezillon .default_color = 6,
135348ef85fSBoris Brezillon .chroma_key = 7,
136348ef85fSBoris Brezillon .chroma_key_mask = 8,
137348ef85fSBoris Brezillon .general_config = 9,
138348ef85fSBoris Brezillon },
139364a7bf5SPeter Rosin .clut_offset = 0x1400,
140348ef85fSBoris Brezillon },
141348ef85fSBoris Brezillon };
142348ef85fSBoris Brezillon
143348ef85fSBoris Brezillon static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9x5 = {
144348ef85fSBoris Brezillon .min_width = 0,
145348ef85fSBoris Brezillon .min_height = 0,
146348ef85fSBoris Brezillon .max_width = 800,
147348ef85fSBoris Brezillon .max_height = 600,
14879a3fc2dSBoris Brezillon .max_spw = 0x3f,
14979a3fc2dSBoris Brezillon .max_vpw = 0x3f,
15079a3fc2dSBoris Brezillon .max_hpw = 0xff,
151aca63b76SBoris Brezillon .conflicting_output_formats = true,
152348ef85fSBoris Brezillon .nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9x5_layers),
153348ef85fSBoris Brezillon .layers = atmel_hlcdc_at91sam9x5_layers,
154348ef85fSBoris Brezillon };
155348ef85fSBoris Brezillon
1561a396789SBoris Brezillon static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
1571a396789SBoris Brezillon {
1581a396789SBoris Brezillon .name = "base",
1591a396789SBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
1601a396789SBoris Brezillon .regs_offset = 0x40,
1611a396789SBoris Brezillon .id = 0,
1621a396789SBoris Brezillon .type = ATMEL_HLCDC_BASE_LAYER,
1639a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
1641a396789SBoris Brezillon .layout = {
1651a396789SBoris Brezillon .xstride = { 2 },
1661a396789SBoris Brezillon .default_color = 3,
1671a396789SBoris Brezillon .general_config = 4,
1681a396789SBoris Brezillon .disc_pos = 5,
1691a396789SBoris Brezillon .disc_size = 6,
1701a396789SBoris Brezillon },
171364a7bf5SPeter Rosin .clut_offset = 0x600,
1721a396789SBoris Brezillon },
1731a396789SBoris Brezillon {
1741a396789SBoris Brezillon .name = "overlay1",
1751a396789SBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
1761a396789SBoris Brezillon .regs_offset = 0x140,
1771a396789SBoris Brezillon .id = 1,
1781a396789SBoris Brezillon .type = ATMEL_HLCDC_OVERLAY_LAYER,
1799a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
1801a396789SBoris Brezillon .layout = {
1811a396789SBoris Brezillon .pos = 2,
1821a396789SBoris Brezillon .size = 3,
1831a396789SBoris Brezillon .xstride = { 4 },
1841a396789SBoris Brezillon .pstride = { 5 },
1851a396789SBoris Brezillon .default_color = 6,
1861a396789SBoris Brezillon .chroma_key = 7,
1871a396789SBoris Brezillon .chroma_key_mask = 8,
1881a396789SBoris Brezillon .general_config = 9,
1891a396789SBoris Brezillon },
190364a7bf5SPeter Rosin .clut_offset = 0xa00,
1911a396789SBoris Brezillon },
1921a396789SBoris Brezillon {
1931a396789SBoris Brezillon .name = "overlay2",
1941a396789SBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
1951a396789SBoris Brezillon .regs_offset = 0x240,
1961a396789SBoris Brezillon .id = 2,
1971a396789SBoris Brezillon .type = ATMEL_HLCDC_OVERLAY_LAYER,
1989a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
1991a396789SBoris Brezillon .layout = {
2001a396789SBoris Brezillon .pos = 2,
2011a396789SBoris Brezillon .size = 3,
2021a396789SBoris Brezillon .xstride = { 4 },
2031a396789SBoris Brezillon .pstride = { 5 },
2041a396789SBoris Brezillon .default_color = 6,
2051a396789SBoris Brezillon .chroma_key = 7,
2061a396789SBoris Brezillon .chroma_key_mask = 8,
2071a396789SBoris Brezillon .general_config = 9,
2081a396789SBoris Brezillon },
209364a7bf5SPeter Rosin .clut_offset = 0xe00,
2101a396789SBoris Brezillon },
2111a396789SBoris Brezillon {
2121a396789SBoris Brezillon .name = "high-end-overlay",
2131a396789SBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
2141a396789SBoris Brezillon .regs_offset = 0x340,
2151a396789SBoris Brezillon .id = 3,
2161a396789SBoris Brezillon .type = ATMEL_HLCDC_OVERLAY_LAYER,
2179a45d33cSBoris Brezillon .cfgs_offset = 0x4c,
2181a396789SBoris Brezillon .layout = {
2191a396789SBoris Brezillon .pos = 2,
2201a396789SBoris Brezillon .size = 3,
2211a396789SBoris Brezillon .memsize = 4,
2221a396789SBoris Brezillon .xstride = { 5, 7 },
2231a396789SBoris Brezillon .pstride = { 6, 8 },
2241a396789SBoris Brezillon .default_color = 9,
2251a396789SBoris Brezillon .chroma_key = 10,
2261a396789SBoris Brezillon .chroma_key_mask = 11,
2271a396789SBoris Brezillon .general_config = 12,
2289a45d33cSBoris Brezillon .scaler_config = 13,
2299a45d33cSBoris Brezillon .phicoeffs = {
2309a45d33cSBoris Brezillon .x = 17,
2319a45d33cSBoris Brezillon .y = 33,
2329a45d33cSBoris Brezillon },
2331a396789SBoris Brezillon .csc = 14,
2341a396789SBoris Brezillon },
235364a7bf5SPeter Rosin .clut_offset = 0x1200,
2361a396789SBoris Brezillon },
2371a396789SBoris Brezillon {
2381a396789SBoris Brezillon .name = "cursor",
2391a396789SBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
2401a396789SBoris Brezillon .regs_offset = 0x440,
2411a396789SBoris Brezillon .id = 4,
2421a396789SBoris Brezillon .type = ATMEL_HLCDC_CURSOR_LAYER,
2431a396789SBoris Brezillon .max_width = 128,
2441a396789SBoris Brezillon .max_height = 128,
2459a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
2461a396789SBoris Brezillon .layout = {
2471a396789SBoris Brezillon .pos = 2,
2481a396789SBoris Brezillon .size = 3,
2491a396789SBoris Brezillon .xstride = { 4 },
2501a396789SBoris Brezillon .pstride = { 5 },
2511a396789SBoris Brezillon .default_color = 6,
2521a396789SBoris Brezillon .chroma_key = 7,
2531a396789SBoris Brezillon .chroma_key_mask = 8,
2541a396789SBoris Brezillon .general_config = 9,
2559a45d33cSBoris Brezillon .scaler_config = 13,
2561a396789SBoris Brezillon },
257364a7bf5SPeter Rosin .clut_offset = 0x1600,
2581a396789SBoris Brezillon },
2591a396789SBoris Brezillon };
2601a396789SBoris Brezillon
2611a396789SBoris Brezillon static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = {
2621a396789SBoris Brezillon .min_width = 0,
2631a396789SBoris Brezillon .min_height = 0,
2641a396789SBoris Brezillon .max_width = 2048,
2651a396789SBoris Brezillon .max_height = 2048,
26679a3fc2dSBoris Brezillon .max_spw = 0x3f,
26779a3fc2dSBoris Brezillon .max_vpw = 0x3f,
26879a3fc2dSBoris Brezillon .max_hpw = 0x1ff,
269aca63b76SBoris Brezillon .conflicting_output_formats = true,
2701a396789SBoris Brezillon .nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d3_layers),
2711a396789SBoris Brezillon .layers = atmel_hlcdc_sama5d3_layers,
2721a396789SBoris Brezillon };
2731a396789SBoris Brezillon
2745b9fb5e6SBoris Brezillon static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = {
2755b9fb5e6SBoris Brezillon {
2765b9fb5e6SBoris Brezillon .name = "base",
2775b9fb5e6SBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
2785b9fb5e6SBoris Brezillon .regs_offset = 0x40,
2795b9fb5e6SBoris Brezillon .id = 0,
2805b9fb5e6SBoris Brezillon .type = ATMEL_HLCDC_BASE_LAYER,
2819a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
2825b9fb5e6SBoris Brezillon .layout = {
2835b9fb5e6SBoris Brezillon .xstride = { 2 },
2845b9fb5e6SBoris Brezillon .default_color = 3,
2855b9fb5e6SBoris Brezillon .general_config = 4,
2865b9fb5e6SBoris Brezillon .disc_pos = 5,
2875b9fb5e6SBoris Brezillon .disc_size = 6,
2885b9fb5e6SBoris Brezillon },
289364a7bf5SPeter Rosin .clut_offset = 0x600,
2905b9fb5e6SBoris Brezillon },
2915b9fb5e6SBoris Brezillon {
2925b9fb5e6SBoris Brezillon .name = "overlay1",
2935b9fb5e6SBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
2945b9fb5e6SBoris Brezillon .regs_offset = 0x140,
2955b9fb5e6SBoris Brezillon .id = 1,
2965b9fb5e6SBoris Brezillon .type = ATMEL_HLCDC_OVERLAY_LAYER,
2979a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
2985b9fb5e6SBoris Brezillon .layout = {
2995b9fb5e6SBoris Brezillon .pos = 2,
3005b9fb5e6SBoris Brezillon .size = 3,
3015b9fb5e6SBoris Brezillon .xstride = { 4 },
3025b9fb5e6SBoris Brezillon .pstride = { 5 },
3035b9fb5e6SBoris Brezillon .default_color = 6,
3045b9fb5e6SBoris Brezillon .chroma_key = 7,
3055b9fb5e6SBoris Brezillon .chroma_key_mask = 8,
3065b9fb5e6SBoris Brezillon .general_config = 9,
3075b9fb5e6SBoris Brezillon },
308364a7bf5SPeter Rosin .clut_offset = 0xa00,
3095b9fb5e6SBoris Brezillon },
3105b9fb5e6SBoris Brezillon {
3115b9fb5e6SBoris Brezillon .name = "overlay2",
3125b9fb5e6SBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_formats,
3135b9fb5e6SBoris Brezillon .regs_offset = 0x240,
3145b9fb5e6SBoris Brezillon .id = 2,
3155b9fb5e6SBoris Brezillon .type = ATMEL_HLCDC_OVERLAY_LAYER,
3169a45d33cSBoris Brezillon .cfgs_offset = 0x2c,
3175b9fb5e6SBoris Brezillon .layout = {
3185b9fb5e6SBoris Brezillon .pos = 2,
3195b9fb5e6SBoris Brezillon .size = 3,
3205b9fb5e6SBoris Brezillon .xstride = { 4 },
3215b9fb5e6SBoris Brezillon .pstride = { 5 },
3225b9fb5e6SBoris Brezillon .default_color = 6,
3235b9fb5e6SBoris Brezillon .chroma_key = 7,
3245b9fb5e6SBoris Brezillon .chroma_key_mask = 8,
3255b9fb5e6SBoris Brezillon .general_config = 9,
3265b9fb5e6SBoris Brezillon },
327364a7bf5SPeter Rosin .clut_offset = 0xe00,
3285b9fb5e6SBoris Brezillon },
3295b9fb5e6SBoris Brezillon {
3305b9fb5e6SBoris Brezillon .name = "high-end-overlay",
3315b9fb5e6SBoris Brezillon .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
3325b9fb5e6SBoris Brezillon .regs_offset = 0x340,
3335b9fb5e6SBoris Brezillon .id = 3,
3345b9fb5e6SBoris Brezillon .type = ATMEL_HLCDC_OVERLAY_LAYER,
3359a45d33cSBoris Brezillon .cfgs_offset = 0x4c,
3365b9fb5e6SBoris Brezillon .layout = {
3375b9fb5e6SBoris Brezillon .pos = 2,
3385b9fb5e6SBoris Brezillon .size = 3,
3395b9fb5e6SBoris Brezillon .memsize = 4,
3405b9fb5e6SBoris Brezillon .xstride = { 5, 7 },
3415b9fb5e6SBoris Brezillon .pstride = { 6, 8 },
3425b9fb5e6SBoris Brezillon .default_color = 9,
3435b9fb5e6SBoris Brezillon .chroma_key = 10,
3445b9fb5e6SBoris Brezillon .chroma_key_mask = 11,
3455b9fb5e6SBoris Brezillon .general_config = 12,
3469a45d33cSBoris Brezillon .scaler_config = 13,
3479a45d33cSBoris Brezillon .phicoeffs = {
3489a45d33cSBoris Brezillon .x = 17,
3499a45d33cSBoris Brezillon .y = 33,
3509a45d33cSBoris Brezillon },
3515b9fb5e6SBoris Brezillon .csc = 14,
3525b9fb5e6SBoris Brezillon },
353364a7bf5SPeter Rosin .clut_offset = 0x1200,
3545b9fb5e6SBoris Brezillon },
3555b9fb5e6SBoris Brezillon };
3565b9fb5e6SBoris Brezillon
3575b9fb5e6SBoris Brezillon static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d4 = {
3585b9fb5e6SBoris Brezillon .min_width = 0,
3595b9fb5e6SBoris Brezillon .min_height = 0,
3605b9fb5e6SBoris Brezillon .max_width = 2048,
3615b9fb5e6SBoris Brezillon .max_height = 2048,
36279a3fc2dSBoris Brezillon .max_spw = 0xff,
36379a3fc2dSBoris Brezillon .max_vpw = 0xff,
36479a3fc2dSBoris Brezillon .max_hpw = 0x3ff,
3655b9fb5e6SBoris Brezillon .nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d4_layers),
3665b9fb5e6SBoris Brezillon .layers = atmel_hlcdc_sama5d4_layers,
3675b9fb5e6SBoris Brezillon };
368e2435eadSSandeep Sheriker Mallikarjun
369e2435eadSSandeep Sheriker Mallikarjun static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sam9x60_layers[] = {
370e2435eadSSandeep Sheriker Mallikarjun {
371e2435eadSSandeep Sheriker Mallikarjun .name = "base",
372e2435eadSSandeep Sheriker Mallikarjun .formats = &atmel_hlcdc_plane_rgb_formats,
373e2435eadSSandeep Sheriker Mallikarjun .regs_offset = 0x60,
374e2435eadSSandeep Sheriker Mallikarjun .id = 0,
375e2435eadSSandeep Sheriker Mallikarjun .type = ATMEL_HLCDC_BASE_LAYER,
376e2435eadSSandeep Sheriker Mallikarjun .cfgs_offset = 0x2c,
377e2435eadSSandeep Sheriker Mallikarjun .layout = {
378e2435eadSSandeep Sheriker Mallikarjun .xstride = { 2 },
379e2435eadSSandeep Sheriker Mallikarjun .default_color = 3,
380e2435eadSSandeep Sheriker Mallikarjun .general_config = 4,
381e2435eadSSandeep Sheriker Mallikarjun .disc_pos = 5,
382e2435eadSSandeep Sheriker Mallikarjun .disc_size = 6,
383e2435eadSSandeep Sheriker Mallikarjun },
384e2435eadSSandeep Sheriker Mallikarjun .clut_offset = 0x600,
385e2435eadSSandeep Sheriker Mallikarjun },
386e2435eadSSandeep Sheriker Mallikarjun {
387e2435eadSSandeep Sheriker Mallikarjun .name = "overlay1",
388e2435eadSSandeep Sheriker Mallikarjun .formats = &atmel_hlcdc_plane_rgb_formats,
389e2435eadSSandeep Sheriker Mallikarjun .regs_offset = 0x160,
390e2435eadSSandeep Sheriker Mallikarjun .id = 1,
391e2435eadSSandeep Sheriker Mallikarjun .type = ATMEL_HLCDC_OVERLAY_LAYER,
392e2435eadSSandeep Sheriker Mallikarjun .cfgs_offset = 0x2c,
393e2435eadSSandeep Sheriker Mallikarjun .layout = {
394e2435eadSSandeep Sheriker Mallikarjun .pos = 2,
395e2435eadSSandeep Sheriker Mallikarjun .size = 3,
396e2435eadSSandeep Sheriker Mallikarjun .xstride = { 4 },
397e2435eadSSandeep Sheriker Mallikarjun .pstride = { 5 },
398e2435eadSSandeep Sheriker Mallikarjun .default_color = 6,
399e2435eadSSandeep Sheriker Mallikarjun .chroma_key = 7,
400e2435eadSSandeep Sheriker Mallikarjun .chroma_key_mask = 8,
401e2435eadSSandeep Sheriker Mallikarjun .general_config = 9,
402e2435eadSSandeep Sheriker Mallikarjun },
403e2435eadSSandeep Sheriker Mallikarjun .clut_offset = 0xa00,
404e2435eadSSandeep Sheriker Mallikarjun },
405e2435eadSSandeep Sheriker Mallikarjun {
406e2435eadSSandeep Sheriker Mallikarjun .name = "overlay2",
407e2435eadSSandeep Sheriker Mallikarjun .formats = &atmel_hlcdc_plane_rgb_formats,
408e2435eadSSandeep Sheriker Mallikarjun .regs_offset = 0x260,
409e2435eadSSandeep Sheriker Mallikarjun .id = 2,
410e2435eadSSandeep Sheriker Mallikarjun .type = ATMEL_HLCDC_OVERLAY_LAYER,
411e2435eadSSandeep Sheriker Mallikarjun .cfgs_offset = 0x2c,
412e2435eadSSandeep Sheriker Mallikarjun .layout = {
413e2435eadSSandeep Sheriker Mallikarjun .pos = 2,
414e2435eadSSandeep Sheriker Mallikarjun .size = 3,
415e2435eadSSandeep Sheriker Mallikarjun .xstride = { 4 },
416e2435eadSSandeep Sheriker Mallikarjun .pstride = { 5 },
417e2435eadSSandeep Sheriker Mallikarjun .default_color = 6,
418e2435eadSSandeep Sheriker Mallikarjun .chroma_key = 7,
419e2435eadSSandeep Sheriker Mallikarjun .chroma_key_mask = 8,
420e2435eadSSandeep Sheriker Mallikarjun .general_config = 9,
421e2435eadSSandeep Sheriker Mallikarjun },
422e2435eadSSandeep Sheriker Mallikarjun .clut_offset = 0xe00,
423e2435eadSSandeep Sheriker Mallikarjun },
424e2435eadSSandeep Sheriker Mallikarjun {
425e2435eadSSandeep Sheriker Mallikarjun .name = "high-end-overlay",
426e2435eadSSandeep Sheriker Mallikarjun .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
427e2435eadSSandeep Sheriker Mallikarjun .regs_offset = 0x360,
428e2435eadSSandeep Sheriker Mallikarjun .id = 3,
429e2435eadSSandeep Sheriker Mallikarjun .type = ATMEL_HLCDC_OVERLAY_LAYER,
430e2435eadSSandeep Sheriker Mallikarjun .cfgs_offset = 0x4c,
431e2435eadSSandeep Sheriker Mallikarjun .layout = {
432e2435eadSSandeep Sheriker Mallikarjun .pos = 2,
433e2435eadSSandeep Sheriker Mallikarjun .size = 3,
434e2435eadSSandeep Sheriker Mallikarjun .memsize = 4,
435e2435eadSSandeep Sheriker Mallikarjun .xstride = { 5, 7 },
436e2435eadSSandeep Sheriker Mallikarjun .pstride = { 6, 8 },
437e2435eadSSandeep Sheriker Mallikarjun .default_color = 9,
438e2435eadSSandeep Sheriker Mallikarjun .chroma_key = 10,
439e2435eadSSandeep Sheriker Mallikarjun .chroma_key_mask = 11,
440e2435eadSSandeep Sheriker Mallikarjun .general_config = 12,
441e2435eadSSandeep Sheriker Mallikarjun .scaler_config = 13,
442e2435eadSSandeep Sheriker Mallikarjun .phicoeffs = {
443e2435eadSSandeep Sheriker Mallikarjun .x = 17,
444e2435eadSSandeep Sheriker Mallikarjun .y = 33,
445e2435eadSSandeep Sheriker Mallikarjun },
446e2435eadSSandeep Sheriker Mallikarjun .csc = 14,
447e2435eadSSandeep Sheriker Mallikarjun },
448e2435eadSSandeep Sheriker Mallikarjun .clut_offset = 0x1200,
449e2435eadSSandeep Sheriker Mallikarjun },
450e2435eadSSandeep Sheriker Mallikarjun };
451e2435eadSSandeep Sheriker Mallikarjun
452e2435eadSSandeep Sheriker Mallikarjun static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sam9x60 = {
453e2435eadSSandeep Sheriker Mallikarjun .min_width = 0,
454e2435eadSSandeep Sheriker Mallikarjun .min_height = 0,
455e2435eadSSandeep Sheriker Mallikarjun .max_width = 2048,
456e2435eadSSandeep Sheriker Mallikarjun .max_height = 2048,
457e2435eadSSandeep Sheriker Mallikarjun .max_spw = 0xff,
458e2435eadSSandeep Sheriker Mallikarjun .max_vpw = 0xff,
459e2435eadSSandeep Sheriker Mallikarjun .max_hpw = 0x3ff,
460e2435eadSSandeep Sheriker Mallikarjun .fixed_clksrc = true,
461e2435eadSSandeep Sheriker Mallikarjun .nlayers = ARRAY_SIZE(atmel_hlcdc_sam9x60_layers),
462e2435eadSSandeep Sheriker Mallikarjun .layers = atmel_hlcdc_sam9x60_layers,
463e2435eadSSandeep Sheriker Mallikarjun };
464e2435eadSSandeep Sheriker Mallikarjun
4651a396789SBoris Brezillon static const struct of_device_id atmel_hlcdc_of_match[] = {
4661a396789SBoris Brezillon {
4676b22cadcSBoris Brezillon .compatible = "atmel,at91sam9n12-hlcdc",
4686b22cadcSBoris Brezillon .data = &atmel_hlcdc_dc_at91sam9n12,
4696b22cadcSBoris Brezillon },
4706b22cadcSBoris Brezillon {
471348ef85fSBoris Brezillon .compatible = "atmel,at91sam9x5-hlcdc",
472348ef85fSBoris Brezillon .data = &atmel_hlcdc_dc_at91sam9x5,
473348ef85fSBoris Brezillon },
474348ef85fSBoris Brezillon {
47534649c40SNicolas Ferre .compatible = "atmel,sama5d2-hlcdc",
47634649c40SNicolas Ferre .data = &atmel_hlcdc_dc_sama5d4,
47734649c40SNicolas Ferre },
47834649c40SNicolas Ferre {
4791a396789SBoris Brezillon .compatible = "atmel,sama5d3-hlcdc",
4801a396789SBoris Brezillon .data = &atmel_hlcdc_dc_sama5d3,
4811a396789SBoris Brezillon },
4825b9fb5e6SBoris Brezillon {
4835b9fb5e6SBoris Brezillon .compatible = "atmel,sama5d4-hlcdc",
4845b9fb5e6SBoris Brezillon .data = &atmel_hlcdc_dc_sama5d4,
4855b9fb5e6SBoris Brezillon },
486e2435eadSSandeep Sheriker Mallikarjun {
487e2435eadSSandeep Sheriker Mallikarjun .compatible = "microchip,sam9x60-hlcdc",
488e2435eadSSandeep Sheriker Mallikarjun .data = &atmel_hlcdc_dc_sam9x60,
489e2435eadSSandeep Sheriker Mallikarjun },
4901a396789SBoris Brezillon { /* sentinel */ },
4911a396789SBoris Brezillon };
492d6ec5ec9SLuis de Bethencourt MODULE_DEVICE_TABLE(of, atmel_hlcdc_of_match);
4931a396789SBoris Brezillon
494a57bf53eSJose Abreu enum drm_mode_status
atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc * dc,const struct drm_display_mode * mode)495a57bf53eSJose Abreu atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
496a57bf53eSJose Abreu const struct drm_display_mode *mode)
4971a396789SBoris Brezillon {
4981a396789SBoris Brezillon int vfront_porch = mode->vsync_start - mode->vdisplay;
4991a396789SBoris Brezillon int vback_porch = mode->vtotal - mode->vsync_end;
5001a396789SBoris Brezillon int vsync_len = mode->vsync_end - mode->vsync_start;
5011a396789SBoris Brezillon int hfront_porch = mode->hsync_start - mode->hdisplay;
5021a396789SBoris Brezillon int hback_porch = mode->htotal - mode->hsync_end;
5031a396789SBoris Brezillon int hsync_len = mode->hsync_end - mode->hsync_start;
5041a396789SBoris Brezillon
50579a3fc2dSBoris Brezillon if (hsync_len > dc->desc->max_spw + 1 || hsync_len < 1)
5061a396789SBoris Brezillon return MODE_HSYNC;
5071a396789SBoris Brezillon
50879a3fc2dSBoris Brezillon if (vsync_len > dc->desc->max_spw + 1 || vsync_len < 1)
5091a396789SBoris Brezillon return MODE_VSYNC;
5101a396789SBoris Brezillon
51179a3fc2dSBoris Brezillon if (hfront_porch > dc->desc->max_hpw + 1 || hfront_porch < 1 ||
51279a3fc2dSBoris Brezillon hback_porch > dc->desc->max_hpw + 1 || hback_porch < 1 ||
5131a396789SBoris Brezillon mode->hdisplay < 1)
5141a396789SBoris Brezillon return MODE_H_ILLEGAL;
5151a396789SBoris Brezillon
51679a3fc2dSBoris Brezillon if (vfront_porch > dc->desc->max_vpw + 1 || vfront_porch < 1 ||
51779a3fc2dSBoris Brezillon vback_porch > dc->desc->max_vpw || vback_porch < 0 ||
5181a396789SBoris Brezillon mode->vdisplay < 1)
5191a396789SBoris Brezillon return MODE_V_ILLEGAL;
5201a396789SBoris Brezillon
5211a396789SBoris Brezillon return MODE_OK;
5221a396789SBoris Brezillon }
5231a396789SBoris Brezillon
atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer * layer)5249a45d33cSBoris Brezillon static void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
5259a45d33cSBoris Brezillon {
5269a45d33cSBoris Brezillon if (!layer)
5279a45d33cSBoris Brezillon return;
5289a45d33cSBoris Brezillon
5299a45d33cSBoris Brezillon if (layer->desc->type == ATMEL_HLCDC_BASE_LAYER ||
5309a45d33cSBoris Brezillon layer->desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
5319a45d33cSBoris Brezillon layer->desc->type == ATMEL_HLCDC_CURSOR_LAYER)
5329a45d33cSBoris Brezillon atmel_hlcdc_plane_irq(atmel_hlcdc_layer_to_plane(layer));
5339a45d33cSBoris Brezillon }
5349a45d33cSBoris Brezillon
atmel_hlcdc_dc_irq_handler(int irq,void * data)5351a396789SBoris Brezillon static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
5361a396789SBoris Brezillon {
5371a396789SBoris Brezillon struct drm_device *dev = data;
5381a396789SBoris Brezillon struct atmel_hlcdc_dc *dc = dev->dev_private;
5391a396789SBoris Brezillon unsigned long status;
5401a396789SBoris Brezillon unsigned int imr, isr;
5411a396789SBoris Brezillon int i;
5421a396789SBoris Brezillon
5431a396789SBoris Brezillon regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_IMR, &imr);
5441a396789SBoris Brezillon regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
5451a396789SBoris Brezillon status = imr & isr;
5461a396789SBoris Brezillon if (!status)
5471a396789SBoris Brezillon return IRQ_NONE;
5481a396789SBoris Brezillon
5491a396789SBoris Brezillon if (status & ATMEL_HLCDC_SOF)
5501a396789SBoris Brezillon atmel_hlcdc_crtc_irq(dc->crtc);
5511a396789SBoris Brezillon
5521a396789SBoris Brezillon for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
5539a45d33cSBoris Brezillon if (ATMEL_HLCDC_LAYER_STATUS(i) & status)
5549a45d33cSBoris Brezillon atmel_hlcdc_layer_irq(dc->layers[i]);
5551a396789SBoris Brezillon }
5561a396789SBoris Brezillon
5571a396789SBoris Brezillon return IRQ_HANDLED;
5581a396789SBoris Brezillon }
5591a396789SBoris Brezillon
atmel_hlcdc_dc_irq_postinstall(struct drm_device * dev)56088965283SThomas Zimmermann static void atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
56188965283SThomas Zimmermann {
56288965283SThomas Zimmermann struct atmel_hlcdc_dc *dc = dev->dev_private;
56388965283SThomas Zimmermann unsigned int cfg = 0;
56488965283SThomas Zimmermann int i;
56588965283SThomas Zimmermann
56688965283SThomas Zimmermann /* Enable interrupts on activated layers */
56788965283SThomas Zimmermann for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
56888965283SThomas Zimmermann if (dc->layers[i])
56988965283SThomas Zimmermann cfg |= ATMEL_HLCDC_LAYER_STATUS(i);
57088965283SThomas Zimmermann }
57188965283SThomas Zimmermann
57288965283SThomas Zimmermann regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, cfg);
57388965283SThomas Zimmermann }
57488965283SThomas Zimmermann
atmel_hlcdc_dc_irq_disable(struct drm_device * dev)57588965283SThomas Zimmermann static void atmel_hlcdc_dc_irq_disable(struct drm_device *dev)
57688965283SThomas Zimmermann {
57788965283SThomas Zimmermann struct atmel_hlcdc_dc *dc = dev->dev_private;
57888965283SThomas Zimmermann unsigned int isr;
57988965283SThomas Zimmermann
58088965283SThomas Zimmermann regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, 0xffffffff);
58188965283SThomas Zimmermann regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
58288965283SThomas Zimmermann }
58388965283SThomas Zimmermann
atmel_hlcdc_dc_irq_install(struct drm_device * dev,unsigned int irq)58488965283SThomas Zimmermann static int atmel_hlcdc_dc_irq_install(struct drm_device *dev, unsigned int irq)
58588965283SThomas Zimmermann {
58688965283SThomas Zimmermann int ret;
58788965283SThomas Zimmermann
58888965283SThomas Zimmermann atmel_hlcdc_dc_irq_disable(dev);
58988965283SThomas Zimmermann
59088965283SThomas Zimmermann ret = devm_request_irq(dev->dev, irq, atmel_hlcdc_dc_irq_handler, 0,
59188965283SThomas Zimmermann dev->driver->name, dev);
59288965283SThomas Zimmermann if (ret)
59388965283SThomas Zimmermann return ret;
59488965283SThomas Zimmermann
59588965283SThomas Zimmermann atmel_hlcdc_dc_irq_postinstall(dev);
59688965283SThomas Zimmermann
59788965283SThomas Zimmermann return 0;
59888965283SThomas Zimmermann }
59988965283SThomas Zimmermann
atmel_hlcdc_dc_irq_uninstall(struct drm_device * dev)60088965283SThomas Zimmermann static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
60188965283SThomas Zimmermann {
60288965283SThomas Zimmermann atmel_hlcdc_dc_irq_disable(dev);
60388965283SThomas Zimmermann }
60488965283SThomas Zimmermann
6051a396789SBoris Brezillon static const struct drm_mode_config_funcs mode_config_funcs = {
606d99382e4SDaniel Vetter .fb_create = drm_gem_fb_create,
6072389fc13SBoris Brezillon .atomic_check = drm_atomic_helper_check,
608eec44d44SDaniel Vetter .atomic_commit = drm_atomic_helper_commit,
6091a396789SBoris Brezillon };
6101a396789SBoris Brezillon
atmel_hlcdc_dc_modeset_init(struct drm_device * dev)6111a396789SBoris Brezillon static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
6121a396789SBoris Brezillon {
6131a396789SBoris Brezillon struct atmel_hlcdc_dc *dc = dev->dev_private;
6141a396789SBoris Brezillon int ret;
6151a396789SBoris Brezillon
6161a396789SBoris Brezillon drm_mode_config_init(dev);
6171a396789SBoris Brezillon
6181a396789SBoris Brezillon ret = atmel_hlcdc_create_outputs(dev);
6191a396789SBoris Brezillon if (ret) {
62017a8e03eSBoris Brezillon dev_err(dev->dev, "failed to create HLCDC outputs: %d\n", ret);
6211a396789SBoris Brezillon return ret;
6221a396789SBoris Brezillon }
6231a396789SBoris Brezillon
6249a45d33cSBoris Brezillon ret = atmel_hlcdc_create_planes(dev);
6259a45d33cSBoris Brezillon if (ret) {
6269a45d33cSBoris Brezillon dev_err(dev->dev, "failed to create planes: %d\n", ret);
6279a45d33cSBoris Brezillon return ret;
6281a396789SBoris Brezillon }
6291a396789SBoris Brezillon
6301a396789SBoris Brezillon ret = atmel_hlcdc_crtc_create(dev);
6311a396789SBoris Brezillon if (ret) {
6321a396789SBoris Brezillon dev_err(dev->dev, "failed to create crtc\n");
6331a396789SBoris Brezillon return ret;
6341a396789SBoris Brezillon }
6351a396789SBoris Brezillon
6361a396789SBoris Brezillon dev->mode_config.min_width = dc->desc->min_width;
6371a396789SBoris Brezillon dev->mode_config.min_height = dc->desc->min_height;
6381a396789SBoris Brezillon dev->mode_config.max_width = dc->desc->max_width;
6391a396789SBoris Brezillon dev->mode_config.max_height = dc->desc->max_height;
6401a396789SBoris Brezillon dev->mode_config.funcs = &mode_config_funcs;
641e541845aSDan Sneddon dev->mode_config.async_page_flip = true;
6421a396789SBoris Brezillon
6431a396789SBoris Brezillon return 0;
6441a396789SBoris Brezillon }
6451a396789SBoris Brezillon
atmel_hlcdc_dc_load(struct drm_device * dev)6461a396789SBoris Brezillon static int atmel_hlcdc_dc_load(struct drm_device *dev)
6471a396789SBoris Brezillon {
6481a396789SBoris Brezillon struct platform_device *pdev = to_platform_device(dev->dev);
6491a396789SBoris Brezillon const struct of_device_id *match;
6501a396789SBoris Brezillon struct atmel_hlcdc_dc *dc;
6511a396789SBoris Brezillon int ret;
6521a396789SBoris Brezillon
6531a396789SBoris Brezillon match = of_match_node(atmel_hlcdc_of_match, dev->dev->parent->of_node);
6541a396789SBoris Brezillon if (!match) {
6551a396789SBoris Brezillon dev_err(&pdev->dev, "invalid compatible string\n");
6561a396789SBoris Brezillon return -ENODEV;
6571a396789SBoris Brezillon }
6581a396789SBoris Brezillon
6591a396789SBoris Brezillon if (!match->data) {
6601a396789SBoris Brezillon dev_err(&pdev->dev, "invalid hlcdc description\n");
6611a396789SBoris Brezillon return -EINVAL;
6621a396789SBoris Brezillon }
6631a396789SBoris Brezillon
6641a396789SBoris Brezillon dc = devm_kzalloc(dev->dev, sizeof(*dc), GFP_KERNEL);
6651a396789SBoris Brezillon if (!dc)
6661a396789SBoris Brezillon return -ENOMEM;
6671a396789SBoris Brezillon
6681a396789SBoris Brezillon dc->desc = match->data;
6691a396789SBoris Brezillon dc->hlcdc = dev_get_drvdata(dev->dev->parent);
6701a396789SBoris Brezillon dev->dev_private = dc;
6711a396789SBoris Brezillon
6721a396789SBoris Brezillon ret = clk_prepare_enable(dc->hlcdc->periph_clk);
6731a396789SBoris Brezillon if (ret) {
6741a396789SBoris Brezillon dev_err(dev->dev, "failed to enable periph_clk\n");
675eec44d44SDaniel Vetter return ret;
6761a396789SBoris Brezillon }
6771a396789SBoris Brezillon
6781a396789SBoris Brezillon pm_runtime_enable(dev->dev);
6791a396789SBoris Brezillon
6808c4b4b0dSBoris Brezillon ret = drm_vblank_init(dev, 1);
6818c4b4b0dSBoris Brezillon if (ret < 0) {
6828c4b4b0dSBoris Brezillon dev_err(dev->dev, "failed to initialize vblank\n");
6838c4b4b0dSBoris Brezillon goto err_periph_clk_disable;
6848c4b4b0dSBoris Brezillon }
6858c4b4b0dSBoris Brezillon
6861a396789SBoris Brezillon ret = atmel_hlcdc_dc_modeset_init(dev);
6871a396789SBoris Brezillon if (ret < 0) {
6881a396789SBoris Brezillon dev_err(dev->dev, "failed to initialize mode setting\n");
6891a396789SBoris Brezillon goto err_periph_clk_disable;
6901a396789SBoris Brezillon }
6911a396789SBoris Brezillon
6922389fc13SBoris Brezillon drm_mode_config_reset(dev);
6932389fc13SBoris Brezillon
6941a396789SBoris Brezillon pm_runtime_get_sync(dev->dev);
69588965283SThomas Zimmermann ret = atmel_hlcdc_dc_irq_install(dev, dc->hlcdc->irq);
6961a396789SBoris Brezillon pm_runtime_put_sync(dev->dev);
6971a396789SBoris Brezillon if (ret < 0) {
6981a396789SBoris Brezillon dev_err(dev->dev, "failed to install IRQ handler\n");
6991a396789SBoris Brezillon goto err_periph_clk_disable;
7001a396789SBoris Brezillon }
7011a396789SBoris Brezillon
7021a396789SBoris Brezillon platform_set_drvdata(pdev, dev);
7031a396789SBoris Brezillon
704db02b761SBoris Brezillon drm_kms_helper_poll_init(dev);
7051a396789SBoris Brezillon
7061a396789SBoris Brezillon return 0;
7071a396789SBoris Brezillon
7081a396789SBoris Brezillon err_periph_clk_disable:
7091a396789SBoris Brezillon pm_runtime_disable(dev->dev);
7101a396789SBoris Brezillon clk_disable_unprepare(dc->hlcdc->periph_clk);
7111a396789SBoris Brezillon
7121a396789SBoris Brezillon return ret;
7131a396789SBoris Brezillon }
7141a396789SBoris Brezillon
atmel_hlcdc_dc_unload(struct drm_device * dev)7151a396789SBoris Brezillon static void atmel_hlcdc_dc_unload(struct drm_device *dev)
7161a396789SBoris Brezillon {
7171a396789SBoris Brezillon struct atmel_hlcdc_dc *dc = dev->dev_private;
7181a396789SBoris Brezillon
7191a396789SBoris Brezillon drm_kms_helper_poll_fini(dev);
720952a08a2SVille Syrjälä drm_atomic_helper_shutdown(dev);
7211a396789SBoris Brezillon drm_mode_config_cleanup(dev);
7221a396789SBoris Brezillon
7231a396789SBoris Brezillon pm_runtime_get_sync(dev->dev);
72488965283SThomas Zimmermann atmel_hlcdc_dc_irq_uninstall(dev);
7251a396789SBoris Brezillon pm_runtime_put_sync(dev->dev);
7261a396789SBoris Brezillon
7271a396789SBoris Brezillon dev->dev_private = NULL;
7281a396789SBoris Brezillon
7291a396789SBoris Brezillon pm_runtime_disable(dev->dev);
7301a396789SBoris Brezillon clk_disable_unprepare(dc->hlcdc->periph_clk);
7311a396789SBoris Brezillon }
7321a396789SBoris Brezillon
7334a83c26aSDanilo Krummrich DEFINE_DRM_GEM_DMA_FOPS(fops);
7341a396789SBoris Brezillon
73570a59dd8SDaniel Vetter static const struct drm_driver atmel_hlcdc_dc_driver = {
7360424fdafSDaniel Vetter .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
7374a83c26aSDanilo Krummrich DRM_GEM_DMA_DRIVER_OPS,
7381a396789SBoris Brezillon .fops = &fops,
7391a396789SBoris Brezillon .name = "atmel-hlcdc",
7401a396789SBoris Brezillon .desc = "Atmel HLCD Controller DRM",
7411a396789SBoris Brezillon .date = "20141504",
7421a396789SBoris Brezillon .major = 1,
7431a396789SBoris Brezillon .minor = 0,
7441a396789SBoris Brezillon };
7451a396789SBoris Brezillon
atmel_hlcdc_dc_drm_probe(struct platform_device * pdev)7461a396789SBoris Brezillon static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
7471a396789SBoris Brezillon {
7481a396789SBoris Brezillon struct drm_device *ddev;
7491a396789SBoris Brezillon int ret;
7501a396789SBoris Brezillon
7511a396789SBoris Brezillon ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev);
7520f288605STom Gundersen if (IS_ERR(ddev))
7530f288605STom Gundersen return PTR_ERR(ddev);
7541a396789SBoris Brezillon
7551a396789SBoris Brezillon ret = atmel_hlcdc_dc_load(ddev);
7561a396789SBoris Brezillon if (ret)
7579cb5f487SThomas Zimmermann goto err_put;
7581a396789SBoris Brezillon
7591a396789SBoris Brezillon ret = drm_dev_register(ddev, 0);
7601a396789SBoris Brezillon if (ret)
7611a396789SBoris Brezillon goto err_unload;
7621a396789SBoris Brezillon
763b3fec11dSThomas Zimmermann drm_fbdev_dma_setup(ddev, 24);
764da6a512fSNoralf Trønnes
7651a396789SBoris Brezillon return 0;
7661a396789SBoris Brezillon
7671a396789SBoris Brezillon err_unload:
7681a396789SBoris Brezillon atmel_hlcdc_dc_unload(ddev);
7691a396789SBoris Brezillon
7709cb5f487SThomas Zimmermann err_put:
7719cb5f487SThomas Zimmermann drm_dev_put(ddev);
7721a396789SBoris Brezillon
7731a396789SBoris Brezillon return ret;
7741a396789SBoris Brezillon }
7751a396789SBoris Brezillon
atmel_hlcdc_dc_drm_remove(struct platform_device * pdev)776*a118fc6eSUwe Kleine-König static void atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
7771a396789SBoris Brezillon {
7781a396789SBoris Brezillon struct drm_device *ddev = platform_get_drvdata(pdev);
7791a396789SBoris Brezillon
7801a396789SBoris Brezillon drm_dev_unregister(ddev);
7811a396789SBoris Brezillon atmel_hlcdc_dc_unload(ddev);
7829cb5f487SThomas Zimmermann drm_dev_put(ddev);
7831a396789SBoris Brezillon }
7841a396789SBoris Brezillon
atmel_hlcdc_dc_drm_suspend(struct device * dev)78558486982SSylvain Rochet static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
78658486982SSylvain Rochet {
78758486982SSylvain Rochet struct drm_device *drm_dev = dev_get_drvdata(dev);
78899ed4d7eSBoris Brezillon struct atmel_hlcdc_dc *dc = drm_dev->dev_private;
78999ed4d7eSBoris Brezillon struct regmap *regmap = dc->hlcdc->regmap;
79099ed4d7eSBoris Brezillon struct drm_atomic_state *state;
79158486982SSylvain Rochet
79299ed4d7eSBoris Brezillon state = drm_atomic_helper_suspend(drm_dev);
79399ed4d7eSBoris Brezillon if (IS_ERR(state))
79499ed4d7eSBoris Brezillon return PTR_ERR(state);
79558486982SSylvain Rochet
79699ed4d7eSBoris Brezillon dc->suspend.state = state;
79799ed4d7eSBoris Brezillon
79899ed4d7eSBoris Brezillon regmap_read(regmap, ATMEL_HLCDC_IMR, &dc->suspend.imr);
79999ed4d7eSBoris Brezillon regmap_write(regmap, ATMEL_HLCDC_IDR, dc->suspend.imr);
80099ed4d7eSBoris Brezillon clk_disable_unprepare(dc->hlcdc->periph_clk);
80199ed4d7eSBoris Brezillon
80258486982SSylvain Rochet return 0;
80358486982SSylvain Rochet }
80458486982SSylvain Rochet
atmel_hlcdc_dc_drm_resume(struct device * dev)80558486982SSylvain Rochet static int atmel_hlcdc_dc_drm_resume(struct device *dev)
80658486982SSylvain Rochet {
80758486982SSylvain Rochet struct drm_device *drm_dev = dev_get_drvdata(dev);
80899ed4d7eSBoris Brezillon struct atmel_hlcdc_dc *dc = drm_dev->dev_private;
80958486982SSylvain Rochet
81099ed4d7eSBoris Brezillon clk_prepare_enable(dc->hlcdc->periph_clk);
81199ed4d7eSBoris Brezillon regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, dc->suspend.imr);
81258486982SSylvain Rochet
81399ed4d7eSBoris Brezillon return drm_atomic_helper_resume(drm_dev, dc->suspend.state);
81458486982SSylvain Rochet }
81558486982SSylvain Rochet
81668c8704dSPaul Cercueil static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
81768c8704dSPaul Cercueil atmel_hlcdc_dc_drm_suspend,
81868c8704dSPaul Cercueil atmel_hlcdc_dc_drm_resume);
81958486982SSylvain Rochet
8201a396789SBoris Brezillon static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
8211a396789SBoris Brezillon { .compatible = "atmel,hlcdc-display-controller" },
8221a396789SBoris Brezillon { },
8231a396789SBoris Brezillon };
8241a396789SBoris Brezillon
8251a396789SBoris Brezillon static struct platform_driver atmel_hlcdc_dc_platform_driver = {
8261a396789SBoris Brezillon .probe = atmel_hlcdc_dc_drm_probe,
827*a118fc6eSUwe Kleine-König .remove_new = atmel_hlcdc_dc_drm_remove,
8281a396789SBoris Brezillon .driver = {
8291a396789SBoris Brezillon .name = "atmel-hlcdc-display-controller",
83068c8704dSPaul Cercueil .pm = pm_sleep_ptr(&atmel_hlcdc_dc_drm_pm_ops),
8311a396789SBoris Brezillon .of_match_table = atmel_hlcdc_dc_of_match,
8321a396789SBoris Brezillon },
8331a396789SBoris Brezillon };
834d5410d69SJavier Martinez Canillas drm_module_platform_driver(atmel_hlcdc_dc_platform_driver);
8351a396789SBoris Brezillon
8361a396789SBoris Brezillon MODULE_AUTHOR("Jean-Jacques Hiblot <jjhiblot@traphandler.com>");
8371a396789SBoris Brezillon MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
8381a396789SBoris Brezillon MODULE_DESCRIPTION("Atmel HLCDC Display Controller DRM Driver");
8391a396789SBoris Brezillon MODULE_LICENSE("GPL");
8401a396789SBoris Brezillon MODULE_ALIAS("platform:atmel-hlcdc-dc");
841