xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/pl111/pl111_drv.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Parts of this file were based on sources as follows:
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (c) 2006-2008 Intel Corporation
8*4882a593Smuzhiyun  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
9*4882a593Smuzhiyun  * Copyright (C) 2011 Texas Instruments
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun /**
13*4882a593Smuzhiyun  * DOC: ARM PrimeCell PL110 and PL111 CLCD Driver
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * The PL110/PL111 is a simple LCD controller that can support TFT
16*4882a593Smuzhiyun  * and STN displays. This driver exposes a standard KMS interface
17*4882a593Smuzhiyun  * for them.
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * The driver currently doesn't expose the cursor.  The DRM API for
20*4882a593Smuzhiyun  * cursors requires support for 64x64 ARGB8888 cursor images, while
21*4882a593Smuzhiyun  * the hardware can only support 64x64 monochrome with masking
22*4882a593Smuzhiyun  * cursors.  While one could imagine trying to hack something together
23*4882a593Smuzhiyun  * to look at the ARGB8888 and program reasonable in monochrome, we
24*4882a593Smuzhiyun  * just don't expose the cursor at all instead, and leave cursor
25*4882a593Smuzhiyun  * support to the application software cursor layer.
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * TODO:
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * - Fix race between setting plane base address and getting IRQ for
30*4882a593Smuzhiyun  *   vsync firing the pageflip completion.
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  * - Read back hardware state at boot to skip reprogramming the
33*4882a593Smuzhiyun  *   hardware when doing a no-op modeset.
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * - Use the CLKSEL bit to support switching between the two external
36*4882a593Smuzhiyun  *   clock parents.
37*4882a593Smuzhiyun  */
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #include <linux/amba/bus.h>
40*4882a593Smuzhiyun #include <linux/dma-buf.h>
41*4882a593Smuzhiyun #include <linux/module.h>
42*4882a593Smuzhiyun #include <linux/of.h>
43*4882a593Smuzhiyun #include <linux/of_graph.h>
44*4882a593Smuzhiyun #include <linux/of_reserved_mem.h>
45*4882a593Smuzhiyun #include <linux/shmem_fs.h>
46*4882a593Smuzhiyun #include <linux/slab.h>
47*4882a593Smuzhiyun #include <linux/version.h>
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #include <drm/drm_atomic_helper.h>
50*4882a593Smuzhiyun #include <drm/drm_bridge.h>
51*4882a593Smuzhiyun #include <drm/drm_drv.h>
52*4882a593Smuzhiyun #include <drm/drm_fb_cma_helper.h>
53*4882a593Smuzhiyun #include <drm/drm_fb_helper.h>
54*4882a593Smuzhiyun #include <drm/drm_gem_cma_helper.h>
55*4882a593Smuzhiyun #include <drm/drm_gem_framebuffer_helper.h>
56*4882a593Smuzhiyun #include <drm/drm_of.h>
57*4882a593Smuzhiyun #include <drm/drm_panel.h>
58*4882a593Smuzhiyun #include <drm/drm_probe_helper.h>
59*4882a593Smuzhiyun #include <drm/drm_vblank.h>
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #include "pl111_drm.h"
62*4882a593Smuzhiyun #include "pl111_versatile.h"
63*4882a593Smuzhiyun #include "pl111_nomadik.h"
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun #define DRIVER_DESC      "DRM module for PL111"
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun static const struct drm_mode_config_funcs mode_config_funcs = {
68*4882a593Smuzhiyun 	.fb_create = drm_gem_fb_create,
69*4882a593Smuzhiyun 	.atomic_check = drm_atomic_helper_check,
70*4882a593Smuzhiyun 	.atomic_commit = drm_atomic_helper_commit,
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
pl111_modeset_init(struct drm_device * dev)73*4882a593Smuzhiyun static int pl111_modeset_init(struct drm_device *dev)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	struct drm_mode_config *mode_config;
76*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = dev->dev_private;
77*4882a593Smuzhiyun 	struct device_node *np = dev->dev->of_node;
78*4882a593Smuzhiyun 	struct device_node *remote;
79*4882a593Smuzhiyun 	struct drm_panel *panel = NULL;
80*4882a593Smuzhiyun 	struct drm_bridge *bridge = NULL;
81*4882a593Smuzhiyun 	bool defer = false;
82*4882a593Smuzhiyun 	int ret;
83*4882a593Smuzhiyun 	int i;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	ret = drmm_mode_config_init(dev);
86*4882a593Smuzhiyun 	if (ret)
87*4882a593Smuzhiyun 		return ret;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	mode_config = &dev->mode_config;
90*4882a593Smuzhiyun 	mode_config->funcs = &mode_config_funcs;
91*4882a593Smuzhiyun 	mode_config->min_width = 1;
92*4882a593Smuzhiyun 	mode_config->max_width = 1024;
93*4882a593Smuzhiyun 	mode_config->min_height = 1;
94*4882a593Smuzhiyun 	mode_config->max_height = 768;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	i = 0;
97*4882a593Smuzhiyun 	for_each_endpoint_of_node(np, remote) {
98*4882a593Smuzhiyun 		struct drm_panel *tmp_panel;
99*4882a593Smuzhiyun 		struct drm_bridge *tmp_bridge;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 		dev_dbg(dev->dev, "checking endpoint %d\n", i);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 		ret = drm_of_find_panel_or_bridge(dev->dev->of_node,
104*4882a593Smuzhiyun 						  0, i,
105*4882a593Smuzhiyun 						  &tmp_panel,
106*4882a593Smuzhiyun 						  &tmp_bridge);
107*4882a593Smuzhiyun 		if (ret) {
108*4882a593Smuzhiyun 			if (ret == -EPROBE_DEFER) {
109*4882a593Smuzhiyun 				/*
110*4882a593Smuzhiyun 				 * Something deferred, but that is often just
111*4882a593Smuzhiyun 				 * another way of saying -ENODEV, but let's
112*4882a593Smuzhiyun 				 * cast a vote for later deferral.
113*4882a593Smuzhiyun 				 */
114*4882a593Smuzhiyun 				defer = true;
115*4882a593Smuzhiyun 			} else if (ret != -ENODEV) {
116*4882a593Smuzhiyun 				/* Continue, maybe something else is working */
117*4882a593Smuzhiyun 				dev_err(dev->dev,
118*4882a593Smuzhiyun 					"endpoint %d returns %d\n", i, ret);
119*4882a593Smuzhiyun 			}
120*4882a593Smuzhiyun 		}
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		if (tmp_panel) {
123*4882a593Smuzhiyun 			dev_info(dev->dev,
124*4882a593Smuzhiyun 				 "found panel on endpoint %d\n", i);
125*4882a593Smuzhiyun 			panel = tmp_panel;
126*4882a593Smuzhiyun 		}
127*4882a593Smuzhiyun 		if (tmp_bridge) {
128*4882a593Smuzhiyun 			dev_info(dev->dev,
129*4882a593Smuzhiyun 				 "found bridge on endpoint %d\n", i);
130*4882a593Smuzhiyun 			bridge = tmp_bridge;
131*4882a593Smuzhiyun 		}
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 		i++;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	/*
137*4882a593Smuzhiyun 	 * If we can't find neither panel nor bridge on any of the
138*4882a593Smuzhiyun 	 * endpoints, and any of them retured -EPROBE_DEFER, then
139*4882a593Smuzhiyun 	 * let's defer this driver too.
140*4882a593Smuzhiyun 	 */
141*4882a593Smuzhiyun 	if ((!panel && !bridge) && defer)
142*4882a593Smuzhiyun 		return -EPROBE_DEFER;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (panel) {
145*4882a593Smuzhiyun 		bridge = drm_panel_bridge_add_typed(panel,
146*4882a593Smuzhiyun 						    DRM_MODE_CONNECTOR_Unknown);
147*4882a593Smuzhiyun 		if (IS_ERR(bridge)) {
148*4882a593Smuzhiyun 			ret = PTR_ERR(bridge);
149*4882a593Smuzhiyun 			goto finish;
150*4882a593Smuzhiyun 		}
151*4882a593Smuzhiyun 	} else if (bridge) {
152*4882a593Smuzhiyun 		dev_info(dev->dev, "Using non-panel bridge\n");
153*4882a593Smuzhiyun 	} else {
154*4882a593Smuzhiyun 		dev_err(dev->dev, "No bridge, exiting\n");
155*4882a593Smuzhiyun 		return -ENODEV;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	priv->bridge = bridge;
159*4882a593Smuzhiyun 	if (panel) {
160*4882a593Smuzhiyun 		priv->panel = panel;
161*4882a593Smuzhiyun 		priv->connector = drm_panel_bridge_connector(bridge);
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	ret = pl111_display_init(dev);
165*4882a593Smuzhiyun 	if (ret != 0) {
166*4882a593Smuzhiyun 		dev_err(dev->dev, "Failed to init display\n");
167*4882a593Smuzhiyun 		goto out_bridge;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	ret = drm_simple_display_pipe_attach_bridge(&priv->pipe,
171*4882a593Smuzhiyun 						    bridge);
172*4882a593Smuzhiyun 	if (ret)
173*4882a593Smuzhiyun 		return ret;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (!priv->variant->broken_vblank) {
176*4882a593Smuzhiyun 		ret = drm_vblank_init(dev, 1);
177*4882a593Smuzhiyun 		if (ret != 0) {
178*4882a593Smuzhiyun 			dev_err(dev->dev, "Failed to init vblank\n");
179*4882a593Smuzhiyun 			goto out_bridge;
180*4882a593Smuzhiyun 		}
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	drm_mode_config_reset(dev);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	drm_kms_helper_poll_init(dev);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	goto finish;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun out_bridge:
190*4882a593Smuzhiyun 	if (panel)
191*4882a593Smuzhiyun 		drm_panel_bridge_remove(bridge);
192*4882a593Smuzhiyun finish:
193*4882a593Smuzhiyun 	return ret;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun static struct drm_gem_object *
pl111_gem_import_sg_table(struct drm_device * dev,struct dma_buf_attachment * attach,struct sg_table * sgt)197*4882a593Smuzhiyun pl111_gem_import_sg_table(struct drm_device *dev,
198*4882a593Smuzhiyun 			  struct dma_buf_attachment *attach,
199*4882a593Smuzhiyun 			  struct sg_table *sgt)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = dev->dev_private;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	/*
204*4882a593Smuzhiyun 	 * When using device-specific reserved memory we can't import
205*4882a593Smuzhiyun 	 * DMA buffers: those are passed by reference in any global
206*4882a593Smuzhiyun 	 * memory and we can only handle a specific range of memory.
207*4882a593Smuzhiyun 	 */
208*4882a593Smuzhiyun 	if (priv->use_device_memory)
209*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	return drm_gem_cma_prime_import_sg_table(dev, attach, sgt);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun static struct drm_driver pl111_drm_driver = {
217*4882a593Smuzhiyun 	.driver_features =
218*4882a593Smuzhiyun 		DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
219*4882a593Smuzhiyun 	.ioctls = NULL,
220*4882a593Smuzhiyun 	.fops = &drm_fops,
221*4882a593Smuzhiyun 	.name = "pl111",
222*4882a593Smuzhiyun 	.desc = DRIVER_DESC,
223*4882a593Smuzhiyun 	.date = "20170317",
224*4882a593Smuzhiyun 	.major = 1,
225*4882a593Smuzhiyun 	.minor = 0,
226*4882a593Smuzhiyun 	.patchlevel = 0,
227*4882a593Smuzhiyun 	.dumb_create = drm_gem_cma_dumb_create,
228*4882a593Smuzhiyun 	.gem_free_object_unlocked = drm_gem_cma_free_object,
229*4882a593Smuzhiyun 	.gem_vm_ops = &drm_gem_cma_vm_ops,
230*4882a593Smuzhiyun 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
231*4882a593Smuzhiyun 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
232*4882a593Smuzhiyun 	.gem_prime_import_sg_table = pl111_gem_import_sg_table,
233*4882a593Smuzhiyun 	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table,
234*4882a593Smuzhiyun 	.gem_prime_mmap = drm_gem_cma_prime_mmap,
235*4882a593Smuzhiyun 	.gem_prime_vmap = drm_gem_cma_prime_vmap,
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun #if defined(CONFIG_DEBUG_FS)
238*4882a593Smuzhiyun 	.debugfs_init = pl111_debugfs_init,
239*4882a593Smuzhiyun #endif
240*4882a593Smuzhiyun };
241*4882a593Smuzhiyun 
pl111_amba_probe(struct amba_device * amba_dev,const struct amba_id * id)242*4882a593Smuzhiyun static int pl111_amba_probe(struct amba_device *amba_dev,
243*4882a593Smuzhiyun 			    const struct amba_id *id)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	struct device *dev = &amba_dev->dev;
246*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv;
247*4882a593Smuzhiyun 	const struct pl111_variant_data *variant = id->data;
248*4882a593Smuzhiyun 	struct drm_device *drm;
249*4882a593Smuzhiyun 	int ret;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
252*4882a593Smuzhiyun 	if (!priv)
253*4882a593Smuzhiyun 		return -ENOMEM;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	drm = drm_dev_alloc(&pl111_drm_driver, dev);
256*4882a593Smuzhiyun 	if (IS_ERR(drm))
257*4882a593Smuzhiyun 		return PTR_ERR(drm);
258*4882a593Smuzhiyun 	amba_set_drvdata(amba_dev, drm);
259*4882a593Smuzhiyun 	priv->drm = drm;
260*4882a593Smuzhiyun 	drm->dev_private = priv;
261*4882a593Smuzhiyun 	priv->variant = variant;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	ret = of_reserved_mem_device_init(dev);
264*4882a593Smuzhiyun 	if (!ret) {
265*4882a593Smuzhiyun 		dev_info(dev, "using device-specific reserved memory\n");
266*4882a593Smuzhiyun 		priv->use_device_memory = true;
267*4882a593Smuzhiyun 	}
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	if (of_property_read_u32(dev->of_node, "max-memory-bandwidth",
270*4882a593Smuzhiyun 				 &priv->memory_bw)) {
271*4882a593Smuzhiyun 		dev_info(dev, "no max memory bandwidth specified, assume unlimited\n");
272*4882a593Smuzhiyun 		priv->memory_bw = 0;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	/* The two main variants swap this register */
276*4882a593Smuzhiyun 	if (variant->is_pl110 || variant->is_lcdc) {
277*4882a593Smuzhiyun 		priv->ienb = CLCD_PL110_IENB;
278*4882a593Smuzhiyun 		priv->ctrl = CLCD_PL110_CNTL;
279*4882a593Smuzhiyun 	} else {
280*4882a593Smuzhiyun 		priv->ienb = CLCD_PL111_IENB;
281*4882a593Smuzhiyun 		priv->ctrl = CLCD_PL111_CNTL;
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	priv->regs = devm_ioremap_resource(dev, &amba_dev->res);
285*4882a593Smuzhiyun 	if (IS_ERR(priv->regs)) {
286*4882a593Smuzhiyun 		dev_err(dev, "%s failed mmio\n", __func__);
287*4882a593Smuzhiyun 		ret = PTR_ERR(priv->regs);
288*4882a593Smuzhiyun 		goto dev_put;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* This may override some variant settings */
292*4882a593Smuzhiyun 	ret = pl111_versatile_init(dev, priv);
293*4882a593Smuzhiyun 	if (ret)
294*4882a593Smuzhiyun 		goto dev_put;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	pl111_nomadik_init(dev);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	/* turn off interrupts before requesting the irq */
299*4882a593Smuzhiyun 	writel(0, priv->regs + priv->ienb);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	ret = devm_request_irq(dev, amba_dev->irq[0], pl111_irq, 0,
302*4882a593Smuzhiyun 			       variant->name, priv);
303*4882a593Smuzhiyun 	if (ret != 0) {
304*4882a593Smuzhiyun 		dev_err(dev, "%s failed irq %d\n", __func__, ret);
305*4882a593Smuzhiyun 		return ret;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	ret = pl111_modeset_init(drm);
309*4882a593Smuzhiyun 	if (ret != 0)
310*4882a593Smuzhiyun 		goto dev_put;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	ret = drm_dev_register(drm, 0);
313*4882a593Smuzhiyun 	if (ret < 0)
314*4882a593Smuzhiyun 		goto dev_put;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	drm_fbdev_generic_setup(drm, priv->variant->fb_bpp);
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	return 0;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun dev_put:
321*4882a593Smuzhiyun 	drm_dev_put(drm);
322*4882a593Smuzhiyun 	of_reserved_mem_device_release(dev);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	return ret;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
pl111_amba_remove(struct amba_device * amba_dev)327*4882a593Smuzhiyun static void pl111_amba_remove(struct amba_device *amba_dev)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun 	struct device *dev = &amba_dev->dev;
330*4882a593Smuzhiyun 	struct drm_device *drm = amba_get_drvdata(amba_dev);
331*4882a593Smuzhiyun 	struct pl111_drm_dev_private *priv = drm->dev_private;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	drm_dev_unregister(drm);
334*4882a593Smuzhiyun 	if (priv->panel)
335*4882a593Smuzhiyun 		drm_panel_bridge_remove(priv->bridge);
336*4882a593Smuzhiyun 	drm_dev_put(drm);
337*4882a593Smuzhiyun 	of_reserved_mem_device_release(dev);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun /*
341*4882a593Smuzhiyun  * This early variant lacks the 565 and 444 pixel formats.
342*4882a593Smuzhiyun  */
343*4882a593Smuzhiyun static const u32 pl110_pixel_formats[] = {
344*4882a593Smuzhiyun 	DRM_FORMAT_ABGR8888,
345*4882a593Smuzhiyun 	DRM_FORMAT_XBGR8888,
346*4882a593Smuzhiyun 	DRM_FORMAT_ARGB8888,
347*4882a593Smuzhiyun 	DRM_FORMAT_XRGB8888,
348*4882a593Smuzhiyun 	DRM_FORMAT_ABGR1555,
349*4882a593Smuzhiyun 	DRM_FORMAT_XBGR1555,
350*4882a593Smuzhiyun 	DRM_FORMAT_ARGB1555,
351*4882a593Smuzhiyun 	DRM_FORMAT_XRGB1555,
352*4882a593Smuzhiyun };
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun static const struct pl111_variant_data pl110_variant = {
355*4882a593Smuzhiyun 	.name = "PL110",
356*4882a593Smuzhiyun 	.is_pl110 = true,
357*4882a593Smuzhiyun 	.formats = pl110_pixel_formats,
358*4882a593Smuzhiyun 	.nformats = ARRAY_SIZE(pl110_pixel_formats),
359*4882a593Smuzhiyun 	.fb_bpp = 16,
360*4882a593Smuzhiyun };
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun /* RealView, Versatile Express etc use this modern variant */
363*4882a593Smuzhiyun static const u32 pl111_pixel_formats[] = {
364*4882a593Smuzhiyun 	DRM_FORMAT_ABGR8888,
365*4882a593Smuzhiyun 	DRM_FORMAT_XBGR8888,
366*4882a593Smuzhiyun 	DRM_FORMAT_ARGB8888,
367*4882a593Smuzhiyun 	DRM_FORMAT_XRGB8888,
368*4882a593Smuzhiyun 	DRM_FORMAT_BGR565,
369*4882a593Smuzhiyun 	DRM_FORMAT_RGB565,
370*4882a593Smuzhiyun 	DRM_FORMAT_ABGR1555,
371*4882a593Smuzhiyun 	DRM_FORMAT_XBGR1555,
372*4882a593Smuzhiyun 	DRM_FORMAT_ARGB1555,
373*4882a593Smuzhiyun 	DRM_FORMAT_XRGB1555,
374*4882a593Smuzhiyun 	DRM_FORMAT_ABGR4444,
375*4882a593Smuzhiyun 	DRM_FORMAT_XBGR4444,
376*4882a593Smuzhiyun 	DRM_FORMAT_ARGB4444,
377*4882a593Smuzhiyun 	DRM_FORMAT_XRGB4444,
378*4882a593Smuzhiyun };
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun static const struct pl111_variant_data pl111_variant = {
381*4882a593Smuzhiyun 	.name = "PL111",
382*4882a593Smuzhiyun 	.formats = pl111_pixel_formats,
383*4882a593Smuzhiyun 	.nformats = ARRAY_SIZE(pl111_pixel_formats),
384*4882a593Smuzhiyun 	.fb_bpp = 32,
385*4882a593Smuzhiyun };
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun static const u32 pl110_nomadik_pixel_formats[] = {
388*4882a593Smuzhiyun 	DRM_FORMAT_RGB888,
389*4882a593Smuzhiyun 	DRM_FORMAT_BGR888,
390*4882a593Smuzhiyun 	DRM_FORMAT_ABGR8888,
391*4882a593Smuzhiyun 	DRM_FORMAT_XBGR8888,
392*4882a593Smuzhiyun 	DRM_FORMAT_ARGB8888,
393*4882a593Smuzhiyun 	DRM_FORMAT_XRGB8888,
394*4882a593Smuzhiyun 	DRM_FORMAT_BGR565,
395*4882a593Smuzhiyun 	DRM_FORMAT_RGB565,
396*4882a593Smuzhiyun 	DRM_FORMAT_ABGR1555,
397*4882a593Smuzhiyun 	DRM_FORMAT_XBGR1555,
398*4882a593Smuzhiyun 	DRM_FORMAT_ARGB1555,
399*4882a593Smuzhiyun 	DRM_FORMAT_XRGB1555,
400*4882a593Smuzhiyun 	DRM_FORMAT_ABGR4444,
401*4882a593Smuzhiyun 	DRM_FORMAT_XBGR4444,
402*4882a593Smuzhiyun 	DRM_FORMAT_ARGB4444,
403*4882a593Smuzhiyun 	DRM_FORMAT_XRGB4444,
404*4882a593Smuzhiyun };
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun static const struct pl111_variant_data pl110_nomadik_variant = {
407*4882a593Smuzhiyun 	.name = "LCDC (PL110 Nomadik)",
408*4882a593Smuzhiyun 	.formats = pl110_nomadik_pixel_formats,
409*4882a593Smuzhiyun 	.nformats = ARRAY_SIZE(pl110_nomadik_pixel_formats),
410*4882a593Smuzhiyun 	.is_lcdc = true,
411*4882a593Smuzhiyun 	.st_bitmux_control = true,
412*4882a593Smuzhiyun 	.broken_vblank = true,
413*4882a593Smuzhiyun 	.fb_bpp = 16,
414*4882a593Smuzhiyun };
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun static const struct amba_id pl111_id_table[] = {
417*4882a593Smuzhiyun 	{
418*4882a593Smuzhiyun 		.id = 0x00041110,
419*4882a593Smuzhiyun 		.mask = 0x000fffff,
420*4882a593Smuzhiyun 		.data = (void *)&pl110_variant,
421*4882a593Smuzhiyun 	},
422*4882a593Smuzhiyun 	{
423*4882a593Smuzhiyun 		.id = 0x00180110,
424*4882a593Smuzhiyun 		.mask = 0x00fffffe,
425*4882a593Smuzhiyun 		.data = (void *)&pl110_nomadik_variant,
426*4882a593Smuzhiyun 	},
427*4882a593Smuzhiyun 	{
428*4882a593Smuzhiyun 		.id = 0x00041111,
429*4882a593Smuzhiyun 		.mask = 0x000fffff,
430*4882a593Smuzhiyun 		.data = (void *)&pl111_variant,
431*4882a593Smuzhiyun 	},
432*4882a593Smuzhiyun 	{0, 0},
433*4882a593Smuzhiyun };
434*4882a593Smuzhiyun MODULE_DEVICE_TABLE(amba, pl111_id_table);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun static struct amba_driver pl111_amba_driver __maybe_unused = {
437*4882a593Smuzhiyun 	.drv = {
438*4882a593Smuzhiyun 		.name = "drm-clcd-pl111",
439*4882a593Smuzhiyun 	},
440*4882a593Smuzhiyun 	.probe = pl111_amba_probe,
441*4882a593Smuzhiyun 	.remove = pl111_amba_remove,
442*4882a593Smuzhiyun 	.id_table = pl111_id_table,
443*4882a593Smuzhiyun };
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun #ifdef CONFIG_ARM_AMBA
446*4882a593Smuzhiyun module_amba_driver(pl111_amba_driver);
447*4882a593Smuzhiyun #endif
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
450*4882a593Smuzhiyun MODULE_AUTHOR("ARM Ltd.");
451*4882a593Smuzhiyun MODULE_LICENSE("GPL");
452