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 16 static struct regmap *versatile_syscon_map; 17 18 /* 19 * We detect the different syscon types from the compatible strings. 20 */ 21 enum 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 32 static 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 95 static 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 145 static 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 154 static 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 198 static 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 207 static 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 */ 217 static 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 */ 229 static 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 242 static 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 */ 263 static 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 */ 277 static 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 */ 291 static 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 */ 303 static 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 311 int 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 } 410 EXPORT_SYMBOL_GPL(pl111_versatile_init); 411