Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#include <linux/amba/clcd-regs.h>
  4#include <linux/bitops.h>
  5#include <linux/device.h>
  6#include <linux/mfd/syscon.h>
  7#include <linux/module.h>
  8#include <linux/of.h>
  9#include <linux/of_platform.h>
 10#include <linux/regmap.h>
 11
 12#include "pl111_versatile.h"
 13#include "pl111_vexpress.h"
 14#include "pl111_drm.h"
 15
 16static struct regmap *versatile_syscon_map;
 17
 18/*
 19 * We detect the different syscon types from the compatible strings.
 20 */
 21enum versatile_clcd {
 22	INTEGRATOR_CLCD_CM,
 23	VERSATILE_CLCD,
 24	REALVIEW_CLCD_EB,
 25	REALVIEW_CLCD_PB1176,
 26	REALVIEW_CLCD_PB11MP,
 27	REALVIEW_CLCD_PBA8,
 28	REALVIEW_CLCD_PBX,
 29	VEXPRESS_CLCD_V2M,
 30};
 31
 32static const struct of_device_id versatile_clcd_of_match[] = {
 33	{
 34		.compatible = "arm,core-module-integrator",
 35		.data = (void *)INTEGRATOR_CLCD_CM,
 36	},
 37	{
 38		.compatible = "arm,versatile-sysreg",
 39		.data = (void *)VERSATILE_CLCD,
 40	},
 41	{
 42		.compatible = "arm,realview-eb-syscon",
 43		.data = (void *)REALVIEW_CLCD_EB,
 44	},
 45	{
 46		.compatible = "arm,realview-pb1176-syscon",
 47		.data = (void *)REALVIEW_CLCD_PB1176,
 48	},
 49	{
 50		.compatible = "arm,realview-pb11mp-syscon",
 51		.data = (void *)REALVIEW_CLCD_PB11MP,
 52	},
 53	{
 54		.compatible = "arm,realview-pba8-syscon",
 55		.data = (void *)REALVIEW_CLCD_PBA8,
 56	},
 57	{
 58		.compatible = "arm,realview-pbx-syscon",
 59		.data = (void *)REALVIEW_CLCD_PBX,
 60	},
 61	{
 62		.compatible = "arm,vexpress-muxfpga",
 63		.data = (void *)VEXPRESS_CLCD_V2M,
 64	},
 65	{},
 66};
 67
 68/*
 69 * Core module CLCD control on the Integrator/CP, bits
 70 * 8 thru 19 of the CM_CONTROL register controls a bunch
 71 * of CLCD settings.
 72 */
 73#define INTEGRATOR_HDR_CTRL_OFFSET	0x0C
 74#define INTEGRATOR_CLCD_LCDBIASEN	BIT(8)
 75#define INTEGRATOR_CLCD_LCDBIASUP	BIT(9)
 76#define INTEGRATOR_CLCD_LCDBIASDN	BIT(10)
 77/* Bits 11,12,13 controls the LCD or VGA bridge type */
 78#define INTEGRATOR_CLCD_LCDMUX_LCD24	BIT(11)
 79#define INTEGRATOR_CLCD_LCDMUX_SHARP	(BIT(11)|BIT(12))
 80#define INTEGRATOR_CLCD_LCDMUX_VGA555	BIT(13)
 81#define INTEGRATOR_CLCD_LCDMUX_VGA24	(BIT(11)|BIT(12)|BIT(13))
 82#define INTEGRATOR_CLCD_LCD0_EN		BIT(14)
 83#define INTEGRATOR_CLCD_LCD1_EN		BIT(15)
 84/* R/L flip on Sharp */
 85#define INTEGRATOR_CLCD_LCD_STATIC1	BIT(16)
 86/* U/D flip on Sharp */
 87#define INTEGRATOR_CLCD_LCD_STATIC2	BIT(17)
 88/* No connection on Sharp */
 89#define INTEGRATOR_CLCD_LCD_STATIC	BIT(18)
 90/* 0 = 24bit VGA, 1 = 18bit VGA */
 91#define INTEGRATOR_CLCD_LCD_N24BITEN	BIT(19)
 92
 93#define INTEGRATOR_CLCD_MASK		GENMASK(19, 8)
 94
 95static void pl111_integrator_enable(struct drm_device *drm, u32 format)
 96{
 97	u32 val;
 98
 99	dev_info(drm->dev, "enable Integrator CLCD connectors\n");
100
101	/* FIXME: really needed? */
102	val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |
103		INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN;
104
105	switch (format) {
106	case DRM_FORMAT_XBGR8888:
107	case DRM_FORMAT_XRGB8888:
108		/* 24bit formats */
109		val |= INTEGRATOR_CLCD_LCDMUX_VGA24;
110		break;
111	case DRM_FORMAT_XBGR1555:
112	case DRM_FORMAT_XRGB1555:
113		/* Pseudocolor, RGB555, BGR555 */
114		val |= INTEGRATOR_CLCD_LCDMUX_VGA555;
115		break;
116	default:
117		dev_err(drm->dev, "unhandled format on Integrator 0x%08x\n",
118			format);
119		break;
120	}
121
122	regmap_update_bits(versatile_syscon_map,
123			   INTEGRATOR_HDR_CTRL_OFFSET,
124			   INTEGRATOR_CLCD_MASK,
125			   val);
126}
127
128/*
129 * This configuration register in the Versatile and RealView
130 * family is uniformly present but appears more and more
131 * unutilized starting with the RealView series.
132 */
133#define SYS_CLCD			0x50
134#define SYS_CLCD_MODE_MASK		(BIT(0)|BIT(1))
135#define SYS_CLCD_MODE_888		0
136#define SYS_CLCD_MODE_5551		BIT(0)
137#define SYS_CLCD_MODE_565_R_LSB		BIT(1)
138#define SYS_CLCD_MODE_565_B_LSB		(BIT(0)|BIT(1))
139#define SYS_CLCD_CONNECTOR_MASK		(BIT(2)|BIT(3)|BIT(4)|BIT(5))
140#define SYS_CLCD_NLCDIOON		BIT(2)
141#define SYS_CLCD_VDDPOSSWITCH		BIT(3)
142#define SYS_CLCD_PWR3V5SWITCH		BIT(4)
143#define SYS_CLCD_VDDNEGSWITCH		BIT(5)
144
145static void pl111_versatile_disable(struct drm_device *drm)
146{
147	dev_info(drm->dev, "disable Versatile CLCD connectors\n");
148	regmap_update_bits(versatile_syscon_map,
149			   SYS_CLCD,
150			   SYS_CLCD_CONNECTOR_MASK,
151			   0);
152}
153
154static void pl111_versatile_enable(struct drm_device *drm, u32 format)
155{
156	u32 val = 0;
157
158	dev_info(drm->dev, "enable Versatile CLCD connectors\n");
159
160	switch (format) {
161	case DRM_FORMAT_ABGR8888:
162	case DRM_FORMAT_XBGR8888:
163	case DRM_FORMAT_ARGB8888:
164	case DRM_FORMAT_XRGB8888:
165		val |= SYS_CLCD_MODE_888;
166		break;
167	case DRM_FORMAT_BGR565:
168		val |= SYS_CLCD_MODE_565_R_LSB;
169		break;
170	case DRM_FORMAT_RGB565:
171		val |= SYS_CLCD_MODE_565_B_LSB;
172		break;
173	case DRM_FORMAT_ABGR1555:
174	case DRM_FORMAT_XBGR1555:
175	case DRM_FORMAT_ARGB1555:
176	case DRM_FORMAT_XRGB1555:
177		val |= SYS_CLCD_MODE_5551;
178		break;
179	default:
180		dev_err(drm->dev, "unhandled format on Versatile 0x%08x\n",
181			format);
182		break;
183	}
184
185	/* Set up the MUX */
186	regmap_update_bits(versatile_syscon_map,
187			   SYS_CLCD,
188			   SYS_CLCD_MODE_MASK,
189			   val);
190
191	/* Then enable the display */
192	regmap_update_bits(versatile_syscon_map,
193			   SYS_CLCD,
194			   SYS_CLCD_CONNECTOR_MASK,
195			   SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
196}
197
198static void pl111_realview_clcd_disable(struct drm_device *drm)
199{
200	dev_info(drm->dev, "disable RealView CLCD connectors\n");
201	regmap_update_bits(versatile_syscon_map,
202			   SYS_CLCD,
203			   SYS_CLCD_CONNECTOR_MASK,
204			   0);
205}
206
207static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format)
208{
209	dev_info(drm->dev, "enable RealView CLCD connectors\n");
210	regmap_update_bits(versatile_syscon_map,
211			   SYS_CLCD,
212			   SYS_CLCD_CONNECTOR_MASK,
213			   SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
214}
215
216/* PL110 pixel formats for Integrator, vanilla PL110 */
217static const u32 pl110_integrator_pixel_formats[] = {
218	DRM_FORMAT_ABGR8888,
219	DRM_FORMAT_XBGR8888,
220	DRM_FORMAT_ARGB8888,
221	DRM_FORMAT_XRGB8888,
222	DRM_FORMAT_ABGR1555,
223	DRM_FORMAT_XBGR1555,
224	DRM_FORMAT_ARGB1555,
225	DRM_FORMAT_XRGB1555,
226};
227
228/* Extended PL110 pixel formats for Integrator and Versatile */
229static const u32 pl110_versatile_pixel_formats[] = {
230	DRM_FORMAT_ABGR8888,
231	DRM_FORMAT_XBGR8888,
232	DRM_FORMAT_ARGB8888,
233	DRM_FORMAT_XRGB8888,
234	DRM_FORMAT_BGR565, /* Uses external PLD */
235	DRM_FORMAT_RGB565, /* Uses external PLD */
236	DRM_FORMAT_ABGR1555,
237	DRM_FORMAT_XBGR1555,
238	DRM_FORMAT_ARGB1555,
239	DRM_FORMAT_XRGB1555,
240};
241
242static const u32 pl111_realview_pixel_formats[] = {
243	DRM_FORMAT_ABGR8888,
244	DRM_FORMAT_XBGR8888,
245	DRM_FORMAT_ARGB8888,
246	DRM_FORMAT_XRGB8888,
247	DRM_FORMAT_BGR565,
248	DRM_FORMAT_RGB565,
249	DRM_FORMAT_ABGR1555,
250	DRM_FORMAT_XBGR1555,
251	DRM_FORMAT_ARGB1555,
252	DRM_FORMAT_XRGB1555,
253	DRM_FORMAT_ABGR4444,
254	DRM_FORMAT_XBGR4444,
255	DRM_FORMAT_ARGB4444,
256	DRM_FORMAT_XRGB4444,
257};
258
259/*
260 * The Integrator variant is a PL110 with a bunch of broken, or not
261 * yet implemented features
262 */
263static const struct pl111_variant_data pl110_integrator = {
264	.name = "PL110 Integrator",
265	.is_pl110 = true,
266	.broken_clockdivider = true,
267	.broken_vblank = true,
268	.formats = pl110_integrator_pixel_formats,
269	.nformats = ARRAY_SIZE(pl110_integrator_pixel_formats),
270	.fb_bpp = 16,
271};
272
273/*
274 * This is the in-between PL110 variant found in the ARM Versatile,
275 * supporting RGB565/BGR565
276 */
277static const struct pl111_variant_data pl110_versatile = {
278	.name = "PL110 Versatile",
279	.is_pl110 = true,
280	.external_bgr = true,
281	.formats = pl110_versatile_pixel_formats,
282	.nformats = ARRAY_SIZE(pl110_versatile_pixel_formats),
283	.fb_bpp = 16,
284};
285
286/*
287 * RealView PL111 variant, the only real difference from the vanilla
288 * PL111 is that we select 16bpp framebuffer by default to be able
289 * to get 1024x768 without saturating the memory bus.
290 */
291static const struct pl111_variant_data pl111_realview = {
292	.name = "PL111 RealView",
293	.formats = pl111_realview_pixel_formats,
294	.nformats = ARRAY_SIZE(pl111_realview_pixel_formats),
295	.fb_bpp = 16,
296};
297
298/*
299 * Versatile Express PL111 variant, again we just push the maximum
300 * BPP to 16 to be able to get 1024x768 without saturating the memory
301 * bus. The clockdivider also seems broken on the Versatile Express.
302 */
303static const struct pl111_variant_data pl111_vexpress = {
304	.name = "PL111 Versatile Express",
305	.formats = pl111_realview_pixel_formats,
306	.nformats = ARRAY_SIZE(pl111_realview_pixel_formats),
307	.fb_bpp = 16,
308	.broken_clockdivider = true,
309};
310
311int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
312{
313	const struct of_device_id *clcd_id;
314	enum versatile_clcd versatile_clcd_type;
315	struct device_node *np;
316	struct regmap *map;
317	int ret;
318
319	np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
320					     &clcd_id);
321	if (!np) {
322		/* Non-ARM reference designs, just bail out */
323		return 0;
324	}
325	versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
326
327	/* Versatile Express special handling */
328	if (versatile_clcd_type == VEXPRESS_CLCD_V2M) {
329		struct platform_device *pdev;
330
331		/* Registers a driver for the muxfpga */
332		ret = vexpress_muxfpga_init();
333		if (ret) {
334			dev_err(dev, "unable to initialize muxfpga driver\n");
335			of_node_put(np);
336			return ret;
337		}
338
339		/* Call into deep Vexpress configuration API */
340		pdev = of_find_device_by_node(np);
341		if (!pdev) {
342			dev_err(dev, "can't find the sysreg device, deferring\n");
343			of_node_put(np);
344			return -EPROBE_DEFER;
345		}
346		map = dev_get_drvdata(&pdev->dev);
347		if (!map) {
348			dev_err(dev, "sysreg has not yet probed\n");
349			platform_device_put(pdev);
350			of_node_put(np);
351			return -EPROBE_DEFER;
352		}
353	} else {
354		map = syscon_node_to_regmap(np);
355	}
356	of_node_put(np);
357
358	if (IS_ERR(map)) {
359		dev_err(dev, "no Versatile syscon regmap\n");
360		return PTR_ERR(map);
361	}
362
363	switch (versatile_clcd_type) {
364	case INTEGRATOR_CLCD_CM:
365		versatile_syscon_map = map;
366		priv->variant = &pl110_integrator;
367		priv->variant_display_enable = pl111_integrator_enable;
368		dev_info(dev, "set up callbacks for Integrator PL110\n");
369		break;
370	case VERSATILE_CLCD:
371		versatile_syscon_map = map;
372		/* This can do RGB565 with external PLD */
373		priv->variant = &pl110_versatile;
374		priv->variant_display_enable = pl111_versatile_enable;
375		priv->variant_display_disable = pl111_versatile_disable;
376		/*
377		 * The Versatile has a variant halfway between PL110
378		 * and PL111 where these two registers have already been
379		 * swapped.
380		 */
381		priv->ienb = CLCD_PL111_IENB;
382		priv->ctrl = CLCD_PL111_CNTL;
383		dev_info(dev, "set up callbacks for Versatile PL110\n");
384		break;
385	case REALVIEW_CLCD_EB:
386	case REALVIEW_CLCD_PB1176:
387	case REALVIEW_CLCD_PB11MP:
388	case REALVIEW_CLCD_PBA8:
389	case REALVIEW_CLCD_PBX:
390		versatile_syscon_map = map;
391		priv->variant = &pl111_realview;
392		priv->variant_display_enable = pl111_realview_clcd_enable;
393		priv->variant_display_disable = pl111_realview_clcd_disable;
394		dev_info(dev, "set up callbacks for RealView PL111\n");
395		break;
396	case VEXPRESS_CLCD_V2M:
397		priv->variant = &pl111_vexpress;
398		dev_info(dev, "initializing Versatile Express PL111\n");
399		ret = pl111_vexpress_clcd_init(dev, priv, map);
400		if (ret)
401			return ret;
402		break;
403	default:
404		dev_info(dev, "unknown Versatile system controller\n");
405		break;
406	}
407
408	return 0;
409}
410EXPORT_SYMBOL_GPL(pl111_versatile_init);