Merge tag 'mtd/for-4.17' of git://git.infradead.org/linux-mtd
[linux-2.6-microblaze.git] / drivers / gpu / drm / pl111 / pl111_versatile.c
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);