2 * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
4 * Parts of this file were based on sources as follows:
6 * Copyright (c) 2006-2008 Intel Corporation
7 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
8 * Copyright (C) 2011 Texas Instruments
10 * This program is free software and is provided to you under the terms of the
11 * GNU General Public License version 2 as published by the Free Software
12 * Foundation, and any use by you of this program is subject to the terms of
18 * DOC: ARM PrimeCell PL111 CLCD Driver
20 * The PL111 is a simple LCD controller that can support TFT and STN
21 * displays. This driver exposes a standard KMS interface for them.
23 * This driver uses the same Device Tree binding as the fbdev CLCD
24 * driver. While the fbdev driver supports panels that may be
25 * connected to the CLCD internally to the CLCD driver, in DRM the
26 * panels get split out to drivers/gpu/drm/panels/. This means that,
27 * in converting from using fbdev to using DRM, you also need to write
28 * a panel driver (which may be as simple as an entry in
31 * The driver currently doesn't expose the cursor. The DRM API for
32 * cursors requires support for 64x64 ARGB8888 cursor images, while
33 * the hardware can only support 64x64 monochrome with masking
34 * cursors. While one could imagine trying to hack something together
35 * to look at the ARGB8888 and program reasonable in monochrome, we
36 * just don't expose the cursor at all instead, and leave cursor
37 * support to the X11 software cursor layer.
41 * - Fix race between setting plane base address and getting IRQ for
42 * vsync firing the pageflip completion.
44 * - Use the "max-memory-bandwidth" DT property to filter the
47 * - Read back hardware state at boot to skip reprogramming the
48 * hardware when doing a no-op modeset.
50 * - Use the CLKSEL bit to support switching between the two external
54 #include <linux/amba/bus.h>
55 #include <linux/amba/clcd-regs.h>
56 #include <linux/version.h>
57 #include <linux/shmem_fs.h>
58 #include <linux/dma-buf.h>
59 #include <linux/module.h>
60 #include <linux/slab.h>
63 #include <drm/drm_atomic_helper.h>
64 #include <drm/drm_crtc_helper.h>
65 #include <drm/drm_gem_cma_helper.h>
66 #include <drm/drm_gem_framebuffer_helper.h>
67 #include <drm/drm_fb_helper.h>
68 #include <drm/drm_fb_cma_helper.h>
69 #include <drm/drm_of.h>
70 #include <drm/drm_bridge.h>
71 #include <drm/drm_panel.h>
73 #include "pl111_drm.h"
74 #include "pl111_versatile.h"
76 #define DRIVER_DESC "DRM module for PL111"
78 static const struct drm_mode_config_funcs mode_config_funcs
= {
79 .fb_create
= drm_gem_fb_create
,
80 .atomic_check
= drm_atomic_helper_check
,
81 .atomic_commit
= drm_atomic_helper_commit
,
84 static int pl111_modeset_init(struct drm_device
*dev
)
86 struct drm_mode_config
*mode_config
;
87 struct pl111_drm_dev_private
*priv
= dev
->dev_private
;
88 struct drm_panel
*panel
;
89 struct drm_bridge
*bridge
;
92 drm_mode_config_init(dev
);
93 mode_config
= &dev
->mode_config
;
94 mode_config
->funcs
= &mode_config_funcs
;
95 mode_config
->min_width
= 1;
96 mode_config
->max_width
= 1024;
97 mode_config
->min_height
= 1;
98 mode_config
->max_height
= 768;
100 ret
= drm_of_find_panel_or_bridge(dev
->dev
->of_node
,
101 0, 0, &panel
, &bridge
);
102 if (ret
&& ret
!= -ENODEV
)
105 bridge
= drm_panel_bridge_add(panel
,
106 DRM_MODE_CONNECTOR_Unknown
);
107 if (IS_ERR(bridge
)) {
108 ret
= PTR_ERR(bridge
);
112 * TODO: when we are using a different bridge than a panel
113 * (such as a dumb VGA connector) we need to devise a different
114 * method to get the connector out of the bridge.
118 ret
= pl111_display_init(dev
);
120 dev_err(dev
->dev
, "Failed to init display\n");
124 ret
= drm_simple_display_pipe_attach_bridge(&priv
->pipe
,
129 priv
->bridge
= bridge
;
131 priv
->connector
= panel
->connector
;
133 ret
= drm_vblank_init(dev
, 1);
135 dev_err(dev
->dev
, "Failed to init vblank\n");
139 drm_mode_config_reset(dev
);
141 drm_fb_cma_fbdev_init(dev
, 32, 0);
143 drm_kms_helper_poll_init(dev
);
149 drm_panel_bridge_remove(bridge
);
151 drm_mode_config_cleanup(dev
);
156 DEFINE_DRM_GEM_CMA_FOPS(drm_fops
);
158 static struct drm_driver pl111_drm_driver
= {
160 DRIVER_MODESET
| DRIVER_GEM
| DRIVER_PRIME
| DRIVER_ATOMIC
,
161 .lastclose
= drm_fb_helper_lastclose
,
170 .dumb_create
= drm_gem_cma_dumb_create
,
171 .gem_free_object_unlocked
= drm_gem_cma_free_object
,
172 .gem_vm_ops
= &drm_gem_cma_vm_ops
,
174 .enable_vblank
= pl111_enable_vblank
,
175 .disable_vblank
= pl111_disable_vblank
,
177 .prime_handle_to_fd
= drm_gem_prime_handle_to_fd
,
178 .prime_fd_to_handle
= drm_gem_prime_fd_to_handle
,
179 .gem_prime_import
= drm_gem_prime_import
,
180 .gem_prime_import_sg_table
= drm_gem_cma_prime_import_sg_table
,
181 .gem_prime_export
= drm_gem_prime_export
,
182 .gem_prime_get_sg_table
= drm_gem_cma_prime_get_sg_table
,
184 #if defined(CONFIG_DEBUG_FS)
185 .debugfs_init
= pl111_debugfs_init
,
189 static int pl111_amba_probe(struct amba_device
*amba_dev
,
190 const struct amba_id
*id
)
192 struct device
*dev
= &amba_dev
->dev
;
193 struct pl111_drm_dev_private
*priv
;
194 struct pl111_variant_data
*variant
= id
->data
;
195 struct drm_device
*drm
;
198 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
202 drm
= drm_dev_alloc(&pl111_drm_driver
, dev
);
205 amba_set_drvdata(amba_dev
, drm
);
207 drm
->dev_private
= priv
;
208 priv
->variant
= variant
;
211 * The PL110 and PL111 variants have two registers
212 * swapped: interrupt enable and control. For this reason
213 * we use offsets that we can change per variant.
215 if (variant
->is_pl110
) {
217 * The ARM Versatile boards are even more special:
218 * their PrimeCell ID say they are PL110 but the
219 * control and interrupt enable registers are anyway
220 * swapped to the PL111 order so they are not following
221 * the PL110 datasheet.
223 if (of_machine_is_compatible("arm,versatile-ab") ||
224 of_machine_is_compatible("arm,versatile-pb")) {
225 priv
->ienb
= CLCD_PL111_IENB
;
226 priv
->ctrl
= CLCD_PL111_CNTL
;
228 priv
->ienb
= CLCD_PL110_IENB
;
229 priv
->ctrl
= CLCD_PL110_CNTL
;
232 priv
->ienb
= CLCD_PL111_IENB
;
233 priv
->ctrl
= CLCD_PL111_CNTL
;
236 priv
->regs
= devm_ioremap_resource(dev
, &amba_dev
->res
);
237 if (IS_ERR(priv
->regs
)) {
238 dev_err(dev
, "%s failed mmio\n", __func__
);
239 return PTR_ERR(priv
->regs
);
242 /* turn off interrupts before requesting the irq */
243 writel(0, priv
->regs
+ priv
->ienb
);
245 ret
= devm_request_irq(dev
, amba_dev
->irq
[0], pl111_irq
, 0,
246 variant
->name
, priv
);
248 dev_err(dev
, "%s failed irq %d\n", __func__
, ret
);
252 ret
= pl111_versatile_init(dev
, priv
);
256 ret
= pl111_modeset_init(drm
);
260 ret
= drm_dev_register(drm
, 0);
271 static int pl111_amba_remove(struct amba_device
*amba_dev
)
273 struct drm_device
*drm
= amba_get_drvdata(amba_dev
);
274 struct pl111_drm_dev_private
*priv
= drm
->dev_private
;
276 drm_dev_unregister(drm
);
277 drm_fb_cma_fbdev_fini(drm
);
279 drm_panel_bridge_remove(priv
->bridge
);
280 drm_mode_config_cleanup(drm
);
287 * This variant exist in early versions like the ARM Integrator
288 * and this version lacks the 565 and 444 pixel formats.
290 static const u32 pl110_pixel_formats
[] = {
301 static const struct pl111_variant_data pl110_variant
= {
304 .formats
= pl110_pixel_formats
,
305 .nformats
= ARRAY_SIZE(pl110_pixel_formats
),
308 /* RealView, Versatile Express etc use this modern variant */
309 static const u32 pl111_pixel_formats
[] = {
326 static const struct pl111_variant_data pl111_variant
= {
328 .formats
= pl111_pixel_formats
,
329 .nformats
= ARRAY_SIZE(pl111_pixel_formats
),
332 static const struct amba_id pl111_id_table
[] = {
336 .data
= (void*)&pl110_variant
,
341 .data
= (void*)&pl111_variant
,
346 static struct amba_driver pl111_amba_driver __maybe_unused
= {
348 .name
= "drm-clcd-pl111",
350 .probe
= pl111_amba_probe
,
351 .remove
= pl111_amba_remove
,
352 .id_table
= pl111_id_table
,
355 #ifdef CONFIG_ARM_AMBA
356 module_amba_driver(pl111_amba_driver
);
359 MODULE_DESCRIPTION(DRIVER_DESC
);
360 MODULE_AUTHOR("ARM Ltd.");
361 MODULE_LICENSE("GPL");