1 #include <linux/device.h> 2 #include <linux/of.h> 3 #include <linux/regmap.h> 4 #include <linux/mfd/syscon.h> 5 #include <linux/bitops.h> 6 #include <linux/module.h> 7 #include <drm/drmP.h> 8 #include "pl111_versatile.h" 9 #include "pl111_drm.h" 10 11 static struct regmap *versatile_syscon_map; 12 13 /* 14 * We detect the different syscon types from the compatible strings. 15 */ 16 enum versatile_clcd { 17 INTEGRATOR_CLCD_CM, 18 VERSATILE_CLCD, 19 REALVIEW_CLCD_EB, 20 REALVIEW_CLCD_PB1176, 21 REALVIEW_CLCD_PB11MP, 22 REALVIEW_CLCD_PBA8, 23 REALVIEW_CLCD_PBX, 24 }; 25 26 static const struct of_device_id versatile_clcd_of_match[] = { 27 { 28 .compatible = "arm,core-module-integrator", 29 .data = (void *)INTEGRATOR_CLCD_CM, 30 }, 31 { 32 .compatible = "arm,versatile-sysreg", 33 .data = (void *)VERSATILE_CLCD, 34 }, 35 { 36 .compatible = "arm,realview-eb-syscon", 37 .data = (void *)REALVIEW_CLCD_EB, 38 }, 39 { 40 .compatible = "arm,realview-pb1176-syscon", 41 .data = (void *)REALVIEW_CLCD_PB1176, 42 }, 43 { 44 .compatible = "arm,realview-pb11mp-syscon", 45 .data = (void *)REALVIEW_CLCD_PB11MP, 46 }, 47 { 48 .compatible = "arm,realview-pba8-syscon", 49 .data = (void *)REALVIEW_CLCD_PBA8, 50 }, 51 { 52 .compatible = "arm,realview-pbx-syscon", 53 .data = (void *)REALVIEW_CLCD_PBX, 54 }, 55 {}, 56 }; 57 58 /* 59 * Core module CLCD control on the Integrator/CP, bits 60 * 8 thru 19 of the CM_CONTROL register controls a bunch 61 * of CLCD settings. 62 */ 63 #define INTEGRATOR_HDR_CTRL_OFFSET 0x0C 64 #define INTEGRATOR_CLCD_LCDBIASEN BIT(8) 65 #define INTEGRATOR_CLCD_LCDBIASUP BIT(9) 66 #define INTEGRATOR_CLCD_LCDBIASDN BIT(10) 67 /* Bits 11,12,13 controls the LCD type */ 68 #define INTEGRATOR_CLCD_LCDMUX_MASK (BIT(11)|BIT(12)|BIT(13)) 69 #define INTEGRATOR_CLCD_LCDMUX_LCD24 BIT(11) 70 #define INTEGRATOR_CLCD_LCDMUX_VGA565 BIT(12) 71 #define INTEGRATOR_CLCD_LCDMUX_SHARP (BIT(11)|BIT(12)) 72 #define INTEGRATOR_CLCD_LCDMUX_VGA555 BIT(13) 73 #define INTEGRATOR_CLCD_LCDMUX_VGA24 (BIT(11)|BIT(12)|BIT(13)) 74 #define INTEGRATOR_CLCD_LCD0_EN BIT(14) 75 #define INTEGRATOR_CLCD_LCD1_EN BIT(15) 76 /* R/L flip on Sharp */ 77 #define INTEGRATOR_CLCD_LCD_STATIC1 BIT(16) 78 /* U/D flip on Sharp */ 79 #define INTEGRATOR_CLCD_LCD_STATIC2 BIT(17) 80 /* No connection on Sharp */ 81 #define INTEGRATOR_CLCD_LCD_STATIC BIT(18) 82 /* 0 = 24bit VGA, 1 = 18bit VGA */ 83 #define INTEGRATOR_CLCD_LCD_N24BITEN BIT(19) 84 85 #define INTEGRATOR_CLCD_MASK (INTEGRATOR_CLCD_LCDBIASEN | \ 86 INTEGRATOR_CLCD_LCDBIASUP | \ 87 INTEGRATOR_CLCD_LCDBIASDN | \ 88 INTEGRATOR_CLCD_LCDMUX_MASK | \ 89 INTEGRATOR_CLCD_LCD0_EN | \ 90 INTEGRATOR_CLCD_LCD1_EN | \ 91 INTEGRATOR_CLCD_LCD_STATIC1 | \ 92 INTEGRATOR_CLCD_LCD_STATIC2 | \ 93 INTEGRATOR_CLCD_LCD_STATIC | \ 94 INTEGRATOR_CLCD_LCD_N24BITEN) 95 96 static void pl111_integrator_enable(struct drm_device *drm, u32 format) 97 { 98 u32 val; 99 100 dev_info(drm->dev, "enable Integrator CLCD connectors\n"); 101 102 /* FIXME: really needed? */ 103 val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 | 104 INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN; 105 106 switch (format) { 107 case DRM_FORMAT_XBGR8888: 108 case DRM_FORMAT_XRGB8888: 109 break; 110 case DRM_FORMAT_BGR565: 111 case DRM_FORMAT_RGB565: 112 /* truecolor RGB565 */ 113 val |= INTEGRATOR_CLCD_LCDMUX_VGA565; 114 break; 115 case DRM_FORMAT_XBGR1555: 116 case DRM_FORMAT_XRGB1555: 117 /* Pseudocolor, RGB555, BGR555 */ 118 val |= INTEGRATOR_CLCD_LCDMUX_VGA555; 119 break; 120 default: 121 dev_err(drm->dev, "unhandled format on Integrator 0x%08x\n", 122 format); 123 break; 124 } 125 126 regmap_update_bits(versatile_syscon_map, 127 INTEGRATOR_HDR_CTRL_OFFSET, 128 INTEGRATOR_CLCD_MASK, 129 val); 130 } 131 132 /* 133 * This configuration register in the Versatile and RealView 134 * family is uniformly present but appears more and more 135 * unutilized starting with the RealView series. 136 */ 137 #define SYS_CLCD 0x50 138 #define SYS_CLCD_MODE_MASK (BIT(0)|BIT(1)) 139 #define SYS_CLCD_MODE_888 0 140 #define SYS_CLCD_MODE_5551 BIT(0) 141 #define SYS_CLCD_MODE_565_R_LSB BIT(1) 142 #define SYS_CLCD_MODE_565_B_LSB (BIT(0)|BIT(1)) 143 #define SYS_CLCD_CONNECTOR_MASK (BIT(2)|BIT(3)|BIT(4)|BIT(5)) 144 #define SYS_CLCD_NLCDIOON BIT(2) 145 #define SYS_CLCD_VDDPOSSWITCH BIT(3) 146 #define SYS_CLCD_PWR3V5SWITCH BIT(4) 147 #define SYS_CLCD_VDDNEGSWITCH BIT(5) 148 149 static void pl111_versatile_disable(struct drm_device *drm) 150 { 151 dev_info(drm->dev, "disable Versatile CLCD connectors\n"); 152 regmap_update_bits(versatile_syscon_map, 153 SYS_CLCD, 154 SYS_CLCD_CONNECTOR_MASK, 155 0); 156 } 157 158 static void pl111_versatile_enable(struct drm_device *drm, u32 format) 159 { 160 u32 val = 0; 161 162 dev_info(drm->dev, "enable Versatile CLCD connectors\n"); 163 164 switch (format) { 165 case DRM_FORMAT_ABGR8888: 166 case DRM_FORMAT_XBGR8888: 167 case DRM_FORMAT_ARGB8888: 168 case DRM_FORMAT_XRGB8888: 169 val |= SYS_CLCD_MODE_888; 170 break; 171 case DRM_FORMAT_BGR565: 172 val |= SYS_CLCD_MODE_565_R_LSB; 173 break; 174 case DRM_FORMAT_RGB565: 175 val |= SYS_CLCD_MODE_565_B_LSB; 176 break; 177 case DRM_FORMAT_ABGR1555: 178 case DRM_FORMAT_XBGR1555: 179 case DRM_FORMAT_ARGB1555: 180 case DRM_FORMAT_XRGB1555: 181 val |= SYS_CLCD_MODE_5551; 182 break; 183 default: 184 dev_err(drm->dev, "unhandled format on Versatile 0x%08x\n", 185 format); 186 break; 187 } 188 189 /* Set up the MUX */ 190 regmap_update_bits(versatile_syscon_map, 191 SYS_CLCD, 192 SYS_CLCD_MODE_MASK, 193 val); 194 195 /* Then enable the display */ 196 regmap_update_bits(versatile_syscon_map, 197 SYS_CLCD, 198 SYS_CLCD_CONNECTOR_MASK, 199 SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); 200 } 201 202 static void pl111_realview_clcd_disable(struct drm_device *drm) 203 { 204 dev_info(drm->dev, "disable RealView CLCD connectors\n"); 205 regmap_update_bits(versatile_syscon_map, 206 SYS_CLCD, 207 SYS_CLCD_CONNECTOR_MASK, 208 0); 209 } 210 211 static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format) 212 { 213 dev_info(drm->dev, "enable RealView CLCD connectors\n"); 214 regmap_update_bits(versatile_syscon_map, 215 SYS_CLCD, 216 SYS_CLCD_CONNECTOR_MASK, 217 SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH); 218 } 219 220 int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) 221 { 222 const struct of_device_id *clcd_id; 223 enum versatile_clcd versatile_clcd_type; 224 struct device_node *np; 225 struct regmap *map; 226 227 np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match, 228 &clcd_id); 229 if (!np) { 230 /* Non-ARM reference designs, just bail out */ 231 return 0; 232 } 233 versatile_clcd_type = (enum versatile_clcd)clcd_id->data; 234 235 map = syscon_node_to_regmap(np); 236 if (IS_ERR(map)) { 237 dev_err(dev, "no Versatile syscon regmap\n"); 238 return PTR_ERR(map); 239 } 240 241 switch (versatile_clcd_type) { 242 case INTEGRATOR_CLCD_CM: 243 versatile_syscon_map = map; 244 priv->variant_display_enable = pl111_integrator_enable; 245 dev_info(dev, "set up callbacks for Integrator PL110\n"); 246 break; 247 case VERSATILE_CLCD: 248 versatile_syscon_map = map; 249 priv->variant_display_enable = pl111_versatile_enable; 250 priv->variant_display_disable = pl111_versatile_disable; 251 dev_info(dev, "set up callbacks for Versatile PL110+\n"); 252 break; 253 case REALVIEW_CLCD_EB: 254 case REALVIEW_CLCD_PB1176: 255 case REALVIEW_CLCD_PB11MP: 256 case REALVIEW_CLCD_PBA8: 257 case REALVIEW_CLCD_PBX: 258 versatile_syscon_map = map; 259 priv->variant_display_enable = pl111_realview_clcd_enable; 260 priv->variant_display_disable = pl111_realview_clcd_disable; 261 dev_info(dev, "set up callbacks for RealView PL111\n"); 262 break; 263 default: 264 dev_info(dev, "unknown Versatile system controller\n"); 265 break; 266 } 267 268 return 0; 269 } 270 EXPORT_SYMBOL_GPL(pl111_versatile_init); 271