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