brintos

brintos / linux-shallow public Read only

0
0
Text · 14.8 KiB · 1e4b28d Raw
566 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 3/*4 * Versatile family (ARM reference designs) handling for the PL11x.5 * This is based on code and know-how in the previous frame buffer6 * driver in drivers/video/fbdev/amba-clcd.c:7 * Copyright (C) 2001 ARM Limited, by David A Rusling8 * Updated to 2.5 by Deep Blue Solutions Ltd.9 * Major contributions and discoveries by Russell King.10 */11 12#include <linux/bitops.h>13#include <linux/device.h>14#include <linux/mfd/syscon.h>15#include <linux/module.h>16#include <linux/of.h>17#include <linux/of_platform.h>18#include <linux/platform_device.h>19#include <linux/regmap.h>20#include <linux/vexpress.h>21 22#include <drm/drm_fourcc.h>23 24#include "pl111_versatile.h"25#include "pl111_drm.h"26 27static struct regmap *versatile_syscon_map;28 29/*30 * We detect the different syscon types from the compatible strings.31 */32enum versatile_clcd {33	INTEGRATOR_IMPD1,34	INTEGRATOR_CLCD_CM,35	VERSATILE_CLCD,36	REALVIEW_CLCD_EB,37	REALVIEW_CLCD_PB1176,38	REALVIEW_CLCD_PB11MP,39	REALVIEW_CLCD_PBA8,40	REALVIEW_CLCD_PBX,41	VEXPRESS_CLCD_V2M,42};43 44static const struct of_device_id versatile_clcd_of_match[] = {45	{46		.compatible = "arm,core-module-integrator",47		.data = (void *)INTEGRATOR_CLCD_CM,48	},49	{50		.compatible = "arm,versatile-sysreg",51		.data = (void *)VERSATILE_CLCD,52	},53	{54		.compatible = "arm,realview-eb-syscon",55		.data = (void *)REALVIEW_CLCD_EB,56	},57	{58		.compatible = "arm,realview-pb1176-syscon",59		.data = (void *)REALVIEW_CLCD_PB1176,60	},61	{62		.compatible = "arm,realview-pb11mp-syscon",63		.data = (void *)REALVIEW_CLCD_PB11MP,64	},65	{66		.compatible = "arm,realview-pba8-syscon",67		.data = (void *)REALVIEW_CLCD_PBA8,68	},69	{70		.compatible = "arm,realview-pbx-syscon",71		.data = (void *)REALVIEW_CLCD_PBX,72	},73	{74		.compatible = "arm,vexpress-muxfpga",75		.data = (void *)VEXPRESS_CLCD_V2M,76	},77	{},78};79 80static const struct of_device_id impd1_clcd_of_match[] = {81	{82		.compatible = "arm,im-pd1-syscon",83		.data = (void *)INTEGRATOR_IMPD1,84	},85	{},86};87 88/*89 * Core module CLCD control on the Integrator/CP, bits90 * 8 thru 19 of the CM_CONTROL register controls a bunch91 * of CLCD settings.92 */93#define INTEGRATOR_HDR_CTRL_OFFSET	0x0C94#define INTEGRATOR_CLCD_LCDBIASEN	BIT(8)95#define INTEGRATOR_CLCD_LCDBIASUP	BIT(9)96#define INTEGRATOR_CLCD_LCDBIASDN	BIT(10)97/* Bits 11,12,13 controls the LCD or VGA bridge type */98#define INTEGRATOR_CLCD_LCDMUX_LCD24	BIT(11)99#define INTEGRATOR_CLCD_LCDMUX_SHARP	(BIT(11)|BIT(12))100#define INTEGRATOR_CLCD_LCDMUX_VGA555	BIT(13)101#define INTEGRATOR_CLCD_LCDMUX_VGA24	(BIT(11)|BIT(12)|BIT(13))102#define INTEGRATOR_CLCD_LCD0_EN		BIT(14)103#define INTEGRATOR_CLCD_LCD1_EN		BIT(15)104/* R/L flip on Sharp */105#define INTEGRATOR_CLCD_LCD_STATIC1	BIT(16)106/* U/D flip on Sharp */107#define INTEGRATOR_CLCD_LCD_STATIC2	BIT(17)108/* No connection on Sharp */109#define INTEGRATOR_CLCD_LCD_STATIC	BIT(18)110/* 0 = 24bit VGA, 1 = 18bit VGA */111#define INTEGRATOR_CLCD_LCD_N24BITEN	BIT(19)112 113#define INTEGRATOR_CLCD_MASK		GENMASK(19, 8)114 115static void pl111_integrator_enable(struct drm_device *drm, u32 format)116{117	u32 val;118 119	dev_info(drm->dev, "enable Integrator CLCD connectors\n");120 121	/* FIXME: really needed? */122	val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |123		INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN;124 125	switch (format) {126	case DRM_FORMAT_XBGR8888:127	case DRM_FORMAT_XRGB8888:128		/* 24bit formats */129		val |= INTEGRATOR_CLCD_LCDMUX_VGA24;130		break;131	case DRM_FORMAT_XBGR1555:132	case DRM_FORMAT_XRGB1555:133		/* Pseudocolor, RGB555, BGR555 */134		val |= INTEGRATOR_CLCD_LCDMUX_VGA555;135		break;136	default:137		dev_err(drm->dev, "unhandled format on Integrator 0x%08x\n",138			format);139		break;140	}141 142	regmap_update_bits(versatile_syscon_map,143			   INTEGRATOR_HDR_CTRL_OFFSET,144			   INTEGRATOR_CLCD_MASK,145			   val);146}147 148#define IMPD1_CTRL_OFFSET	0x18149#define IMPD1_CTRL_DISP_LCD	(0 << 0)150#define IMPD1_CTRL_DISP_VGA	(1 << 0)151#define IMPD1_CTRL_DISP_LCD1	(2 << 0)152#define IMPD1_CTRL_DISP_ENABLE	(1 << 2)153#define IMPD1_CTRL_DISP_MASK	(7 << 0)154 155static void pl111_impd1_enable(struct drm_device *drm, u32 format)156{157	u32 val;158 159	dev_info(drm->dev, "enable IM-PD1 CLCD connectors\n");160	val = IMPD1_CTRL_DISP_VGA | IMPD1_CTRL_DISP_ENABLE;161 162	regmap_update_bits(versatile_syscon_map,163			   IMPD1_CTRL_OFFSET,164			   IMPD1_CTRL_DISP_MASK,165			   val);166}167 168static void pl111_impd1_disable(struct drm_device *drm)169{170	dev_info(drm->dev, "disable IM-PD1 CLCD connectors\n");171 172	regmap_update_bits(versatile_syscon_map,173			   IMPD1_CTRL_OFFSET,174			   IMPD1_CTRL_DISP_MASK,175			   0);176}177 178/*179 * This configuration register in the Versatile and RealView180 * family is uniformly present but appears more and more181 * unutilized starting with the RealView series.182 */183#define SYS_CLCD			0x50184#define SYS_CLCD_MODE_MASK		(BIT(0)|BIT(1))185#define SYS_CLCD_MODE_888		0186#define SYS_CLCD_MODE_5551		BIT(0)187#define SYS_CLCD_MODE_565_R_LSB		BIT(1)188#define SYS_CLCD_MODE_565_B_LSB		(BIT(0)|BIT(1))189#define SYS_CLCD_CONNECTOR_MASK		(BIT(2)|BIT(3)|BIT(4)|BIT(5))190#define SYS_CLCD_NLCDIOON		BIT(2)191#define SYS_CLCD_VDDPOSSWITCH		BIT(3)192#define SYS_CLCD_PWR3V5SWITCH		BIT(4)193#define SYS_CLCD_VDDNEGSWITCH		BIT(5)194 195static void pl111_versatile_disable(struct drm_device *drm)196{197	dev_info(drm->dev, "disable Versatile CLCD connectors\n");198	regmap_update_bits(versatile_syscon_map,199			   SYS_CLCD,200			   SYS_CLCD_CONNECTOR_MASK,201			   0);202}203 204static void pl111_versatile_enable(struct drm_device *drm, u32 format)205{206	u32 val = 0;207 208	dev_info(drm->dev, "enable Versatile CLCD connectors\n");209 210	switch (format) {211	case DRM_FORMAT_ABGR8888:212	case DRM_FORMAT_XBGR8888:213	case DRM_FORMAT_ARGB8888:214	case DRM_FORMAT_XRGB8888:215		val |= SYS_CLCD_MODE_888;216		break;217	case DRM_FORMAT_BGR565:218		val |= SYS_CLCD_MODE_565_R_LSB;219		break;220	case DRM_FORMAT_RGB565:221		val |= SYS_CLCD_MODE_565_B_LSB;222		break;223	case DRM_FORMAT_ABGR1555:224	case DRM_FORMAT_XBGR1555:225	case DRM_FORMAT_ARGB1555:226	case DRM_FORMAT_XRGB1555:227		val |= SYS_CLCD_MODE_5551;228		break;229	default:230		dev_err(drm->dev, "unhandled format on Versatile 0x%08x\n",231			format);232		break;233	}234 235	/* Set up the MUX */236	regmap_update_bits(versatile_syscon_map,237			   SYS_CLCD,238			   SYS_CLCD_MODE_MASK,239			   val);240 241	/* Then enable the display */242	regmap_update_bits(versatile_syscon_map,243			   SYS_CLCD,244			   SYS_CLCD_CONNECTOR_MASK,245			   SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);246}247 248static void pl111_realview_clcd_disable(struct drm_device *drm)249{250	dev_info(drm->dev, "disable RealView CLCD connectors\n");251	regmap_update_bits(versatile_syscon_map,252			   SYS_CLCD,253			   SYS_CLCD_CONNECTOR_MASK,254			   0);255}256 257static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format)258{259	dev_info(drm->dev, "enable RealView CLCD connectors\n");260	regmap_update_bits(versatile_syscon_map,261			   SYS_CLCD,262			   SYS_CLCD_CONNECTOR_MASK,263			   SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);264}265 266/* PL110 pixel formats for Integrator, vanilla PL110 */267static const u32 pl110_integrator_pixel_formats[] = {268	DRM_FORMAT_ABGR8888,269	DRM_FORMAT_XBGR8888,270	DRM_FORMAT_ARGB8888,271	DRM_FORMAT_XRGB8888,272	DRM_FORMAT_ABGR1555,273	DRM_FORMAT_XBGR1555,274	DRM_FORMAT_ARGB1555,275	DRM_FORMAT_XRGB1555,276};277 278/* Extended PL110 pixel formats for Integrator and Versatile */279static const u32 pl110_versatile_pixel_formats[] = {280	DRM_FORMAT_ABGR8888,281	DRM_FORMAT_XBGR8888,282	DRM_FORMAT_ARGB8888,283	DRM_FORMAT_XRGB8888,284	DRM_FORMAT_BGR565, /* Uses external PLD */285	DRM_FORMAT_RGB565, /* Uses external PLD */286	DRM_FORMAT_ABGR1555,287	DRM_FORMAT_XBGR1555,288	DRM_FORMAT_ARGB1555,289	DRM_FORMAT_XRGB1555,290};291 292static const u32 pl111_realview_pixel_formats[] = {293	DRM_FORMAT_ABGR8888,294	DRM_FORMAT_XBGR8888,295	DRM_FORMAT_ARGB8888,296	DRM_FORMAT_XRGB8888,297	DRM_FORMAT_BGR565,298	DRM_FORMAT_RGB565,299	DRM_FORMAT_ABGR1555,300	DRM_FORMAT_XBGR1555,301	DRM_FORMAT_ARGB1555,302	DRM_FORMAT_XRGB1555,303	DRM_FORMAT_ABGR4444,304	DRM_FORMAT_XBGR4444,305	DRM_FORMAT_ARGB4444,306	DRM_FORMAT_XRGB4444,307};308 309/*310 * The Integrator variant is a PL110 with a bunch of broken, or not311 * yet implemented features312 */313static const struct pl111_variant_data pl110_integrator = {314	.name = "PL110 Integrator",315	.is_pl110 = true,316	.broken_clockdivider = true,317	.broken_vblank = true,318	.formats = pl110_integrator_pixel_formats,319	.nformats = ARRAY_SIZE(pl110_integrator_pixel_formats),320	.fb_depth = 16,321};322 323/*324 * The IM-PD1 variant is a PL110 with a bunch of broken, or not325 * yet implemented features326 */327static const struct pl111_variant_data pl110_impd1 = {328	.name = "PL110 IM-PD1",329	.is_pl110 = true,330	.broken_clockdivider = true,331	.broken_vblank = true,332	.formats = pl110_integrator_pixel_formats,333	.nformats = ARRAY_SIZE(pl110_integrator_pixel_formats),334	.fb_depth = 15,335};336 337/*338 * This is the in-between PL110 variant found in the ARM Versatile,339 * supporting RGB565/BGR565340 */341static const struct pl111_variant_data pl110_versatile = {342	.name = "PL110 Versatile",343	.is_pl110 = true,344	.external_bgr = true,345	.formats = pl110_versatile_pixel_formats,346	.nformats = ARRAY_SIZE(pl110_versatile_pixel_formats),347	.fb_depth = 16,348};349 350/*351 * RealView PL111 variant, the only real difference from the vanilla352 * PL111 is that we select 16bpp framebuffer by default to be able353 * to get 1024x768 without saturating the memory bus.354 */355static const struct pl111_variant_data pl111_realview = {356	.name = "PL111 RealView",357	.formats = pl111_realview_pixel_formats,358	.nformats = ARRAY_SIZE(pl111_realview_pixel_formats),359	.fb_depth = 16,360};361 362/*363 * Versatile Express PL111 variant, again we just push the maximum364 * BPP to 16 to be able to get 1024x768 without saturating the memory365 * bus. The clockdivider also seems broken on the Versatile Express.366 */367static const struct pl111_variant_data pl111_vexpress = {368	.name = "PL111 Versatile Express",369	.formats = pl111_realview_pixel_formats,370	.nformats = ARRAY_SIZE(pl111_realview_pixel_formats),371	.fb_depth = 16,372	.broken_clockdivider = true,373};374 375#define VEXPRESS_FPGAMUX_MOTHERBOARD		0x00376#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1	0x01377#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2	0x02378 379static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np,380				    struct pl111_drm_dev_private *priv)381{382	struct platform_device *pdev;383	struct device_node *root;384	struct device_node *child;385	struct device_node *ct_clcd = NULL;386	struct regmap *map;387	bool has_coretile_clcd = false;388	bool has_coretile_hdlcd = false;389	bool mux_motherboard = true;390	u32 val;391	int ret;392 393	if (!IS_ENABLED(CONFIG_VEXPRESS_CONFIG))394		return -ENODEV;395 396	/*397	 * Check if we have a CLCD or HDLCD on the core tile by checking if a398	 * CLCD or HDLCD is available in the root of the device tree.399	 */400	root = of_find_node_by_path("/");401	if (!root)402		return -EINVAL;403 404	for_each_available_child_of_node(root, child) {405		if (of_device_is_compatible(child, "arm,pl111")) {406			has_coretile_clcd = true;407			ct_clcd = child;408			of_node_put(child);409			break;410		}411		if (of_device_is_compatible(child, "arm,hdlcd")) {412			has_coretile_hdlcd = true;413			of_node_put(child);414			break;415		}416	}417 418	of_node_put(root);419 420	/*421	 * If there is a coretile HDLCD and it has a driver,422	 * do not mux the CLCD on the motherboard to the DVI.423	 */424	if (has_coretile_hdlcd && IS_ENABLED(CONFIG_DRM_HDLCD))425		mux_motherboard = false;426 427	/*428	 * On the Vexpress CA9 we let the CLCD on the coretile429	 * take precedence, so also in this case do not mux the430	 * motherboard to the DVI.431	 */432	if (has_coretile_clcd)433		mux_motherboard = false;434 435	if (mux_motherboard) {436		dev_info(dev, "DVI muxed to motherboard CLCD\n");437		val = VEXPRESS_FPGAMUX_MOTHERBOARD;438	} else if (ct_clcd == dev->of_node) {439		dev_info(dev,440			 "DVI muxed to daughterboard 1 (core tile) CLCD\n");441		val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1;442	} else {443		dev_info(dev, "core tile graphics present\n");444		dev_info(dev, "this device will be deactivated\n");445		return -ENODEV;446	}447 448	/* Call into deep Vexpress configuration API */449	pdev = of_find_device_by_node(np);450	if (!pdev) {451		dev_err(dev, "can't find the sysreg device, deferring\n");452		return -EPROBE_DEFER;453	}454 455	map = devm_regmap_init_vexpress_config(&pdev->dev);456	if (IS_ERR(map)) {457		platform_device_put(pdev);458		return PTR_ERR(map);459	}460 461	ret = regmap_write(map, 0, val);462	platform_device_put(pdev);463	if (ret) {464		dev_err(dev, "error setting DVI muxmode\n");465		return -ENODEV;466	}467 468	priv->variant = &pl111_vexpress;469	dev_info(dev, "initializing Versatile Express PL111\n");470 471	return 0;472}473 474int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)475{476	const struct of_device_id *clcd_id;477	enum versatile_clcd versatile_clcd_type;478	struct device_node *np;479	struct regmap *map;480 481	np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,482					     &clcd_id);483	if (!np) {484		/* Non-ARM reference designs, just bail out */485		return 0;486	}487 488	versatile_clcd_type = (enum versatile_clcd)clcd_id->data;489 490	/* Versatile Express special handling */491	if (versatile_clcd_type == VEXPRESS_CLCD_V2M) {492		int ret = pl111_vexpress_clcd_init(dev, np, priv);493		of_node_put(np);494		if (ret)495			dev_err(dev, "Versatile Express init failed - %d", ret);496		return ret;497	}498 499	/*500	 * On the Integrator, check if we should use the IM-PD1 instead,501	 * if we find it, it will take precedence. This is on the Integrator/AP502	 * which only has this option for PL110 graphics.503	 */504	 if (versatile_clcd_type == INTEGRATOR_CLCD_CM) {505		np = of_find_matching_node_and_match(NULL, impd1_clcd_of_match,506						     &clcd_id);507		if (np)508			versatile_clcd_type = (enum versatile_clcd)clcd_id->data;509	}510 511	map = syscon_node_to_regmap(np);512	of_node_put(np);513	if (IS_ERR(map)) {514		dev_err(dev, "no Versatile syscon regmap\n");515		return PTR_ERR(map);516	}517 518	switch (versatile_clcd_type) {519	case INTEGRATOR_CLCD_CM:520		versatile_syscon_map = map;521		priv->variant = &pl110_integrator;522		priv->variant_display_enable = pl111_integrator_enable;523		dev_info(dev, "set up callbacks for Integrator PL110\n");524		break;525	case INTEGRATOR_IMPD1:526		versatile_syscon_map = map;527		priv->variant = &pl110_impd1;528		priv->variant_display_enable = pl111_impd1_enable;529		priv->variant_display_disable = pl111_impd1_disable;530		dev_info(dev, "set up callbacks for IM-PD1 PL110\n");531		break;532	case VERSATILE_CLCD:533		versatile_syscon_map = map;534		/* This can do RGB565 with external PLD */535		priv->variant = &pl110_versatile;536		priv->variant_display_enable = pl111_versatile_enable;537		priv->variant_display_disable = pl111_versatile_disable;538		/*539		 * The Versatile has a variant halfway between PL110540		 * and PL111 where these two registers have already been541		 * swapped.542		 */543		priv->ienb = CLCD_PL111_IENB;544		priv->ctrl = CLCD_PL111_CNTL;545		dev_info(dev, "set up callbacks for Versatile PL110\n");546		break;547	case REALVIEW_CLCD_EB:548	case REALVIEW_CLCD_PB1176:549	case REALVIEW_CLCD_PB11MP:550	case REALVIEW_CLCD_PBA8:551	case REALVIEW_CLCD_PBX:552		versatile_syscon_map = map;553		priv->variant = &pl111_realview;554		priv->variant_display_enable = pl111_realview_clcd_enable;555		priv->variant_display_disable = pl111_realview_clcd_disable;556		dev_info(dev, "set up callbacks for RealView PL111\n");557		break;558	default:559		dev_info(dev, "unknown Versatile system controller\n");560		break;561	}562 563	return 0;564}565EXPORT_SYMBOL_GPL(pl111_versatile_init);566