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