aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/arm
diff options
context:
space:
mode:
authorLiviu Dudau <Liviu.Dudau@arm.com>2015-04-02 14:48:39 -0400
committerLiviu Dudau <Liviu.Dudau@arm.com>2016-02-10 08:44:16 -0500
commit8e22d79240d95c92b6cbc4c4e4139848de458927 (patch)
tree2cf63bcf6d7efeffb09ecda8ac0cd9f85ec83dae /drivers/gpu/drm/arm
parent10c1b6183a163aca59ba92b88f2b4c4cecd20d4c (diff)
drm: Add support for ARM's HDLCD controller.
The HDLCD controller is a display controller that supports resolutions up to 4096x4096 pixels. It is present on various development boards produced by ARM Ltd and emulated by the latest Fast Models from the company. Cc: David Airlie <airlied@linux.ie> Cc: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> [Kconfig cleanup and !CONFIG_PM fixes] Signed-off-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/arm')
-rw-r--r--drivers/gpu/drm/arm/Kconfig27
-rw-r--r--drivers/gpu/drm/arm/Makefile2
-rw-r--r--drivers/gpu/drm/arm/hdlcd_crtc.c327
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.c550
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.h42
-rw-r--r--drivers/gpu/drm/arm/hdlcd_regs.h87
6 files changed, 1035 insertions, 0 deletions
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
new file mode 100644
index 000000000000..eaed454e043c
--- /dev/null
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -0,0 +1,27 @@
1config DRM_ARM
2 bool
3 help
4 Choose this option to select drivers for ARM's devices
5
6config DRM_HDLCD
7 tristate "ARM HDLCD"
8 depends on DRM && OF && (ARM || ARM64)
9 depends on COMMON_CLK
10 select DRM_ARM
11 select DRM_KMS_HELPER
12 select DRM_KMS_FB_HELPER
13 select DRM_KMS_CMA_HELPER
14 help
15 Choose this option if you have an ARM High Definition Colour LCD
16 controller.
17
18 If M is selected the module will be called hdlcd.
19
20config DRM_HDLCD_SHOW_UNDERRUN
21 bool "Show underrun conditions"
22 depends on DRM_HDLCD
23 default n
24 help
25 Enable this option to show in red colour the pixels that the
26 HDLCD device did not fetch from framebuffer due to underrun
27 conditions.
diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile
new file mode 100644
index 000000000000..89dcb7bab93a
--- /dev/null
+++ b/drivers/gpu/drm/arm/Makefile
@@ -0,0 +1,2 @@
1hdlcd-y := hdlcd_drv.o hdlcd_crtc.o
2obj-$(CONFIG_DRM_HDLCD) += hdlcd.o
diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
new file mode 100644
index 000000000000..fef1b04c2aab
--- /dev/null
+++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
@@ -0,0 +1,327 @@
1/*
2 * Copyright (C) 2013-2015 ARM Limited
3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4 *
5 * This file is subject to the terms and conditions of the GNU General Public
6 * License. See the file COPYING in the main directory of this archive
7 * for more details.
8 *
9 * Implementation of a CRTC class for the HDLCD driver.
10 */
11
12#include <drm/drmP.h>
13#include <drm/drm_atomic_helper.h>
14#include <drm/drm_crtc.h>
15#include <drm/drm_crtc_helper.h>
16#include <drm/drm_fb_helper.h>
17#include <drm/drm_fb_cma_helper.h>
18#include <drm/drm_gem_cma_helper.h>
19#include <drm/drm_of.h>
20#include <drm/drm_plane_helper.h>
21#include <linux/clk.h>
22#include <linux/of_graph.h>
23#include <linux/platform_data/simplefb.h>
24#include <video/videomode.h>
25
26#include "hdlcd_drv.h"
27#include "hdlcd_regs.h"
28
29/*
30 * The HDLCD controller is a dumb RGB streamer that gets connected to
31 * a single HDMI transmitter or in the case of the ARM Models it gets
32 * emulated by the software that does the actual rendering.
33 *
34 */
35
36static const struct drm_crtc_funcs hdlcd_crtc_funcs = {
37 .destroy = drm_crtc_cleanup,
38 .set_config = drm_atomic_helper_set_config,
39 .page_flip = drm_atomic_helper_page_flip,
40 .reset = drm_atomic_helper_crtc_reset,
41 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
42 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
43};
44
45static struct simplefb_format supported_formats[] = SIMPLEFB_FORMATS;
46
47/*
48 * Setup the HDLCD registers for decoding the pixels out of the framebuffer
49 */
50static int hdlcd_set_pxl_fmt(struct drm_crtc *crtc)
51{
52 unsigned int btpp;
53 struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
54 uint32_t pixel_format;
55 struct simplefb_format *format = NULL;
56 int i;
57
58 pixel_format = crtc->primary->state->fb->pixel_format;
59
60 for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
61 if (supported_formats[i].fourcc == pixel_format)
62 format = &supported_formats[i];
63 }
64
65 if (WARN_ON(!format))
66 return 0;
67
68 /* HDLCD uses 'bytes per pixel', zero means 1 byte */
69 btpp = (format->bits_per_pixel + 7) / 8;
70 hdlcd_write(hdlcd, HDLCD_REG_PIXEL_FORMAT, (btpp - 1) << 3);
71
72 /*
73 * The format of the HDLCD_REG_<color>_SELECT register is:
74 * - bits[23:16] - default value for that color component
75 * - bits[11:8] - number of bits to extract for each color component
76 * - bits[4:0] - index of the lowest bit to extract
77 *
78 * The default color value is used when bits[11:8] are zero, when the
79 * pixel is outside the visible frame area or when there is a
80 * buffer underrun.
81 */
82 hdlcd_write(hdlcd, HDLCD_REG_RED_SELECT, format->red.offset |
83#ifdef CONFIG_DRM_HDLCD_SHOW_UNDERRUN
84 0x00ff0000 | /* show underruns in red */
85#endif
86 ((format->red.length & 0xf) << 8));
87 hdlcd_write(hdlcd, HDLCD_REG_GREEN_SELECT, format->green.offset |
88 ((format->green.length & 0xf) << 8));
89 hdlcd_write(hdlcd, HDLCD_REG_BLUE_SELECT, format->blue.offset |
90 ((format->blue.length & 0xf) << 8));
91
92 return 0;
93}
94
95static void hdlcd_crtc_mode_set_nofb(struct drm_crtc *crtc)
96{
97 struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
98 struct drm_display_mode *m = &crtc->state->adjusted_mode;
99 struct videomode vm;
100 unsigned int polarities, line_length, err;
101
102 vm.vfront_porch = m->crtc_vsync_start - m->crtc_vdisplay;
103 vm.vback_porch = m->crtc_vtotal - m->crtc_vsync_end;
104 vm.vsync_len = m->crtc_vsync_end - m->crtc_vsync_start;
105 vm.hfront_porch = m->crtc_hsync_start - m->crtc_hdisplay;
106 vm.hback_porch = m->crtc_htotal - m->crtc_hsync_end;
107 vm.hsync_len = m->crtc_hsync_end - m->crtc_hsync_start;
108
109 polarities = HDLCD_POLARITY_DATAEN | HDLCD_POLARITY_DATA;
110
111 if (m->flags & DRM_MODE_FLAG_PHSYNC)
112 polarities |= HDLCD_POLARITY_HSYNC;
113 if (m->flags & DRM_MODE_FLAG_PVSYNC)
114 polarities |= HDLCD_POLARITY_VSYNC;
115
116 line_length = crtc->primary->state->fb->pitches[0];
117
118 /* Allow max number of outstanding requests and largest burst size */
119 hdlcd_write(hdlcd, HDLCD_REG_BUS_OPTIONS,
120 HDLCD_BUS_MAX_OUTSTAND | HDLCD_BUS_BURST_16);
121
122 hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_LENGTH, line_length);
123 hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_PITCH, line_length);
124 hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_COUNT, m->crtc_vdisplay - 1);
125 hdlcd_write(hdlcd, HDLCD_REG_V_DATA, m->crtc_vdisplay - 1);
126 hdlcd_write(hdlcd, HDLCD_REG_V_BACK_PORCH, vm.vback_porch - 1);
127 hdlcd_write(hdlcd, HDLCD_REG_V_FRONT_PORCH, vm.vfront_porch - 1);
128 hdlcd_write(hdlcd, HDLCD_REG_V_SYNC, vm.vsync_len - 1);
129 hdlcd_write(hdlcd, HDLCD_REG_H_BACK_PORCH, vm.hback_porch - 1);
130 hdlcd_write(hdlcd, HDLCD_REG_H_FRONT_PORCH, vm.hfront_porch - 1);
131 hdlcd_write(hdlcd, HDLCD_REG_H_SYNC, vm.hsync_len - 1);
132 hdlcd_write(hdlcd, HDLCD_REG_H_DATA, m->crtc_hdisplay - 1);
133 hdlcd_write(hdlcd, HDLCD_REG_POLARITIES, polarities);
134
135 err = hdlcd_set_pxl_fmt(crtc);
136 if (err)
137 return;
138
139 clk_set_rate(hdlcd->clk, m->crtc_clock * 1000);
140}
141
142static void hdlcd_crtc_enable(struct drm_crtc *crtc)
143{
144 struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
145
146 clk_prepare_enable(hdlcd->clk);
147 hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 1);
148 drm_crtc_vblank_on(crtc);
149}
150
151static void hdlcd_crtc_disable(struct drm_crtc *crtc)
152{
153 struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
154
155 if (!crtc->primary->fb)
156 return;
157
158 clk_disable_unprepare(hdlcd->clk);
159 hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
160 drm_crtc_vblank_off(crtc);
161}
162
163static int hdlcd_crtc_atomic_check(struct drm_crtc *crtc,
164 struct drm_crtc_state *state)
165{
166 struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
167 struct drm_display_mode *mode = &state->adjusted_mode;
168 long rate, clk_rate = mode->clock * 1000;
169
170 rate = clk_round_rate(hdlcd->clk, clk_rate);
171 if (rate != clk_rate) {
172 /* clock required by mode not supported by hardware */
173 return -EINVAL;
174 }
175
176 return 0;
177}
178
179static void hdlcd_crtc_atomic_begin(struct drm_crtc *crtc,
180 struct drm_crtc_state *state)
181{
182 struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
183 unsigned long flags;
184
185 if (crtc->state->event) {
186 struct drm_pending_vblank_event *event = crtc->state->event;
187
188 crtc->state->event = NULL;
189 event->pipe = drm_crtc_index(crtc);
190
191 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
192
193 spin_lock_irqsave(&crtc->dev->event_lock, flags);
194 list_add_tail(&event->base.link, &hdlcd->event_list);
195 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
196 }
197}
198
199static void hdlcd_crtc_atomic_flush(struct drm_crtc *crtc,
200 struct drm_crtc_state *state)
201{
202}
203
204static bool hdlcd_crtc_mode_fixup(struct drm_crtc *crtc,
205 const struct drm_display_mode *mode,
206 struct drm_display_mode *adjusted_mode)
207{
208 return true;
209}
210
211static const struct drm_crtc_helper_funcs hdlcd_crtc_helper_funcs = {
212 .mode_fixup = hdlcd_crtc_mode_fixup,
213 .mode_set = drm_helper_crtc_mode_set,
214 .mode_set_base = drm_helper_crtc_mode_set_base,
215 .mode_set_nofb = hdlcd_crtc_mode_set_nofb,
216 .enable = hdlcd_crtc_enable,
217 .disable = hdlcd_crtc_disable,
218 .prepare = hdlcd_crtc_disable,
219 .commit = hdlcd_crtc_enable,
220 .atomic_check = hdlcd_crtc_atomic_check,
221 .atomic_begin = hdlcd_crtc_atomic_begin,
222 .atomic_flush = hdlcd_crtc_atomic_flush,
223};
224
225static int hdlcd_plane_atomic_check(struct drm_plane *plane,
226 struct drm_plane_state *state)
227{
228 return 0;
229}
230
231static void hdlcd_plane_atomic_update(struct drm_plane *plane,
232 struct drm_plane_state *state)
233{
234 struct hdlcd_drm_private *hdlcd;
235 struct drm_gem_cma_object *gem;
236 dma_addr_t scanout_start;
237
238 if (!plane->state->crtc || !plane->state->fb)
239 return;
240
241 hdlcd = crtc_to_hdlcd_priv(plane->state->crtc);
242 gem = drm_fb_cma_get_gem_obj(plane->state->fb, 0);
243 scanout_start = gem->paddr;
244 hdlcd_write(hdlcd, HDLCD_REG_FB_BASE, scanout_start);
245}
246
247static const struct drm_plane_helper_funcs hdlcd_plane_helper_funcs = {
248 .prepare_fb = NULL,
249 .cleanup_fb = NULL,
250 .atomic_check = hdlcd_plane_atomic_check,
251 .atomic_update = hdlcd_plane_atomic_update,
252};
253
254static void hdlcd_plane_destroy(struct drm_plane *plane)
255{
256 drm_plane_helper_disable(plane);
257 drm_plane_cleanup(plane);
258}
259
260static const struct drm_plane_funcs hdlcd_plane_funcs = {
261 .update_plane = drm_atomic_helper_update_plane,
262 .disable_plane = drm_atomic_helper_disable_plane,
263 .destroy = hdlcd_plane_destroy,
264 .reset = drm_atomic_helper_plane_reset,
265 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
266 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
267};
268
269static struct drm_plane *hdlcd_plane_init(struct drm_device *drm)
270{
271 struct hdlcd_drm_private *hdlcd = drm->dev_private;
272 struct drm_plane *plane = NULL;
273 u32 formats[ARRAY_SIZE(supported_formats)], i;
274 int ret;
275
276 plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL);
277 if (!plane)
278 return ERR_PTR(-ENOMEM);
279
280 for (i = 0; i < ARRAY_SIZE(supported_formats); i++)
281 formats[i] = supported_formats[i].fourcc;
282
283 ret = drm_universal_plane_init(drm, plane, 0xff, &hdlcd_plane_funcs,
284 formats, ARRAY_SIZE(formats),
285 DRM_PLANE_TYPE_PRIMARY, NULL);
286 if (ret) {
287 devm_kfree(drm->dev, plane);
288 return ERR_PTR(ret);
289 }
290
291 drm_plane_helper_add(plane, &hdlcd_plane_helper_funcs);
292 hdlcd->plane = plane;
293
294 return plane;
295}
296
297void hdlcd_crtc_suspend(struct drm_crtc *crtc)
298{
299 hdlcd_crtc_disable(crtc);
300}
301
302void hdlcd_crtc_resume(struct drm_crtc *crtc)
303{
304 hdlcd_crtc_enable(crtc);
305}
306
307int hdlcd_setup_crtc(struct drm_device *drm)
308{
309 struct hdlcd_drm_private *hdlcd = drm->dev_private;
310 struct drm_plane *primary;
311 int ret;
312
313 primary = hdlcd_plane_init(drm);
314 if (IS_ERR(primary))
315 return PTR_ERR(primary);
316
317 ret = drm_crtc_init_with_planes(drm, &hdlcd->crtc, primary, NULL,
318 &hdlcd_crtc_funcs, NULL);
319 if (ret) {
320 hdlcd_plane_destroy(primary);
321 devm_kfree(drm->dev, primary);
322 return ret;
323 }
324
325 drm_crtc_helper_add(&hdlcd->crtc, &hdlcd_crtc_helper_funcs);
326 return 0;
327}
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
new file mode 100644
index 000000000000..56b829f97699
--- /dev/null
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -0,0 +1,550 @@
1/*
2 * Copyright (C) 2013-2015 ARM Limited
3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4 *
5 * This file is subject to the terms and conditions of the GNU General Public
6 * License. See the file COPYING in the main directory of this archive
7 * for more details.
8 *
9 * ARM HDLCD Driver
10 */
11
12#include <linux/module.h>
13#include <linux/spinlock.h>
14#include <linux/clk.h>
15#include <linux/component.h>
16#include <linux/list.h>
17#include <linux/of_graph.h>
18#include <linux/of_reserved_mem.h>
19#include <linux/pm_runtime.h>
20
21#include <drm/drmP.h>
22#include <drm/drm_atomic_helper.h>
23#include <drm/drm_crtc.h>
24#include <drm/drm_crtc_helper.h>
25#include <drm/drm_fb_helper.h>
26#include <drm/drm_fb_cma_helper.h>
27#include <drm/drm_gem_cma_helper.h>
28#include <drm/drm_of.h>
29
30#include "hdlcd_drv.h"
31#include "hdlcd_regs.h"
32
33static int hdlcd_load(struct drm_device *drm, unsigned long flags)
34{
35 struct hdlcd_drm_private *hdlcd = drm->dev_private;
36 struct platform_device *pdev = to_platform_device(drm->dev);
37 struct resource *res;
38 u32 version;
39 int ret;
40
41 hdlcd->clk = devm_clk_get(drm->dev, "pxlclk");
42 if (IS_ERR(hdlcd->clk))
43 return PTR_ERR(hdlcd->clk);
44
45#ifdef CONFIG_DEBUG_FS
46 atomic_set(&hdlcd->buffer_underrun_count, 0);
47 atomic_set(&hdlcd->bus_error_count, 0);
48 atomic_set(&hdlcd->vsync_count, 0);
49 atomic_set(&hdlcd->dma_end_count, 0);
50#endif
51
52 INIT_LIST_HEAD(&hdlcd->event_list);
53
54 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
55 hdlcd->mmio = devm_ioremap_resource(drm->dev, res);
56 if (IS_ERR(hdlcd->mmio)) {
57 DRM_ERROR("failed to map control registers area\n");
58 ret = PTR_ERR(hdlcd->mmio);
59 hdlcd->mmio = NULL;
60 goto fail;
61 }
62
63 version = hdlcd_read(hdlcd, HDLCD_REG_VERSION);
64 if ((version & HDLCD_PRODUCT_MASK) != HDLCD_PRODUCT_ID) {
65 DRM_ERROR("unknown product id: 0x%x\n", version);
66 ret = -EINVAL;
67 goto fail;
68 }
69 DRM_INFO("found ARM HDLCD version r%dp%d\n",
70 (version & HDLCD_VERSION_MAJOR_MASK) >> 8,
71 version & HDLCD_VERSION_MINOR_MASK);
72
73 /* Get the optional framebuffer memory resource */
74 ret = of_reserved_mem_device_init(drm->dev);
75 if (ret && ret != -ENODEV)
76 goto fail;
77
78 ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
79 if (ret)
80 goto setup_fail;
81
82 ret = hdlcd_setup_crtc(drm);
83 if (ret < 0) {
84 DRM_ERROR("failed to create crtc\n");
85 goto setup_fail;
86 }
87
88 pm_runtime_enable(drm->dev);
89
90 pm_runtime_get_sync(drm->dev);
91 ret = drm_irq_install(drm, platform_get_irq(pdev, 0));
92 pm_runtime_put_sync(drm->dev);
93 if (ret < 0) {
94 DRM_ERROR("failed to install IRQ handler\n");
95 goto irq_fail;
96 }
97
98 return 0;
99
100irq_fail:
101 drm_crtc_cleanup(&hdlcd->crtc);
102setup_fail:
103 of_reserved_mem_device_release(drm->dev);
104fail:
105 devm_clk_put(drm->dev, hdlcd->clk);
106
107 return ret;
108}
109
110static void hdlcd_fb_output_poll_changed(struct drm_device *drm)
111{
112 struct hdlcd_drm_private *hdlcd = drm->dev_private;
113
114 if (hdlcd->fbdev)
115 drm_fbdev_cma_hotplug_event(hdlcd->fbdev);
116}
117
118static int hdlcd_atomic_commit(struct drm_device *dev,
119 struct drm_atomic_state *state, bool async)
120{
121 return drm_atomic_helper_commit(dev, state, false);
122}
123
124static const struct drm_mode_config_funcs hdlcd_mode_config_funcs = {
125 .fb_create = drm_fb_cma_create,
126 .output_poll_changed = hdlcd_fb_output_poll_changed,
127 .atomic_check = drm_atomic_helper_check,
128 .atomic_commit = hdlcd_atomic_commit,
129};
130
131static void hdlcd_setup_mode_config(struct drm_device *drm)
132{
133 drm_mode_config_init(drm);
134 drm->mode_config.min_width = 0;
135 drm->mode_config.min_height = 0;
136 drm->mode_config.max_width = HDLCD_MAX_XRES;
137 drm->mode_config.max_height = HDLCD_MAX_YRES;
138 drm->mode_config.funcs = &hdlcd_mode_config_funcs;
139}
140
141static void hdlcd_lastclose(struct drm_device *drm)
142{
143 struct hdlcd_drm_private *hdlcd = drm->dev_private;
144
145 drm_fbdev_cma_restore_mode(hdlcd->fbdev);
146}
147
148static irqreturn_t hdlcd_irq(int irq, void *arg)
149{
150 struct drm_device *drm = arg;
151 struct hdlcd_drm_private *hdlcd = drm->dev_private;
152 unsigned long irq_status;
153
154 irq_status = hdlcd_read(hdlcd, HDLCD_REG_INT_STATUS);
155
156#ifdef CONFIG_DEBUG_FS
157 if (irq_status & HDLCD_INTERRUPT_UNDERRUN)
158 atomic_inc(&hdlcd->buffer_underrun_count);
159
160 if (irq_status & HDLCD_INTERRUPT_DMA_END)
161 atomic_inc(&hdlcd->dma_end_count);
162
163 if (irq_status & HDLCD_INTERRUPT_BUS_ERROR)
164 atomic_inc(&hdlcd->bus_error_count);
165
166 if (irq_status & HDLCD_INTERRUPT_VSYNC)
167 atomic_inc(&hdlcd->vsync_count);
168
169#endif
170 if (irq_status & HDLCD_INTERRUPT_VSYNC) {
171 bool events_sent = false;
172 unsigned long flags;
173 struct drm_pending_vblank_event *e, *t;
174
175 drm_crtc_handle_vblank(&hdlcd->crtc);
176
177 spin_lock_irqsave(&drm->event_lock, flags);
178 list_for_each_entry_safe(e, t, &hdlcd->event_list, base.link) {
179 list_del(&e->base.link);
180 drm_crtc_send_vblank_event(&hdlcd->crtc, e);
181 events_sent = true;
182 }
183 if (events_sent)
184 drm_crtc_vblank_put(&hdlcd->crtc);
185 spin_unlock_irqrestore(&drm->event_lock, flags);
186 }
187
188 /* acknowledge interrupt(s) */
189 hdlcd_write(hdlcd, HDLCD_REG_INT_CLEAR, irq_status);
190
191 return IRQ_HANDLED;
192}
193
194static void hdlcd_irq_preinstall(struct drm_device *drm)
195{
196 struct hdlcd_drm_private *hdlcd = drm->dev_private;
197 /* Ensure interrupts are disabled */
198 hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, 0);
199 hdlcd_write(hdlcd, HDLCD_REG_INT_CLEAR, ~0);
200}
201
202static int hdlcd_irq_postinstall(struct drm_device *drm)
203{
204#ifdef CONFIG_DEBUG_FS
205 struct hdlcd_drm_private *hdlcd = drm->dev_private;
206 unsigned long irq_mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
207
208 /* enable debug interrupts */
209 irq_mask |= HDLCD_DEBUG_INT_MASK;
210
211 hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, irq_mask);
212#endif
213 return 0;
214}
215
216static void hdlcd_irq_uninstall(struct drm_device *drm)
217{
218 struct hdlcd_drm_private *hdlcd = drm->dev_private;
219 /* disable all the interrupts that we might have enabled */
220 unsigned long irq_mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
221
222#ifdef CONFIG_DEBUG_FS
223 /* disable debug interrupts */
224 irq_mask &= ~HDLCD_DEBUG_INT_MASK;
225#endif
226
227 /* disable vsync interrupts */
228 irq_mask &= ~HDLCD_INTERRUPT_VSYNC;
229
230 hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, irq_mask);
231}
232
233static int hdlcd_enable_vblank(struct drm_device *drm, unsigned int crtc)
234{
235 struct hdlcd_drm_private *hdlcd = drm->dev_private;
236 unsigned int mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
237
238 hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, mask | HDLCD_INTERRUPT_VSYNC);
239
240 return 0;
241}
242
243static void hdlcd_disable_vblank(struct drm_device *drm, unsigned int crtc)
244{
245 struct hdlcd_drm_private *hdlcd = drm->dev_private;
246 unsigned int mask = hdlcd_read(hdlcd, HDLCD_REG_INT_MASK);
247
248 hdlcd_write(hdlcd, HDLCD_REG_INT_MASK, mask & ~HDLCD_INTERRUPT_VSYNC);
249}
250
251#ifdef CONFIG_DEBUG_FS
252static int hdlcd_show_underrun_count(struct seq_file *m, void *arg)
253{
254 struct drm_info_node *node = (struct drm_info_node *)m->private;
255 struct drm_device *drm = node->minor->dev;
256 struct hdlcd_drm_private *hdlcd = drm->dev_private;
257
258 seq_printf(m, "underrun : %d\n", atomic_read(&hdlcd->buffer_underrun_count));
259 seq_printf(m, "dma_end : %d\n", atomic_read(&hdlcd->dma_end_count));
260 seq_printf(m, "bus_error: %d\n", atomic_read(&hdlcd->bus_error_count));
261 seq_printf(m, "vsync : %d\n", atomic_read(&hdlcd->vsync_count));
262 return 0;
263}
264
265static int hdlcd_show_pxlclock(struct seq_file *m, void *arg)
266{
267 struct drm_info_node *node = (struct drm_info_node *)m->private;
268 struct drm_device *drm = node->minor->dev;
269 struct hdlcd_drm_private *hdlcd = drm->dev_private;
270 unsigned long clkrate = clk_get_rate(hdlcd->clk);
271 unsigned long mode_clock = hdlcd->crtc.mode.crtc_clock * 1000;
272
273 seq_printf(m, "hw : %lu\n", clkrate);
274 seq_printf(m, "mode: %lu\n", mode_clock);
275 return 0;
276}
277
278static struct drm_info_list hdlcd_debugfs_list[] = {
279 { "interrupt_count", hdlcd_show_underrun_count, 0 },
280 { "clocks", hdlcd_show_pxlclock, 0 },
281};
282
283static int hdlcd_debugfs_init(struct drm_minor *minor)
284{
285 return drm_debugfs_create_files(hdlcd_debugfs_list,
286 ARRAY_SIZE(hdlcd_debugfs_list), minor->debugfs_root, minor);
287}
288
289static void hdlcd_debugfs_cleanup(struct drm_minor *minor)
290{
291 drm_debugfs_remove_files(hdlcd_debugfs_list,
292 ARRAY_SIZE(hdlcd_debugfs_list), minor);
293}
294#endif
295
296static const struct file_operations fops = {
297 .owner = THIS_MODULE,
298 .open = drm_open,
299 .release = drm_release,
300 .unlocked_ioctl = drm_ioctl,
301#ifdef CONFIG_COMPAT
302 .compat_ioctl = drm_compat_ioctl,
303#endif
304 .poll = drm_poll,
305 .read = drm_read,
306 .llseek = noop_llseek,
307 .mmap = drm_gem_cma_mmap,
308};
309
310static struct drm_driver hdlcd_driver = {
311 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
312 DRIVER_MODESET | DRIVER_PRIME |
313 DRIVER_ATOMIC,
314 .lastclose = hdlcd_lastclose,
315 .irq_handler = hdlcd_irq,
316 .irq_preinstall = hdlcd_irq_preinstall,
317 .irq_postinstall = hdlcd_irq_postinstall,
318 .irq_uninstall = hdlcd_irq_uninstall,
319 .get_vblank_counter = drm_vblank_no_hw_counter,
320 .enable_vblank = hdlcd_enable_vblank,
321 .disable_vblank = hdlcd_disable_vblank,
322 .gem_free_object = drm_gem_cma_free_object,
323 .gem_vm_ops = &drm_gem_cma_vm_ops,
324 .dumb_create = drm_gem_cma_dumb_create,
325 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
326 .dumb_destroy = drm_gem_dumb_destroy,
327 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
328 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
329 .gem_prime_export = drm_gem_prime_export,
330 .gem_prime_import = drm_gem_prime_import,
331 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
332 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
333 .gem_prime_vmap = drm_gem_cma_prime_vmap,
334 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
335 .gem_prime_mmap = drm_gem_cma_prime_mmap,
336#ifdef CONFIG_DEBUG_FS
337 .debugfs_init = hdlcd_debugfs_init,
338 .debugfs_cleanup = hdlcd_debugfs_cleanup,
339#endif
340 .fops = &fops,
341 .name = "hdlcd",
342 .desc = "ARM HDLCD Controller DRM",
343 .date = "20151021",
344 .major = 1,
345 .minor = 0,
346};
347
348static int hdlcd_drm_bind(struct device *dev)
349{
350 struct drm_device *drm;
351 struct hdlcd_drm_private *hdlcd;
352 int ret;
353
354 hdlcd = devm_kzalloc(dev, sizeof(*hdlcd), GFP_KERNEL);
355 if (!hdlcd)
356 return -ENOMEM;
357
358 drm = drm_dev_alloc(&hdlcd_driver, dev);
359 if (!drm)
360 return -ENOMEM;
361
362 drm->dev_private = hdlcd;
363 hdlcd_setup_mode_config(drm);
364 ret = hdlcd_load(drm, 0);
365 if (ret)
366 goto err_free;
367
368 ret = drm_dev_register(drm, 0);
369 if (ret)
370 goto err_unload;
371
372 dev_set_drvdata(dev, drm);
373
374 ret = component_bind_all(dev, drm);
375 if (ret) {
376 DRM_ERROR("Failed to bind all components\n");
377 goto err_unregister;
378 }
379
380 ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
381 if (ret < 0) {
382 DRM_ERROR("failed to initialise vblank\n");
383 goto err_vblank;
384 }
385 drm->vblank_disable_allowed = true;
386
387 drm_mode_config_reset(drm);
388 drm_kms_helper_poll_init(drm);
389
390 hdlcd->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
391 drm->mode_config.num_connector);
392
393 if (IS_ERR(hdlcd->fbdev)) {
394 ret = PTR_ERR(hdlcd->fbdev);
395 hdlcd->fbdev = NULL;
396 goto err_fbdev;
397 }
398
399 return 0;
400
401err_fbdev:
402 drm_kms_helper_poll_fini(drm);
403 drm_mode_config_cleanup(drm);
404 drm_vblank_cleanup(drm);
405err_vblank:
406 component_unbind_all(dev, drm);
407err_unregister:
408 drm_dev_unregister(drm);
409err_unload:
410 pm_runtime_get_sync(drm->dev);
411 drm_irq_uninstall(drm);
412 pm_runtime_put_sync(drm->dev);
413 pm_runtime_disable(drm->dev);
414 of_reserved_mem_device_release(drm->dev);
415 devm_clk_put(dev, hdlcd->clk);
416err_free:
417 drm_dev_unref(drm);
418
419 return ret;
420}
421
422static void hdlcd_drm_unbind(struct device *dev)
423{
424 struct drm_device *drm = dev_get_drvdata(dev);
425 struct hdlcd_drm_private *hdlcd = drm->dev_private;
426
427 if (hdlcd->fbdev) {
428 drm_fbdev_cma_fini(hdlcd->fbdev);
429 hdlcd->fbdev = NULL;
430 }
431 drm_kms_helper_poll_fini(drm);
432 component_unbind_all(dev, drm);
433 drm_vblank_cleanup(drm);
434 pm_runtime_get_sync(drm->dev);
435 drm_irq_uninstall(drm);
436 pm_runtime_put_sync(drm->dev);
437 pm_runtime_disable(drm->dev);
438 of_reserved_mem_device_release(drm->dev);
439 if (!IS_ERR(hdlcd->clk)) {
440 devm_clk_put(drm->dev, hdlcd->clk);
441 hdlcd->clk = NULL;
442 }
443 drm_mode_config_cleanup(drm);
444 drm_dev_unregister(drm);
445 drm_dev_unref(drm);
446 drm->dev_private = NULL;
447 dev_set_drvdata(dev, NULL);
448}
449
450static const struct component_master_ops hdlcd_master_ops = {
451 .bind = hdlcd_drm_bind,
452 .unbind = hdlcd_drm_unbind,
453};
454
455static int compare_dev(struct device *dev, void *data)
456{
457 return dev->of_node == data;
458}
459
460static int hdlcd_probe(struct platform_device *pdev)
461{
462 struct device_node *port, *ep;
463 struct component_match *match = NULL;
464
465 if (!pdev->dev.of_node)
466 return -ENODEV;
467
468 /* there is only one output port inside each device, find it */
469 ep = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
470 if (!ep)
471 return -ENODEV;
472
473 if (!of_device_is_available(ep)) {
474 of_node_put(ep);
475 return -ENODEV;
476 }
477
478 /* add the remote encoder port as component */
479 port = of_graph_get_remote_port_parent(ep);
480 of_node_put(ep);
481 if (!port || !of_device_is_available(port)) {
482 of_node_put(port);
483 return -EAGAIN;
484 }
485
486 component_match_add(&pdev->dev, &match, compare_dev, port);
487
488 return component_master_add_with_match(&pdev->dev, &hdlcd_master_ops,
489 match);
490}
491
492static int hdlcd_remove(struct platform_device *pdev)
493{
494 component_master_del(&pdev->dev, &hdlcd_master_ops);
495 return 0;
496}
497
498static const struct of_device_id hdlcd_of_match[] = {
499 { .compatible = "arm,hdlcd" },
500 {},
501};
502MODULE_DEVICE_TABLE(of, hdlcd_of_match);
503
504static int __maybe_unused hdlcd_pm_suspend(struct device *dev)
505{
506 struct drm_device *drm = dev_get_drvdata(dev);
507 struct drm_crtc *crtc;
508
509 if (pm_runtime_suspended(dev))
510 return 0;
511
512 drm_modeset_lock_all(drm);
513 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
514 hdlcd_crtc_suspend(crtc);
515 drm_modeset_unlock_all(drm);
516 return 0;
517}
518
519static int __maybe_unused hdlcd_pm_resume(struct device *dev)
520{
521 struct drm_device *drm = dev_get_drvdata(dev);
522 struct drm_crtc *crtc;
523
524 if (!pm_runtime_suspended(dev))
525 return 0;
526
527 drm_modeset_lock_all(drm);
528 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
529 hdlcd_crtc_resume(crtc);
530 drm_modeset_unlock_all(drm);
531 return 0;
532}
533
534static SIMPLE_DEV_PM_OPS(hdlcd_pm_ops, hdlcd_pm_suspend, hdlcd_pm_resume);
535
536static struct platform_driver hdlcd_platform_driver = {
537 .probe = hdlcd_probe,
538 .remove = hdlcd_remove,
539 .driver = {
540 .name = "hdlcd",
541 .pm = &hdlcd_pm_ops,
542 .of_match_table = hdlcd_of_match,
543 },
544};
545
546module_platform_driver(hdlcd_platform_driver);
547
548MODULE_AUTHOR("Liviu Dudau");
549MODULE_DESCRIPTION("ARM HDLCD DRM driver");
550MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h
new file mode 100644
index 000000000000..aa234784f053
--- /dev/null
+++ b/drivers/gpu/drm/arm/hdlcd_drv.h
@@ -0,0 +1,42 @@
1/*
2 * ARM HDLCD Controller register definition
3 */
4
5#ifndef __HDLCD_DRV_H__
6#define __HDLCD_DRV_H__
7
8struct hdlcd_drm_private {
9 void __iomem *mmio;
10 struct clk *clk;
11 struct drm_fbdev_cma *fbdev;
12 struct drm_framebuffer *fb;
13 struct list_head event_list;
14 struct drm_crtc crtc;
15 struct drm_plane *plane;
16#ifdef CONFIG_DEBUG_FS
17 atomic_t buffer_underrun_count;
18 atomic_t bus_error_count;
19 atomic_t vsync_count;
20 atomic_t dma_end_count;
21#endif
22};
23
24#define crtc_to_hdlcd_priv(x) container_of(x, struct hdlcd_drm_private, crtc)
25
26static inline void hdlcd_write(struct hdlcd_drm_private *hdlcd,
27 unsigned int reg, u32 value)
28{
29 writel(value, hdlcd->mmio + reg);
30}
31
32static inline u32 hdlcd_read(struct hdlcd_drm_private *hdlcd, unsigned int reg)
33{
34 return readl(hdlcd->mmio + reg);
35}
36
37int hdlcd_setup_crtc(struct drm_device *dev);
38void hdlcd_set_scanout(struct hdlcd_drm_private *hdlcd);
39void hdlcd_crtc_suspend(struct drm_crtc *crtc);
40void hdlcd_crtc_resume(struct drm_crtc *crtc);
41
42#endif /* __HDLCD_DRV_H__ */
diff --git a/drivers/gpu/drm/arm/hdlcd_regs.h b/drivers/gpu/drm/arm/hdlcd_regs.h
new file mode 100644
index 000000000000..66799ebef6d3
--- /dev/null
+++ b/drivers/gpu/drm/arm/hdlcd_regs.h
@@ -0,0 +1,87 @@
1/*
2 * Copyright (C) 2013,2014 ARM Limited
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file COPYING in the main directory of this archive
6 * for more details.
7 *
8 * ARM HDLCD Controller register definition
9 */
10
11#ifndef __HDLCD_REGS_H__
12#define __HDLCD_REGS_H__
13
14/* register offsets */
15#define HDLCD_REG_VERSION 0x0000 /* ro */
16#define HDLCD_REG_INT_RAWSTAT 0x0010 /* rw */
17#define HDLCD_REG_INT_CLEAR 0x0014 /* wo */
18#define HDLCD_REG_INT_MASK 0x0018 /* rw */
19#define HDLCD_REG_INT_STATUS 0x001c /* ro */
20#define HDLCD_REG_FB_BASE 0x0100 /* rw */
21#define HDLCD_REG_FB_LINE_LENGTH 0x0104 /* rw */
22#define HDLCD_REG_FB_LINE_COUNT 0x0108 /* rw */
23#define HDLCD_REG_FB_LINE_PITCH 0x010c /* rw */
24#define HDLCD_REG_BUS_OPTIONS 0x0110 /* rw */
25#define HDLCD_REG_V_SYNC 0x0200 /* rw */
26#define HDLCD_REG_V_BACK_PORCH 0x0204 /* rw */
27#define HDLCD_REG_V_DATA 0x0208 /* rw */
28#define HDLCD_REG_V_FRONT_PORCH 0x020c /* rw */
29#define HDLCD_REG_H_SYNC 0x0210 /* rw */
30#define HDLCD_REG_H_BACK_PORCH 0x0214 /* rw */
31#define HDLCD_REG_H_DATA 0x0218 /* rw */
32#define HDLCD_REG_H_FRONT_PORCH 0x021c /* rw */
33#define HDLCD_REG_POLARITIES 0x0220 /* rw */
34#define HDLCD_REG_COMMAND 0x0230 /* rw */
35#define HDLCD_REG_PIXEL_FORMAT 0x0240 /* rw */
36#define HDLCD_REG_RED_SELECT 0x0244 /* rw */
37#define HDLCD_REG_GREEN_SELECT 0x0248 /* rw */
38#define HDLCD_REG_BLUE_SELECT 0x024c /* rw */
39
40/* version */
41#define HDLCD_PRODUCT_ID 0x1CDC0000
42#define HDLCD_PRODUCT_MASK 0xFFFF0000
43#define HDLCD_VERSION_MAJOR_MASK 0x0000FF00
44#define HDLCD_VERSION_MINOR_MASK 0x000000FF
45
46/* interrupts */
47#define HDLCD_INTERRUPT_DMA_END (1 << 0)
48#define HDLCD_INTERRUPT_BUS_ERROR (1 << 1)
49#define HDLCD_INTERRUPT_VSYNC (1 << 2)
50#define HDLCD_INTERRUPT_UNDERRUN (1 << 3)
51#define HDLCD_DEBUG_INT_MASK (HDLCD_INTERRUPT_DMA_END | \
52 HDLCD_INTERRUPT_BUS_ERROR | \
53 HDLCD_INTERRUPT_UNDERRUN)
54
55/* polarities */
56#define HDLCD_POLARITY_VSYNC (1 << 0)
57#define HDLCD_POLARITY_HSYNC (1 << 1)
58#define HDLCD_POLARITY_DATAEN (1 << 2)
59#define HDLCD_POLARITY_DATA (1 << 3)
60#define HDLCD_POLARITY_PIXELCLK (1 << 4)
61
62/* commands */
63#define HDLCD_COMMAND_DISABLE (0 << 0)
64#define HDLCD_COMMAND_ENABLE (1 << 0)
65
66/* pixel format */
67#define HDLCD_PIXEL_FMT_LITTLE_ENDIAN (0 << 31)
68#define HDLCD_PIXEL_FMT_BIG_ENDIAN (1 << 31)
69#define HDLCD_BYTES_PER_PIXEL_MASK (3 << 3)
70
71/* bus options */
72#define HDLCD_BUS_BURST_MASK 0x01f
73#define HDLCD_BUS_MAX_OUTSTAND 0xf00
74#define HDLCD_BUS_BURST_NONE (0 << 0)
75#define HDLCD_BUS_BURST_1 (1 << 0)
76#define HDLCD_BUS_BURST_2 (1 << 1)
77#define HDLCD_BUS_BURST_4 (1 << 2)
78#define HDLCD_BUS_BURST_8 (1 << 3)
79#define HDLCD_BUS_BURST_16 (1 << 4)
80
81/* Max resolution supported is 4096x4096, 32bpp */
82#define HDLCD_MAX_XRES 4096
83#define HDLCD_MAX_YRES 4096
84
85#define NR_PALETTE 256
86
87#endif /* __HDLCD_REGS_H__ */