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