18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * Versatile family (ARM reference designs) handling for the PL11x. 58c2ecf20Sopenharmony_ci * This is based on code and know-how in the previous frame buffer 68c2ecf20Sopenharmony_ci * driver in drivers/video/fbdev/amba-clcd.c: 78c2ecf20Sopenharmony_ci * Copyright (C) 2001 ARM Limited, by David A Rusling 88c2ecf20Sopenharmony_ci * Updated to 2.5 by Deep Blue Solutions Ltd. 98c2ecf20Sopenharmony_ci * Major contributions and discoveries by Russell King. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/bitops.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci#include <linux/vexpress.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "pl111_versatile.h" 228c2ecf20Sopenharmony_ci#include "pl111_drm.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic struct regmap *versatile_syscon_map; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * We detect the different syscon types from the compatible strings. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cienum versatile_clcd { 308c2ecf20Sopenharmony_ci INTEGRATOR_IMPD1, 318c2ecf20Sopenharmony_ci INTEGRATOR_CLCD_CM, 328c2ecf20Sopenharmony_ci VERSATILE_CLCD, 338c2ecf20Sopenharmony_ci REALVIEW_CLCD_EB, 348c2ecf20Sopenharmony_ci REALVIEW_CLCD_PB1176, 358c2ecf20Sopenharmony_ci REALVIEW_CLCD_PB11MP, 368c2ecf20Sopenharmony_ci REALVIEW_CLCD_PBA8, 378c2ecf20Sopenharmony_ci REALVIEW_CLCD_PBX, 388c2ecf20Sopenharmony_ci VEXPRESS_CLCD_V2M, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic const struct of_device_id versatile_clcd_of_match[] = { 428c2ecf20Sopenharmony_ci { 438c2ecf20Sopenharmony_ci .compatible = "arm,core-module-integrator", 448c2ecf20Sopenharmony_ci .data = (void *)INTEGRATOR_CLCD_CM, 458c2ecf20Sopenharmony_ci }, 468c2ecf20Sopenharmony_ci { 478c2ecf20Sopenharmony_ci .compatible = "arm,versatile-sysreg", 488c2ecf20Sopenharmony_ci .data = (void *)VERSATILE_CLCD, 498c2ecf20Sopenharmony_ci }, 508c2ecf20Sopenharmony_ci { 518c2ecf20Sopenharmony_ci .compatible = "arm,realview-eb-syscon", 528c2ecf20Sopenharmony_ci .data = (void *)REALVIEW_CLCD_EB, 538c2ecf20Sopenharmony_ci }, 548c2ecf20Sopenharmony_ci { 558c2ecf20Sopenharmony_ci .compatible = "arm,realview-pb1176-syscon", 568c2ecf20Sopenharmony_ci .data = (void *)REALVIEW_CLCD_PB1176, 578c2ecf20Sopenharmony_ci }, 588c2ecf20Sopenharmony_ci { 598c2ecf20Sopenharmony_ci .compatible = "arm,realview-pb11mp-syscon", 608c2ecf20Sopenharmony_ci .data = (void *)REALVIEW_CLCD_PB11MP, 618c2ecf20Sopenharmony_ci }, 628c2ecf20Sopenharmony_ci { 638c2ecf20Sopenharmony_ci .compatible = "arm,realview-pba8-syscon", 648c2ecf20Sopenharmony_ci .data = (void *)REALVIEW_CLCD_PBA8, 658c2ecf20Sopenharmony_ci }, 668c2ecf20Sopenharmony_ci { 678c2ecf20Sopenharmony_ci .compatible = "arm,realview-pbx-syscon", 688c2ecf20Sopenharmony_ci .data = (void *)REALVIEW_CLCD_PBX, 698c2ecf20Sopenharmony_ci }, 708c2ecf20Sopenharmony_ci { 718c2ecf20Sopenharmony_ci .compatible = "arm,vexpress-muxfpga", 728c2ecf20Sopenharmony_ci .data = (void *)VEXPRESS_CLCD_V2M, 738c2ecf20Sopenharmony_ci }, 748c2ecf20Sopenharmony_ci {}, 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic const struct of_device_id impd1_clcd_of_match[] = { 788c2ecf20Sopenharmony_ci { 798c2ecf20Sopenharmony_ci .compatible = "arm,im-pd1-syscon", 808c2ecf20Sopenharmony_ci .data = (void *)INTEGRATOR_IMPD1, 818c2ecf20Sopenharmony_ci }, 828c2ecf20Sopenharmony_ci {}, 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * Core module CLCD control on the Integrator/CP, bits 878c2ecf20Sopenharmony_ci * 8 thru 19 of the CM_CONTROL register controls a bunch 888c2ecf20Sopenharmony_ci * of CLCD settings. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C 918c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCDBIASEN BIT(8) 928c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCDBIASUP BIT(9) 938c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCDBIASDN BIT(10) 948c2ecf20Sopenharmony_ci/* Bits 11,12,13 controls the LCD or VGA bridge type */ 958c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCDMUX_LCD24 BIT(11) 968c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCDMUX_SHARP (BIT(11)|BIT(12)) 978c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCDMUX_VGA555 BIT(13) 988c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCDMUX_VGA24 (BIT(11)|BIT(12)|BIT(13)) 998c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCD0_EN BIT(14) 1008c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCD1_EN BIT(15) 1018c2ecf20Sopenharmony_ci/* R/L flip on Sharp */ 1028c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCD_STATIC1 BIT(16) 1038c2ecf20Sopenharmony_ci/* U/D flip on Sharp */ 1048c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCD_STATIC2 BIT(17) 1058c2ecf20Sopenharmony_ci/* No connection on Sharp */ 1068c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCD_STATIC BIT(18) 1078c2ecf20Sopenharmony_ci/* 0 = 24bit VGA, 1 = 18bit VGA */ 1088c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_LCD_N24BITEN BIT(19) 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#define INTEGRATOR_CLCD_MASK GENMASK(19, 8) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void pl111_integrator_enable(struct drm_device *drm, u32 format) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci u32 val; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci dev_info(drm->dev, "enable Integrator CLCD connectors\n"); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* FIXME: really needed? */ 1198c2ecf20Sopenharmony_ci val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 | 1208c2ecf20Sopenharmony_ci INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci switch (format) { 1238c2ecf20Sopenharmony_ci case DRM_FORMAT_XBGR8888: 1248c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB8888: 1258c2ecf20Sopenharmony_ci /* 24bit formats */ 1268c2ecf20Sopenharmony_ci val |= INTEGRATOR_CLCD_LCDMUX_VGA24; 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci case DRM_FORMAT_XBGR1555: 1298c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB1555: 1308c2ecf20Sopenharmony_ci /* Pseudocolor, RGB555, BGR555 */ 1318c2ecf20Sopenharmony_ci val |= INTEGRATOR_CLCD_LCDMUX_VGA555; 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci default: 1348c2ecf20Sopenharmony_ci dev_err(drm->dev, "unhandled format on Integrator 0x%08x\n", 1358c2ecf20Sopenharmony_ci format); 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci regmap_update_bits(versatile_syscon_map, 1408c2ecf20Sopenharmony_ci INTEGRATOR_HDR_CTRL_OFFSET, 1418c2ecf20Sopenharmony_ci INTEGRATOR_CLCD_MASK, 1428c2ecf20Sopenharmony_ci val); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define IMPD1_CTRL_OFFSET 0x18 1468c2ecf20Sopenharmony_ci#define IMPD1_CTRL_DISP_LCD (0 << 0) 1478c2ecf20Sopenharmony_ci#define IMPD1_CTRL_DISP_VGA (1 << 0) 1488c2ecf20Sopenharmony_ci#define IMPD1_CTRL_DISP_LCD1 (2 << 0) 1498c2ecf20Sopenharmony_ci#define IMPD1_CTRL_DISP_ENABLE (1 << 2) 1508c2ecf20Sopenharmony_ci#define IMPD1_CTRL_DISP_MASK (7 << 0) 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void pl111_impd1_enable(struct drm_device *drm, u32 format) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci u32 val; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci dev_info(drm->dev, "enable IM-PD1 CLCD connectors\n"); 1578c2ecf20Sopenharmony_ci val = IMPD1_CTRL_DISP_VGA | IMPD1_CTRL_DISP_ENABLE; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci regmap_update_bits(versatile_syscon_map, 1608c2ecf20Sopenharmony_ci IMPD1_CTRL_OFFSET, 1618c2ecf20Sopenharmony_ci IMPD1_CTRL_DISP_MASK, 1628c2ecf20Sopenharmony_ci val); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void pl111_impd1_disable(struct drm_device *drm) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci dev_info(drm->dev, "disable IM-PD1 CLCD connectors\n"); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci regmap_update_bits(versatile_syscon_map, 1708c2ecf20Sopenharmony_ci IMPD1_CTRL_OFFSET, 1718c2ecf20Sopenharmony_ci IMPD1_CTRL_DISP_MASK, 1728c2ecf20Sopenharmony_ci 0); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* 1768c2ecf20Sopenharmony_ci * This configuration register in the Versatile and RealView 1778c2ecf20Sopenharmony_ci * family is uniformly present but appears more and more 1788c2ecf20Sopenharmony_ci * unutilized starting with the RealView series. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci#define SYS_CLCD 0x50 1818c2ecf20Sopenharmony_ci#define SYS_CLCD_MODE_MASK (BIT(0)|BIT(1)) 1828c2ecf20Sopenharmony_ci#define SYS_CLCD_MODE_888 0 1838c2ecf20Sopenharmony_ci#define SYS_CLCD_MODE_5551 BIT(0) 1848c2ecf20Sopenharmony_ci#define SYS_CLCD_MODE_565_R_LSB BIT(1) 1858c2ecf20Sopenharmony_ci#define SYS_CLCD_MODE_565_B_LSB (BIT(0)|BIT(1)) 1868c2ecf20Sopenharmony_ci#define SYS_CLCD_CONNECTOR_MASK (BIT(2)|BIT(3)|BIT(4)|BIT(5)) 1878c2ecf20Sopenharmony_ci#define SYS_CLCD_NLCDIOON BIT(2) 1888c2ecf20Sopenharmony_ci#define SYS_CLCD_VDDPOSSWITCH BIT(3) 1898c2ecf20Sopenharmony_ci#define SYS_CLCD_PWR3V5SWITCH BIT(4) 1908c2ecf20Sopenharmony_ci#define SYS_CLCD_VDDNEGSWITCH BIT(5) 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void pl111_versatile_disable(struct drm_device *drm) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci dev_info(drm->dev, "disable Versatile CLCD connectors\n"); 1958c2ecf20Sopenharmony_ci regmap_update_bits(versatile_syscon_map, 1968c2ecf20Sopenharmony_ci SYS_CLCD, 1978c2ecf20Sopenharmony_ci SYS_CLCD_CONNECTOR_MASK, 1988c2ecf20Sopenharmony_ci 0); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic void pl111_versatile_enable(struct drm_device *drm, u32 format) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci u32 val = 0; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci dev_info(drm->dev, "enable Versatile CLCD connectors\n"); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci switch (format) { 2088c2ecf20Sopenharmony_ci case DRM_FORMAT_ABGR8888: 2098c2ecf20Sopenharmony_ci case DRM_FORMAT_XBGR8888: 2108c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB8888: 2118c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB8888: 2128c2ecf20Sopenharmony_ci val |= SYS_CLCD_MODE_888; 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci case DRM_FORMAT_BGR565: 2158c2ecf20Sopenharmony_ci val |= SYS_CLCD_MODE_565_R_LSB; 2168c2ecf20Sopenharmony_ci break; 2178c2ecf20Sopenharmony_ci case DRM_FORMAT_RGB565: 2188c2ecf20Sopenharmony_ci val |= SYS_CLCD_MODE_565_B_LSB; 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci case DRM_FORMAT_ABGR1555: 2218c2ecf20Sopenharmony_ci case DRM_FORMAT_XBGR1555: 2228c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB1555: 2238c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB1555: 2248c2ecf20Sopenharmony_ci val |= SYS_CLCD_MODE_5551; 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci default: 2278c2ecf20Sopenharmony_ci dev_err(drm->dev, "unhandled format on Versatile 0x%08x\n", 2288c2ecf20Sopenharmony_ci format); 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Set up the MUX */ 2338c2ecf20Sopenharmony_ci regmap_update_bits(versatile_syscon_map, 2348c2ecf20Sopenharmony_ci SYS_CLCD, 2358c2ecf20Sopenharmony_ci SYS_CLCD_MODE_MASK, 2368c2ecf20Sopenharmony_ci val); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Then enable the display */ 2398c2ecf20Sopenharmony_ci regmap_update_bits(versatile_syscon_map, 2408c2ecf20Sopenharmony_ci SYS_CLCD, 2418c2ecf20Sopenharmony_ci SYS_CLCD_CONNECTOR_MASK, 2428c2ecf20Sopenharmony_ci SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void pl111_realview_clcd_disable(struct drm_device *drm) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci dev_info(drm->dev, "disable RealView CLCD connectors\n"); 2488c2ecf20Sopenharmony_ci regmap_update_bits(versatile_syscon_map, 2498c2ecf20Sopenharmony_ci SYS_CLCD, 2508c2ecf20Sopenharmony_ci SYS_CLCD_CONNECTOR_MASK, 2518c2ecf20Sopenharmony_ci 0); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void pl111_realview_clcd_enable(struct drm_device *drm, u32 format) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci dev_info(drm->dev, "enable RealView CLCD connectors\n"); 2578c2ecf20Sopenharmony_ci regmap_update_bits(versatile_syscon_map, 2588c2ecf20Sopenharmony_ci SYS_CLCD, 2598c2ecf20Sopenharmony_ci SYS_CLCD_CONNECTOR_MASK, 2608c2ecf20Sopenharmony_ci SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/* PL110 pixel formats for Integrator, vanilla PL110 */ 2648c2ecf20Sopenharmony_cistatic const u32 pl110_integrator_pixel_formats[] = { 2658c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR8888, 2668c2ecf20Sopenharmony_ci DRM_FORMAT_XBGR8888, 2678c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB8888, 2688c2ecf20Sopenharmony_ci DRM_FORMAT_XRGB8888, 2698c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR1555, 2708c2ecf20Sopenharmony_ci DRM_FORMAT_XBGR1555, 2718c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB1555, 2728c2ecf20Sopenharmony_ci DRM_FORMAT_XRGB1555, 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* Extended PL110 pixel formats for Integrator and Versatile */ 2768c2ecf20Sopenharmony_cistatic const u32 pl110_versatile_pixel_formats[] = { 2778c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR8888, 2788c2ecf20Sopenharmony_ci DRM_FORMAT_XBGR8888, 2798c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB8888, 2808c2ecf20Sopenharmony_ci DRM_FORMAT_XRGB8888, 2818c2ecf20Sopenharmony_ci DRM_FORMAT_BGR565, /* Uses external PLD */ 2828c2ecf20Sopenharmony_ci DRM_FORMAT_RGB565, /* Uses external PLD */ 2838c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR1555, 2848c2ecf20Sopenharmony_ci DRM_FORMAT_XBGR1555, 2858c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB1555, 2868c2ecf20Sopenharmony_ci DRM_FORMAT_XRGB1555, 2878c2ecf20Sopenharmony_ci}; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic const u32 pl111_realview_pixel_formats[] = { 2908c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR8888, 2918c2ecf20Sopenharmony_ci DRM_FORMAT_XBGR8888, 2928c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB8888, 2938c2ecf20Sopenharmony_ci DRM_FORMAT_XRGB8888, 2948c2ecf20Sopenharmony_ci DRM_FORMAT_BGR565, 2958c2ecf20Sopenharmony_ci DRM_FORMAT_RGB565, 2968c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR1555, 2978c2ecf20Sopenharmony_ci DRM_FORMAT_XBGR1555, 2988c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB1555, 2998c2ecf20Sopenharmony_ci DRM_FORMAT_XRGB1555, 3008c2ecf20Sopenharmony_ci DRM_FORMAT_ABGR4444, 3018c2ecf20Sopenharmony_ci DRM_FORMAT_XBGR4444, 3028c2ecf20Sopenharmony_ci DRM_FORMAT_ARGB4444, 3038c2ecf20Sopenharmony_ci DRM_FORMAT_XRGB4444, 3048c2ecf20Sopenharmony_ci}; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* 3078c2ecf20Sopenharmony_ci * The Integrator variant is a PL110 with a bunch of broken, or not 3088c2ecf20Sopenharmony_ci * yet implemented features 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_cistatic const struct pl111_variant_data pl110_integrator = { 3118c2ecf20Sopenharmony_ci .name = "PL110 Integrator", 3128c2ecf20Sopenharmony_ci .is_pl110 = true, 3138c2ecf20Sopenharmony_ci .broken_clockdivider = true, 3148c2ecf20Sopenharmony_ci .broken_vblank = true, 3158c2ecf20Sopenharmony_ci .formats = pl110_integrator_pixel_formats, 3168c2ecf20Sopenharmony_ci .nformats = ARRAY_SIZE(pl110_integrator_pixel_formats), 3178c2ecf20Sopenharmony_ci .fb_bpp = 16, 3188c2ecf20Sopenharmony_ci}; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/* 3218c2ecf20Sopenharmony_ci * The IM-PD1 variant is a PL110 with a bunch of broken, or not 3228c2ecf20Sopenharmony_ci * yet implemented features 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_cistatic const struct pl111_variant_data pl110_impd1 = { 3258c2ecf20Sopenharmony_ci .name = "PL110 IM-PD1", 3268c2ecf20Sopenharmony_ci .is_pl110 = true, 3278c2ecf20Sopenharmony_ci .broken_clockdivider = true, 3288c2ecf20Sopenharmony_ci .broken_vblank = true, 3298c2ecf20Sopenharmony_ci .formats = pl110_integrator_pixel_formats, 3308c2ecf20Sopenharmony_ci .nformats = ARRAY_SIZE(pl110_integrator_pixel_formats), 3318c2ecf20Sopenharmony_ci .fb_bpp = 16, 3328c2ecf20Sopenharmony_ci}; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * This is the in-between PL110 variant found in the ARM Versatile, 3368c2ecf20Sopenharmony_ci * supporting RGB565/BGR565 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_cistatic const struct pl111_variant_data pl110_versatile = { 3398c2ecf20Sopenharmony_ci .name = "PL110 Versatile", 3408c2ecf20Sopenharmony_ci .is_pl110 = true, 3418c2ecf20Sopenharmony_ci .external_bgr = true, 3428c2ecf20Sopenharmony_ci .formats = pl110_versatile_pixel_formats, 3438c2ecf20Sopenharmony_ci .nformats = ARRAY_SIZE(pl110_versatile_pixel_formats), 3448c2ecf20Sopenharmony_ci .fb_bpp = 16, 3458c2ecf20Sopenharmony_ci}; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci/* 3488c2ecf20Sopenharmony_ci * RealView PL111 variant, the only real difference from the vanilla 3498c2ecf20Sopenharmony_ci * PL111 is that we select 16bpp framebuffer by default to be able 3508c2ecf20Sopenharmony_ci * to get 1024x768 without saturating the memory bus. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_cistatic const struct pl111_variant_data pl111_realview = { 3538c2ecf20Sopenharmony_ci .name = "PL111 RealView", 3548c2ecf20Sopenharmony_ci .formats = pl111_realview_pixel_formats, 3558c2ecf20Sopenharmony_ci .nformats = ARRAY_SIZE(pl111_realview_pixel_formats), 3568c2ecf20Sopenharmony_ci .fb_bpp = 16, 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/* 3608c2ecf20Sopenharmony_ci * Versatile Express PL111 variant, again we just push the maximum 3618c2ecf20Sopenharmony_ci * BPP to 16 to be able to get 1024x768 without saturating the memory 3628c2ecf20Sopenharmony_ci * bus. The clockdivider also seems broken on the Versatile Express. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_cistatic const struct pl111_variant_data pl111_vexpress = { 3658c2ecf20Sopenharmony_ci .name = "PL111 Versatile Express", 3668c2ecf20Sopenharmony_ci .formats = pl111_realview_pixel_formats, 3678c2ecf20Sopenharmony_ci .nformats = ARRAY_SIZE(pl111_realview_pixel_formats), 3688c2ecf20Sopenharmony_ci .fb_bpp = 16, 3698c2ecf20Sopenharmony_ci .broken_clockdivider = true, 3708c2ecf20Sopenharmony_ci}; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci#define VEXPRESS_FPGAMUX_MOTHERBOARD 0x00 3738c2ecf20Sopenharmony_ci#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01 3748c2ecf20Sopenharmony_ci#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np, 3778c2ecf20Sopenharmony_ci struct pl111_drm_dev_private *priv) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct platform_device *pdev; 3808c2ecf20Sopenharmony_ci struct device_node *root; 3818c2ecf20Sopenharmony_ci struct device_node *child; 3828c2ecf20Sopenharmony_ci struct device_node *ct_clcd = NULL; 3838c2ecf20Sopenharmony_ci struct regmap *map; 3848c2ecf20Sopenharmony_ci bool has_coretile_clcd = false; 3858c2ecf20Sopenharmony_ci bool has_coretile_hdlcd = false; 3868c2ecf20Sopenharmony_ci bool mux_motherboard = true; 3878c2ecf20Sopenharmony_ci u32 val; 3888c2ecf20Sopenharmony_ci int ret; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_VEXPRESS_CONFIG)) 3918c2ecf20Sopenharmony_ci return -ENODEV; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* 3948c2ecf20Sopenharmony_ci * Check if we have a CLCD or HDLCD on the core tile by checking if a 3958c2ecf20Sopenharmony_ci * CLCD or HDLCD is available in the root of the device tree. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci root = of_find_node_by_path("/"); 3988c2ecf20Sopenharmony_ci if (!root) 3998c2ecf20Sopenharmony_ci return -EINVAL; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci for_each_available_child_of_node(root, child) { 4028c2ecf20Sopenharmony_ci if (of_device_is_compatible(child, "arm,pl111")) { 4038c2ecf20Sopenharmony_ci has_coretile_clcd = true; 4048c2ecf20Sopenharmony_ci ct_clcd = child; 4058c2ecf20Sopenharmony_ci of_node_put(child); 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci if (of_device_is_compatible(child, "arm,hdlcd")) { 4098c2ecf20Sopenharmony_ci has_coretile_hdlcd = true; 4108c2ecf20Sopenharmony_ci of_node_put(child); 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci of_node_put(root); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* 4188c2ecf20Sopenharmony_ci * If there is a coretile HDLCD and it has a driver, 4198c2ecf20Sopenharmony_ci * do not mux the CLCD on the motherboard to the DVI. 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci if (has_coretile_hdlcd && IS_ENABLED(CONFIG_DRM_HDLCD)) 4228c2ecf20Sopenharmony_ci mux_motherboard = false; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* 4258c2ecf20Sopenharmony_ci * On the Vexpress CA9 we let the CLCD on the coretile 4268c2ecf20Sopenharmony_ci * take precedence, so also in this case do not mux the 4278c2ecf20Sopenharmony_ci * motherboard to the DVI. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci if (has_coretile_clcd) 4308c2ecf20Sopenharmony_ci mux_motherboard = false; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (mux_motherboard) { 4338c2ecf20Sopenharmony_ci dev_info(dev, "DVI muxed to motherboard CLCD\n"); 4348c2ecf20Sopenharmony_ci val = VEXPRESS_FPGAMUX_MOTHERBOARD; 4358c2ecf20Sopenharmony_ci } else if (ct_clcd == dev->of_node) { 4368c2ecf20Sopenharmony_ci dev_info(dev, 4378c2ecf20Sopenharmony_ci "DVI muxed to daughterboard 1 (core tile) CLCD\n"); 4388c2ecf20Sopenharmony_ci val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1; 4398c2ecf20Sopenharmony_ci } else { 4408c2ecf20Sopenharmony_ci dev_info(dev, "core tile graphics present\n"); 4418c2ecf20Sopenharmony_ci dev_info(dev, "this device will be deactivated\n"); 4428c2ecf20Sopenharmony_ci return -ENODEV; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* Call into deep Vexpress configuration API */ 4468c2ecf20Sopenharmony_ci pdev = of_find_device_by_node(np); 4478c2ecf20Sopenharmony_ci if (!pdev) { 4488c2ecf20Sopenharmony_ci dev_err(dev, "can't find the sysreg device, deferring\n"); 4498c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci map = devm_regmap_init_vexpress_config(&pdev->dev); 4538c2ecf20Sopenharmony_ci if (IS_ERR(map)) { 4548c2ecf20Sopenharmony_ci platform_device_put(pdev); 4558c2ecf20Sopenharmony_ci return PTR_ERR(map); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci ret = regmap_write(map, 0, val); 4598c2ecf20Sopenharmony_ci platform_device_put(pdev); 4608c2ecf20Sopenharmony_ci if (ret) { 4618c2ecf20Sopenharmony_ci dev_err(dev, "error setting DVI muxmode\n"); 4628c2ecf20Sopenharmony_ci return -ENODEV; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci priv->variant = &pl111_vexpress; 4668c2ecf20Sopenharmony_ci dev_info(dev, "initializing Versatile Express PL111\n"); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ciint pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci const struct of_device_id *clcd_id; 4748c2ecf20Sopenharmony_ci enum versatile_clcd versatile_clcd_type; 4758c2ecf20Sopenharmony_ci struct device_node *np; 4768c2ecf20Sopenharmony_ci struct regmap *map; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match, 4798c2ecf20Sopenharmony_ci &clcd_id); 4808c2ecf20Sopenharmony_ci if (!np) { 4818c2ecf20Sopenharmony_ci /* Non-ARM reference designs, just bail out */ 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci versatile_clcd_type = (enum versatile_clcd)clcd_id->data; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* Versatile Express special handling */ 4888c2ecf20Sopenharmony_ci if (versatile_clcd_type == VEXPRESS_CLCD_V2M) { 4898c2ecf20Sopenharmony_ci int ret = pl111_vexpress_clcd_init(dev, np, priv); 4908c2ecf20Sopenharmony_ci of_node_put(np); 4918c2ecf20Sopenharmony_ci if (ret) 4928c2ecf20Sopenharmony_ci dev_err(dev, "Versatile Express init failed - %d", ret); 4938c2ecf20Sopenharmony_ci return ret; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * On the Integrator, check if we should use the IM-PD1 instead, 4988c2ecf20Sopenharmony_ci * if we find it, it will take precedence. This is on the Integrator/AP 4998c2ecf20Sopenharmony_ci * which only has this option for PL110 graphics. 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_ci if (versatile_clcd_type == INTEGRATOR_CLCD_CM) { 5028c2ecf20Sopenharmony_ci np = of_find_matching_node_and_match(NULL, impd1_clcd_of_match, 5038c2ecf20Sopenharmony_ci &clcd_id); 5048c2ecf20Sopenharmony_ci if (np) 5058c2ecf20Sopenharmony_ci versatile_clcd_type = (enum versatile_clcd)clcd_id->data; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci map = syscon_node_to_regmap(np); 5098c2ecf20Sopenharmony_ci of_node_put(np); 5108c2ecf20Sopenharmony_ci if (IS_ERR(map)) { 5118c2ecf20Sopenharmony_ci dev_err(dev, "no Versatile syscon regmap\n"); 5128c2ecf20Sopenharmony_ci return PTR_ERR(map); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci switch (versatile_clcd_type) { 5168c2ecf20Sopenharmony_ci case INTEGRATOR_CLCD_CM: 5178c2ecf20Sopenharmony_ci versatile_syscon_map = map; 5188c2ecf20Sopenharmony_ci priv->variant = &pl110_integrator; 5198c2ecf20Sopenharmony_ci priv->variant_display_enable = pl111_integrator_enable; 5208c2ecf20Sopenharmony_ci dev_info(dev, "set up callbacks for Integrator PL110\n"); 5218c2ecf20Sopenharmony_ci break; 5228c2ecf20Sopenharmony_ci case INTEGRATOR_IMPD1: 5238c2ecf20Sopenharmony_ci versatile_syscon_map = map; 5248c2ecf20Sopenharmony_ci priv->variant = &pl110_impd1; 5258c2ecf20Sopenharmony_ci priv->variant_display_enable = pl111_impd1_enable; 5268c2ecf20Sopenharmony_ci priv->variant_display_disable = pl111_impd1_disable; 5278c2ecf20Sopenharmony_ci dev_info(dev, "set up callbacks for IM-PD1 PL110\n"); 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci case VERSATILE_CLCD: 5308c2ecf20Sopenharmony_ci versatile_syscon_map = map; 5318c2ecf20Sopenharmony_ci /* This can do RGB565 with external PLD */ 5328c2ecf20Sopenharmony_ci priv->variant = &pl110_versatile; 5338c2ecf20Sopenharmony_ci priv->variant_display_enable = pl111_versatile_enable; 5348c2ecf20Sopenharmony_ci priv->variant_display_disable = pl111_versatile_disable; 5358c2ecf20Sopenharmony_ci /* 5368c2ecf20Sopenharmony_ci * The Versatile has a variant halfway between PL110 5378c2ecf20Sopenharmony_ci * and PL111 where these two registers have already been 5388c2ecf20Sopenharmony_ci * swapped. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_ci priv->ienb = CLCD_PL111_IENB; 5418c2ecf20Sopenharmony_ci priv->ctrl = CLCD_PL111_CNTL; 5428c2ecf20Sopenharmony_ci dev_info(dev, "set up callbacks for Versatile PL110\n"); 5438c2ecf20Sopenharmony_ci break; 5448c2ecf20Sopenharmony_ci case REALVIEW_CLCD_EB: 5458c2ecf20Sopenharmony_ci case REALVIEW_CLCD_PB1176: 5468c2ecf20Sopenharmony_ci case REALVIEW_CLCD_PB11MP: 5478c2ecf20Sopenharmony_ci case REALVIEW_CLCD_PBA8: 5488c2ecf20Sopenharmony_ci case REALVIEW_CLCD_PBX: 5498c2ecf20Sopenharmony_ci versatile_syscon_map = map; 5508c2ecf20Sopenharmony_ci priv->variant = &pl111_realview; 5518c2ecf20Sopenharmony_ci priv->variant_display_enable = pl111_realview_clcd_enable; 5528c2ecf20Sopenharmony_ci priv->variant_display_disable = pl111_realview_clcd_disable; 5538c2ecf20Sopenharmony_ci dev_info(dev, "set up callbacks for RealView PL111\n"); 5548c2ecf20Sopenharmony_ci break; 5558c2ecf20Sopenharmony_ci default: 5568c2ecf20Sopenharmony_ci dev_info(dev, "unknown Versatile system controller\n"); 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return 0; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pl111_versatile_init); 563