Merge branch 'linus-4.14-rc4-acp-prereq' of git://people.freedesktop.org/~agd5f/linux...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / pl111 / pl111_versatile.c
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);