diff options
author | Kirill A. Shutemov <kirill.shutemov@linux.intel.com> | 2012-03-08 11:02:20 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-03-10 08:05:48 -0500 |
commit | 026abc333205c1fff80138b8c2cac3d0347685f4 (patch) | |
tree | dbcb2ad763f96b5f0c99ec5650f477aa103a8528 /drivers/gpu/drm/gma500 | |
parent | c6265ff593467d472814aa9f16f89f6c1dc90a5d (diff) |
gma500: initial medfield merge
We need to merge this ahead of some of the cleanup because a lot of needed
cleanup spans both new and old chips. If we try and clean up and the merge
we end up fighting ourselves.
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
[With a load of the cleanup stuff folded in, register stuff reworked sanely]
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/gma500')
20 files changed, 6318 insertions, 0 deletions
diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig index f92a7f4208d1..42e665c7e90a 100644 --- a/drivers/gpu/drm/gma500/Kconfig +++ b/drivers/gpu/drm/gma500/Kconfig | |||
@@ -24,3 +24,10 @@ config DRM_GMA3600 | |||
24 | help | 24 | help |
25 | Say yes to include basic support for Intel GMA3600/3650 (Intel | 25 | Say yes to include basic support for Intel GMA3600/3650 (Intel |
26 | Cedar Trail) platforms. | 26 | Cedar Trail) platforms. |
27 | |||
28 | config DRM_MEDFIELD | ||
29 | bool "Intel Medfield support (Experimental)" | ||
30 | depends on DRM_GMA500 && X86_INTEL_MID | ||
31 | help | ||
32 | Say yes to include support for the Intel Medfield platform. | ||
33 | |||
diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile index 81c103be5e21..1583982917ce 100644 --- a/drivers/gpu/drm/gma500/Makefile +++ b/drivers/gpu/drm/gma500/Makefile | |||
@@ -37,4 +37,14 @@ gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \ | |||
37 | oaktrail_hdmi.o \ | 37 | oaktrail_hdmi.o \ |
38 | oaktrail_hdmi_i2c.o | 38 | oaktrail_hdmi_i2c.o |
39 | 39 | ||
40 | gma500_gfx-$(CONFIG_DRM_MEDFIELD) += mdfld_device.o \ | ||
41 | mdfld_output.o \ | ||
42 | mdfld_intel_display.o \ | ||
43 | mdfld_dsi_output.o \ | ||
44 | mdfld_dsi_dpi.o \ | ||
45 | mdfld_dsi_pkg_sender.o \ | ||
46 | mdfld_tpo_vid.o \ | ||
47 | mdfld_tmd_vid.o \ | ||
48 | tc35876x-dsi-lvds.o | ||
49 | |||
40 | obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o | 50 | obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o |
diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c new file mode 100644 index 000000000000..6cfdda90eef1 --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_device.c | |||
@@ -0,0 +1,691 @@ | |||
1 | /************************************************************************** | ||
2 | * Copyright (c) 2011, Intel Corporation. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
17 | * | ||
18 | **************************************************************************/ | ||
19 | |||
20 | #include "psb_drv.h" | ||
21 | #include "mid_bios.h" | ||
22 | #include "mdfld_output.h" | ||
23 | #include "mdfld_dsi_output.h" | ||
24 | #include "tc35876x-dsi-lvds.h" | ||
25 | |||
26 | #include <asm/intel_scu_ipc.h> | ||
27 | |||
28 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
29 | |||
30 | #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF | ||
31 | #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ | ||
32 | #define BLC_PWM_FREQ_CALC_CONSTANT 32 | ||
33 | #define MHz 1000000 | ||
34 | #define BRIGHTNESS_MIN_LEVEL 1 | ||
35 | #define BRIGHTNESS_MAX_LEVEL 100 | ||
36 | #define BRIGHTNESS_MASK 0xFF | ||
37 | #define BLC_POLARITY_NORMAL 0 | ||
38 | #define BLC_POLARITY_INVERSE 1 | ||
39 | #define BLC_ADJUSTMENT_MAX 100 | ||
40 | |||
41 | #define MDFLD_BLC_PWM_PRECISION_FACTOR 10 | ||
42 | #define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE | ||
43 | #define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2 | ||
44 | |||
45 | #define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) | ||
46 | #define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16) | ||
47 | |||
48 | static struct backlight_device *mdfld_backlight_device; | ||
49 | |||
50 | int mdfld_set_brightness(struct backlight_device *bd) | ||
51 | { | ||
52 | struct drm_device *dev = | ||
53 | (struct drm_device *)bl_get_data(mdfld_backlight_device); | ||
54 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
55 | int level = bd->props.brightness; | ||
56 | |||
57 | DRM_DEBUG_DRIVER("backlight level set to %d\n", level); | ||
58 | |||
59 | /* Perform value bounds checking */ | ||
60 | if (level < BRIGHTNESS_MIN_LEVEL) | ||
61 | level = BRIGHTNESS_MIN_LEVEL; | ||
62 | |||
63 | if (gma_power_begin(dev, false)) { | ||
64 | u32 adjusted_level = 0; | ||
65 | |||
66 | /* | ||
67 | * Adjust the backlight level with the percent in | ||
68 | * dev_priv->blc_adj2 | ||
69 | */ | ||
70 | adjusted_level = level * dev_priv->blc_adj2; | ||
71 | adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX; | ||
72 | dev_priv->brightness_adjusted = adjusted_level; | ||
73 | |||
74 | if (mdfld_get_panel_type(dev, 0) == TC35876X) { | ||
75 | if (dev_priv->dpi_panel_on[0] || | ||
76 | dev_priv->dpi_panel_on[2]) | ||
77 | tc35876x_brightness_control(dev, | ||
78 | dev_priv->brightness_adjusted); | ||
79 | } else { | ||
80 | if (dev_priv->dpi_panel_on[0]) | ||
81 | mdfld_dsi_brightness_control(dev, 0, | ||
82 | dev_priv->brightness_adjusted); | ||
83 | } | ||
84 | |||
85 | if (dev_priv->dpi_panel_on[2]) | ||
86 | mdfld_dsi_brightness_control(dev, 2, | ||
87 | dev_priv->brightness_adjusted); | ||
88 | gma_power_end(dev); | ||
89 | } | ||
90 | |||
91 | /* cache the brightness for later use */ | ||
92 | dev_priv->brightness = level; | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | int mdfld_get_brightness(struct backlight_device *bd) | ||
97 | { | ||
98 | struct drm_device *dev = | ||
99 | (struct drm_device *)bl_get_data(mdfld_backlight_device); | ||
100 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
101 | |||
102 | DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness); | ||
103 | |||
104 | /* return locally cached var instead of HW read (due to DPST etc.) */ | ||
105 | return dev_priv->brightness; | ||
106 | } | ||
107 | |||
108 | static const struct backlight_ops mdfld_ops = { | ||
109 | .get_brightness = mdfld_get_brightness, | ||
110 | .update_status = mdfld_set_brightness, | ||
111 | }; | ||
112 | |||
113 | static int device_backlight_init(struct drm_device *dev) | ||
114 | { | ||
115 | struct drm_psb_private *dev_priv = (struct drm_psb_private *) | ||
116 | dev->dev_private; | ||
117 | |||
118 | dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX; | ||
119 | dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX; | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | int mdfld_backlight_init(struct drm_device *dev) | ||
125 | { | ||
126 | struct backlight_properties props; | ||
127 | int ret = 0; | ||
128 | |||
129 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
130 | props.max_brightness = BRIGHTNESS_MAX_LEVEL; | ||
131 | props.type = BACKLIGHT_PLATFORM; | ||
132 | mdfld_backlight_device = backlight_device_register("mdfld-bl", | ||
133 | NULL, (void *)dev, &mdfld_ops, &props); | ||
134 | |||
135 | if (IS_ERR(mdfld_backlight_device)) | ||
136 | return PTR_ERR(mdfld_backlight_device); | ||
137 | |||
138 | ret = device_backlight_init(dev); | ||
139 | if (ret) | ||
140 | return ret; | ||
141 | |||
142 | mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL; | ||
143 | mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL; | ||
144 | backlight_update_status(mdfld_backlight_device); | ||
145 | return 0; | ||
146 | } | ||
147 | #endif | ||
148 | |||
149 | struct backlight_device *mdfld_get_backlight_device(void) | ||
150 | { | ||
151 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
152 | return mdfld_backlight_device; | ||
153 | #else | ||
154 | return NULL; | ||
155 | #endif | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * mdfld_save_display_registers | ||
160 | * | ||
161 | * Description: We are going to suspend so save current display | ||
162 | * register state. | ||
163 | * | ||
164 | * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio | ||
165 | */ | ||
166 | static int mdfld_save_display_registers(struct drm_device *dev, int pipe) | ||
167 | { | ||
168 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
169 | struct medfield_state *regs = &dev_priv->regs.mdfld; | ||
170 | int i; | ||
171 | |||
172 | /* register */ | ||
173 | u32 dpll_reg = MRST_DPLL_A; | ||
174 | u32 fp_reg = MRST_FPA0; | ||
175 | u32 pipeconf_reg = PIPEACONF; | ||
176 | u32 htot_reg = HTOTAL_A; | ||
177 | u32 hblank_reg = HBLANK_A; | ||
178 | u32 hsync_reg = HSYNC_A; | ||
179 | u32 vtot_reg = VTOTAL_A; | ||
180 | u32 vblank_reg = VBLANK_A; | ||
181 | u32 vsync_reg = VSYNC_A; | ||
182 | u32 pipesrc_reg = PIPEASRC; | ||
183 | u32 dspstride_reg = DSPASTRIDE; | ||
184 | u32 dsplinoff_reg = DSPALINOFF; | ||
185 | u32 dsptileoff_reg = DSPATILEOFF; | ||
186 | u32 dspsize_reg = DSPASIZE; | ||
187 | u32 dsppos_reg = DSPAPOS; | ||
188 | u32 dspsurf_reg = DSPASURF; | ||
189 | u32 mipi_reg = MIPI; | ||
190 | u32 dspcntr_reg = DSPACNTR; | ||
191 | u32 dspstatus_reg = PIPEASTAT; | ||
192 | u32 palette_reg = PALETTE_A; | ||
193 | |||
194 | /* pointer to values */ | ||
195 | u32 *dpll_val = ®s->saveDPLL_A; | ||
196 | u32 *fp_val = ®s->saveFPA0; | ||
197 | u32 *pipeconf_val = ®s->savePIPEACONF; | ||
198 | u32 *htot_val = ®s->saveHTOTAL_A; | ||
199 | u32 *hblank_val = ®s->saveHBLANK_A; | ||
200 | u32 *hsync_val = ®s->saveHSYNC_A; | ||
201 | u32 *vtot_val = ®s->saveVTOTAL_A; | ||
202 | u32 *vblank_val = ®s->saveVBLANK_A; | ||
203 | u32 *vsync_val = ®s->saveVSYNC_A; | ||
204 | u32 *pipesrc_val = ®s->savePIPEASRC; | ||
205 | u32 *dspstride_val = ®s->saveDSPASTRIDE; | ||
206 | u32 *dsplinoff_val = ®s->saveDSPALINOFF; | ||
207 | u32 *dsptileoff_val = ®s->saveDSPATILEOFF; | ||
208 | u32 *dspsize_val = ®s->saveDSPASIZE; | ||
209 | u32 *dsppos_val = ®s->saveDSPAPOS; | ||
210 | u32 *dspsurf_val = ®s->saveDSPASURF; | ||
211 | u32 *mipi_val = ®s->saveMIPI; | ||
212 | u32 *dspcntr_val = ®s->saveDSPACNTR; | ||
213 | u32 *dspstatus_val = ®s->saveDSPASTATUS; | ||
214 | u32 *palette_val = regs->save_palette_a; | ||
215 | |||
216 | switch (pipe) { | ||
217 | case 0: | ||
218 | break; | ||
219 | case 1: | ||
220 | /* regester */ | ||
221 | dpll_reg = MDFLD_DPLL_B; | ||
222 | fp_reg = MDFLD_DPLL_DIV0; | ||
223 | pipeconf_reg = PIPEBCONF; | ||
224 | htot_reg = HTOTAL_B; | ||
225 | hblank_reg = HBLANK_B; | ||
226 | hsync_reg = HSYNC_B; | ||
227 | vtot_reg = VTOTAL_B; | ||
228 | vblank_reg = VBLANK_B; | ||
229 | vsync_reg = VSYNC_B; | ||
230 | pipesrc_reg = PIPEBSRC; | ||
231 | dspstride_reg = DSPBSTRIDE; | ||
232 | dsplinoff_reg = DSPBLINOFF; | ||
233 | dsptileoff_reg = DSPBTILEOFF; | ||
234 | dspsize_reg = DSPBSIZE; | ||
235 | dsppos_reg = DSPBPOS; | ||
236 | dspsurf_reg = DSPBSURF; | ||
237 | dspcntr_reg = DSPBCNTR; | ||
238 | dspstatus_reg = PIPEBSTAT; | ||
239 | palette_reg = PALETTE_B; | ||
240 | |||
241 | /* values */ | ||
242 | dpll_val = ®s->saveDPLL_B; | ||
243 | fp_val = ®s->saveFPB0; | ||
244 | pipeconf_val = ®s->savePIPEBCONF; | ||
245 | htot_val = ®s->saveHTOTAL_B; | ||
246 | hblank_val = ®s->saveHBLANK_B; | ||
247 | hsync_val = ®s->saveHSYNC_B; | ||
248 | vtot_val = ®s->saveVTOTAL_B; | ||
249 | vblank_val = ®s->saveVBLANK_B; | ||
250 | vsync_val = ®s->saveVSYNC_B; | ||
251 | pipesrc_val = ®s->savePIPEBSRC; | ||
252 | dspstride_val = ®s->saveDSPBSTRIDE; | ||
253 | dsplinoff_val = ®s->saveDSPBLINOFF; | ||
254 | dsptileoff_val = ®s->saveDSPBTILEOFF; | ||
255 | dspsize_val = ®s->saveDSPBSIZE; | ||
256 | dsppos_val = ®s->saveDSPBPOS; | ||
257 | dspsurf_val = ®s->saveDSPBSURF; | ||
258 | dspcntr_val = ®s->saveDSPBCNTR; | ||
259 | dspstatus_val = ®s->saveDSPBSTATUS; | ||
260 | palette_val = regs->save_palette_b; | ||
261 | break; | ||
262 | case 2: | ||
263 | /* register */ | ||
264 | pipeconf_reg = PIPECCONF; | ||
265 | htot_reg = HTOTAL_C; | ||
266 | hblank_reg = HBLANK_C; | ||
267 | hsync_reg = HSYNC_C; | ||
268 | vtot_reg = VTOTAL_C; | ||
269 | vblank_reg = VBLANK_C; | ||
270 | vsync_reg = VSYNC_C; | ||
271 | pipesrc_reg = PIPECSRC; | ||
272 | dspstride_reg = DSPCSTRIDE; | ||
273 | dsplinoff_reg = DSPCLINOFF; | ||
274 | dsptileoff_reg = DSPCTILEOFF; | ||
275 | dspsize_reg = DSPCSIZE; | ||
276 | dsppos_reg = DSPCPOS; | ||
277 | dspsurf_reg = DSPCSURF; | ||
278 | mipi_reg = MIPI_C; | ||
279 | dspcntr_reg = DSPCCNTR; | ||
280 | dspstatus_reg = PIPECSTAT; | ||
281 | palette_reg = PALETTE_C; | ||
282 | |||
283 | /* pointer to values */ | ||
284 | pipeconf_val = ®s->savePIPECCONF; | ||
285 | htot_val = ®s->saveHTOTAL_C; | ||
286 | hblank_val = ®s->saveHBLANK_C; | ||
287 | hsync_val = ®s->saveHSYNC_C; | ||
288 | vtot_val = ®s->saveVTOTAL_C; | ||
289 | vblank_val = ®s->saveVBLANK_C; | ||
290 | vsync_val = ®s->saveVSYNC_C; | ||
291 | pipesrc_val = ®s->savePIPECSRC; | ||
292 | dspstride_val = ®s->saveDSPCSTRIDE; | ||
293 | dsplinoff_val = ®s->saveDSPCLINOFF; | ||
294 | dsptileoff_val = ®s->saveDSPCTILEOFF; | ||
295 | dspsize_val = ®s->saveDSPCSIZE; | ||
296 | dsppos_val = ®s->saveDSPCPOS; | ||
297 | dspsurf_val = ®s->saveDSPCSURF; | ||
298 | mipi_val = ®s->saveMIPI_C; | ||
299 | dspcntr_val = ®s->saveDSPCCNTR; | ||
300 | dspstatus_val = ®s->saveDSPCSTATUS; | ||
301 | palette_val = regs->save_palette_c; | ||
302 | break; | ||
303 | default: | ||
304 | DRM_ERROR("%s, invalid pipe number.\n", __func__); | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | /* Pipe & plane A info */ | ||
309 | *dpll_val = PSB_RVDC32(dpll_reg); | ||
310 | *fp_val = PSB_RVDC32(fp_reg); | ||
311 | *pipeconf_val = PSB_RVDC32(pipeconf_reg); | ||
312 | *htot_val = PSB_RVDC32(htot_reg); | ||
313 | *hblank_val = PSB_RVDC32(hblank_reg); | ||
314 | *hsync_val = PSB_RVDC32(hsync_reg); | ||
315 | *vtot_val = PSB_RVDC32(vtot_reg); | ||
316 | *vblank_val = PSB_RVDC32(vblank_reg); | ||
317 | *vsync_val = PSB_RVDC32(vsync_reg); | ||
318 | *pipesrc_val = PSB_RVDC32(pipesrc_reg); | ||
319 | *dspstride_val = PSB_RVDC32(dspstride_reg); | ||
320 | *dsplinoff_val = PSB_RVDC32(dsplinoff_reg); | ||
321 | *dsptileoff_val = PSB_RVDC32(dsptileoff_reg); | ||
322 | *dspsize_val = PSB_RVDC32(dspsize_reg); | ||
323 | *dsppos_val = PSB_RVDC32(dsppos_reg); | ||
324 | *dspsurf_val = PSB_RVDC32(dspsurf_reg); | ||
325 | *dspcntr_val = PSB_RVDC32(dspcntr_reg); | ||
326 | *dspstatus_val = PSB_RVDC32(dspstatus_reg); | ||
327 | |||
328 | /*save palette (gamma) */ | ||
329 | for (i = 0; i < 256; i++) | ||
330 | palette_val[i] = PSB_RVDC32(palette_reg + (i << 2)); | ||
331 | |||
332 | if (pipe == 1) { | ||
333 | regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL); | ||
334 | regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS); | ||
335 | |||
336 | regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL); | ||
337 | regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL); | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | *mipi_val = PSB_RVDC32(mipi_reg); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * mdfld_restore_display_registers | ||
347 | * | ||
348 | * Description: We are going to resume so restore display register state. | ||
349 | * | ||
350 | * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio | ||
351 | */ | ||
352 | static int mdfld_restore_display_registers(struct drm_device *dev, int pipe) | ||
353 | { | ||
354 | /* To get panel out of ULPS mode. */ | ||
355 | u32 temp = 0; | ||
356 | u32 device_ready_reg = DEVICE_READY_REG; | ||
357 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
358 | struct mdfld_dsi_config *dsi_config = NULL; | ||
359 | struct medfield_state *regs = &dev_priv->regs.mdfld; | ||
360 | u32 i = 0; | ||
361 | u32 dpll = 0; | ||
362 | u32 timeout = 0; | ||
363 | |||
364 | /* regester */ | ||
365 | u32 dpll_reg = MRST_DPLL_A; | ||
366 | u32 fp_reg = MRST_FPA0; | ||
367 | u32 pipeconf_reg = PIPEACONF; | ||
368 | u32 htot_reg = HTOTAL_A; | ||
369 | u32 hblank_reg = HBLANK_A; | ||
370 | u32 hsync_reg = HSYNC_A; | ||
371 | u32 vtot_reg = VTOTAL_A; | ||
372 | u32 vblank_reg = VBLANK_A; | ||
373 | u32 vsync_reg = VSYNC_A; | ||
374 | u32 pipesrc_reg = PIPEASRC; | ||
375 | u32 dspstride_reg = DSPASTRIDE; | ||
376 | u32 dsplinoff_reg = DSPALINOFF; | ||
377 | u32 dsptileoff_reg = DSPATILEOFF; | ||
378 | u32 dspsize_reg = DSPASIZE; | ||
379 | u32 dsppos_reg = DSPAPOS; | ||
380 | u32 dspsurf_reg = DSPASURF; | ||
381 | u32 dspstatus_reg = PIPEASTAT; | ||
382 | u32 mipi_reg = MIPI; | ||
383 | u32 dspcntr_reg = DSPACNTR; | ||
384 | u32 palette_reg = PALETTE_A; | ||
385 | |||
386 | /* values */ | ||
387 | u32 dpll_val = regs->saveDPLL_A & ~DPLL_VCO_ENABLE; | ||
388 | u32 fp_val = regs->saveFPA0; | ||
389 | u32 pipeconf_val = regs->savePIPEACONF; | ||
390 | u32 htot_val = regs->saveHTOTAL_A; | ||
391 | u32 hblank_val = regs->saveHBLANK_A; | ||
392 | u32 hsync_val = regs->saveHSYNC_A; | ||
393 | u32 vtot_val = regs->saveVTOTAL_A; | ||
394 | u32 vblank_val = regs->saveVBLANK_A; | ||
395 | u32 vsync_val = regs->saveVSYNC_A; | ||
396 | u32 pipesrc_val = regs->savePIPEASRC; | ||
397 | u32 dspstride_val = regs->saveDSPASTRIDE; | ||
398 | u32 dsplinoff_val = regs->saveDSPALINOFF; | ||
399 | u32 dsptileoff_val = regs->saveDSPATILEOFF; | ||
400 | u32 dspsize_val = regs->saveDSPASIZE; | ||
401 | u32 dsppos_val = regs->saveDSPAPOS; | ||
402 | u32 dspsurf_val = regs->saveDSPASURF; | ||
403 | u32 dspstatus_val = regs->saveDSPASTATUS; | ||
404 | u32 mipi_val = regs->saveMIPI; | ||
405 | u32 dspcntr_val = regs->saveDSPACNTR; | ||
406 | u32 *palette_val = regs->save_palette_a; | ||
407 | |||
408 | switch (pipe) { | ||
409 | case 0: | ||
410 | dsi_config = dev_priv->dsi_configs[0]; | ||
411 | break; | ||
412 | case 1: | ||
413 | /* regester */ | ||
414 | dpll_reg = MDFLD_DPLL_B; | ||
415 | fp_reg = MDFLD_DPLL_DIV0; | ||
416 | pipeconf_reg = PIPEBCONF; | ||
417 | htot_reg = HTOTAL_B; | ||
418 | hblank_reg = HBLANK_B; | ||
419 | hsync_reg = HSYNC_B; | ||
420 | vtot_reg = VTOTAL_B; | ||
421 | vblank_reg = VBLANK_B; | ||
422 | vsync_reg = VSYNC_B; | ||
423 | pipesrc_reg = PIPEBSRC; | ||
424 | dspstride_reg = DSPBSTRIDE; | ||
425 | dsplinoff_reg = DSPBLINOFF; | ||
426 | dsptileoff_reg = DSPBTILEOFF; | ||
427 | dspsize_reg = DSPBSIZE; | ||
428 | dsppos_reg = DSPBPOS; | ||
429 | dspsurf_reg = DSPBSURF; | ||
430 | dspcntr_reg = DSPBCNTR; | ||
431 | dspstatus_reg = PIPEBSTAT; | ||
432 | palette_reg = PALETTE_B; | ||
433 | |||
434 | /* values */ | ||
435 | dpll_val = regs->saveDPLL_B & ~DPLL_VCO_ENABLE; | ||
436 | fp_val = regs->saveFPB0; | ||
437 | pipeconf_val = regs->savePIPEBCONF; | ||
438 | htot_val = regs->saveHTOTAL_B; | ||
439 | hblank_val = regs->saveHBLANK_B; | ||
440 | hsync_val = regs->saveHSYNC_B; | ||
441 | vtot_val = regs->saveVTOTAL_B; | ||
442 | vblank_val = regs->saveVBLANK_B; | ||
443 | vsync_val = regs->saveVSYNC_B; | ||
444 | pipesrc_val = regs->savePIPEBSRC; | ||
445 | dspstride_val = regs->saveDSPBSTRIDE; | ||
446 | dsplinoff_val = regs->saveDSPBLINOFF; | ||
447 | dsptileoff_val = regs->saveDSPBTILEOFF; | ||
448 | dspsize_val = regs->saveDSPBSIZE; | ||
449 | dsppos_val = regs->saveDSPBPOS; | ||
450 | dspsurf_val = regs->saveDSPBSURF; | ||
451 | dspcntr_val = regs->saveDSPBCNTR; | ||
452 | dspstatus_val = regs->saveDSPBSTATUS; | ||
453 | palette_val = regs->save_palette_b; | ||
454 | break; | ||
455 | case 2: | ||
456 | /* regester */ | ||
457 | pipeconf_reg = PIPECCONF; | ||
458 | htot_reg = HTOTAL_C; | ||
459 | hblank_reg = HBLANK_C; | ||
460 | hsync_reg = HSYNC_C; | ||
461 | vtot_reg = VTOTAL_C; | ||
462 | vblank_reg = VBLANK_C; | ||
463 | vsync_reg = VSYNC_C; | ||
464 | pipesrc_reg = PIPECSRC; | ||
465 | dspstride_reg = DSPCSTRIDE; | ||
466 | dsplinoff_reg = DSPCLINOFF; | ||
467 | dsptileoff_reg = DSPCTILEOFF; | ||
468 | dspsize_reg = DSPCSIZE; | ||
469 | dsppos_reg = DSPCPOS; | ||
470 | dspsurf_reg = DSPCSURF; | ||
471 | mipi_reg = MIPI_C; | ||
472 | dspcntr_reg = DSPCCNTR; | ||
473 | dspstatus_reg = PIPECSTAT; | ||
474 | palette_reg = PALETTE_C; | ||
475 | |||
476 | /* values */ | ||
477 | pipeconf_val = regs->savePIPECCONF; | ||
478 | htot_val = regs->saveHTOTAL_C; | ||
479 | hblank_val = regs->saveHBLANK_C; | ||
480 | hsync_val = regs->saveHSYNC_C; | ||
481 | vtot_val = regs->saveVTOTAL_C; | ||
482 | vblank_val = regs->saveVBLANK_C; | ||
483 | vsync_val = regs->saveVSYNC_C; | ||
484 | pipesrc_val = regs->savePIPECSRC; | ||
485 | dspstride_val = regs->saveDSPCSTRIDE; | ||
486 | dsplinoff_val = regs->saveDSPCLINOFF; | ||
487 | dsptileoff_val = regs->saveDSPCTILEOFF; | ||
488 | dspsize_val = regs->saveDSPCSIZE; | ||
489 | dsppos_val = regs->saveDSPCPOS; | ||
490 | dspsurf_val = regs->saveDSPCSURF; | ||
491 | mipi_val = regs->saveMIPI_C; | ||
492 | dspcntr_val = regs->saveDSPCCNTR; | ||
493 | dspstatus_val = regs->saveDSPCSTATUS; | ||
494 | palette_val = regs->save_palette_c; | ||
495 | |||
496 | dsi_config = dev_priv->dsi_configs[1]; | ||
497 | break; | ||
498 | default: | ||
499 | DRM_ERROR("%s, invalid pipe number.\n", __func__); | ||
500 | return -EINVAL; | ||
501 | } | ||
502 | |||
503 | /*make sure VGA plane is off. it initializes to on after reset!*/ | ||
504 | PSB_WVDC32(0x80000000, VGACNTRL); | ||
505 | |||
506 | if (pipe == 1) { | ||
507 | PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, dpll_reg); | ||
508 | PSB_RVDC32(dpll_reg); | ||
509 | |||
510 | PSB_WVDC32(fp_val, fp_reg); | ||
511 | } else { | ||
512 | |||
513 | dpll = PSB_RVDC32(dpll_reg); | ||
514 | |||
515 | if (!(dpll & DPLL_VCO_ENABLE)) { | ||
516 | |||
517 | /* When ungating power of DPLL, needs to wait 0.5us | ||
518 | before enable the VCO */ | ||
519 | if (dpll & MDFLD_PWR_GATE_EN) { | ||
520 | dpll &= ~MDFLD_PWR_GATE_EN; | ||
521 | PSB_WVDC32(dpll, dpll_reg); | ||
522 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | ||
523 | udelay(500); | ||
524 | } | ||
525 | |||
526 | PSB_WVDC32(fp_val, fp_reg); | ||
527 | PSB_WVDC32(dpll_val, dpll_reg); | ||
528 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | ||
529 | udelay(500); | ||
530 | |||
531 | dpll_val |= DPLL_VCO_ENABLE; | ||
532 | PSB_WVDC32(dpll_val, dpll_reg); | ||
533 | PSB_RVDC32(dpll_reg); | ||
534 | |||
535 | /* wait for DSI PLL to lock */ | ||
536 | while (timeout < 20000 && | ||
537 | !(PSB_RVDC32(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) { | ||
538 | udelay(150); | ||
539 | timeout++; | ||
540 | } | ||
541 | |||
542 | if (timeout == 20000) { | ||
543 | DRM_ERROR("%s, can't lock DSIPLL.\n", | ||
544 | __func__); | ||
545 | return -EINVAL; | ||
546 | } | ||
547 | } | ||
548 | } | ||
549 | /* Restore mode */ | ||
550 | PSB_WVDC32(htot_val, htot_reg); | ||
551 | PSB_WVDC32(hblank_val, hblank_reg); | ||
552 | PSB_WVDC32(hsync_val, hsync_reg); | ||
553 | PSB_WVDC32(vtot_val, vtot_reg); | ||
554 | PSB_WVDC32(vblank_val, vblank_reg); | ||
555 | PSB_WVDC32(vsync_val, vsync_reg); | ||
556 | PSB_WVDC32(pipesrc_val, pipesrc_reg); | ||
557 | PSB_WVDC32(dspstatus_val, dspstatus_reg); | ||
558 | |||
559 | /*set up the plane*/ | ||
560 | PSB_WVDC32(dspstride_val, dspstride_reg); | ||
561 | PSB_WVDC32(dsplinoff_val, dsplinoff_reg); | ||
562 | PSB_WVDC32(dsptileoff_val, dsptileoff_reg); | ||
563 | PSB_WVDC32(dspsize_val, dspsize_reg); | ||
564 | PSB_WVDC32(dsppos_val, dsppos_reg); | ||
565 | PSB_WVDC32(dspsurf_val, dspsurf_reg); | ||
566 | |||
567 | if (pipe == 1) { | ||
568 | /* restore palette (gamma) */ | ||
569 | /*DRM_UDELAY(50000); */ | ||
570 | for (i = 0; i < 256; i++) | ||
571 | PSB_WVDC32(palette_val[i], palette_reg + (i << 2)); | ||
572 | |||
573 | PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL); | ||
574 | PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS); | ||
575 | |||
576 | /*TODO: resume HDMI port */ | ||
577 | |||
578 | /*TODO: resume pipe*/ | ||
579 | |||
580 | /*enable the plane*/ | ||
581 | PSB_WVDC32(dspcntr_val & ~DISPLAY_PLANE_ENABLE, dspcntr_reg); | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | /*set up pipe related registers*/ | ||
587 | PSB_WVDC32(mipi_val, mipi_reg); | ||
588 | |||
589 | /*setup MIPI adapter + MIPI IP registers*/ | ||
590 | if (dsi_config) | ||
591 | mdfld_dsi_controller_init(dsi_config, pipe); | ||
592 | |||
593 | if (in_atomic() || in_interrupt()) | ||
594 | mdelay(20); | ||
595 | else | ||
596 | msleep(20); | ||
597 | |||
598 | /*enable the plane*/ | ||
599 | PSB_WVDC32(dspcntr_val, dspcntr_reg); | ||
600 | |||
601 | if (in_atomic() || in_interrupt()) | ||
602 | mdelay(20); | ||
603 | else | ||
604 | msleep(20); | ||
605 | |||
606 | /* LP Hold Release */ | ||
607 | temp = REG_READ(mipi_reg); | ||
608 | temp |= LP_OUTPUT_HOLD_RELEASE; | ||
609 | REG_WRITE(mipi_reg, temp); | ||
610 | mdelay(1); | ||
611 | |||
612 | |||
613 | /* Set DSI host to exit from Utra Low Power State */ | ||
614 | temp = REG_READ(device_ready_reg); | ||
615 | temp &= ~ULPS_MASK; | ||
616 | temp |= 0x3; | ||
617 | temp |= EXIT_ULPS_DEV_READY; | ||
618 | REG_WRITE(device_ready_reg, temp); | ||
619 | mdelay(1); | ||
620 | |||
621 | temp = REG_READ(device_ready_reg); | ||
622 | temp &= ~ULPS_MASK; | ||
623 | temp |= EXITING_ULPS; | ||
624 | REG_WRITE(device_ready_reg, temp); | ||
625 | mdelay(1); | ||
626 | |||
627 | /*enable the pipe*/ | ||
628 | PSB_WVDC32(pipeconf_val, pipeconf_reg); | ||
629 | |||
630 | /* restore palette (gamma) */ | ||
631 | /*DRM_UDELAY(50000); */ | ||
632 | for (i = 0; i < 256; i++) | ||
633 | PSB_WVDC32(palette_val[i], palette_reg + (i << 2)); | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static int mdfld_save_registers(struct drm_device *dev) | ||
639 | { | ||
640 | /* mdfld_save_cursor_overlay_registers(dev); */ | ||
641 | mdfld_save_display_registers(dev, 0); | ||
642 | mdfld_save_display_registers(dev, 2); | ||
643 | mdfld_disable_crtc(dev, 0); | ||
644 | mdfld_disable_crtc(dev, 2); | ||
645 | |||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | static int mdfld_restore_registers(struct drm_device *dev) | ||
650 | { | ||
651 | mdfld_restore_display_registers(dev, 2); | ||
652 | mdfld_restore_display_registers(dev, 0); | ||
653 | /* mdfld_restore_cursor_overlay_registers(dev); */ | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int mdfld_power_down(struct drm_device *dev) | ||
659 | { | ||
660 | /* FIXME */ | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static int mdfld_power_up(struct drm_device *dev) | ||
665 | { | ||
666 | /* FIXME */ | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | const struct psb_ops mdfld_chip_ops = { | ||
671 | .name = "mdfld", | ||
672 | .accel_2d = 0, | ||
673 | .pipes = 3, | ||
674 | .crtcs = 3, | ||
675 | .sgx_offset = MRST_SGX_OFFSET, | ||
676 | |||
677 | .chip_setup = mid_chip_setup, | ||
678 | .crtc_helper = &mdfld_helper_funcs, | ||
679 | .crtc_funcs = &psb_intel_crtc_funcs, | ||
680 | |||
681 | .output_init = mdfld_output_init, | ||
682 | |||
683 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE | ||
684 | .backlight_init = mdfld_backlight_init, | ||
685 | #endif | ||
686 | |||
687 | .save_regs = mdfld_save_registers, | ||
688 | .restore_regs = mdfld_restore_registers, | ||
689 | .power_down = mdfld_power_down, | ||
690 | .power_up = mdfld_power_up, | ||
691 | }; | ||
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c new file mode 100644 index 000000000000..fc0df28a668c --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c | |||
@@ -0,0 +1,1024 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * jim liu <jim.liu@intel.com> | ||
25 | * Jackie Li<yaodong.li@intel.com> | ||
26 | */ | ||
27 | |||
28 | #include "mdfld_dsi_dpi.h" | ||
29 | #include "mdfld_output.h" | ||
30 | #include "mdfld_dsi_pkg_sender.h" | ||
31 | #include "psb_drv.h" | ||
32 | #include "tc35876x-dsi-lvds.h" | ||
33 | |||
34 | static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output, | ||
35 | int pipe); | ||
36 | |||
37 | static void mdfld_wait_for_HS_DATA_FIFO(struct drm_device *dev, u32 pipe) | ||
38 | { | ||
39 | u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); | ||
40 | int timeout = 0; | ||
41 | |||
42 | udelay(500); | ||
43 | |||
44 | /* This will time out after approximately 2+ seconds */ | ||
45 | while ((timeout < 20000) && | ||
46 | (REG_READ(gen_fifo_stat_reg) & DSI_FIFO_GEN_HS_DATA_FULL)) { | ||
47 | udelay(100); | ||
48 | timeout++; | ||
49 | } | ||
50 | |||
51 | if (timeout == 20000) | ||
52 | DRM_INFO("MIPI: HS Data FIFO was never cleared!\n"); | ||
53 | } | ||
54 | |||
55 | static void mdfld_wait_for_HS_CTRL_FIFO(struct drm_device *dev, u32 pipe) | ||
56 | { | ||
57 | u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); | ||
58 | int timeout = 0; | ||
59 | |||
60 | udelay(500); | ||
61 | |||
62 | /* This will time out after approximately 2+ seconds */ | ||
63 | while ((timeout < 20000) && (REG_READ(gen_fifo_stat_reg) | ||
64 | & DSI_FIFO_GEN_HS_CTRL_FULL)) { | ||
65 | udelay(100); | ||
66 | timeout++; | ||
67 | } | ||
68 | if (timeout == 20000) | ||
69 | DRM_INFO("MIPI: HS CMD FIFO was never cleared!\n"); | ||
70 | } | ||
71 | |||
72 | static void mdfld_wait_for_DPI_CTRL_FIFO(struct drm_device *dev, u32 pipe) | ||
73 | { | ||
74 | u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); | ||
75 | int timeout = 0; | ||
76 | |||
77 | udelay(500); | ||
78 | |||
79 | /* This will time out after approximately 2+ seconds */ | ||
80 | while ((timeout < 20000) && ((REG_READ(gen_fifo_stat_reg) & | ||
81 | DPI_FIFO_EMPTY) != DPI_FIFO_EMPTY)) { | ||
82 | udelay(100); | ||
83 | timeout++; | ||
84 | } | ||
85 | |||
86 | if (timeout == 20000) | ||
87 | DRM_ERROR("MIPI: DPI FIFO was never cleared\n"); | ||
88 | } | ||
89 | |||
90 | static void mdfld_wait_for_SPL_PKG_SENT(struct drm_device *dev, u32 pipe) | ||
91 | { | ||
92 | u32 intr_stat_reg = MIPI_INTR_STAT_REG(pipe); | ||
93 | int timeout = 0; | ||
94 | |||
95 | udelay(500); | ||
96 | |||
97 | /* This will time out after approximately 2+ seconds */ | ||
98 | while ((timeout < 20000) && (!(REG_READ(intr_stat_reg) | ||
99 | & DSI_INTR_STATE_SPL_PKG_SENT))) { | ||
100 | udelay(100); | ||
101 | timeout++; | ||
102 | } | ||
103 | |||
104 | if (timeout == 20000) | ||
105 | DRM_ERROR("MIPI: SPL_PKT_SENT_INTERRUPT was not sent successfully!\n"); | ||
106 | } | ||
107 | |||
108 | /* For TC35876X */ | ||
109 | |||
110 | static void dsi_set_device_ready_state(struct drm_device *dev, int state, | ||
111 | int pipe) | ||
112 | { | ||
113 | REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), !!state, 0, 0); | ||
114 | } | ||
115 | |||
116 | static void dsi_set_pipe_plane_enable_state(struct drm_device *dev, | ||
117 | int state, int pipe) | ||
118 | { | ||
119 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
120 | u32 pipeconf_reg = PIPEACONF; | ||
121 | u32 dspcntr_reg = DSPACNTR; | ||
122 | |||
123 | u32 dspcntr = dev_priv->dspcntr[pipe]; | ||
124 | u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; | ||
125 | |||
126 | if (pipe) { | ||
127 | pipeconf_reg = PIPECCONF; | ||
128 | dspcntr_reg = DSPCCNTR; | ||
129 | } else | ||
130 | mipi &= (~0x03); | ||
131 | |||
132 | if (state) { | ||
133 | /*Set up pipe */ | ||
134 | REG_WRITE(pipeconf_reg, BIT(31)); | ||
135 | |||
136 | if (REG_BIT_WAIT(pipeconf_reg, 1, 30)) | ||
137 | dev_err(&dev->pdev->dev, "%s: Pipe enable timeout\n", | ||
138 | __func__); | ||
139 | |||
140 | /*Set up display plane */ | ||
141 | REG_WRITE(dspcntr_reg, dspcntr); | ||
142 | } else { | ||
143 | u32 dspbase_reg = pipe ? MDFLD_DSPCBASE : MRST_DSPABASE; | ||
144 | |||
145 | /* Put DSI lanes to ULPS to disable pipe */ | ||
146 | REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 2, 2, 1); | ||
147 | REG_READ(MIPI_DEVICE_READY_REG(pipe)); /* posted write? */ | ||
148 | |||
149 | /* LP Hold */ | ||
150 | REG_FLD_MOD(MIPI_PORT_CONTROL(pipe), 0, 16, 16); | ||
151 | REG_READ(MIPI_PORT_CONTROL(pipe)); /* posted write? */ | ||
152 | |||
153 | /* Disable display plane */ | ||
154 | REG_FLD_MOD(dspcntr_reg, 0, 31, 31); | ||
155 | |||
156 | /* Flush the plane changes ??? posted write? */ | ||
157 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
158 | REG_READ(dspbase_reg); | ||
159 | |||
160 | /* Disable PIPE */ | ||
161 | REG_FLD_MOD(pipeconf_reg, 0, 31, 31); | ||
162 | |||
163 | if (REG_BIT_WAIT(pipeconf_reg, 0, 30)) | ||
164 | dev_err(&dev->pdev->dev, "%s: Pipe disable timeout\n", | ||
165 | __func__); | ||
166 | |||
167 | if (REG_BIT_WAIT(MIPI_GEN_FIFO_STAT_REG(pipe), 1, 28)) | ||
168 | dev_err(&dev->pdev->dev, "%s: FIFO not empty\n", | ||
169 | __func__); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static void mdfld_dsi_configure_down(struct mdfld_dsi_encoder *dsi_encoder, | ||
174 | int pipe) | ||
175 | { | ||
176 | struct mdfld_dsi_dpi_output *dpi_output = | ||
177 | MDFLD_DSI_DPI_OUTPUT(dsi_encoder); | ||
178 | struct mdfld_dsi_config *dsi_config = | ||
179 | mdfld_dsi_encoder_get_config(dsi_encoder); | ||
180 | struct drm_device *dev = dsi_config->dev; | ||
181 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
182 | |||
183 | if (!dev_priv->dpi_panel_on[pipe]) { | ||
184 | dev_err(dev->dev, "DPI panel is already off\n"); | ||
185 | return; | ||
186 | } | ||
187 | tc35876x_toshiba_bridge_panel_off(dev); | ||
188 | tc35876x_set_bridge_reset_state(dev, 1); | ||
189 | dsi_set_pipe_plane_enable_state(dev, 0, pipe); | ||
190 | mdfld_dsi_dpi_shut_down(dpi_output, pipe); | ||
191 | dsi_set_device_ready_state(dev, 0, pipe); | ||
192 | } | ||
193 | |||
194 | static void mdfld_dsi_configure_up(struct mdfld_dsi_encoder *dsi_encoder, | ||
195 | int pipe) | ||
196 | { | ||
197 | struct mdfld_dsi_dpi_output *dpi_output = | ||
198 | MDFLD_DSI_DPI_OUTPUT(dsi_encoder); | ||
199 | struct mdfld_dsi_config *dsi_config = | ||
200 | mdfld_dsi_encoder_get_config(dsi_encoder); | ||
201 | struct drm_device *dev = dsi_config->dev; | ||
202 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
203 | |||
204 | if (dev_priv->dpi_panel_on[pipe]) { | ||
205 | dev_err(dev->dev, "DPI panel is already on\n"); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | /* For resume path sequence */ | ||
210 | mdfld_dsi_dpi_shut_down(dpi_output, pipe); | ||
211 | dsi_set_device_ready_state(dev, 0, pipe); | ||
212 | |||
213 | dsi_set_device_ready_state(dev, 1, pipe); | ||
214 | tc35876x_set_bridge_reset_state(dev, 0); | ||
215 | tc35876x_configure_lvds_bridge(dev); | ||
216 | mdfld_dsi_dpi_turn_on(dpi_output, pipe); /* Send turn on command */ | ||
217 | dsi_set_pipe_plane_enable_state(dev, 1, pipe); | ||
218 | } | ||
219 | /* End for TC35876X */ | ||
220 | |||
221 | /* ************************************************************************* *\ | ||
222 | * FUNCTION: mdfld_dsi_tpo_ic_init | ||
223 | * | ||
224 | * DESCRIPTION: This function is called only by mrst_dsi_mode_set and | ||
225 | * restore_display_registers. since this function does not | ||
226 | * acquire the mutex, it is important that the calling function | ||
227 | * does! | ||
228 | \* ************************************************************************* */ | ||
229 | static void mdfld_dsi_tpo_ic_init(struct mdfld_dsi_config *dsi_config, u32 pipe) | ||
230 | { | ||
231 | struct drm_device *dev = dsi_config->dev; | ||
232 | u32 dcsChannelNumber = dsi_config->channel_num; | ||
233 | u32 gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe); | ||
234 | u32 gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe); | ||
235 | u32 gen_ctrl_val = GEN_LONG_WRITE; | ||
236 | |||
237 | DRM_INFO("Enter mrst init TPO MIPI display.\n"); | ||
238 | |||
239 | gen_ctrl_val |= dcsChannelNumber << DCS_CHANNEL_NUMBER_POS; | ||
240 | |||
241 | /* Flip page order */ | ||
242 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
243 | REG_WRITE(gen_data_reg, 0x00008036); | ||
244 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
245 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS)); | ||
246 | |||
247 | /* 0xF0 */ | ||
248 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
249 | REG_WRITE(gen_data_reg, 0x005a5af0); | ||
250 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
251 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); | ||
252 | |||
253 | /* Write protection key */ | ||
254 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
255 | REG_WRITE(gen_data_reg, 0x005a5af1); | ||
256 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
257 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); | ||
258 | |||
259 | /* 0xFC */ | ||
260 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
261 | REG_WRITE(gen_data_reg, 0x005a5afc); | ||
262 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
263 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); | ||
264 | |||
265 | /* 0xB7 */ | ||
266 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
267 | REG_WRITE(gen_data_reg, 0x770000b7); | ||
268 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
269 | REG_WRITE(gen_data_reg, 0x00000044); | ||
270 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
271 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x05 << WORD_COUNTS_POS)); | ||
272 | |||
273 | /* 0xB6 */ | ||
274 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
275 | REG_WRITE(gen_data_reg, 0x000a0ab6); | ||
276 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
277 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); | ||
278 | |||
279 | /* 0xF2 */ | ||
280 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
281 | REG_WRITE(gen_data_reg, 0x081010f2); | ||
282 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
283 | REG_WRITE(gen_data_reg, 0x4a070708); | ||
284 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
285 | REG_WRITE(gen_data_reg, 0x000000c5); | ||
286 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
287 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS)); | ||
288 | |||
289 | /* 0xF8 */ | ||
290 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
291 | REG_WRITE(gen_data_reg, 0x024003f8); | ||
292 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
293 | REG_WRITE(gen_data_reg, 0x01030a04); | ||
294 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
295 | REG_WRITE(gen_data_reg, 0x0e020220); | ||
296 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
297 | REG_WRITE(gen_data_reg, 0x00000004); | ||
298 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
299 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x0d << WORD_COUNTS_POS)); | ||
300 | |||
301 | /* 0xE2 */ | ||
302 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
303 | REG_WRITE(gen_data_reg, 0x398fc3e2); | ||
304 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
305 | REG_WRITE(gen_data_reg, 0x0000916f); | ||
306 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
307 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x06 << WORD_COUNTS_POS)); | ||
308 | |||
309 | /* 0xB0 */ | ||
310 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
311 | REG_WRITE(gen_data_reg, 0x000000b0); | ||
312 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
313 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS)); | ||
314 | |||
315 | /* 0xF4 */ | ||
316 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
317 | REG_WRITE(gen_data_reg, 0x240242f4); | ||
318 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
319 | REG_WRITE(gen_data_reg, 0x78ee2002); | ||
320 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
321 | REG_WRITE(gen_data_reg, 0x2a071050); | ||
322 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
323 | REG_WRITE(gen_data_reg, 0x507fee10); | ||
324 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
325 | REG_WRITE(gen_data_reg, 0x10300710); | ||
326 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
327 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x14 << WORD_COUNTS_POS)); | ||
328 | |||
329 | /* 0xBA */ | ||
330 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
331 | REG_WRITE(gen_data_reg, 0x19fe07ba); | ||
332 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
333 | REG_WRITE(gen_data_reg, 0x101c0a31); | ||
334 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
335 | REG_WRITE(gen_data_reg, 0x00000010); | ||
336 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
337 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS)); | ||
338 | |||
339 | /* 0xBB */ | ||
340 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
341 | REG_WRITE(gen_data_reg, 0x28ff07bb); | ||
342 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
343 | REG_WRITE(gen_data_reg, 0x24280a31); | ||
344 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
345 | REG_WRITE(gen_data_reg, 0x00000034); | ||
346 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
347 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS)); | ||
348 | |||
349 | /* 0xFB */ | ||
350 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
351 | REG_WRITE(gen_data_reg, 0x535d05fb); | ||
352 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
353 | REG_WRITE(gen_data_reg, 0x1b1a2130); | ||
354 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
355 | REG_WRITE(gen_data_reg, 0x221e180e); | ||
356 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
357 | REG_WRITE(gen_data_reg, 0x131d2120); | ||
358 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
359 | REG_WRITE(gen_data_reg, 0x535d0508); | ||
360 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
361 | REG_WRITE(gen_data_reg, 0x1c1a2131); | ||
362 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
363 | REG_WRITE(gen_data_reg, 0x231f160d); | ||
364 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
365 | REG_WRITE(gen_data_reg, 0x111b2220); | ||
366 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
367 | REG_WRITE(gen_data_reg, 0x535c2008); | ||
368 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
369 | REG_WRITE(gen_data_reg, 0x1f1d2433); | ||
370 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
371 | REG_WRITE(gen_data_reg, 0x2c251a10); | ||
372 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
373 | REG_WRITE(gen_data_reg, 0x2c34372d); | ||
374 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
375 | REG_WRITE(gen_data_reg, 0x00000023); | ||
376 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
377 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS)); | ||
378 | |||
379 | /* 0xFA */ | ||
380 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
381 | REG_WRITE(gen_data_reg, 0x525c0bfa); | ||
382 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
383 | REG_WRITE(gen_data_reg, 0x1c1c232f); | ||
384 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
385 | REG_WRITE(gen_data_reg, 0x2623190e); | ||
386 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
387 | REG_WRITE(gen_data_reg, 0x18212625); | ||
388 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
389 | REG_WRITE(gen_data_reg, 0x545d0d0e); | ||
390 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
391 | REG_WRITE(gen_data_reg, 0x1e1d2333); | ||
392 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
393 | REG_WRITE(gen_data_reg, 0x26231a10); | ||
394 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
395 | REG_WRITE(gen_data_reg, 0x1a222725); | ||
396 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
397 | REG_WRITE(gen_data_reg, 0x545d280f); | ||
398 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
399 | REG_WRITE(gen_data_reg, 0x21202635); | ||
400 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
401 | REG_WRITE(gen_data_reg, 0x31292013); | ||
402 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
403 | REG_WRITE(gen_data_reg, 0x31393d33); | ||
404 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
405 | REG_WRITE(gen_data_reg, 0x00000029); | ||
406 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
407 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS)); | ||
408 | |||
409 | /* Set DM */ | ||
410 | mdfld_wait_for_HS_DATA_FIFO(dev, pipe); | ||
411 | REG_WRITE(gen_data_reg, 0x000100f7); | ||
412 | mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); | ||
413 | REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); | ||
414 | } | ||
415 | |||
416 | static u16 mdfld_dsi_dpi_to_byte_clock_count(int pixel_clock_count, | ||
417 | int num_lane, int bpp) | ||
418 | { | ||
419 | return (u16)((pixel_clock_count * bpp) / (num_lane * 8)); | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Calculate the dpi time basing on a given drm mode @mode | ||
424 | * return 0 on success. | ||
425 | * FIXME: I was using proposed mode value for calculation, may need to | ||
426 | * use crtc mode values later | ||
427 | */ | ||
428 | int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode, | ||
429 | struct mdfld_dsi_dpi_timing *dpi_timing, | ||
430 | int num_lane, int bpp) | ||
431 | { | ||
432 | int pclk_hsync, pclk_hfp, pclk_hbp, pclk_hactive; | ||
433 | int pclk_vsync, pclk_vfp, pclk_vbp, pclk_vactive; | ||
434 | |||
435 | pclk_hactive = mode->hdisplay; | ||
436 | pclk_hfp = mode->hsync_start - mode->hdisplay; | ||
437 | pclk_hsync = mode->hsync_end - mode->hsync_start; | ||
438 | pclk_hbp = mode->htotal - mode->hsync_end; | ||
439 | |||
440 | pclk_vactive = mode->vdisplay; | ||
441 | pclk_vfp = mode->vsync_start - mode->vdisplay; | ||
442 | pclk_vsync = mode->vsync_end - mode->vsync_start; | ||
443 | pclk_vbp = mode->vtotal - mode->vsync_end; | ||
444 | |||
445 | /* | ||
446 | * byte clock counts were calculated by following formula | ||
447 | * bclock_count = pclk_count * bpp / num_lane / 8 | ||
448 | */ | ||
449 | dpi_timing->hsync_count = mdfld_dsi_dpi_to_byte_clock_count( | ||
450 | pclk_hsync, num_lane, bpp); | ||
451 | dpi_timing->hbp_count = mdfld_dsi_dpi_to_byte_clock_count( | ||
452 | pclk_hbp, num_lane, bpp); | ||
453 | dpi_timing->hfp_count = mdfld_dsi_dpi_to_byte_clock_count( | ||
454 | pclk_hfp, num_lane, bpp); | ||
455 | dpi_timing->hactive_count = mdfld_dsi_dpi_to_byte_clock_count( | ||
456 | pclk_hactive, num_lane, bpp); | ||
457 | dpi_timing->vsync_count = mdfld_dsi_dpi_to_byte_clock_count( | ||
458 | pclk_vsync, num_lane, bpp); | ||
459 | dpi_timing->vbp_count = mdfld_dsi_dpi_to_byte_clock_count( | ||
460 | pclk_vbp, num_lane, bpp); | ||
461 | dpi_timing->vfp_count = mdfld_dsi_dpi_to_byte_clock_count( | ||
462 | pclk_vfp, num_lane, bpp); | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config, | ||
468 | int pipe) | ||
469 | { | ||
470 | struct drm_device *dev = dsi_config->dev; | ||
471 | int lane_count = dsi_config->lane_count; | ||
472 | struct mdfld_dsi_dpi_timing dpi_timing; | ||
473 | struct drm_display_mode *mode = dsi_config->mode; | ||
474 | u32 val; | ||
475 | |||
476 | /*un-ready device*/ | ||
477 | REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 0, 0, 0); | ||
478 | |||
479 | /*init dsi adapter before kicking off*/ | ||
480 | REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018); | ||
481 | |||
482 | /*enable all interrupts*/ | ||
483 | REG_WRITE(MIPI_INTR_EN_REG(pipe), 0xffffffff); | ||
484 | |||
485 | /*set up func_prg*/ | ||
486 | val = lane_count; | ||
487 | val |= dsi_config->channel_num << DSI_DPI_VIRT_CHANNEL_OFFSET; | ||
488 | |||
489 | switch (dsi_config->bpp) { | ||
490 | case 16: | ||
491 | val |= DSI_DPI_COLOR_FORMAT_RGB565; | ||
492 | break; | ||
493 | case 18: | ||
494 | val |= DSI_DPI_COLOR_FORMAT_RGB666; | ||
495 | break; | ||
496 | case 24: | ||
497 | val |= DSI_DPI_COLOR_FORMAT_RGB888; | ||
498 | break; | ||
499 | default: | ||
500 | DRM_ERROR("unsupported color format, bpp = %d\n", | ||
501 | dsi_config->bpp); | ||
502 | } | ||
503 | REG_WRITE(MIPI_DSI_FUNC_PRG_REG(pipe), val); | ||
504 | |||
505 | REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe), | ||
506 | (mode->vtotal * mode->htotal * dsi_config->bpp / | ||
507 | (8 * lane_count)) & DSI_HS_TX_TIMEOUT_MASK); | ||
508 | REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe), | ||
509 | 0xffff & DSI_LP_RX_TIMEOUT_MASK); | ||
510 | |||
511 | /*max value: 20 clock cycles of txclkesc*/ | ||
512 | REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe), | ||
513 | 0x14 & DSI_TURN_AROUND_TIMEOUT_MASK); | ||
514 | |||
515 | /*min 21 txclkesc, max: ffffh*/ | ||
516 | REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe), | ||
517 | 0xffff & DSI_RESET_TIMER_MASK); | ||
518 | |||
519 | REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe), | ||
520 | mode->vdisplay << 16 | mode->hdisplay); | ||
521 | |||
522 | /*set DPI timing registers*/ | ||
523 | mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing, | ||
524 | dsi_config->lane_count, dsi_config->bpp); | ||
525 | |||
526 | REG_WRITE(MIPI_HSYNC_COUNT_REG(pipe), | ||
527 | dpi_timing.hsync_count & DSI_DPI_TIMING_MASK); | ||
528 | REG_WRITE(MIPI_HBP_COUNT_REG(pipe), | ||
529 | dpi_timing.hbp_count & DSI_DPI_TIMING_MASK); | ||
530 | REG_WRITE(MIPI_HFP_COUNT_REG(pipe), | ||
531 | dpi_timing.hfp_count & DSI_DPI_TIMING_MASK); | ||
532 | REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe), | ||
533 | dpi_timing.hactive_count & DSI_DPI_TIMING_MASK); | ||
534 | REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe), | ||
535 | dpi_timing.vsync_count & DSI_DPI_TIMING_MASK); | ||
536 | REG_WRITE(MIPI_VBP_COUNT_REG(pipe), | ||
537 | dpi_timing.vbp_count & DSI_DPI_TIMING_MASK); | ||
538 | REG_WRITE(MIPI_VFP_COUNT_REG(pipe), | ||
539 | dpi_timing.vfp_count & DSI_DPI_TIMING_MASK); | ||
540 | |||
541 | REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x46); | ||
542 | |||
543 | /*min: 7d0 max: 4e20*/ | ||
544 | REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0x000007d0); | ||
545 | |||
546 | /*set up video mode*/ | ||
547 | val = dsi_config->video_mode | DSI_DPI_COMPLETE_LAST_LINE; | ||
548 | REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), val); | ||
549 | |||
550 | REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000); | ||
551 | |||
552 | REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004); | ||
553 | |||
554 | /*TODO: figure out how to setup these registers*/ | ||
555 | if (mdfld_get_panel_type(dev, pipe) == TC35876X) | ||
556 | REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008); | ||
557 | else | ||
558 | REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150c3408); | ||
559 | |||
560 | REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14); | ||
561 | |||
562 | if (mdfld_get_panel_type(dev, pipe) == TC35876X) | ||
563 | tc35876x_set_bridge_reset_state(dev, 0); /*Pull High Reset */ | ||
564 | |||
565 | /*set device ready*/ | ||
566 | REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 1, 0, 0); | ||
567 | } | ||
568 | |||
569 | void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, int pipe) | ||
570 | { | ||
571 | struct drm_device *dev = output->dev; | ||
572 | |||
573 | /* clear special packet sent bit */ | ||
574 | if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT) | ||
575 | REG_WRITE(MIPI_INTR_STAT_REG(pipe), | ||
576 | DSI_INTR_STATE_SPL_PKG_SENT); | ||
577 | |||
578 | /*send turn on package*/ | ||
579 | REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), DSI_DPI_CTRL_HS_TURN_ON); | ||
580 | |||
581 | /*wait for SPL_PKG_SENT interrupt*/ | ||
582 | mdfld_wait_for_SPL_PKG_SENT(dev, pipe); | ||
583 | |||
584 | if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT) | ||
585 | REG_WRITE(MIPI_INTR_STAT_REG(pipe), | ||
586 | DSI_INTR_STATE_SPL_PKG_SENT); | ||
587 | |||
588 | output->panel_on = 1; | ||
589 | |||
590 | /* FIXME the following is disabled to WA the X slow start issue | ||
591 | for TMD panel | ||
592 | if (pipe == 2) | ||
593 | dev_priv->dpi_panel_on2 = true; | ||
594 | else if (pipe == 0) | ||
595 | dev_priv->dpi_panel_on = true; */ | ||
596 | } | ||
597 | |||
598 | static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output, | ||
599 | int pipe) | ||
600 | { | ||
601 | struct drm_device *dev = output->dev; | ||
602 | |||
603 | /*if output is on, or mode setting didn't happen, ignore this*/ | ||
604 | if ((!output->panel_on) || output->first_boot) { | ||
605 | output->first_boot = 0; | ||
606 | return; | ||
607 | } | ||
608 | |||
609 | /* Wait for dpi fifo to empty */ | ||
610 | mdfld_wait_for_DPI_CTRL_FIFO(dev, pipe); | ||
611 | |||
612 | /* Clear the special packet interrupt bit if set */ | ||
613 | if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT) | ||
614 | REG_WRITE(MIPI_INTR_STAT_REG(pipe), | ||
615 | DSI_INTR_STATE_SPL_PKG_SENT); | ||
616 | |||
617 | if (REG_READ(MIPI_DPI_CONTROL_REG(pipe)) == DSI_DPI_CTRL_HS_SHUTDOWN) | ||
618 | goto shutdown_out; | ||
619 | |||
620 | REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), DSI_DPI_CTRL_HS_SHUTDOWN); | ||
621 | |||
622 | shutdown_out: | ||
623 | output->panel_on = 0; | ||
624 | output->first_boot = 0; | ||
625 | |||
626 | /* FIXME the following is disabled to WA the X slow start issue | ||
627 | for TMD panel | ||
628 | if (pipe == 2) | ||
629 | dev_priv->dpi_panel_on2 = false; | ||
630 | else if (pipe == 0) | ||
631 | dev_priv->dpi_panel_on = false; */ | ||
632 | } | ||
633 | |||
634 | static void mdfld_dsi_dpi_set_power(struct drm_encoder *encoder, bool on) | ||
635 | { | ||
636 | struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder); | ||
637 | struct mdfld_dsi_dpi_output *dpi_output = | ||
638 | MDFLD_DSI_DPI_OUTPUT(dsi_encoder); | ||
639 | struct mdfld_dsi_config *dsi_config = | ||
640 | mdfld_dsi_encoder_get_config(dsi_encoder); | ||
641 | int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder); | ||
642 | struct drm_device *dev = dsi_config->dev; | ||
643 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
644 | u32 pipeconf_reg = PIPEACONF; | ||
645 | |||
646 | if (pipe) | ||
647 | pipeconf_reg = PIPECCONF; | ||
648 | |||
649 | /*start up display island if it was shutdown*/ | ||
650 | if (!gma_power_begin(dev, true)) | ||
651 | return; | ||
652 | |||
653 | if (on) { | ||
654 | if (mdfld_get_panel_type(dev, pipe) == TMD_VID) | ||
655 | mdfld_dsi_dpi_turn_on(dpi_output, pipe); | ||
656 | else if (mdfld_get_panel_type(dev, pipe) == TC35876X) | ||
657 | mdfld_dsi_configure_up(dsi_encoder, pipe); | ||
658 | else { | ||
659 | /*enable mipi port*/ | ||
660 | REG_WRITE(MIPI_PORT_CONTROL(pipe), | ||
661 | REG_READ(MIPI_PORT_CONTROL(pipe)) | BIT(31)); | ||
662 | REG_READ(MIPI_PORT_CONTROL(pipe)); | ||
663 | |||
664 | mdfld_dsi_dpi_turn_on(dpi_output, pipe); | ||
665 | mdfld_dsi_tpo_ic_init(dsi_config, pipe); | ||
666 | } | ||
667 | dev_priv->dpi_panel_on[pipe] = true; | ||
668 | } else { | ||
669 | if (mdfld_get_panel_type(dev, pipe) == TMD_VID) | ||
670 | mdfld_dsi_dpi_shut_down(dpi_output, pipe); | ||
671 | else if (mdfld_get_panel_type(dev, pipe) == TC35876X) | ||
672 | mdfld_dsi_configure_down(dsi_encoder, pipe); | ||
673 | else { | ||
674 | mdfld_dsi_dpi_shut_down(dpi_output, pipe); | ||
675 | |||
676 | /*disable mipi port*/ | ||
677 | REG_WRITE(MIPI_PORT_CONTROL(pipe), | ||
678 | REG_READ(MIPI_PORT_CONTROL(pipe)) & ~BIT(31)); | ||
679 | REG_READ(MIPI_PORT_CONTROL(pipe)); | ||
680 | } | ||
681 | dev_priv->dpi_panel_on[pipe] = false; | ||
682 | } | ||
683 | gma_power_end(dev); | ||
684 | } | ||
685 | |||
686 | void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode) | ||
687 | { | ||
688 | mdfld_dsi_dpi_set_power(encoder, mode == DRM_MODE_DPMS_ON); | ||
689 | } | ||
690 | |||
691 | bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder, | ||
692 | struct drm_display_mode *mode, | ||
693 | struct drm_display_mode *adjusted_mode) | ||
694 | { | ||
695 | struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder); | ||
696 | struct mdfld_dsi_config *dsi_config = | ||
697 | mdfld_dsi_encoder_get_config(dsi_encoder); | ||
698 | struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; | ||
699 | |||
700 | if (fixed_mode) { | ||
701 | adjusted_mode->hdisplay = fixed_mode->hdisplay; | ||
702 | adjusted_mode->hsync_start = fixed_mode->hsync_start; | ||
703 | adjusted_mode->hsync_end = fixed_mode->hsync_end; | ||
704 | adjusted_mode->htotal = fixed_mode->htotal; | ||
705 | adjusted_mode->vdisplay = fixed_mode->vdisplay; | ||
706 | adjusted_mode->vsync_start = fixed_mode->vsync_start; | ||
707 | adjusted_mode->vsync_end = fixed_mode->vsync_end; | ||
708 | adjusted_mode->vtotal = fixed_mode->vtotal; | ||
709 | adjusted_mode->clock = fixed_mode->clock; | ||
710 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
711 | } | ||
712 | return true; | ||
713 | } | ||
714 | |||
715 | void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder) | ||
716 | { | ||
717 | mdfld_dsi_dpi_set_power(encoder, false); | ||
718 | } | ||
719 | |||
720 | void mdfld_dsi_dpi_commit(struct drm_encoder *encoder) | ||
721 | { | ||
722 | mdfld_dsi_dpi_set_power(encoder, true); | ||
723 | } | ||
724 | |||
725 | /* For TC35876X */ | ||
726 | /* This functionality was implemented in FW in iCDK */ | ||
727 | /* But removed in DV0 and later. So need to add here. */ | ||
728 | static void mipi_set_properties(struct mdfld_dsi_config *dsi_config, int pipe) | ||
729 | { | ||
730 | struct drm_device *dev = dsi_config->dev; | ||
731 | |||
732 | REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018); | ||
733 | REG_WRITE(MIPI_INTR_EN_REG(pipe), 0xffffffff); | ||
734 | REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe), 0xffffff); | ||
735 | REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe), 0xffffff); | ||
736 | REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe), 0x14); | ||
737 | REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe), 0xff); | ||
738 | REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x25); | ||
739 | REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0xf0); | ||
740 | REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000); | ||
741 | REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004); | ||
742 | REG_WRITE(MIPI_DBI_BW_CTRL_REG(pipe), 0x00000820); | ||
743 | REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14); | ||
744 | } | ||
745 | |||
746 | static void mdfld_mipi_set_video_timing(struct mdfld_dsi_config *dsi_config, | ||
747 | int pipe) | ||
748 | { | ||
749 | struct drm_device *dev = dsi_config->dev; | ||
750 | struct mdfld_dsi_dpi_timing dpi_timing; | ||
751 | struct drm_display_mode *mode = dsi_config->mode; | ||
752 | |||
753 | mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing, | ||
754 | dsi_config->lane_count, | ||
755 | dsi_config->bpp); | ||
756 | |||
757 | REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe), | ||
758 | mode->vdisplay << 16 | mode->hdisplay); | ||
759 | REG_WRITE(MIPI_HSYNC_COUNT_REG(pipe), | ||
760 | dpi_timing.hsync_count & DSI_DPI_TIMING_MASK); | ||
761 | REG_WRITE(MIPI_HBP_COUNT_REG(pipe), | ||
762 | dpi_timing.hbp_count & DSI_DPI_TIMING_MASK); | ||
763 | REG_WRITE(MIPI_HFP_COUNT_REG(pipe), | ||
764 | dpi_timing.hfp_count & DSI_DPI_TIMING_MASK); | ||
765 | REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe), | ||
766 | dpi_timing.hactive_count & DSI_DPI_TIMING_MASK); | ||
767 | REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe), | ||
768 | dpi_timing.vsync_count & DSI_DPI_TIMING_MASK); | ||
769 | REG_WRITE(MIPI_VBP_COUNT_REG(pipe), | ||
770 | dpi_timing.vbp_count & DSI_DPI_TIMING_MASK); | ||
771 | REG_WRITE(MIPI_VFP_COUNT_REG(pipe), | ||
772 | dpi_timing.vfp_count & DSI_DPI_TIMING_MASK); | ||
773 | } | ||
774 | |||
775 | static void mdfld_mipi_config(struct mdfld_dsi_config *dsi_config, int pipe) | ||
776 | { | ||
777 | struct drm_device *dev = dsi_config->dev; | ||
778 | int lane_count = dsi_config->lane_count; | ||
779 | |||
780 | if (pipe) { | ||
781 | REG_WRITE(MIPI_PORT_CONTROL(0), 0x00000002); | ||
782 | REG_WRITE(MIPI_PORT_CONTROL(2), 0x80000000); | ||
783 | } else { | ||
784 | REG_WRITE(MIPI_PORT_CONTROL(0), 0x80010000); | ||
785 | REG_WRITE(MIPI_PORT_CONTROL(2), 0x00); | ||
786 | } | ||
787 | |||
788 | REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150A600F); | ||
789 | REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), 0x0000000F); | ||
790 | |||
791 | /* lane_count = 3 */ | ||
792 | REG_WRITE(MIPI_DSI_FUNC_PRG_REG(pipe), 0x00000200 | lane_count); | ||
793 | |||
794 | mdfld_mipi_set_video_timing(dsi_config, pipe); | ||
795 | } | ||
796 | |||
797 | static void mdfld_set_pipe_timing(struct mdfld_dsi_config *dsi_config, int pipe) | ||
798 | { | ||
799 | struct drm_device *dev = dsi_config->dev; | ||
800 | struct drm_display_mode *mode = dsi_config->mode; | ||
801 | |||
802 | REG_WRITE(HTOTAL_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1)); | ||
803 | REG_WRITE(HBLANK_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1)); | ||
804 | REG_WRITE(HSYNC_A, | ||
805 | ((mode->hsync_end - 1) << 16) | (mode->hsync_start - 1)); | ||
806 | |||
807 | REG_WRITE(VTOTAL_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1)); | ||
808 | REG_WRITE(VBLANK_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1)); | ||
809 | REG_WRITE(VSYNC_A, | ||
810 | ((mode->vsync_end - 1) << 16) | (mode->vsync_start - 1)); | ||
811 | |||
812 | REG_WRITE(PIPEASRC, | ||
813 | ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); | ||
814 | } | ||
815 | /* End for TC35876X */ | ||
816 | |||
817 | void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder, | ||
818 | struct drm_display_mode *mode, | ||
819 | struct drm_display_mode *adjusted_mode) | ||
820 | { | ||
821 | struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder); | ||
822 | struct mdfld_dsi_dpi_output *dpi_output = | ||
823 | MDFLD_DSI_DPI_OUTPUT(dsi_encoder); | ||
824 | struct mdfld_dsi_config *dsi_config = | ||
825 | mdfld_dsi_encoder_get_config(dsi_encoder); | ||
826 | struct drm_device *dev = dsi_config->dev; | ||
827 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
828 | int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder); | ||
829 | |||
830 | u32 pipeconf_reg = PIPEACONF; | ||
831 | u32 dspcntr_reg = DSPACNTR; | ||
832 | |||
833 | u32 pipeconf = dev_priv->pipeconf[pipe]; | ||
834 | u32 dspcntr = dev_priv->dspcntr[pipe]; | ||
835 | u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; | ||
836 | |||
837 | if (pipe) { | ||
838 | pipeconf_reg = PIPECCONF; | ||
839 | dspcntr_reg = DSPCCNTR; | ||
840 | } else { | ||
841 | if (mdfld_get_panel_type(dev, pipe) == TC35876X) | ||
842 | mipi &= (~0x03); /* Use all four lanes */ | ||
843 | else | ||
844 | mipi |= 2; | ||
845 | } | ||
846 | |||
847 | /*start up display island if it was shutdown*/ | ||
848 | if (!gma_power_begin(dev, true)) | ||
849 | return; | ||
850 | |||
851 | if (mdfld_get_panel_type(dev, pipe) == TC35876X) { | ||
852 | /* | ||
853 | * The following logic is required to reset the bridge and | ||
854 | * configure. This also starts the DSI clock at 200MHz. | ||
855 | */ | ||
856 | tc35876x_set_bridge_reset_state(dev, 0); /*Pull High Reset */ | ||
857 | tc35876x_toshiba_bridge_panel_on(dev); | ||
858 | udelay(100); | ||
859 | /* Now start the DSI clock */ | ||
860 | REG_WRITE(MRST_DPLL_A, 0x00); | ||
861 | REG_WRITE(MRST_FPA0, 0xC1); | ||
862 | REG_WRITE(MRST_DPLL_A, 0x00800000); | ||
863 | udelay(500); | ||
864 | REG_WRITE(MRST_DPLL_A, 0x80800000); | ||
865 | |||
866 | if (REG_BIT_WAIT(pipeconf_reg, 1, 29)) | ||
867 | dev_err(&dev->pdev->dev, "%s: DSI PLL lock timeout\n", | ||
868 | __func__); | ||
869 | |||
870 | REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008); | ||
871 | |||
872 | mipi_set_properties(dsi_config, pipe); | ||
873 | mdfld_mipi_config(dsi_config, pipe); | ||
874 | mdfld_set_pipe_timing(dsi_config, pipe); | ||
875 | |||
876 | REG_WRITE(DSPABASE, 0x00); | ||
877 | REG_WRITE(DSPASTRIDE, (mode->hdisplay * 4)); | ||
878 | REG_WRITE(DSPASIZE, | ||
879 | ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); | ||
880 | |||
881 | REG_WRITE(DSPACNTR, 0x98000000); | ||
882 | REG_WRITE(DSPASURF, 0x00); | ||
883 | |||
884 | REG_WRITE(VGACNTRL, 0x80000000); | ||
885 | REG_WRITE(DEVICE_READY_REG, 0x00000001); | ||
886 | |||
887 | REG_WRITE(MIPI_PORT_CONTROL(pipe), 0x80810000); | ||
888 | } else { | ||
889 | /*set up mipi port FIXME: do at init time */ | ||
890 | REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi); | ||
891 | } | ||
892 | REG_READ(MIPI_PORT_CONTROL(pipe)); | ||
893 | |||
894 | if (mdfld_get_panel_type(dev, pipe) == TMD_VID) { | ||
895 | /* NOP */ | ||
896 | } else if (mdfld_get_panel_type(dev, pipe) == TC35876X) { | ||
897 | /* set up DSI controller DPI interface */ | ||
898 | mdfld_dsi_dpi_controller_init(dsi_config, pipe); | ||
899 | |||
900 | /* Configure MIPI Bridge and Panel */ | ||
901 | tc35876x_configure_lvds_bridge(dev); | ||
902 | dev_priv->dpi_panel_on[pipe] = true; | ||
903 | } else { | ||
904 | /*turn on DPI interface*/ | ||
905 | mdfld_dsi_dpi_turn_on(dpi_output, pipe); | ||
906 | } | ||
907 | |||
908 | /*set up pipe*/ | ||
909 | REG_WRITE(pipeconf_reg, pipeconf); | ||
910 | REG_READ(pipeconf_reg); | ||
911 | |||
912 | /*set up display plane*/ | ||
913 | REG_WRITE(dspcntr_reg, dspcntr); | ||
914 | REG_READ(dspcntr_reg); | ||
915 | |||
916 | msleep(20); /* FIXME: this should wait for vblank */ | ||
917 | |||
918 | if (mdfld_get_panel_type(dev, pipe) == TMD_VID) { | ||
919 | /* NOP */ | ||
920 | } else if (mdfld_get_panel_type(dev, pipe) == TC35876X) { | ||
921 | mdfld_dsi_dpi_turn_on(dpi_output, pipe); | ||
922 | } else { | ||
923 | /* init driver ic */ | ||
924 | mdfld_dsi_tpo_ic_init(dsi_config, pipe); | ||
925 | /*init backlight*/ | ||
926 | mdfld_dsi_brightness_init(dsi_config, pipe); | ||
927 | } | ||
928 | |||
929 | gma_power_end(dev); | ||
930 | } | ||
931 | |||
932 | /* | ||
933 | * Init DSI DPI encoder. | ||
934 | * Allocate an mdfld_dsi_encoder and attach it to given @dsi_connector | ||
935 | * return pointer of newly allocated DPI encoder, NULL on error | ||
936 | */ | ||
937 | struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, | ||
938 | struct mdfld_dsi_connector *dsi_connector, | ||
939 | const struct panel_funcs *p_funcs) | ||
940 | { | ||
941 | struct mdfld_dsi_dpi_output *dpi_output = NULL; | ||
942 | struct mdfld_dsi_config *dsi_config; | ||
943 | struct drm_connector *connector = NULL; | ||
944 | struct drm_encoder *encoder = NULL; | ||
945 | struct drm_display_mode *fixed_mode = NULL; | ||
946 | int pipe; | ||
947 | u32 data; | ||
948 | int ret; | ||
949 | |||
950 | pipe = dsi_connector->pipe; | ||
951 | |||
952 | if (mdfld_get_panel_type(dev, pipe) != TC35876X) { | ||
953 | dsi_config = mdfld_dsi_get_config(dsi_connector); | ||
954 | |||
955 | /* panel hard-reset */ | ||
956 | if (p_funcs->reset) { | ||
957 | ret = p_funcs->reset(pipe); | ||
958 | if (ret) { | ||
959 | DRM_ERROR("Panel %d hard-reset failed\n", pipe); | ||
960 | return NULL; | ||
961 | } | ||
962 | } | ||
963 | |||
964 | /* panel drvIC init */ | ||
965 | if (p_funcs->drv_ic_init) | ||
966 | p_funcs->drv_ic_init(dsi_config, pipe); | ||
967 | |||
968 | /* panel power mode detect */ | ||
969 | ret = mdfld_dsi_get_power_mode(dsi_config, &data, false); | ||
970 | if (ret) { | ||
971 | DRM_ERROR("Panel %d get power mode failed\n", pipe); | ||
972 | dsi_connector->status = connector_status_disconnected; | ||
973 | } else { | ||
974 | DRM_INFO("pipe %d power mode 0x%x\n", pipe, data); | ||
975 | dsi_connector->status = connector_status_connected; | ||
976 | } | ||
977 | } | ||
978 | |||
979 | dpi_output = kzalloc(sizeof(struct mdfld_dsi_dpi_output), GFP_KERNEL); | ||
980 | if (!dpi_output) { | ||
981 | DRM_ERROR("No memory\n"); | ||
982 | return NULL; | ||
983 | } | ||
984 | |||
985 | if (dsi_connector->pipe) | ||
986 | dpi_output->panel_on = 0; | ||
987 | else | ||
988 | dpi_output->panel_on = 0; | ||
989 | |||
990 | dpi_output->dev = dev; | ||
991 | if (mdfld_get_panel_type(dev, pipe) != TC35876X) | ||
992 | dpi_output->p_funcs = p_funcs; | ||
993 | dpi_output->first_boot = 1; | ||
994 | |||
995 | /*get fixed mode*/ | ||
996 | dsi_config = mdfld_dsi_get_config(dsi_connector); | ||
997 | fixed_mode = dsi_config->fixed_mode; | ||
998 | |||
999 | /*create drm encoder object*/ | ||
1000 | connector = &dsi_connector->base.base; | ||
1001 | encoder = &dpi_output->base.base.base; | ||
1002 | drm_encoder_init(dev, | ||
1003 | encoder, | ||
1004 | p_funcs->encoder_funcs, | ||
1005 | DRM_MODE_ENCODER_LVDS); | ||
1006 | drm_encoder_helper_add(encoder, | ||
1007 | p_funcs->encoder_helper_funcs); | ||
1008 | |||
1009 | /*attach to given connector*/ | ||
1010 | drm_mode_connector_attach_encoder(connector, encoder); | ||
1011 | |||
1012 | /*set possible crtcs and clones*/ | ||
1013 | if (dsi_connector->pipe) { | ||
1014 | encoder->possible_crtcs = (1 << 2); | ||
1015 | encoder->possible_clones = (1 << 1); | ||
1016 | } else { | ||
1017 | encoder->possible_crtcs = (1 << 0); | ||
1018 | encoder->possible_clones = (1 << 0); | ||
1019 | } | ||
1020 | |||
1021 | dsi_connector->base.encoder = &dpi_output->base.base; | ||
1022 | |||
1023 | return &dpi_output->base; | ||
1024 | } | ||
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h new file mode 100644 index 000000000000..6f762478b959 --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * jim liu <jim.liu@intel.com> | ||
25 | * Jackie Li<yaodong.li@intel.com> | ||
26 | */ | ||
27 | |||
28 | #ifndef __MDFLD_DSI_DPI_H__ | ||
29 | #define __MDFLD_DSI_DPI_H__ | ||
30 | |||
31 | #include "mdfld_dsi_output.h" | ||
32 | #include "mdfld_output.h" | ||
33 | |||
34 | struct mdfld_dsi_dpi_timing { | ||
35 | u16 hsync_count; | ||
36 | u16 hbp_count; | ||
37 | u16 hfp_count; | ||
38 | u16 hactive_count; | ||
39 | u16 vsync_count; | ||
40 | u16 vbp_count; | ||
41 | u16 vfp_count; | ||
42 | }; | ||
43 | |||
44 | struct mdfld_dsi_dpi_output { | ||
45 | struct mdfld_dsi_encoder base; | ||
46 | struct drm_device *dev; | ||
47 | |||
48 | int panel_on; | ||
49 | int first_boot; | ||
50 | |||
51 | const struct panel_funcs *p_funcs; | ||
52 | }; | ||
53 | |||
54 | #define MDFLD_DSI_DPI_OUTPUT(dsi_encoder)\ | ||
55 | container_of(dsi_encoder, struct mdfld_dsi_dpi_output, base) | ||
56 | |||
57 | /* Export functions */ | ||
58 | extern int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode, | ||
59 | struct mdfld_dsi_dpi_timing *dpi_timing, | ||
60 | int num_lane, int bpp); | ||
61 | extern struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, | ||
62 | struct mdfld_dsi_connector *dsi_connector, | ||
63 | const struct panel_funcs *p_funcs); | ||
64 | |||
65 | /* MDFLD DPI helper functions */ | ||
66 | extern void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode); | ||
67 | extern bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder, | ||
68 | struct drm_display_mode *mode, | ||
69 | struct drm_display_mode *adjusted_mode); | ||
70 | extern void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder); | ||
71 | extern void mdfld_dsi_dpi_commit(struct drm_encoder *encoder); | ||
72 | extern void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder, | ||
73 | struct drm_display_mode *mode, | ||
74 | struct drm_display_mode *adjusted_mode); | ||
75 | extern void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, | ||
76 | int pipe); | ||
77 | extern void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config, | ||
78 | int pipe); | ||
79 | #endif /*__MDFLD_DSI_DPI_H__*/ | ||
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c new file mode 100644 index 000000000000..9338c28f3999 --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c | |||
@@ -0,0 +1,635 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * jim liu <jim.liu@intel.com> | ||
25 | * Jackie Li<yaodong.li@intel.com> | ||
26 | */ | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | |||
30 | #include "mdfld_dsi_output.h" | ||
31 | #include "mdfld_dsi_dpi.h" | ||
32 | #include "mdfld_output.h" | ||
33 | #include "mdfld_dsi_pkg_sender.h" | ||
34 | #include "tc35876x-dsi-lvds.h" | ||
35 | #include <linux/pm_runtime.h> | ||
36 | #include <asm/intel_scu_ipc.h> | ||
37 | |||
38 | /* get the LABC from command line. */ | ||
39 | static int LABC_control = 1; | ||
40 | |||
41 | #ifdef MODULE | ||
42 | module_param(LABC_control, int, 0644); | ||
43 | #else | ||
44 | |||
45 | static int __init parse_LABC_control(char *arg) | ||
46 | { | ||
47 | /* LABC control can be passed in as a cmdline parameter */ | ||
48 | /* to enable this feature add LABC=1 to cmdline */ | ||
49 | /* to disable this feature add LABC=0 to cmdline */ | ||
50 | if (!arg) | ||
51 | return -EINVAL; | ||
52 | |||
53 | if (!strcasecmp(arg, "0")) | ||
54 | LABC_control = 0; | ||
55 | else if (!strcasecmp(arg, "1")) | ||
56 | LABC_control = 1; | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | early_param("LABC", parse_LABC_control); | ||
61 | #endif | ||
62 | |||
63 | /** | ||
64 | * Check and see if the generic control or data buffer is empty and ready. | ||
65 | */ | ||
66 | void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, u32 gen_fifo_stat_reg, | ||
67 | u32 fifo_stat) | ||
68 | { | ||
69 | u32 GEN_BF_time_out_count; | ||
70 | |||
71 | /* Check MIPI Adatper command registers */ | ||
72 | for (GEN_BF_time_out_count = 0; | ||
73 | GEN_BF_time_out_count < GEN_FB_TIME_OUT; | ||
74 | GEN_BF_time_out_count++) { | ||
75 | if ((REG_READ(gen_fifo_stat_reg) & fifo_stat) == fifo_stat) | ||
76 | break; | ||
77 | udelay(100); | ||
78 | } | ||
79 | |||
80 | if (GEN_BF_time_out_count == GEN_FB_TIME_OUT) | ||
81 | DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n", | ||
82 | gen_fifo_stat_reg); | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * Manage the DSI MIPI keyboard and display brightness. | ||
87 | * FIXME: this is exported to OSPM code. should work out an specific | ||
88 | * display interface to OSPM. | ||
89 | */ | ||
90 | |||
91 | void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe) | ||
92 | { | ||
93 | struct mdfld_dsi_pkg_sender *sender = | ||
94 | mdfld_dsi_get_pkg_sender(dsi_config); | ||
95 | struct drm_device *dev = sender->dev; | ||
96 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
97 | u32 gen_ctrl_val; | ||
98 | |||
99 | if (!sender) { | ||
100 | DRM_ERROR("No sender found\n"); | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | /* Set default display backlight value to 85% (0xd8)*/ | ||
105 | mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1, | ||
106 | true); | ||
107 | |||
108 | /* Set minimum brightness setting of CABC function to 20% (0x33)*/ | ||
109 | mdfld_dsi_send_mcs_short(sender, write_cabc_min_bright, 0x33, 1, true); | ||
110 | |||
111 | /* Enable backlight or/and LABC */ | ||
112 | gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON | | ||
113 | BACKLIGHT_ON; | ||
114 | if (LABC_control == 1) | ||
115 | gen_ctrl_val |= DISPLAY_DIMMING_ON | DISPLAY_BRIGHTNESS_AUTO | ||
116 | | GAMMA_AUTO; | ||
117 | |||
118 | if (LABC_control == 1) | ||
119 | gen_ctrl_val |= AMBIENT_LIGHT_SENSE_ON; | ||
120 | |||
121 | dev_priv->mipi_ctrl_display = gen_ctrl_val; | ||
122 | |||
123 | mdfld_dsi_send_mcs_short(sender, write_ctrl_display, (u8)gen_ctrl_val, | ||
124 | 1, true); | ||
125 | |||
126 | mdfld_dsi_send_mcs_short(sender, write_ctrl_cabc, UI_IMAGE, 1, true); | ||
127 | } | ||
128 | |||
129 | void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, int level) | ||
130 | { | ||
131 | struct mdfld_dsi_pkg_sender *sender; | ||
132 | struct drm_psb_private *dev_priv; | ||
133 | struct mdfld_dsi_config *dsi_config; | ||
134 | u32 gen_ctrl_val = 0; | ||
135 | int p_type = TMD_VID; | ||
136 | |||
137 | if (!dev || (pipe != 0 && pipe != 2)) { | ||
138 | DRM_ERROR("Invalid parameter\n"); | ||
139 | return; | ||
140 | } | ||
141 | |||
142 | p_type = mdfld_get_panel_type(dev, 0); | ||
143 | |||
144 | dev_priv = dev->dev_private; | ||
145 | |||
146 | if (pipe) | ||
147 | dsi_config = dev_priv->dsi_configs[1]; | ||
148 | else | ||
149 | dsi_config = dev_priv->dsi_configs[0]; | ||
150 | |||
151 | sender = mdfld_dsi_get_pkg_sender(dsi_config); | ||
152 | |||
153 | if (!sender) { | ||
154 | DRM_ERROR("No sender found\n"); | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | gen_ctrl_val = (level * 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff; | ||
159 | |||
160 | dev_dbg(sender->dev->dev, "pipe = %d, gen_ctrl_val = %d.\n", | ||
161 | pipe, gen_ctrl_val); | ||
162 | |||
163 | if (p_type == TMD_VID) { | ||
164 | /* Set display backlight value */ | ||
165 | mdfld_dsi_send_mcs_short(sender, tmd_write_display_brightness, | ||
166 | (u8)gen_ctrl_val, 1, true); | ||
167 | } else { | ||
168 | /* Set display backlight value */ | ||
169 | mdfld_dsi_send_mcs_short(sender, write_display_brightness, | ||
170 | (u8)gen_ctrl_val, 1, true); | ||
171 | |||
172 | /* Enable backlight control */ | ||
173 | if (level == 0) | ||
174 | gen_ctrl_val = 0; | ||
175 | else | ||
176 | gen_ctrl_val = dev_priv->mipi_ctrl_display; | ||
177 | |||
178 | mdfld_dsi_send_mcs_short(sender, write_ctrl_display, | ||
179 | (u8)gen_ctrl_val, 1, true); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config, | ||
184 | u8 dcs, u32 *data, bool hs) | ||
185 | { | ||
186 | struct mdfld_dsi_pkg_sender *sender | ||
187 | = mdfld_dsi_get_pkg_sender(dsi_config); | ||
188 | |||
189 | if (!sender || !data) { | ||
190 | DRM_ERROR("Invalid parameter\n"); | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | |||
194 | return mdfld_dsi_read_mcs(sender, dcs, data, 1, hs); | ||
195 | } | ||
196 | |||
197 | int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode, | ||
198 | bool hs) | ||
199 | { | ||
200 | if (!dsi_config || !mode) { | ||
201 | DRM_ERROR("Invalid parameter\n"); | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | |||
205 | return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, hs); | ||
206 | } | ||
207 | |||
208 | int mdfld_dsi_get_diagnostic_result(struct mdfld_dsi_config *dsi_config, | ||
209 | u32 *result, bool hs) | ||
210 | { | ||
211 | if (!dsi_config || !result) { | ||
212 | DRM_ERROR("Invalid parameter\n"); | ||
213 | return -EINVAL; | ||
214 | } | ||
215 | |||
216 | return mdfld_dsi_get_panel_status(dsi_config, 0x0f, result, hs); | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * NOTE: this function was used by OSPM. | ||
221 | * TODO: will be removed later, should work out display interfaces for OSPM | ||
222 | */ | ||
223 | void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe) | ||
224 | { | ||
225 | if (!dsi_config || ((pipe != 0) && (pipe != 2))) { | ||
226 | DRM_ERROR("Invalid parameters\n"); | ||
227 | return; | ||
228 | } | ||
229 | |||
230 | mdfld_dsi_dpi_controller_init(dsi_config, pipe); | ||
231 | } | ||
232 | |||
233 | static void mdfld_dsi_connector_save(struct drm_connector *connector) | ||
234 | { | ||
235 | } | ||
236 | |||
237 | static void mdfld_dsi_connector_restore(struct drm_connector *connector) | ||
238 | { | ||
239 | } | ||
240 | |||
241 | /* FIXME: start using the force parameter */ | ||
242 | static enum drm_connector_status | ||
243 | mdfld_dsi_connector_detect(struct drm_connector *connector, bool force) | ||
244 | { | ||
245 | struct mdfld_dsi_connector *dsi_connector | ||
246 | = mdfld_dsi_connector(connector); | ||
247 | |||
248 | dsi_connector->status = connector_status_connected; | ||
249 | |||
250 | return dsi_connector->status; | ||
251 | } | ||
252 | |||
253 | static int mdfld_dsi_connector_set_property(struct drm_connector *connector, | ||
254 | struct drm_property *property, | ||
255 | uint64_t value) | ||
256 | { | ||
257 | struct drm_encoder *encoder = connector->encoder; | ||
258 | struct backlight_device *psb_bd; | ||
259 | |||
260 | if (!strcmp(property->name, "scaling mode") && encoder) { | ||
261 | struct psb_intel_crtc *psb_crtc = | ||
262 | to_psb_intel_crtc(encoder->crtc); | ||
263 | bool centerechange; | ||
264 | uint64_t val; | ||
265 | |||
266 | if (!psb_crtc) | ||
267 | goto set_prop_error; | ||
268 | |||
269 | switch (value) { | ||
270 | case DRM_MODE_SCALE_FULLSCREEN: | ||
271 | break; | ||
272 | case DRM_MODE_SCALE_NO_SCALE: | ||
273 | break; | ||
274 | case DRM_MODE_SCALE_ASPECT: | ||
275 | break; | ||
276 | default: | ||
277 | goto set_prop_error; | ||
278 | } | ||
279 | |||
280 | if (drm_connector_property_get_value(connector, property, &val)) | ||
281 | goto set_prop_error; | ||
282 | |||
283 | if (val == value) | ||
284 | goto set_prop_done; | ||
285 | |||
286 | if (drm_connector_property_set_value(connector, | ||
287 | property, value)) | ||
288 | goto set_prop_error; | ||
289 | |||
290 | centerechange = (val == DRM_MODE_SCALE_NO_SCALE) || | ||
291 | (value == DRM_MODE_SCALE_NO_SCALE); | ||
292 | |||
293 | if (psb_crtc->saved_mode.hdisplay != 0 && | ||
294 | psb_crtc->saved_mode.vdisplay != 0) { | ||
295 | if (centerechange) { | ||
296 | if (!drm_crtc_helper_set_mode(encoder->crtc, | ||
297 | &psb_crtc->saved_mode, | ||
298 | encoder->crtc->x, | ||
299 | encoder->crtc->y, | ||
300 | encoder->crtc->fb)) | ||
301 | goto set_prop_error; | ||
302 | } else { | ||
303 | struct drm_encoder_helper_funcs *funcs = | ||
304 | encoder->helper_private; | ||
305 | funcs->mode_set(encoder, | ||
306 | &psb_crtc->saved_mode, | ||
307 | &psb_crtc->saved_adjusted_mode); | ||
308 | } | ||
309 | } | ||
310 | } else if (!strcmp(property->name, "backlight") && encoder) { | ||
311 | if (drm_connector_property_set_value(connector, property, | ||
312 | value)) | ||
313 | goto set_prop_error; | ||
314 | else { | ||
315 | psb_bd = mdfld_get_backlight_device(); | ||
316 | if (psb_bd) { | ||
317 | psb_bd->props.brightness = value; | ||
318 | mdfld_set_brightness(psb_bd); | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | set_prop_done: | ||
323 | return 0; | ||
324 | set_prop_error: | ||
325 | return -1; | ||
326 | } | ||
327 | |||
328 | static void mdfld_dsi_connector_destroy(struct drm_connector *connector) | ||
329 | { | ||
330 | struct mdfld_dsi_connector *dsi_connector = | ||
331 | mdfld_dsi_connector(connector); | ||
332 | struct mdfld_dsi_pkg_sender *sender; | ||
333 | |||
334 | if (!dsi_connector) | ||
335 | return; | ||
336 | drm_sysfs_connector_remove(connector); | ||
337 | drm_connector_cleanup(connector); | ||
338 | sender = dsi_connector->pkg_sender; | ||
339 | mdfld_dsi_pkg_sender_destroy(sender); | ||
340 | kfree(dsi_connector); | ||
341 | } | ||
342 | |||
343 | static int mdfld_dsi_connector_get_modes(struct drm_connector *connector) | ||
344 | { | ||
345 | struct mdfld_dsi_connector *dsi_connector = | ||
346 | mdfld_dsi_connector(connector); | ||
347 | struct mdfld_dsi_config *dsi_config = | ||
348 | mdfld_dsi_get_config(dsi_connector); | ||
349 | struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; | ||
350 | struct drm_display_mode *dup_mode = NULL; | ||
351 | struct drm_device *dev = connector->dev; | ||
352 | |||
353 | connector->display_info.min_vfreq = 0; | ||
354 | connector->display_info.max_vfreq = 200; | ||
355 | connector->display_info.min_hfreq = 0; | ||
356 | connector->display_info.max_hfreq = 200; | ||
357 | |||
358 | if (fixed_mode) { | ||
359 | dev_dbg(dev->dev, "fixed_mode %dx%d\n", | ||
360 | fixed_mode->hdisplay, fixed_mode->vdisplay); | ||
361 | dup_mode = drm_mode_duplicate(dev, fixed_mode); | ||
362 | drm_mode_probed_add(connector, dup_mode); | ||
363 | return 1; | ||
364 | } | ||
365 | DRM_ERROR("Didn't get any modes!\n"); | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector, | ||
370 | struct drm_display_mode *mode) | ||
371 | { | ||
372 | struct mdfld_dsi_connector *dsi_connector = | ||
373 | mdfld_dsi_connector(connector); | ||
374 | struct mdfld_dsi_config *dsi_config = | ||
375 | mdfld_dsi_get_config(dsi_connector); | ||
376 | struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; | ||
377 | |||
378 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
379 | return MODE_NO_DBLESCAN; | ||
380 | |||
381 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | ||
382 | return MODE_NO_INTERLACE; | ||
383 | |||
384 | /** | ||
385 | * FIXME: current DC has no fitting unit, reject any mode setting | ||
386 | * request | ||
387 | * Will figure out a way to do up-scaling(pannel fitting) later. | ||
388 | **/ | ||
389 | if (fixed_mode) { | ||
390 | if (mode->hdisplay != fixed_mode->hdisplay) | ||
391 | return MODE_PANEL; | ||
392 | |||
393 | if (mode->vdisplay != fixed_mode->vdisplay) | ||
394 | return MODE_PANEL; | ||
395 | } | ||
396 | |||
397 | return MODE_OK; | ||
398 | } | ||
399 | |||
400 | static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode) | ||
401 | { | ||
402 | if (mode == connector->dpms) | ||
403 | return; | ||
404 | |||
405 | /*first, execute dpms*/ | ||
406 | |||
407 | drm_helper_connector_dpms(connector, mode); | ||
408 | } | ||
409 | |||
410 | static struct drm_encoder *mdfld_dsi_connector_best_encoder( | ||
411 | struct drm_connector *connector) | ||
412 | { | ||
413 | struct mdfld_dsi_connector *dsi_connector = | ||
414 | mdfld_dsi_connector(connector); | ||
415 | struct mdfld_dsi_config *dsi_config = | ||
416 | mdfld_dsi_get_config(dsi_connector); | ||
417 | return &dsi_config->encoder->base.base; | ||
418 | } | ||
419 | |||
420 | /*DSI connector funcs*/ | ||
421 | static const struct drm_connector_funcs mdfld_dsi_connector_funcs = { | ||
422 | .dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms, | ||
423 | .save = mdfld_dsi_connector_save, | ||
424 | .restore = mdfld_dsi_connector_restore, | ||
425 | .detect = mdfld_dsi_connector_detect, | ||
426 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
427 | .set_property = mdfld_dsi_connector_set_property, | ||
428 | .destroy = mdfld_dsi_connector_destroy, | ||
429 | }; | ||
430 | |||
431 | /*DSI connector helper funcs*/ | ||
432 | static const struct drm_connector_helper_funcs | ||
433 | mdfld_dsi_connector_helper_funcs = { | ||
434 | .get_modes = mdfld_dsi_connector_get_modes, | ||
435 | .mode_valid = mdfld_dsi_connector_mode_valid, | ||
436 | .best_encoder = mdfld_dsi_connector_best_encoder, | ||
437 | }; | ||
438 | |||
439 | static int mdfld_dsi_get_default_config(struct drm_device *dev, | ||
440 | struct mdfld_dsi_config *config, int pipe) | ||
441 | { | ||
442 | if (!dev || !config) { | ||
443 | DRM_ERROR("Invalid parameters"); | ||
444 | return -EINVAL; | ||
445 | } | ||
446 | |||
447 | config->bpp = 24; | ||
448 | if (mdfld_get_panel_type(dev, pipe) == TC35876X) | ||
449 | config->lane_count = 4; | ||
450 | else | ||
451 | config->lane_count = 2; | ||
452 | config->channel_num = 0; | ||
453 | |||
454 | if (mdfld_get_panel_type(dev, pipe) == TMD_VID) | ||
455 | config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE; | ||
456 | else if (mdfld_get_panel_type(dev, pipe) == TC35876X) | ||
457 | config->video_mode = | ||
458 | MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS; | ||
459 | else | ||
460 | config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE; | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | int mdfld_dsi_panel_reset(int pipe) | ||
466 | { | ||
467 | unsigned gpio; | ||
468 | int ret = 0; | ||
469 | |||
470 | switch (pipe) { | ||
471 | case 0: | ||
472 | gpio = 128; | ||
473 | break; | ||
474 | case 2: | ||
475 | gpio = 34; | ||
476 | break; | ||
477 | default: | ||
478 | DRM_ERROR("Invalid output\n"); | ||
479 | return -EINVAL; | ||
480 | } | ||
481 | |||
482 | ret = gpio_request(gpio, "gfx"); | ||
483 | if (ret) { | ||
484 | DRM_ERROR("gpio_rqueset failed\n"); | ||
485 | return ret; | ||
486 | } | ||
487 | |||
488 | ret = gpio_direction_output(gpio, 1); | ||
489 | if (ret) { | ||
490 | DRM_ERROR("gpio_direction_output failed\n"); | ||
491 | goto gpio_error; | ||
492 | } | ||
493 | |||
494 | gpio_get_value(128); | ||
495 | |||
496 | gpio_error: | ||
497 | if (gpio_is_valid(gpio)) | ||
498 | gpio_free(gpio); | ||
499 | |||
500 | return ret; | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * MIPI output init | ||
505 | * @dev drm device | ||
506 | * @pipe pipe number. 0 or 2 | ||
507 | * @config | ||
508 | * | ||
509 | * Do the initialization of a MIPI output, including create DRM mode objects | ||
510 | * initialization of DSI output on @pipe | ||
511 | */ | ||
512 | void mdfld_dsi_output_init(struct drm_device *dev, | ||
513 | int pipe, | ||
514 | struct mdfld_dsi_config *config, | ||
515 | const struct panel_funcs *p_vid_funcs) | ||
516 | { | ||
517 | struct mdfld_dsi_config *dsi_config; | ||
518 | struct mdfld_dsi_connector *dsi_connector; | ||
519 | struct drm_connector *connector; | ||
520 | struct mdfld_dsi_encoder *encoder; | ||
521 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
522 | struct panel_info dsi_panel_info; | ||
523 | u32 width_mm, height_mm; | ||
524 | |||
525 | dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe); | ||
526 | |||
527 | if (!dev || ((pipe != 0) && (pipe != 2))) { | ||
528 | DRM_ERROR("Invalid parameter\n"); | ||
529 | return; | ||
530 | } | ||
531 | |||
532 | /*create a new connetor*/ | ||
533 | dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL); | ||
534 | if (!dsi_connector) { | ||
535 | DRM_ERROR("No memory"); | ||
536 | return; | ||
537 | } | ||
538 | |||
539 | dsi_connector->pipe = pipe; | ||
540 | |||
541 | /*set DSI config*/ | ||
542 | if (config) | ||
543 | dsi_config = config; | ||
544 | else { | ||
545 | dsi_config = kzalloc(sizeof(struct mdfld_dsi_config), | ||
546 | GFP_KERNEL); | ||
547 | if (!dsi_config) { | ||
548 | DRM_ERROR("cannot allocate memory for DSI config\n"); | ||
549 | goto dsi_init_err0; | ||
550 | } | ||
551 | mdfld_dsi_get_default_config(dev, dsi_config, pipe); | ||
552 | } | ||
553 | |||
554 | dsi_connector->private = dsi_config; | ||
555 | |||
556 | dsi_config->changed = 1; | ||
557 | dsi_config->dev = dev; | ||
558 | |||
559 | dsi_config->fixed_mode = p_vid_funcs->get_config_mode(dev); | ||
560 | if (p_vid_funcs->get_panel_info(dev, pipe, &dsi_panel_info)) | ||
561 | goto dsi_init_err0; | ||
562 | |||
563 | width_mm = dsi_panel_info.width_mm; | ||
564 | height_mm = dsi_panel_info.height_mm; | ||
565 | |||
566 | dsi_config->mode = dsi_config->fixed_mode; | ||
567 | dsi_config->connector = dsi_connector; | ||
568 | |||
569 | if (!dsi_config->fixed_mode) { | ||
570 | DRM_ERROR("No pannel fixed mode was found\n"); | ||
571 | goto dsi_init_err0; | ||
572 | } | ||
573 | |||
574 | if (pipe && dev_priv->dsi_configs[0]) { | ||
575 | dsi_config->dvr_ic_inited = 0; | ||
576 | dev_priv->dsi_configs[1] = dsi_config; | ||
577 | } else if (pipe == 0) { | ||
578 | dsi_config->dvr_ic_inited = 1; | ||
579 | dev_priv->dsi_configs[0] = dsi_config; | ||
580 | } else { | ||
581 | DRM_ERROR("Trying to init MIPI1 before MIPI0\n"); | ||
582 | goto dsi_init_err0; | ||
583 | } | ||
584 | |||
585 | |||
586 | connector = &dsi_connector->base.base; | ||
587 | drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs, | ||
588 | DRM_MODE_CONNECTOR_LVDS); | ||
589 | drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs); | ||
590 | |||
591 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
592 | connector->display_info.width_mm = width_mm; | ||
593 | connector->display_info.height_mm = height_mm; | ||
594 | connector->interlace_allowed = false; | ||
595 | connector->doublescan_allowed = false; | ||
596 | |||
597 | /*attach properties*/ | ||
598 | drm_connector_attach_property(connector, | ||
599 | dev->mode_config.scaling_mode_property, | ||
600 | DRM_MODE_SCALE_FULLSCREEN); | ||
601 | drm_connector_attach_property(connector, | ||
602 | dev_priv->backlight_property, | ||
603 | MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); | ||
604 | |||
605 | /*init DSI package sender on this output*/ | ||
606 | if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) { | ||
607 | DRM_ERROR("Package Sender initialization failed on pipe %d\n", | ||
608 | pipe); | ||
609 | goto dsi_init_err0; | ||
610 | } | ||
611 | |||
612 | encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs); | ||
613 | if (!encoder) { | ||
614 | DRM_ERROR("Create DPI encoder failed\n"); | ||
615 | goto dsi_init_err1; | ||
616 | } | ||
617 | encoder->private = dsi_config; | ||
618 | dsi_config->encoder = encoder; | ||
619 | encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI : | ||
620 | INTEL_OUTPUT_MIPI2; | ||
621 | drm_sysfs_connector_add(connector); | ||
622 | return; | ||
623 | |||
624 | /*TODO: add code to destroy outputs on error*/ | ||
625 | dsi_init_err1: | ||
626 | /*destroy sender*/ | ||
627 | mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender); | ||
628 | |||
629 | drm_connector_cleanup(connector); | ||
630 | |||
631 | kfree(dsi_config->fixed_mode); | ||
632 | kfree(dsi_config); | ||
633 | dsi_init_err0: | ||
634 | kfree(dsi_connector); | ||
635 | } | ||
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.h b/drivers/gpu/drm/gma500/mdfld_dsi_output.h new file mode 100644 index 000000000000..2cdf666536df --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.h | |||
@@ -0,0 +1,389 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * jim liu <jim.liu@intel.com> | ||
25 | * Jackie Li<yaodong.li@intel.com> | ||
26 | */ | ||
27 | |||
28 | #ifndef __MDFLD_DSI_OUTPUT_H__ | ||
29 | #define __MDFLD_DSI_OUTPUT_H__ | ||
30 | |||
31 | #include <linux/backlight.h> | ||
32 | #include <linux/version.h> | ||
33 | #include <drm/drmP.h> | ||
34 | #include <drm/drm.h> | ||
35 | #include <drm/drm_crtc.h> | ||
36 | #include <drm/drm_edid.h> | ||
37 | |||
38 | #include "psb_drv.h" | ||
39 | #include "psb_intel_drv.h" | ||
40 | #include "psb_intel_reg.h" | ||
41 | #include "mdfld_output.h" | ||
42 | |||
43 | #include <asm/mrst.h> | ||
44 | |||
45 | #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) | ||
46 | #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) | ||
47 | #define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end)) | ||
48 | #define FLD_MOD(orig, val, start, end) \ | ||
49 | (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end)) | ||
50 | |||
51 | #define REG_FLD_MOD(reg, val, start, end) \ | ||
52 | REG_WRITE(reg, FLD_MOD(REG_READ(reg), val, start, end)) | ||
53 | |||
54 | static inline int REGISTER_FLD_WAIT(struct drm_device *dev, u32 reg, | ||
55 | u32 val, int start, int end) | ||
56 | { | ||
57 | int t = 100000; | ||
58 | |||
59 | while (FLD_GET(REG_READ(reg), start, end) != val) { | ||
60 | if (--t == 0) | ||
61 | return 1; | ||
62 | } | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | #define REG_FLD_WAIT(reg, val, start, end) \ | ||
68 | REGISTER_FLD_WAIT(dev, reg, val, start, end) | ||
69 | |||
70 | #define REG_BIT_WAIT(reg, val, bitnum) \ | ||
71 | REGISTER_FLD_WAIT(dev, reg, val, bitnum, bitnum) | ||
72 | |||
73 | #define MDFLD_DSI_BRIGHTNESS_MAX_LEVEL 100 | ||
74 | |||
75 | #ifdef DEBUG | ||
76 | #define CHECK_PIPE(pipe) ({ \ | ||
77 | const typeof(pipe) __pipe = (pipe); \ | ||
78 | BUG_ON(__pipe != 0 && __pipe != 2); \ | ||
79 | __pipe; }) | ||
80 | #else | ||
81 | #define CHECK_PIPE(pipe) (pipe) | ||
82 | #endif | ||
83 | |||
84 | /* | ||
85 | * Actual MIPIA->MIPIC reg offset is 0x800, value 0x400 is valid for 0 and 2 | ||
86 | */ | ||
87 | #define REG_OFFSET(pipe) (CHECK_PIPE(pipe) * 0x400) | ||
88 | |||
89 | /* mdfld DSI controller registers */ | ||
90 | #define MIPI_DEVICE_READY_REG(pipe) (0xb000 + REG_OFFSET(pipe)) | ||
91 | #define MIPI_INTR_STAT_REG(pipe) (0xb004 + REG_OFFSET(pipe)) | ||
92 | #define MIPI_INTR_EN_REG(pipe) (0xb008 + REG_OFFSET(pipe)) | ||
93 | #define MIPI_DSI_FUNC_PRG_REG(pipe) (0xb00c + REG_OFFSET(pipe)) | ||
94 | #define MIPI_HS_TX_TIMEOUT_REG(pipe) (0xb010 + REG_OFFSET(pipe)) | ||
95 | #define MIPI_LP_RX_TIMEOUT_REG(pipe) (0xb014 + REG_OFFSET(pipe)) | ||
96 | #define MIPI_TURN_AROUND_TIMEOUT_REG(pipe) (0xb018 + REG_OFFSET(pipe)) | ||
97 | #define MIPI_DEVICE_RESET_TIMER_REG(pipe) (0xb01c + REG_OFFSET(pipe)) | ||
98 | #define MIPI_DPI_RESOLUTION_REG(pipe) (0xb020 + REG_OFFSET(pipe)) | ||
99 | #define MIPI_DBI_FIFO_THROTTLE_REG(pipe) (0xb024 + REG_OFFSET(pipe)) | ||
100 | #define MIPI_HSYNC_COUNT_REG(pipe) (0xb028 + REG_OFFSET(pipe)) | ||
101 | #define MIPI_HBP_COUNT_REG(pipe) (0xb02c + REG_OFFSET(pipe)) | ||
102 | #define MIPI_HFP_COUNT_REG(pipe) (0xb030 + REG_OFFSET(pipe)) | ||
103 | #define MIPI_HACTIVE_COUNT_REG(pipe) (0xb034 + REG_OFFSET(pipe)) | ||
104 | #define MIPI_VSYNC_COUNT_REG(pipe) (0xb038 + REG_OFFSET(pipe)) | ||
105 | #define MIPI_VBP_COUNT_REG(pipe) (0xb03c + REG_OFFSET(pipe)) | ||
106 | #define MIPI_VFP_COUNT_REG(pipe) (0xb040 + REG_OFFSET(pipe)) | ||
107 | #define MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe) (0xb044 + REG_OFFSET(pipe)) | ||
108 | #define MIPI_DPI_CONTROL_REG(pipe) (0xb048 + REG_OFFSET(pipe)) | ||
109 | #define MIPI_DPI_DATA_REG(pipe) (0xb04c + REG_OFFSET(pipe)) | ||
110 | #define MIPI_INIT_COUNT_REG(pipe) (0xb050 + REG_OFFSET(pipe)) | ||
111 | #define MIPI_MAX_RETURN_PACK_SIZE_REG(pipe) (0xb054 + REG_OFFSET(pipe)) | ||
112 | #define MIPI_VIDEO_MODE_FORMAT_REG(pipe) (0xb058 + REG_OFFSET(pipe)) | ||
113 | #define MIPI_EOT_DISABLE_REG(pipe) (0xb05c + REG_OFFSET(pipe)) | ||
114 | #define MIPI_LP_BYTECLK_REG(pipe) (0xb060 + REG_OFFSET(pipe)) | ||
115 | #define MIPI_LP_GEN_DATA_REG(pipe) (0xb064 + REG_OFFSET(pipe)) | ||
116 | #define MIPI_HS_GEN_DATA_REG(pipe) (0xb068 + REG_OFFSET(pipe)) | ||
117 | #define MIPI_LP_GEN_CTRL_REG(pipe) (0xb06c + REG_OFFSET(pipe)) | ||
118 | #define MIPI_HS_GEN_CTRL_REG(pipe) (0xb070 + REG_OFFSET(pipe)) | ||
119 | #define MIPI_GEN_FIFO_STAT_REG(pipe) (0xb074 + REG_OFFSET(pipe)) | ||
120 | #define MIPI_HS_LS_DBI_ENABLE_REG(pipe) (0xb078 + REG_OFFSET(pipe)) | ||
121 | #define MIPI_DPHY_PARAM_REG(pipe) (0xb080 + REG_OFFSET(pipe)) | ||
122 | #define MIPI_DBI_BW_CTRL_REG(pipe) (0xb084 + REG_OFFSET(pipe)) | ||
123 | #define MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe) (0xb088 + REG_OFFSET(pipe)) | ||
124 | |||
125 | #define MIPI_CTRL_REG(pipe) (0xb104 + REG_OFFSET(pipe)) | ||
126 | #define MIPI_DATA_ADD_REG(pipe) (0xb108 + REG_OFFSET(pipe)) | ||
127 | #define MIPI_DATA_LEN_REG(pipe) (0xb10c + REG_OFFSET(pipe)) | ||
128 | #define MIPI_CMD_ADD_REG(pipe) (0xb110 + REG_OFFSET(pipe)) | ||
129 | #define MIPI_CMD_LEN_REG(pipe) (0xb114 + REG_OFFSET(pipe)) | ||
130 | |||
131 | /* non-uniform reg offset */ | ||
132 | #define MIPI_PORT_CONTROL(pipe) (CHECK_PIPE(pipe) ? MIPI_C : MIPI) | ||
133 | |||
134 | #define DSI_DEVICE_READY (0x1) | ||
135 | #define DSI_POWER_STATE_ULPS_ENTER (0x2 << 1) | ||
136 | #define DSI_POWER_STATE_ULPS_EXIT (0x1 << 1) | ||
137 | #define DSI_POWER_STATE_ULPS_OFFSET (0x1) | ||
138 | |||
139 | |||
140 | #define DSI_ONE_DATA_LANE (0x1) | ||
141 | #define DSI_TWO_DATA_LANE (0x2) | ||
142 | #define DSI_THREE_DATA_LANE (0X3) | ||
143 | #define DSI_FOUR_DATA_LANE (0x4) | ||
144 | #define DSI_DPI_VIRT_CHANNEL_OFFSET (0x3) | ||
145 | #define DSI_DBI_VIRT_CHANNEL_OFFSET (0x5) | ||
146 | #define DSI_DPI_COLOR_FORMAT_RGB565 (0x01 << 7) | ||
147 | #define DSI_DPI_COLOR_FORMAT_RGB666 (0x02 << 7) | ||
148 | #define DSI_DPI_COLOR_FORMAT_RGB666_UNPACK (0x03 << 7) | ||
149 | #define DSI_DPI_COLOR_FORMAT_RGB888 (0x04 << 7) | ||
150 | #define DSI_DBI_COLOR_FORMAT_OPTION2 (0x05 << 13) | ||
151 | |||
152 | #define DSI_INTR_STATE_RXSOTERROR BIT(0) | ||
153 | |||
154 | #define DSI_INTR_STATE_SPL_PKG_SENT BIT(30) | ||
155 | #define DSI_INTR_STATE_TE BIT(31) | ||
156 | |||
157 | #define DSI_HS_TX_TIMEOUT_MASK (0xffffff) | ||
158 | |||
159 | #define DSI_LP_RX_TIMEOUT_MASK (0xffffff) | ||
160 | |||
161 | #define DSI_TURN_AROUND_TIMEOUT_MASK (0x3f) | ||
162 | |||
163 | #define DSI_RESET_TIMER_MASK (0xffff) | ||
164 | |||
165 | #define DSI_DBI_FIFO_WM_HALF (0x0) | ||
166 | #define DSI_DBI_FIFO_WM_QUARTER (0x1) | ||
167 | #define DSI_DBI_FIFO_WM_LOW (0x2) | ||
168 | |||
169 | #define DSI_DPI_TIMING_MASK (0xffff) | ||
170 | |||
171 | #define DSI_INIT_TIMER_MASK (0xffff) | ||
172 | |||
173 | #define DSI_DBI_RETURN_PACK_SIZE_MASK (0x3ff) | ||
174 | |||
175 | #define DSI_LP_BYTECLK_MASK (0x0ffff) | ||
176 | |||
177 | #define DSI_HS_CTRL_GEN_SHORT_W0 (0x03) | ||
178 | #define DSI_HS_CTRL_GEN_SHORT_W1 (0x13) | ||
179 | #define DSI_HS_CTRL_GEN_SHORT_W2 (0x23) | ||
180 | #define DSI_HS_CTRL_GEN_R0 (0x04) | ||
181 | #define DSI_HS_CTRL_GEN_R1 (0x14) | ||
182 | #define DSI_HS_CTRL_GEN_R2 (0x24) | ||
183 | #define DSI_HS_CTRL_GEN_LONG_W (0x29) | ||
184 | #define DSI_HS_CTRL_MCS_SHORT_W0 (0x05) | ||
185 | #define DSI_HS_CTRL_MCS_SHORT_W1 (0x15) | ||
186 | #define DSI_HS_CTRL_MCS_R0 (0x06) | ||
187 | #define DSI_HS_CTRL_MCS_LONG_W (0x39) | ||
188 | #define DSI_HS_CTRL_VC_OFFSET (0x06) | ||
189 | #define DSI_HS_CTRL_WC_OFFSET (0x08) | ||
190 | |||
191 | #define DSI_FIFO_GEN_HS_DATA_FULL BIT(0) | ||
192 | #define DSI_FIFO_GEN_HS_DATA_HALF_EMPTY BIT(1) | ||
193 | #define DSI_FIFO_GEN_HS_DATA_EMPTY BIT(2) | ||
194 | #define DSI_FIFO_GEN_LP_DATA_FULL BIT(8) | ||
195 | #define DSI_FIFO_GEN_LP_DATA_HALF_EMPTY BIT(9) | ||
196 | #define DSI_FIFO_GEN_LP_DATA_EMPTY BIT(10) | ||
197 | #define DSI_FIFO_GEN_HS_CTRL_FULL BIT(16) | ||
198 | #define DSI_FIFO_GEN_HS_CTRL_HALF_EMPTY BIT(17) | ||
199 | #define DSI_FIFO_GEN_HS_CTRL_EMPTY BIT(18) | ||
200 | #define DSI_FIFO_GEN_LP_CTRL_FULL BIT(24) | ||
201 | #define DSI_FIFO_GEN_LP_CTRL_HALF_EMPTY BIT(25) | ||
202 | #define DSI_FIFO_GEN_LP_CTRL_EMPTY BIT(26) | ||
203 | #define DSI_FIFO_DBI_EMPTY BIT(27) | ||
204 | #define DSI_FIFO_DPI_EMPTY BIT(28) | ||
205 | |||
206 | #define DSI_DBI_HS_LP_SWITCH_MASK (0x1) | ||
207 | |||
208 | #define DSI_HS_LP_SWITCH_COUNTER_OFFSET (0x0) | ||
209 | #define DSI_LP_HS_SWITCH_COUNTER_OFFSET (0x16) | ||
210 | |||
211 | #define DSI_DPI_CTRL_HS_SHUTDOWN (0x00000001) | ||
212 | #define DSI_DPI_CTRL_HS_TURN_ON (0x00000002) | ||
213 | |||
214 | /*dsi power modes*/ | ||
215 | #define DSI_POWER_MODE_DISPLAY_ON BIT(2) | ||
216 | #define DSI_POWER_MODE_NORMAL_ON BIT(3) | ||
217 | #define DSI_POWER_MODE_SLEEP_OUT BIT(4) | ||
218 | #define DSI_POWER_MODE_PARTIAL_ON BIT(5) | ||
219 | #define DSI_POWER_MODE_IDLE_ON BIT(6) | ||
220 | |||
221 | enum { | ||
222 | MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE = 1, | ||
223 | MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS = 2, | ||
224 | MDFLD_DSI_VIDEO_BURST_MODE = 3, | ||
225 | }; | ||
226 | |||
227 | #define DSI_DPI_COMPLETE_LAST_LINE BIT(2) | ||
228 | #define DSI_DPI_DISABLE_BTA BIT(3) | ||
229 | |||
230 | struct mdfld_dsi_connector_state { | ||
231 | u32 mipi_ctrl_reg; | ||
232 | }; | ||
233 | |||
234 | struct mdfld_dsi_encoder_state { | ||
235 | |||
236 | }; | ||
237 | |||
238 | struct mdfld_dsi_connector { | ||
239 | struct psb_intel_connector base; | ||
240 | |||
241 | int pipe; | ||
242 | void *private; | ||
243 | void *pkg_sender; | ||
244 | |||
245 | /* Connection status */ | ||
246 | enum drm_connector_status status; | ||
247 | }; | ||
248 | |||
249 | struct mdfld_dsi_encoder { | ||
250 | struct psb_intel_encoder base; | ||
251 | void *private; | ||
252 | }; | ||
253 | |||
254 | /* | ||
255 | * DSI config, consists of one DSI connector, two DSI encoders. | ||
256 | * DRM will pick up on DSI encoder basing on differents configs. | ||
257 | */ | ||
258 | struct mdfld_dsi_config { | ||
259 | struct drm_device *dev; | ||
260 | struct drm_display_mode *fixed_mode; | ||
261 | struct drm_display_mode *mode; | ||
262 | |||
263 | struct mdfld_dsi_connector *connector; | ||
264 | struct mdfld_dsi_encoder *encoder; | ||
265 | |||
266 | int changed; | ||
267 | |||
268 | int bpp; | ||
269 | int lane_count; | ||
270 | /*Virtual channel number for this encoder*/ | ||
271 | int channel_num; | ||
272 | /*video mode configure*/ | ||
273 | int video_mode; | ||
274 | |||
275 | int dvr_ic_inited; | ||
276 | }; | ||
277 | |||
278 | static inline struct mdfld_dsi_connector *mdfld_dsi_connector( | ||
279 | struct drm_connector *connector) | ||
280 | { | ||
281 | struct psb_intel_connector *psb_connector; | ||
282 | |||
283 | psb_connector = to_psb_intel_connector(connector); | ||
284 | |||
285 | return container_of(psb_connector, struct mdfld_dsi_connector, base); | ||
286 | } | ||
287 | |||
288 | static inline struct mdfld_dsi_encoder *mdfld_dsi_encoder( | ||
289 | struct drm_encoder *encoder) | ||
290 | { | ||
291 | struct psb_intel_encoder *psb_encoder; | ||
292 | |||
293 | psb_encoder = to_psb_intel_encoder(encoder); | ||
294 | |||
295 | return container_of(psb_encoder, struct mdfld_dsi_encoder, base); | ||
296 | } | ||
297 | |||
298 | static inline struct mdfld_dsi_config * | ||
299 | mdfld_dsi_get_config(struct mdfld_dsi_connector *connector) | ||
300 | { | ||
301 | if (!connector) | ||
302 | return NULL; | ||
303 | return (struct mdfld_dsi_config *)connector->private; | ||
304 | } | ||
305 | |||
306 | static inline void *mdfld_dsi_get_pkg_sender(struct mdfld_dsi_config *config) | ||
307 | { | ||
308 | struct mdfld_dsi_connector *dsi_connector; | ||
309 | |||
310 | if (!config) | ||
311 | return NULL; | ||
312 | |||
313 | dsi_connector = config->connector; | ||
314 | |||
315 | if (!dsi_connector) | ||
316 | return NULL; | ||
317 | |||
318 | return dsi_connector->pkg_sender; | ||
319 | } | ||
320 | |||
321 | static inline struct mdfld_dsi_config * | ||
322 | mdfld_dsi_encoder_get_config(struct mdfld_dsi_encoder *encoder) | ||
323 | { | ||
324 | if (!encoder) | ||
325 | return NULL; | ||
326 | return (struct mdfld_dsi_config *)encoder->private; | ||
327 | } | ||
328 | |||
329 | static inline struct mdfld_dsi_connector * | ||
330 | mdfld_dsi_encoder_get_connector(struct mdfld_dsi_encoder *encoder) | ||
331 | { | ||
332 | struct mdfld_dsi_config *config; | ||
333 | |||
334 | if (!encoder) | ||
335 | return NULL; | ||
336 | |||
337 | config = mdfld_dsi_encoder_get_config(encoder); | ||
338 | if (!config) | ||
339 | return NULL; | ||
340 | |||
341 | return config->connector; | ||
342 | } | ||
343 | |||
344 | static inline void *mdfld_dsi_encoder_get_pkg_sender( | ||
345 | struct mdfld_dsi_encoder *encoder) | ||
346 | { | ||
347 | struct mdfld_dsi_config *dsi_config; | ||
348 | |||
349 | dsi_config = mdfld_dsi_encoder_get_config(encoder); | ||
350 | if (!dsi_config) | ||
351 | return NULL; | ||
352 | |||
353 | return mdfld_dsi_get_pkg_sender(dsi_config); | ||
354 | } | ||
355 | |||
356 | static inline int mdfld_dsi_encoder_get_pipe(struct mdfld_dsi_encoder *encoder) | ||
357 | { | ||
358 | struct mdfld_dsi_connector *connector; | ||
359 | |||
360 | if (!encoder) | ||
361 | return -1; | ||
362 | |||
363 | connector = mdfld_dsi_encoder_get_connector(encoder); | ||
364 | if (!connector) | ||
365 | return -1; | ||
366 | return connector->pipe; | ||
367 | } | ||
368 | |||
369 | /* Export functions */ | ||
370 | extern void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, | ||
371 | u32 gen_fifo_stat_reg, u32 fifo_stat); | ||
372 | extern void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, | ||
373 | int pipe); | ||
374 | extern void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, | ||
375 | int level); | ||
376 | extern void mdfld_dsi_output_init(struct drm_device *dev, | ||
377 | int pipe, | ||
378 | struct mdfld_dsi_config *config, | ||
379 | const struct panel_funcs *p_vid_funcs); | ||
380 | extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, | ||
381 | int pipe); | ||
382 | |||
383 | extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, | ||
384 | u32 *mode, bool hs); | ||
385 | extern int mdfld_dsi_get_diagnostic_result(struct mdfld_dsi_config *dsi_config, | ||
386 | u32 *result, bool hs); | ||
387 | extern int mdfld_dsi_panel_reset(int pipe); | ||
388 | |||
389 | #endif /*__MDFLD_DSI_OUTPUT_H__*/ | ||
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c new file mode 100644 index 000000000000..f193acec657e --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c | |||
@@ -0,0 +1,694 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Jackie Li<yaodong.li@intel.com> | ||
25 | */ | ||
26 | |||
27 | #include <linux/freezer.h> | ||
28 | |||
29 | #include "mdfld_dsi_output.h" | ||
30 | #include "mdfld_dsi_pkg_sender.h" | ||
31 | #include "mdfld_dsi_dpi.h" | ||
32 | |||
33 | #define MDFLD_DSI_READ_MAX_COUNT 5000 | ||
34 | |||
35 | enum data_type { | ||
36 | DSI_DT_GENERIC_SHORT_WRITE_0 = 0x03, | ||
37 | DSI_DT_GENERIC_SHORT_WRITE_1 = 0x13, | ||
38 | DSI_DT_GENERIC_SHORT_WRITE_2 = 0x23, | ||
39 | DSI_DT_GENERIC_READ_0 = 0x04, | ||
40 | DSI_DT_GENERIC_READ_1 = 0x14, | ||
41 | DSI_DT_GENERIC_READ_2 = 0x24, | ||
42 | DSI_DT_GENERIC_LONG_WRITE = 0x29, | ||
43 | DSI_DT_DCS_SHORT_WRITE_0 = 0x05, | ||
44 | DSI_DT_DCS_SHORT_WRITE_1 = 0x15, | ||
45 | DSI_DT_DCS_READ = 0x06, | ||
46 | DSI_DT_DCS_LONG_WRITE = 0x39, | ||
47 | }; | ||
48 | |||
49 | enum { | ||
50 | MDFLD_DSI_PANEL_MODE_SLEEP = 0x1, | ||
51 | }; | ||
52 | |||
53 | enum { | ||
54 | MDFLD_DSI_PKG_SENDER_FREE = 0x0, | ||
55 | MDFLD_DSI_PKG_SENDER_BUSY = 0x1, | ||
56 | }; | ||
57 | |||
58 | static const char *const dsi_errors[] = { | ||
59 | "RX SOT Error", | ||
60 | "RX SOT Sync Error", | ||
61 | "RX EOT Sync Error", | ||
62 | "RX Escape Mode Entry Error", | ||
63 | "RX LP TX Sync Error", | ||
64 | "RX HS Receive Timeout Error", | ||
65 | "RX False Control Error", | ||
66 | "RX ECC Single Bit Error", | ||
67 | "RX ECC Multibit Error", | ||
68 | "RX Checksum Error", | ||
69 | "RX DSI Data Type Not Recognised", | ||
70 | "RX DSI VC ID Invalid", | ||
71 | "TX False Control Error", | ||
72 | "TX ECC Single Bit Error", | ||
73 | "TX ECC Multibit Error", | ||
74 | "TX Checksum Error", | ||
75 | "TX DSI Data Type Not Recognised", | ||
76 | "TX DSI VC ID invalid", | ||
77 | "High Contention", | ||
78 | "Low contention", | ||
79 | "DPI FIFO Under run", | ||
80 | "HS TX Timeout", | ||
81 | "LP RX Timeout", | ||
82 | "Turn Around ACK Timeout", | ||
83 | "ACK With No Error", | ||
84 | "RX Invalid TX Length", | ||
85 | "RX Prot Violation", | ||
86 | "HS Generic Write FIFO Full", | ||
87 | "LP Generic Write FIFO Full", | ||
88 | "Generic Read Data Avail" | ||
89 | "Special Packet Sent", | ||
90 | "Tearing Effect", | ||
91 | }; | ||
92 | |||
93 | static inline int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender, | ||
94 | u32 mask) | ||
95 | { | ||
96 | struct drm_device *dev = sender->dev; | ||
97 | u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg; | ||
98 | int retry = 0xffff; | ||
99 | |||
100 | while (retry--) { | ||
101 | if ((mask & REG_READ(gen_fifo_stat_reg)) == mask) | ||
102 | return 0; | ||
103 | udelay(100); | ||
104 | } | ||
105 | DRM_ERROR("fifo is NOT empty 0x%08x\n", REG_READ(gen_fifo_stat_reg)); | ||
106 | return -EIO; | ||
107 | } | ||
108 | |||
109 | static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender) | ||
110 | { | ||
111 | return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(10) | BIT(18) | | ||
112 | BIT(26) | BIT(27) | BIT(28))); | ||
113 | } | ||
114 | |||
115 | static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender) | ||
116 | { | ||
117 | return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26))); | ||
118 | } | ||
119 | |||
120 | static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender) | ||
121 | { | ||
122 | return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18))); | ||
123 | } | ||
124 | |||
125 | static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask) | ||
126 | { | ||
127 | u32 intr_stat_reg = sender->mipi_intr_stat_reg; | ||
128 | struct drm_device *dev = sender->dev; | ||
129 | |||
130 | dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask); | ||
131 | |||
132 | switch (mask) { | ||
133 | case BIT(0): | ||
134 | case BIT(1): | ||
135 | case BIT(2): | ||
136 | case BIT(3): | ||
137 | case BIT(4): | ||
138 | case BIT(5): | ||
139 | case BIT(6): | ||
140 | case BIT(7): | ||
141 | case BIT(8): | ||
142 | case BIT(9): | ||
143 | case BIT(10): | ||
144 | case BIT(11): | ||
145 | case BIT(12): | ||
146 | case BIT(13): | ||
147 | dev_dbg(sender->dev->dev, "No Action required\n"); | ||
148 | break; | ||
149 | case BIT(14): | ||
150 | /*wait for all fifo empty*/ | ||
151 | /*wait_for_all_fifos_empty(sender)*/; | ||
152 | break; | ||
153 | case BIT(15): | ||
154 | dev_dbg(sender->dev->dev, "No Action required\n"); | ||
155 | break; | ||
156 | case BIT(16): | ||
157 | break; | ||
158 | case BIT(17): | ||
159 | break; | ||
160 | case BIT(18): | ||
161 | case BIT(19): | ||
162 | dev_dbg(sender->dev->dev, "High/Low contention detected\n"); | ||
163 | /*wait for contention recovery time*/ | ||
164 | /*mdelay(10);*/ | ||
165 | /*wait for all fifo empty*/ | ||
166 | if (0) | ||
167 | wait_for_all_fifos_empty(sender); | ||
168 | break; | ||
169 | case BIT(20): | ||
170 | dev_dbg(sender->dev->dev, "No Action required\n"); | ||
171 | break; | ||
172 | case BIT(21): | ||
173 | /*wait for all fifo empty*/ | ||
174 | /*wait_for_all_fifos_empty(sender);*/ | ||
175 | break; | ||
176 | case BIT(22): | ||
177 | break; | ||
178 | case BIT(23): | ||
179 | case BIT(24): | ||
180 | case BIT(25): | ||
181 | case BIT(26): | ||
182 | case BIT(27): | ||
183 | dev_dbg(sender->dev->dev, "HS Gen fifo full\n"); | ||
184 | REG_WRITE(intr_stat_reg, mask); | ||
185 | wait_for_hs_fifos_empty(sender); | ||
186 | break; | ||
187 | case BIT(28): | ||
188 | dev_dbg(sender->dev->dev, "LP Gen fifo full\n"); | ||
189 | REG_WRITE(intr_stat_reg, mask); | ||
190 | wait_for_lp_fifos_empty(sender); | ||
191 | break; | ||
192 | case BIT(29): | ||
193 | case BIT(30): | ||
194 | case BIT(31): | ||
195 | dev_dbg(sender->dev->dev, "No Action required\n"); | ||
196 | break; | ||
197 | } | ||
198 | |||
199 | if (mask & REG_READ(intr_stat_reg)) | ||
200 | dev_dbg(sender->dev->dev, | ||
201 | "Cannot clean interrupt 0x%08x\n", mask); | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender) | ||
206 | { | ||
207 | struct drm_device *dev = sender->dev; | ||
208 | u32 intr_stat_reg = sender->mipi_intr_stat_reg; | ||
209 | u32 mask; | ||
210 | u32 intr_stat; | ||
211 | int i; | ||
212 | int err = 0; | ||
213 | |||
214 | intr_stat = REG_READ(intr_stat_reg); | ||
215 | |||
216 | for (i = 0; i < 32; i++) { | ||
217 | mask = (0x00000001UL) << i; | ||
218 | if (intr_stat & mask) { | ||
219 | dev_dbg(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]); | ||
220 | err = handle_dsi_error(sender, mask); | ||
221 | if (err) | ||
222 | DRM_ERROR("Cannot handle error\n"); | ||
223 | } | ||
224 | } | ||
225 | return err; | ||
226 | } | ||
227 | |||
228 | static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
229 | u8 cmd, u8 param, bool hs) | ||
230 | { | ||
231 | struct drm_device *dev = sender->dev; | ||
232 | u32 ctrl_reg; | ||
233 | u32 val; | ||
234 | u8 virtual_channel = 0; | ||
235 | |||
236 | if (hs) { | ||
237 | ctrl_reg = sender->mipi_hs_gen_ctrl_reg; | ||
238 | |||
239 | /* FIXME: wait_for_hs_fifos_empty(sender); */ | ||
240 | } else { | ||
241 | ctrl_reg = sender->mipi_lp_gen_ctrl_reg; | ||
242 | |||
243 | /* FIXME: wait_for_lp_fifos_empty(sender); */ | ||
244 | } | ||
245 | |||
246 | val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) | | ||
247 | FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0); | ||
248 | |||
249 | REG_WRITE(ctrl_reg, val); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
255 | u8 *data, int len, bool hs) | ||
256 | { | ||
257 | struct drm_device *dev = sender->dev; | ||
258 | u32 ctrl_reg; | ||
259 | u32 data_reg; | ||
260 | u32 val; | ||
261 | u8 *p; | ||
262 | u8 b1, b2, b3, b4; | ||
263 | u8 virtual_channel = 0; | ||
264 | int i; | ||
265 | |||
266 | if (hs) { | ||
267 | ctrl_reg = sender->mipi_hs_gen_ctrl_reg; | ||
268 | data_reg = sender->mipi_hs_gen_data_reg; | ||
269 | |||
270 | /* FIXME: wait_for_hs_fifos_empty(sender); */ | ||
271 | } else { | ||
272 | ctrl_reg = sender->mipi_lp_gen_ctrl_reg; | ||
273 | data_reg = sender->mipi_lp_gen_data_reg; | ||
274 | |||
275 | /* FIXME: wait_for_lp_fifos_empty(sender); */ | ||
276 | } | ||
277 | |||
278 | p = data; | ||
279 | for (i = 0; i < len / 4; i++) { | ||
280 | b1 = *p++; | ||
281 | b2 = *p++; | ||
282 | b3 = *p++; | ||
283 | b4 = *p++; | ||
284 | |||
285 | REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1); | ||
286 | } | ||
287 | |||
288 | i = len % 4; | ||
289 | if (i) { | ||
290 | b1 = 0; b2 = 0; b3 = 0; | ||
291 | |||
292 | switch (i) { | ||
293 | case 3: | ||
294 | b1 = *p++; | ||
295 | b2 = *p++; | ||
296 | b3 = *p++; | ||
297 | break; | ||
298 | case 2: | ||
299 | b1 = *p++; | ||
300 | b2 = *p++; | ||
301 | break; | ||
302 | case 1: | ||
303 | b1 = *p++; | ||
304 | break; | ||
305 | } | ||
306 | |||
307 | REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1); | ||
308 | } | ||
309 | |||
310 | val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) | | ||
311 | FLD_VAL(data_type, 5, 0); | ||
312 | |||
313 | REG_WRITE(ctrl_reg, val); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
319 | u8 *data, u16 len) | ||
320 | { | ||
321 | u8 cmd; | ||
322 | |||
323 | switch (data_type) { | ||
324 | case DSI_DT_DCS_SHORT_WRITE_0: | ||
325 | case DSI_DT_DCS_SHORT_WRITE_1: | ||
326 | case DSI_DT_DCS_LONG_WRITE: | ||
327 | cmd = *data; | ||
328 | break; | ||
329 | default: | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /*this prevents other package sending while doing msleep*/ | ||
334 | sender->status = MDFLD_DSI_PKG_SENDER_BUSY; | ||
335 | |||
336 | /*wait for 120 milliseconds in case exit_sleep_mode just be sent*/ | ||
337 | if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) { | ||
338 | /*TODO: replace it with msleep later*/ | ||
339 | mdelay(120); | ||
340 | } | ||
341 | |||
342 | if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) { | ||
343 | /*TODO: replace it with msleep later*/ | ||
344 | mdelay(120); | ||
345 | } | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
350 | u8 *data, u16 len) | ||
351 | { | ||
352 | u8 cmd; | ||
353 | |||
354 | switch (data_type) { | ||
355 | case DSI_DT_DCS_SHORT_WRITE_0: | ||
356 | case DSI_DT_DCS_SHORT_WRITE_1: | ||
357 | case DSI_DT_DCS_LONG_WRITE: | ||
358 | cmd = *data; | ||
359 | break; | ||
360 | default: | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | /*update panel status*/ | ||
365 | if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) { | ||
366 | sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP; | ||
367 | /*TODO: replace it with msleep later*/ | ||
368 | mdelay(120); | ||
369 | } else if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) { | ||
370 | sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP; | ||
371 | /*TODO: replace it with msleep later*/ | ||
372 | mdelay(120); | ||
373 | } else if (unlikely(cmd == DCS_SOFT_RESET)) { | ||
374 | /*TODO: replace it with msleep later*/ | ||
375 | mdelay(5); | ||
376 | } | ||
377 | |||
378 | sender->status = MDFLD_DSI_PKG_SENDER_FREE; | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
384 | u8 *data, u16 len, bool hs) | ||
385 | { | ||
386 | int ret; | ||
387 | |||
388 | /*handle DSI error*/ | ||
389 | ret = dsi_error_handler(sender); | ||
390 | if (ret) { | ||
391 | DRM_ERROR("Error handling failed\n"); | ||
392 | return -EAGAIN; | ||
393 | } | ||
394 | |||
395 | /* send pkg */ | ||
396 | if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) { | ||
397 | DRM_ERROR("sender is busy\n"); | ||
398 | return -EAGAIN; | ||
399 | } | ||
400 | |||
401 | ret = send_pkg_prepare(sender, data_type, data, len); | ||
402 | if (ret) { | ||
403 | DRM_ERROR("send_pkg_prepare error\n"); | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | switch (data_type) { | ||
408 | case DSI_DT_GENERIC_SHORT_WRITE_0: | ||
409 | case DSI_DT_GENERIC_SHORT_WRITE_1: | ||
410 | case DSI_DT_GENERIC_SHORT_WRITE_2: | ||
411 | case DSI_DT_GENERIC_READ_0: | ||
412 | case DSI_DT_GENERIC_READ_1: | ||
413 | case DSI_DT_GENERIC_READ_2: | ||
414 | case DSI_DT_DCS_SHORT_WRITE_0: | ||
415 | case DSI_DT_DCS_SHORT_WRITE_1: | ||
416 | case DSI_DT_DCS_READ: | ||
417 | ret = send_short_pkg(sender, data_type, data[0], data[1], hs); | ||
418 | break; | ||
419 | case DSI_DT_GENERIC_LONG_WRITE: | ||
420 | case DSI_DT_DCS_LONG_WRITE: | ||
421 | ret = send_long_pkg(sender, data_type, data, len, hs); | ||
422 | break; | ||
423 | } | ||
424 | |||
425 | send_pkg_done(sender, data_type, data, len); | ||
426 | |||
427 | /*FIXME: should I query complete and fifo empty here?*/ | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, | ||
433 | u32 len, bool hs) | ||
434 | { | ||
435 | unsigned long flags; | ||
436 | |||
437 | if (!sender || !data || !len) { | ||
438 | DRM_ERROR("Invalid parameters\n"); | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | spin_lock_irqsave(&sender->lock, flags); | ||
443 | send_pkg(sender, DSI_DT_DCS_LONG_WRITE, data, len, hs); | ||
444 | spin_unlock_irqrestore(&sender->lock, flags); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd, | ||
450 | u8 param, u8 param_num, bool hs) | ||
451 | { | ||
452 | u8 data[2]; | ||
453 | unsigned long flags; | ||
454 | u8 data_type; | ||
455 | |||
456 | if (!sender) { | ||
457 | DRM_ERROR("Invalid parameter\n"); | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | |||
461 | data[0] = cmd; | ||
462 | |||
463 | if (param_num) { | ||
464 | data_type = DSI_DT_DCS_SHORT_WRITE_1; | ||
465 | data[1] = param; | ||
466 | } else { | ||
467 | data_type = DSI_DT_DCS_SHORT_WRITE_0; | ||
468 | data[1] = 0; | ||
469 | } | ||
470 | |||
471 | spin_lock_irqsave(&sender->lock, flags); | ||
472 | send_pkg(sender, data_type, data, sizeof(data), hs); | ||
473 | spin_unlock_irqrestore(&sender->lock, flags); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0, | ||
479 | u8 param1, u8 param_num, bool hs) | ||
480 | { | ||
481 | u8 data[2]; | ||
482 | unsigned long flags; | ||
483 | u8 data_type; | ||
484 | |||
485 | if (!sender || param_num < 0 || param_num > 2) { | ||
486 | DRM_ERROR("Invalid parameter\n"); | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | |||
490 | switch (param_num) { | ||
491 | case 0: | ||
492 | data_type = DSI_DT_GENERIC_SHORT_WRITE_0; | ||
493 | data[0] = 0; | ||
494 | data[1] = 0; | ||
495 | break; | ||
496 | case 1: | ||
497 | data_type = DSI_DT_GENERIC_SHORT_WRITE_1; | ||
498 | data[0] = param0; | ||
499 | data[1] = 0; | ||
500 | break; | ||
501 | case 2: | ||
502 | data_type = DSI_DT_GENERIC_SHORT_WRITE_2; | ||
503 | data[0] = param0; | ||
504 | data[1] = param1; | ||
505 | break; | ||
506 | } | ||
507 | |||
508 | spin_lock_irqsave(&sender->lock, flags); | ||
509 | send_pkg(sender, data_type, data, sizeof(data), hs); | ||
510 | spin_unlock_irqrestore(&sender->lock, flags); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, | ||
516 | u32 len, bool hs) | ||
517 | { | ||
518 | unsigned long flags; | ||
519 | |||
520 | if (!sender || !data || !len) { | ||
521 | DRM_ERROR("Invalid parameters\n"); | ||
522 | return -EINVAL; | ||
523 | } | ||
524 | |||
525 | spin_lock_irqsave(&sender->lock, flags); | ||
526 | send_pkg(sender, DSI_DT_GENERIC_LONG_WRITE, data, len, hs); | ||
527 | spin_unlock_irqrestore(&sender->lock, flags); | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type, | ||
533 | u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs) | ||
534 | { | ||
535 | unsigned long flags; | ||
536 | struct drm_device *dev = sender->dev; | ||
537 | int i; | ||
538 | u32 gen_data_reg; | ||
539 | int retry = MDFLD_DSI_READ_MAX_COUNT; | ||
540 | |||
541 | if (!sender || !data_out || !len_out) { | ||
542 | DRM_ERROR("Invalid parameters\n"); | ||
543 | return -EINVAL; | ||
544 | } | ||
545 | |||
546 | /** | ||
547 | * do reading. | ||
548 | * 0) send out generic read request | ||
549 | * 1) polling read data avail interrupt | ||
550 | * 2) read data | ||
551 | */ | ||
552 | spin_lock_irqsave(&sender->lock, flags); | ||
553 | |||
554 | REG_WRITE(sender->mipi_intr_stat_reg, BIT(29)); | ||
555 | |||
556 | if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) | ||
557 | DRM_ERROR("Can NOT clean read data valid interrupt\n"); | ||
558 | |||
559 | /*send out read request*/ | ||
560 | send_pkg(sender, data_type, data, len, hs); | ||
561 | |||
562 | /*polling read data avail interrupt*/ | ||
563 | while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) { | ||
564 | udelay(100); | ||
565 | retry--; | ||
566 | } | ||
567 | |||
568 | if (!retry) { | ||
569 | spin_unlock_irqrestore(&sender->lock, flags); | ||
570 | return -ETIMEDOUT; | ||
571 | } | ||
572 | |||
573 | REG_WRITE(sender->mipi_intr_stat_reg, BIT(29)); | ||
574 | |||
575 | /*read data*/ | ||
576 | if (hs) | ||
577 | gen_data_reg = sender->mipi_hs_gen_data_reg; | ||
578 | else | ||
579 | gen_data_reg = sender->mipi_lp_gen_data_reg; | ||
580 | |||
581 | for (i = 0; i < len_out; i++) | ||
582 | *(data_out + i) = REG_READ(gen_data_reg); | ||
583 | |||
584 | spin_unlock_irqrestore(&sender->lock, flags); | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd, | ||
590 | u32 *data, u16 len, bool hs) | ||
591 | { | ||
592 | if (!sender || !data || !len) { | ||
593 | DRM_ERROR("Invalid parameters\n"); | ||
594 | return -EINVAL; | ||
595 | } | ||
596 | |||
597 | return __read_panel_data(sender, DSI_DT_DCS_READ, &cmd, 1, | ||
598 | data, len, hs); | ||
599 | } | ||
600 | |||
601 | int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector, | ||
602 | int pipe) | ||
603 | { | ||
604 | struct mdfld_dsi_pkg_sender *pkg_sender; | ||
605 | struct mdfld_dsi_config *dsi_config = | ||
606 | mdfld_dsi_get_config(dsi_connector); | ||
607 | struct drm_device *dev = dsi_config->dev; | ||
608 | u32 mipi_val = 0; | ||
609 | |||
610 | if (!dsi_connector) { | ||
611 | DRM_ERROR("Invalid parameter\n"); | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | |||
615 | pkg_sender = dsi_connector->pkg_sender; | ||
616 | |||
617 | if (!pkg_sender || IS_ERR(pkg_sender)) { | ||
618 | pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender), | ||
619 | GFP_KERNEL); | ||
620 | if (!pkg_sender) { | ||
621 | DRM_ERROR("Create DSI pkg sender failed\n"); | ||
622 | return -ENOMEM; | ||
623 | } | ||
624 | dsi_connector->pkg_sender = (void *)pkg_sender; | ||
625 | } | ||
626 | |||
627 | pkg_sender->dev = dev; | ||
628 | pkg_sender->dsi_connector = dsi_connector; | ||
629 | pkg_sender->pipe = pipe; | ||
630 | pkg_sender->pkg_num = 0; | ||
631 | pkg_sender->panel_mode = 0; | ||
632 | pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE; | ||
633 | |||
634 | /*init regs*/ | ||
635 | if (pipe == 0) { | ||
636 | pkg_sender->dpll_reg = MRST_DPLL_A; | ||
637 | pkg_sender->dspcntr_reg = DSPACNTR; | ||
638 | pkg_sender->pipeconf_reg = PIPEACONF; | ||
639 | pkg_sender->dsplinoff_reg = DSPALINOFF; | ||
640 | pkg_sender->dspsurf_reg = DSPASURF; | ||
641 | pkg_sender->pipestat_reg = PIPEASTAT; | ||
642 | } else if (pipe == 2) { | ||
643 | pkg_sender->dpll_reg = MRST_DPLL_A; | ||
644 | pkg_sender->dspcntr_reg = DSPCCNTR; | ||
645 | pkg_sender->pipeconf_reg = PIPECCONF; | ||
646 | pkg_sender->dsplinoff_reg = DSPCLINOFF; | ||
647 | pkg_sender->dspsurf_reg = DSPCSURF; | ||
648 | pkg_sender->pipestat_reg = PIPECSTAT; | ||
649 | } | ||
650 | |||
651 | pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe); | ||
652 | pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe); | ||
653 | pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe); | ||
654 | pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe); | ||
655 | pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe); | ||
656 | pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); | ||
657 | pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe); | ||
658 | pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe); | ||
659 | pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe); | ||
660 | pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe); | ||
661 | |||
662 | /*init lock*/ | ||
663 | spin_lock_init(&pkg_sender->lock); | ||
664 | |||
665 | if (mdfld_get_panel_type(dev, pipe) != TC35876X) { | ||
666 | /** | ||
667 | * For video mode, don't enable DPI timing output here, | ||
668 | * will init the DPI timing output during mode setting. | ||
669 | */ | ||
670 | mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; | ||
671 | |||
672 | if (pipe == 0) | ||
673 | mipi_val |= 0x2; | ||
674 | |||
675 | REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val); | ||
676 | REG_READ(MIPI_PORT_CONTROL(pipe)); | ||
677 | |||
678 | /* do dsi controller init */ | ||
679 | mdfld_dsi_controller_init(dsi_config, pipe); | ||
680 | } | ||
681 | |||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender) | ||
686 | { | ||
687 | if (!sender || IS_ERR(sender)) | ||
688 | return; | ||
689 | |||
690 | /*free*/ | ||
691 | kfree(sender); | ||
692 | } | ||
693 | |||
694 | |||
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h new file mode 100644 index 000000000000..459cd7ea8b81 --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Jackie Li<yaodong.li@intel.com> | ||
25 | */ | ||
26 | #ifndef __MDFLD_DSI_PKG_SENDER_H__ | ||
27 | #define __MDFLD_DSI_PKG_SENDER_H__ | ||
28 | |||
29 | #include <linux/kthread.h> | ||
30 | |||
31 | #define MDFLD_MAX_DCS_PARAM 8 | ||
32 | |||
33 | struct mdfld_dsi_pkg_sender { | ||
34 | struct drm_device *dev; | ||
35 | struct mdfld_dsi_connector *dsi_connector; | ||
36 | u32 status; | ||
37 | u32 panel_mode; | ||
38 | |||
39 | int pipe; | ||
40 | |||
41 | spinlock_t lock; | ||
42 | |||
43 | u32 pkg_num; | ||
44 | |||
45 | /* Registers */ | ||
46 | u32 dpll_reg; | ||
47 | u32 dspcntr_reg; | ||
48 | u32 pipeconf_reg; | ||
49 | u32 pipestat_reg; | ||
50 | u32 dsplinoff_reg; | ||
51 | u32 dspsurf_reg; | ||
52 | |||
53 | u32 mipi_intr_stat_reg; | ||
54 | u32 mipi_lp_gen_data_reg; | ||
55 | u32 mipi_hs_gen_data_reg; | ||
56 | u32 mipi_lp_gen_ctrl_reg; | ||
57 | u32 mipi_hs_gen_ctrl_reg; | ||
58 | u32 mipi_gen_fifo_stat_reg; | ||
59 | u32 mipi_data_addr_reg; | ||
60 | u32 mipi_data_len_reg; | ||
61 | u32 mipi_cmd_addr_reg; | ||
62 | u32 mipi_cmd_len_reg; | ||
63 | }; | ||
64 | |||
65 | /* DCS definitions */ | ||
66 | #define DCS_SOFT_RESET 0x01 | ||
67 | #define DCS_ENTER_SLEEP_MODE 0x10 | ||
68 | #define DCS_EXIT_SLEEP_MODE 0x11 | ||
69 | #define DCS_SET_DISPLAY_OFF 0x28 | ||
70 | #define DCS_SET_DISPLAY_ON 0x29 | ||
71 | #define DCS_SET_COLUMN_ADDRESS 0x2a | ||
72 | #define DCS_SET_PAGE_ADDRESS 0x2b | ||
73 | #define DCS_WRITE_MEM_START 0x2c | ||
74 | #define DCS_SET_TEAR_OFF 0x34 | ||
75 | #define DCS_SET_TEAR_ON 0x35 | ||
76 | |||
77 | extern int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector, | ||
78 | int pipe); | ||
79 | extern void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender); | ||
80 | int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd, | ||
81 | u8 param, u8 param_num, bool hs); | ||
82 | int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, | ||
83 | u32 len, bool hs); | ||
84 | int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0, | ||
85 | u8 param1, u8 param_num, bool hs); | ||
86 | int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, | ||
87 | u32 len, bool hs); | ||
88 | /* Read interfaces */ | ||
89 | int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd, | ||
90 | u32 *data, u16 len, bool hs); | ||
91 | |||
92 | #endif | ||
diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c new file mode 100644 index 000000000000..55e5af5cbd3d --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c | |||
@@ -0,0 +1,1192 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2007 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | */ | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | |||
24 | #include <drm/drmP.h> | ||
25 | #include "psb_intel_reg.h" | ||
26 | #include "psb_intel_display.h" | ||
27 | #include "framebuffer.h" | ||
28 | #include "mdfld_output.h" | ||
29 | #include "mdfld_dsi_output.h" | ||
30 | |||
31 | /* Hardcoded currently */ | ||
32 | static int ksel = KSEL_CRYSTAL_19; | ||
33 | |||
34 | struct psb_intel_range_t { | ||
35 | int min, max; | ||
36 | }; | ||
37 | |||
38 | struct mrst_limit_t { | ||
39 | struct psb_intel_range_t dot, m, p1; | ||
40 | }; | ||
41 | |||
42 | struct mrst_clock_t { | ||
43 | /* derived values */ | ||
44 | int dot; | ||
45 | int m; | ||
46 | int p1; | ||
47 | }; | ||
48 | |||
49 | #define COUNT_MAX 0x10000000 | ||
50 | |||
51 | void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe) | ||
52 | { | ||
53 | int count, temp; | ||
54 | u32 pipeconf_reg = PIPEACONF; | ||
55 | |||
56 | switch (pipe) { | ||
57 | case 0: | ||
58 | break; | ||
59 | case 1: | ||
60 | pipeconf_reg = PIPEBCONF; | ||
61 | break; | ||
62 | case 2: | ||
63 | pipeconf_reg = PIPECCONF; | ||
64 | break; | ||
65 | default: | ||
66 | DRM_ERROR("Illegal Pipe Number.\n"); | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | /* FIXME JLIU7_PO */ | ||
71 | psb_intel_wait_for_vblank(dev); | ||
72 | return; | ||
73 | |||
74 | /* Wait for for the pipe disable to take effect. */ | ||
75 | for (count = 0; count < COUNT_MAX; count++) { | ||
76 | temp = REG_READ(pipeconf_reg); | ||
77 | if ((temp & PIPEACONF_PIPE_STATE) == 0) | ||
78 | break; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe) | ||
83 | { | ||
84 | int count, temp; | ||
85 | u32 pipeconf_reg = PIPEACONF; | ||
86 | |||
87 | switch (pipe) { | ||
88 | case 0: | ||
89 | break; | ||
90 | case 1: | ||
91 | pipeconf_reg = PIPEBCONF; | ||
92 | break; | ||
93 | case 2: | ||
94 | pipeconf_reg = PIPECCONF; | ||
95 | break; | ||
96 | default: | ||
97 | DRM_ERROR("Illegal Pipe Number.\n"); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | /* FIXME JLIU7_PO */ | ||
102 | psb_intel_wait_for_vblank(dev); | ||
103 | return; | ||
104 | |||
105 | /* Wait for for the pipe enable to take effect. */ | ||
106 | for (count = 0; count < COUNT_MAX; count++) { | ||
107 | temp = REG_READ(pipeconf_reg); | ||
108 | if ((temp & PIPEACONF_PIPE_STATE) == 1) | ||
109 | break; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | static void psb_intel_crtc_prepare(struct drm_crtc *crtc) | ||
114 | { | ||
115 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
116 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
117 | } | ||
118 | |||
119 | static void psb_intel_crtc_commit(struct drm_crtc *crtc) | ||
120 | { | ||
121 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
122 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
123 | } | ||
124 | |||
125 | static bool psb_intel_crtc_mode_fixup(struct drm_crtc *crtc, | ||
126 | struct drm_display_mode *mode, | ||
127 | struct drm_display_mode *adjusted_mode) | ||
128 | { | ||
129 | return true; | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * Return the pipe currently connected to the panel fitter, | ||
134 | * or -1 if the panel fitter is not present or not in use | ||
135 | */ | ||
136 | static int psb_intel_panel_fitter_pipe(struct drm_device *dev) | ||
137 | { | ||
138 | u32 pfit_control; | ||
139 | |||
140 | pfit_control = REG_READ(PFIT_CONTROL); | ||
141 | |||
142 | /* See if the panel fitter is in use */ | ||
143 | if ((pfit_control & PFIT_ENABLE) == 0) | ||
144 | return -1; | ||
145 | |||
146 | /* 965 can place panel fitter on either pipe */ | ||
147 | return (pfit_control >> 29) & 0x3; | ||
148 | } | ||
149 | |||
150 | static struct drm_device globle_dev; | ||
151 | |||
152 | void mdfld__intel_plane_set_alpha(int enable) | ||
153 | { | ||
154 | struct drm_device *dev = &globle_dev; | ||
155 | int dspcntr_reg = DSPACNTR; | ||
156 | u32 dspcntr; | ||
157 | |||
158 | dspcntr = REG_READ(dspcntr_reg); | ||
159 | |||
160 | if (enable) { | ||
161 | dspcntr &= ~DISPPLANE_32BPP_NO_ALPHA; | ||
162 | dspcntr |= DISPPLANE_32BPP; | ||
163 | } else { | ||
164 | dspcntr &= ~DISPPLANE_32BPP; | ||
165 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | ||
166 | } | ||
167 | |||
168 | REG_WRITE(dspcntr_reg, dspcntr); | ||
169 | } | ||
170 | |||
171 | static int check_fb(struct drm_framebuffer *fb) | ||
172 | { | ||
173 | if (!fb) | ||
174 | return 0; | ||
175 | |||
176 | switch (fb->bits_per_pixel) { | ||
177 | case 8: | ||
178 | case 16: | ||
179 | case 24: | ||
180 | case 32: | ||
181 | return 0; | ||
182 | default: | ||
183 | DRM_ERROR("Unknown color depth\n"); | ||
184 | return -EINVAL; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, | ||
189 | struct drm_framebuffer *old_fb) | ||
190 | { | ||
191 | struct drm_device *dev = crtc->dev; | ||
192 | /* struct drm_i915_master_private *master_priv; */ | ||
193 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
194 | struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); | ||
195 | int pipe = psb_intel_crtc->pipe; | ||
196 | unsigned long start, offset; | ||
197 | int dsplinoff = DSPALINOFF; | ||
198 | int dspsurf = DSPASURF; | ||
199 | int dspstride = DSPASTRIDE; | ||
200 | int dspcntr_reg = DSPACNTR; | ||
201 | u32 dspcntr; | ||
202 | int ret; | ||
203 | |||
204 | memcpy(&globle_dev, dev, sizeof(struct drm_device)); | ||
205 | |||
206 | dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe); | ||
207 | |||
208 | /* no fb bound */ | ||
209 | if (!crtc->fb) { | ||
210 | dev_dbg(dev->dev, "No FB bound\n"); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | ret = check_fb(crtc->fb); | ||
215 | if (ret) | ||
216 | return ret; | ||
217 | |||
218 | switch (pipe) { | ||
219 | case 0: | ||
220 | dsplinoff = DSPALINOFF; | ||
221 | break; | ||
222 | case 1: | ||
223 | dsplinoff = DSPBLINOFF; | ||
224 | dspsurf = DSPBSURF; | ||
225 | dspstride = DSPBSTRIDE; | ||
226 | dspcntr_reg = DSPBCNTR; | ||
227 | break; | ||
228 | case 2: | ||
229 | dsplinoff = DSPCLINOFF; | ||
230 | dspsurf = DSPCSURF; | ||
231 | dspstride = DSPCSTRIDE; | ||
232 | dspcntr_reg = DSPCCNTR; | ||
233 | break; | ||
234 | default: | ||
235 | DRM_ERROR("Illegal Pipe Number.\n"); | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | if (!gma_power_begin(dev, true)) | ||
240 | return 0; | ||
241 | |||
242 | start = psbfb->gtt->offset; | ||
243 | offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); | ||
244 | |||
245 | REG_WRITE(dspstride, crtc->fb->pitches[0]); | ||
246 | dspcntr = REG_READ(dspcntr_reg); | ||
247 | dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; | ||
248 | |||
249 | switch (crtc->fb->bits_per_pixel) { | ||
250 | case 8: | ||
251 | dspcntr |= DISPPLANE_8BPP; | ||
252 | break; | ||
253 | case 16: | ||
254 | if (crtc->fb->depth == 15) | ||
255 | dspcntr |= DISPPLANE_15_16BPP; | ||
256 | else | ||
257 | dspcntr |= DISPPLANE_16BPP; | ||
258 | break; | ||
259 | case 24: | ||
260 | case 32: | ||
261 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | ||
262 | break; | ||
263 | } | ||
264 | REG_WRITE(dspcntr_reg, dspcntr); | ||
265 | |||
266 | dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n", | ||
267 | start, offset, x, y); | ||
268 | REG_WRITE(dsplinoff, offset); | ||
269 | REG_READ(dsplinoff); | ||
270 | REG_WRITE(dspsurf, start); | ||
271 | REG_READ(dspsurf); | ||
272 | |||
273 | gma_power_end(dev); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * Disable the pipe, plane and pll. | ||
280 | * | ||
281 | */ | ||
282 | void mdfld_disable_crtc(struct drm_device *dev, int pipe) | ||
283 | { | ||
284 | int dpll_reg = MRST_DPLL_A; | ||
285 | int dspcntr_reg = DSPACNTR; | ||
286 | int dspbase_reg = MRST_DSPABASE; | ||
287 | int pipeconf_reg = PIPEACONF; | ||
288 | u32 temp; | ||
289 | |||
290 | dev_dbg(dev->dev, "pipe = %d\n", pipe); | ||
291 | |||
292 | |||
293 | switch (pipe) { | ||
294 | case 0: | ||
295 | break; | ||
296 | case 1: | ||
297 | dpll_reg = MDFLD_DPLL_B; | ||
298 | dspcntr_reg = DSPBCNTR; | ||
299 | dspbase_reg = DSPBSURF; | ||
300 | pipeconf_reg = PIPEBCONF; | ||
301 | break; | ||
302 | case 2: | ||
303 | dpll_reg = MRST_DPLL_A; | ||
304 | dspcntr_reg = DSPCCNTR; | ||
305 | dspbase_reg = MDFLD_DSPCBASE; | ||
306 | pipeconf_reg = PIPECCONF; | ||
307 | break; | ||
308 | default: | ||
309 | DRM_ERROR("Illegal Pipe Number.\n"); | ||
310 | return; | ||
311 | } | ||
312 | |||
313 | if (pipe != 1) | ||
314 | mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe), | ||
315 | HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); | ||
316 | |||
317 | /* Disable display plane */ | ||
318 | temp = REG_READ(dspcntr_reg); | ||
319 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
320 | REG_WRITE(dspcntr_reg, | ||
321 | temp & ~DISPLAY_PLANE_ENABLE); | ||
322 | /* Flush the plane changes */ | ||
323 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
324 | REG_READ(dspbase_reg); | ||
325 | } | ||
326 | |||
327 | /* FIXME_JLIU7 MDFLD_PO revisit */ | ||
328 | |||
329 | /* Next, disable display pipes */ | ||
330 | temp = REG_READ(pipeconf_reg); | ||
331 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
332 | temp &= ~PIPEACONF_ENABLE; | ||
333 | temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; | ||
334 | REG_WRITE(pipeconf_reg, temp); | ||
335 | REG_READ(pipeconf_reg); | ||
336 | |||
337 | /* Wait for for the pipe disable to take effect. */ | ||
338 | mdfldWaitForPipeDisable(dev, pipe); | ||
339 | } | ||
340 | |||
341 | temp = REG_READ(dpll_reg); | ||
342 | if (temp & DPLL_VCO_ENABLE) { | ||
343 | if ((pipe != 1 && | ||
344 | !((REG_READ(PIPEACONF) | REG_READ(PIPECCONF)) | ||
345 | & PIPEACONF_ENABLE)) || pipe == 1) { | ||
346 | temp &= ~(DPLL_VCO_ENABLE); | ||
347 | REG_WRITE(dpll_reg, temp); | ||
348 | REG_READ(dpll_reg); | ||
349 | /* Wait for the clocks to turn off. */ | ||
350 | /* FIXME_MDFLD PO may need more delay */ | ||
351 | udelay(500); | ||
352 | |||
353 | if (!(temp & MDFLD_PWR_GATE_EN)) { | ||
354 | /* gating power of DPLL */ | ||
355 | REG_WRITE(dpll_reg, temp | MDFLD_PWR_GATE_EN); | ||
356 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | ||
357 | udelay(5000); | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | |||
362 | } | ||
363 | |||
364 | /** | ||
365 | * Sets the power management mode of the pipe and plane. | ||
366 | * | ||
367 | * This code should probably grow support for turning the cursor off and back | ||
368 | * on appropriately at the same time as we're turning the pipe off/on. | ||
369 | */ | ||
370 | static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
371 | { | ||
372 | struct drm_device *dev = crtc->dev; | ||
373 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
374 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
375 | int pipe = psb_intel_crtc->pipe; | ||
376 | int dpll_reg = MRST_DPLL_A; | ||
377 | int dspcntr_reg = DSPACNTR; | ||
378 | int dspbase_reg = MRST_DSPABASE; | ||
379 | int pipeconf_reg = PIPEACONF; | ||
380 | u32 pipestat_reg = PIPEASTAT; | ||
381 | u32 pipeconf = dev_priv->pipeconf[pipe]; | ||
382 | u32 temp; | ||
383 | bool enabled; | ||
384 | int timeout = 0; | ||
385 | |||
386 | dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe); | ||
387 | |||
388 | /* FIXME_JLIU7 MDFLD_PO replaced w/ the following function */ | ||
389 | /* mdfld_dbi_dpms (struct drm_device *dev, int pipe, bool enabled) */ | ||
390 | |||
391 | switch (pipe) { | ||
392 | case 0: | ||
393 | break; | ||
394 | case 1: | ||
395 | dpll_reg = DPLL_B; | ||
396 | dspcntr_reg = DSPBCNTR; | ||
397 | dspbase_reg = MRST_DSPBBASE; | ||
398 | pipeconf_reg = PIPEBCONF; | ||
399 | dpll_reg = MDFLD_DPLL_B; | ||
400 | break; | ||
401 | case 2: | ||
402 | dpll_reg = MRST_DPLL_A; | ||
403 | dspcntr_reg = DSPCCNTR; | ||
404 | dspbase_reg = MDFLD_DSPCBASE; | ||
405 | pipeconf_reg = PIPECCONF; | ||
406 | pipestat_reg = PIPECSTAT; | ||
407 | break; | ||
408 | default: | ||
409 | DRM_ERROR("Illegal Pipe Number.\n"); | ||
410 | return; | ||
411 | } | ||
412 | |||
413 | if (!gma_power_begin(dev, true)) | ||
414 | return; | ||
415 | |||
416 | /* XXX: When our outputs are all unaware of DPMS modes other than off | ||
417 | * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. | ||
418 | */ | ||
419 | switch (mode) { | ||
420 | case DRM_MODE_DPMS_ON: | ||
421 | case DRM_MODE_DPMS_STANDBY: | ||
422 | case DRM_MODE_DPMS_SUSPEND: | ||
423 | /* Enable the DPLL */ | ||
424 | temp = REG_READ(dpll_reg); | ||
425 | |||
426 | if ((temp & DPLL_VCO_ENABLE) == 0) { | ||
427 | /* When ungating power of DPLL, needs to wait 0.5us | ||
428 | before enable the VCO */ | ||
429 | if (temp & MDFLD_PWR_GATE_EN) { | ||
430 | temp &= ~MDFLD_PWR_GATE_EN; | ||
431 | REG_WRITE(dpll_reg, temp); | ||
432 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | ||
433 | udelay(500); | ||
434 | } | ||
435 | |||
436 | REG_WRITE(dpll_reg, temp); | ||
437 | REG_READ(dpll_reg); | ||
438 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | ||
439 | udelay(500); | ||
440 | |||
441 | REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
442 | REG_READ(dpll_reg); | ||
443 | |||
444 | /** | ||
445 | * wait for DSI PLL to lock | ||
446 | * NOTE: only need to poll status of pipe 0 and pipe 1, | ||
447 | * since both MIPI pipes share the same PLL. | ||
448 | */ | ||
449 | while ((pipe != 2) && (timeout < 20000) && | ||
450 | !(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) { | ||
451 | udelay(150); | ||
452 | timeout++; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | /* Enable the plane */ | ||
457 | temp = REG_READ(dspcntr_reg); | ||
458 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { | ||
459 | REG_WRITE(dspcntr_reg, | ||
460 | temp | DISPLAY_PLANE_ENABLE); | ||
461 | /* Flush the plane changes */ | ||
462 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
463 | } | ||
464 | |||
465 | /* Enable the pipe */ | ||
466 | temp = REG_READ(pipeconf_reg); | ||
467 | if ((temp & PIPEACONF_ENABLE) == 0) { | ||
468 | REG_WRITE(pipeconf_reg, pipeconf); | ||
469 | |||
470 | /* Wait for for the pipe enable to take effect. */ | ||
471 | mdfldWaitForPipeEnable(dev, pipe); | ||
472 | } | ||
473 | |||
474 | /*workaround for sighting 3741701 Random X blank display*/ | ||
475 | /*perform w/a in video mode only on pipe A or C*/ | ||
476 | if (pipe == 0 || pipe == 2) { | ||
477 | REG_WRITE(pipestat_reg, REG_READ(pipestat_reg)); | ||
478 | msleep(100); | ||
479 | if (PIPE_VBLANK_STATUS & REG_READ(pipestat_reg)) | ||
480 | dev_dbg(dev->dev, "OK"); | ||
481 | else { | ||
482 | dev_dbg(dev->dev, "STUCK!!!!"); | ||
483 | /*shutdown controller*/ | ||
484 | temp = REG_READ(dspcntr_reg); | ||
485 | REG_WRITE(dspcntr_reg, | ||
486 | temp & ~DISPLAY_PLANE_ENABLE); | ||
487 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
488 | /*mdfld_dsi_dpi_shut_down(dev, pipe);*/ | ||
489 | REG_WRITE(0xb048, 1); | ||
490 | msleep(100); | ||
491 | temp = REG_READ(pipeconf_reg); | ||
492 | temp &= ~PIPEACONF_ENABLE; | ||
493 | REG_WRITE(pipeconf_reg, temp); | ||
494 | msleep(100); /*wait for pipe disable*/ | ||
495 | REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0); | ||
496 | msleep(100); | ||
497 | REG_WRITE(0xb004, REG_READ(0xb004)); | ||
498 | /* try to bring the controller back up again*/ | ||
499 | REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1); | ||
500 | temp = REG_READ(dspcntr_reg); | ||
501 | REG_WRITE(dspcntr_reg, | ||
502 | temp | DISPLAY_PLANE_ENABLE); | ||
503 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
504 | /*mdfld_dsi_dpi_turn_on(dev, pipe);*/ | ||
505 | REG_WRITE(0xb048, 2); | ||
506 | msleep(100); | ||
507 | temp = REG_READ(pipeconf_reg); | ||
508 | temp |= PIPEACONF_ENABLE; | ||
509 | REG_WRITE(pipeconf_reg, temp); | ||
510 | } | ||
511 | } | ||
512 | |||
513 | psb_intel_crtc_load_lut(crtc); | ||
514 | |||
515 | /* Give the overlay scaler a chance to enable | ||
516 | if it's on this pipe */ | ||
517 | /* psb_intel_crtc_dpms_video(crtc, true); TODO */ | ||
518 | |||
519 | break; | ||
520 | case DRM_MODE_DPMS_OFF: | ||
521 | /* Give the overlay scaler a chance to disable | ||
522 | * if it's on this pipe */ | ||
523 | /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */ | ||
524 | if (pipe != 1) | ||
525 | mdfld_dsi_gen_fifo_ready(dev, | ||
526 | MIPI_GEN_FIFO_STAT_REG(pipe), | ||
527 | HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); | ||
528 | |||
529 | /* Disable the VGA plane that we never use */ | ||
530 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
531 | |||
532 | /* Disable display plane */ | ||
533 | temp = REG_READ(dspcntr_reg); | ||
534 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
535 | REG_WRITE(dspcntr_reg, | ||
536 | temp & ~DISPLAY_PLANE_ENABLE); | ||
537 | /* Flush the plane changes */ | ||
538 | REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); | ||
539 | REG_READ(dspbase_reg); | ||
540 | } | ||
541 | |||
542 | /* Next, disable display pipes */ | ||
543 | temp = REG_READ(pipeconf_reg); | ||
544 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
545 | temp &= ~PIPEACONF_ENABLE; | ||
546 | temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; | ||
547 | REG_WRITE(pipeconf_reg, temp); | ||
548 | REG_READ(pipeconf_reg); | ||
549 | |||
550 | /* Wait for for the pipe disable to take effect. */ | ||
551 | mdfldWaitForPipeDisable(dev, pipe); | ||
552 | } | ||
553 | |||
554 | temp = REG_READ(dpll_reg); | ||
555 | if (temp & DPLL_VCO_ENABLE) { | ||
556 | if ((pipe != 1 && !((REG_READ(PIPEACONF) | ||
557 | | REG_READ(PIPECCONF)) & PIPEACONF_ENABLE)) | ||
558 | || pipe == 1) { | ||
559 | temp &= ~(DPLL_VCO_ENABLE); | ||
560 | REG_WRITE(dpll_reg, temp); | ||
561 | REG_READ(dpll_reg); | ||
562 | /* Wait for the clocks to turn off. */ | ||
563 | /* FIXME_MDFLD PO may need more delay */ | ||
564 | udelay(500); | ||
565 | } | ||
566 | } | ||
567 | break; | ||
568 | } | ||
569 | enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; | ||
570 | gma_power_end(dev); | ||
571 | } | ||
572 | |||
573 | |||
574 | #define MDFLD_LIMT_DPLL_19 0 | ||
575 | #define MDFLD_LIMT_DPLL_25 1 | ||
576 | #define MDFLD_LIMT_DPLL_83 2 | ||
577 | #define MDFLD_LIMT_DPLL_100 3 | ||
578 | #define MDFLD_LIMT_DSIPLL_19 4 | ||
579 | #define MDFLD_LIMT_DSIPLL_25 5 | ||
580 | #define MDFLD_LIMT_DSIPLL_83 6 | ||
581 | #define MDFLD_LIMT_DSIPLL_100 7 | ||
582 | |||
583 | #define MDFLD_DOT_MIN 19750 | ||
584 | #define MDFLD_DOT_MAX 120000 | ||
585 | #define MDFLD_DPLL_M_MIN_19 113 | ||
586 | #define MDFLD_DPLL_M_MAX_19 155 | ||
587 | #define MDFLD_DPLL_P1_MIN_19 2 | ||
588 | #define MDFLD_DPLL_P1_MAX_19 10 | ||
589 | #define MDFLD_DPLL_M_MIN_25 101 | ||
590 | #define MDFLD_DPLL_M_MAX_25 130 | ||
591 | #define MDFLD_DPLL_P1_MIN_25 2 | ||
592 | #define MDFLD_DPLL_P1_MAX_25 10 | ||
593 | #define MDFLD_DPLL_M_MIN_83 64 | ||
594 | #define MDFLD_DPLL_M_MAX_83 64 | ||
595 | #define MDFLD_DPLL_P1_MIN_83 2 | ||
596 | #define MDFLD_DPLL_P1_MAX_83 2 | ||
597 | #define MDFLD_DPLL_M_MIN_100 64 | ||
598 | #define MDFLD_DPLL_M_MAX_100 64 | ||
599 | #define MDFLD_DPLL_P1_MIN_100 2 | ||
600 | #define MDFLD_DPLL_P1_MAX_100 2 | ||
601 | #define MDFLD_DSIPLL_M_MIN_19 131 | ||
602 | #define MDFLD_DSIPLL_M_MAX_19 175 | ||
603 | #define MDFLD_DSIPLL_P1_MIN_19 3 | ||
604 | #define MDFLD_DSIPLL_P1_MAX_19 8 | ||
605 | #define MDFLD_DSIPLL_M_MIN_25 97 | ||
606 | #define MDFLD_DSIPLL_M_MAX_25 140 | ||
607 | #define MDFLD_DSIPLL_P1_MIN_25 3 | ||
608 | #define MDFLD_DSIPLL_P1_MAX_25 9 | ||
609 | #define MDFLD_DSIPLL_M_MIN_83 33 | ||
610 | #define MDFLD_DSIPLL_M_MAX_83 92 | ||
611 | #define MDFLD_DSIPLL_P1_MIN_83 2 | ||
612 | #define MDFLD_DSIPLL_P1_MAX_83 3 | ||
613 | #define MDFLD_DSIPLL_M_MIN_100 97 | ||
614 | #define MDFLD_DSIPLL_M_MAX_100 140 | ||
615 | #define MDFLD_DSIPLL_P1_MIN_100 3 | ||
616 | #define MDFLD_DSIPLL_P1_MAX_100 9 | ||
617 | |||
618 | static const struct mrst_limit_t mdfld_limits[] = { | ||
619 | { /* MDFLD_LIMT_DPLL_19 */ | ||
620 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | ||
621 | .m = {.min = MDFLD_DPLL_M_MIN_19, .max = MDFLD_DPLL_M_MAX_19}, | ||
622 | .p1 = {.min = MDFLD_DPLL_P1_MIN_19, .max = MDFLD_DPLL_P1_MAX_19}, | ||
623 | }, | ||
624 | { /* MDFLD_LIMT_DPLL_25 */ | ||
625 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | ||
626 | .m = {.min = MDFLD_DPLL_M_MIN_25, .max = MDFLD_DPLL_M_MAX_25}, | ||
627 | .p1 = {.min = MDFLD_DPLL_P1_MIN_25, .max = MDFLD_DPLL_P1_MAX_25}, | ||
628 | }, | ||
629 | { /* MDFLD_LIMT_DPLL_83 */ | ||
630 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | ||
631 | .m = {.min = MDFLD_DPLL_M_MIN_83, .max = MDFLD_DPLL_M_MAX_83}, | ||
632 | .p1 = {.min = MDFLD_DPLL_P1_MIN_83, .max = MDFLD_DPLL_P1_MAX_83}, | ||
633 | }, | ||
634 | { /* MDFLD_LIMT_DPLL_100 */ | ||
635 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | ||
636 | .m = {.min = MDFLD_DPLL_M_MIN_100, .max = MDFLD_DPLL_M_MAX_100}, | ||
637 | .p1 = {.min = MDFLD_DPLL_P1_MIN_100, .max = MDFLD_DPLL_P1_MAX_100}, | ||
638 | }, | ||
639 | { /* MDFLD_LIMT_DSIPLL_19 */ | ||
640 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | ||
641 | .m = {.min = MDFLD_DSIPLL_M_MIN_19, .max = MDFLD_DSIPLL_M_MAX_19}, | ||
642 | .p1 = {.min = MDFLD_DSIPLL_P1_MIN_19, .max = MDFLD_DSIPLL_P1_MAX_19}, | ||
643 | }, | ||
644 | { /* MDFLD_LIMT_DSIPLL_25 */ | ||
645 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | ||
646 | .m = {.min = MDFLD_DSIPLL_M_MIN_25, .max = MDFLD_DSIPLL_M_MAX_25}, | ||
647 | .p1 = {.min = MDFLD_DSIPLL_P1_MIN_25, .max = MDFLD_DSIPLL_P1_MAX_25}, | ||
648 | }, | ||
649 | { /* MDFLD_LIMT_DSIPLL_83 */ | ||
650 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | ||
651 | .m = {.min = MDFLD_DSIPLL_M_MIN_83, .max = MDFLD_DSIPLL_M_MAX_83}, | ||
652 | .p1 = {.min = MDFLD_DSIPLL_P1_MIN_83, .max = MDFLD_DSIPLL_P1_MAX_83}, | ||
653 | }, | ||
654 | { /* MDFLD_LIMT_DSIPLL_100 */ | ||
655 | .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, | ||
656 | .m = {.min = MDFLD_DSIPLL_M_MIN_100, .max = MDFLD_DSIPLL_M_MAX_100}, | ||
657 | .p1 = {.min = MDFLD_DSIPLL_P1_MIN_100, .max = MDFLD_DSIPLL_P1_MAX_100}, | ||
658 | }, | ||
659 | }; | ||
660 | |||
661 | #define MDFLD_M_MIN 21 | ||
662 | #define MDFLD_M_MAX 180 | ||
663 | static const u32 mdfld_m_converts[] = { | ||
664 | /* M configuration table from 9-bit LFSR table */ | ||
665 | 224, 368, 440, 220, 366, 439, 219, 365, 182, 347, /* 21 - 30 */ | ||
666 | 173, 342, 171, 85, 298, 149, 74, 37, 18, 265, /* 31 - 40 */ | ||
667 | 388, 194, 353, 432, 216, 108, 310, 155, 333, 166, /* 41 - 50 */ | ||
668 | 83, 41, 276, 138, 325, 162, 337, 168, 340, 170, /* 51 - 60 */ | ||
669 | 341, 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 61 - 70 */ | ||
670 | 461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */ | ||
671 | 106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */ | ||
672 | 71, 35, 273, 136, 324, 418, 465, 488, 500, 506, /* 91 - 100 */ | ||
673 | 253, 126, 63, 287, 399, 455, 483, 241, 376, 444, /* 101 - 110 */ | ||
674 | 478, 495, 503, 251, 381, 446, 479, 239, 375, 443, /* 111 - 120 */ | ||
675 | 477, 238, 119, 315, 157, 78, 295, 147, 329, 420, /* 121 - 130 */ | ||
676 | 210, 105, 308, 154, 77, 38, 275, 137, 68, 290, /* 131 - 140 */ | ||
677 | 145, 328, 164, 82, 297, 404, 458, 485, 498, 249, /* 141 - 150 */ | ||
678 | 380, 190, 351, 431, 471, 235, 117, 314, 413, 206, /* 151 - 160 */ | ||
679 | 103, 51, 25, 12, 262, 387, 193, 96, 48, 280, /* 161 - 170 */ | ||
680 | 396, 198, 99, 305, 152, 76, 294, 403, 457, 228, /* 171 - 180 */ | ||
681 | }; | ||
682 | |||
683 | static const struct mrst_limit_t *mdfld_limit(struct drm_crtc *crtc) | ||
684 | { | ||
685 | const struct mrst_limit_t *limit = NULL; | ||
686 | struct drm_device *dev = crtc->dev; | ||
687 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
688 | |||
689 | if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI) | ||
690 | || psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI2)) { | ||
691 | if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) | ||
692 | limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_19]; | ||
693 | else if (ksel == KSEL_BYPASS_25) | ||
694 | limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_25]; | ||
695 | else if ((ksel == KSEL_BYPASS_83_100) && | ||
696 | (dev_priv->core_freq == 166)) | ||
697 | limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_83]; | ||
698 | else if ((ksel == KSEL_BYPASS_83_100) && | ||
699 | (dev_priv->core_freq == 100 || | ||
700 | dev_priv->core_freq == 200)) | ||
701 | limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_100]; | ||
702 | } else if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) { | ||
703 | if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) | ||
704 | limit = &mdfld_limits[MDFLD_LIMT_DPLL_19]; | ||
705 | else if (ksel == KSEL_BYPASS_25) | ||
706 | limit = &mdfld_limits[MDFLD_LIMT_DPLL_25]; | ||
707 | else if ((ksel == KSEL_BYPASS_83_100) && | ||
708 | (dev_priv->core_freq == 166)) | ||
709 | limit = &mdfld_limits[MDFLD_LIMT_DPLL_83]; | ||
710 | else if ((ksel == KSEL_BYPASS_83_100) && | ||
711 | (dev_priv->core_freq == 100 || | ||
712 | dev_priv->core_freq == 200)) | ||
713 | limit = &mdfld_limits[MDFLD_LIMT_DPLL_100]; | ||
714 | } else { | ||
715 | limit = NULL; | ||
716 | dev_dbg(dev->dev, "mdfld_limit Wrong display type.\n"); | ||
717 | } | ||
718 | |||
719 | return limit; | ||
720 | } | ||
721 | |||
722 | /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ | ||
723 | static void mdfld_clock(int refclk, struct mrst_clock_t *clock) | ||
724 | { | ||
725 | clock->dot = (refclk * clock->m) / clock->p1; | ||
726 | } | ||
727 | |||
728 | /** | ||
729 | * Returns a set of divisors for the desired target clock with the given refclk, | ||
730 | * or FALSE. Divisor values are the actual divisors for | ||
731 | */ | ||
732 | static bool | ||
733 | mdfldFindBestPLL(struct drm_crtc *crtc, int target, int refclk, | ||
734 | struct mrst_clock_t *best_clock) | ||
735 | { | ||
736 | struct mrst_clock_t clock; | ||
737 | const struct mrst_limit_t *limit = mdfld_limit(crtc); | ||
738 | int err = target; | ||
739 | |||
740 | memset(best_clock, 0, sizeof(*best_clock)); | ||
741 | |||
742 | for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { | ||
743 | for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; | ||
744 | clock.p1++) { | ||
745 | int this_err; | ||
746 | |||
747 | mdfld_clock(refclk, &clock); | ||
748 | |||
749 | this_err = abs(clock.dot - target); | ||
750 | if (this_err < err) { | ||
751 | *best_clock = clock; | ||
752 | err = this_err; | ||
753 | } | ||
754 | } | ||
755 | } | ||
756 | return err != target; | ||
757 | } | ||
758 | |||
759 | static int mdfld_crtc_mode_set(struct drm_crtc *crtc, | ||
760 | struct drm_display_mode *mode, | ||
761 | struct drm_display_mode *adjusted_mode, | ||
762 | int x, int y, | ||
763 | struct drm_framebuffer *old_fb) | ||
764 | { | ||
765 | struct drm_device *dev = crtc->dev; | ||
766 | struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||
767 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
768 | int pipe = psb_intel_crtc->pipe; | ||
769 | int fp_reg = MRST_FPA0; | ||
770 | int dpll_reg = MRST_DPLL_A; | ||
771 | int dspcntr_reg = DSPACNTR; | ||
772 | int pipeconf_reg = PIPEACONF; | ||
773 | int htot_reg = HTOTAL_A; | ||
774 | int hblank_reg = HBLANK_A; | ||
775 | int hsync_reg = HSYNC_A; | ||
776 | int vtot_reg = VTOTAL_A; | ||
777 | int vblank_reg = VBLANK_A; | ||
778 | int vsync_reg = VSYNC_A; | ||
779 | int dspsize_reg = DSPASIZE; | ||
780 | int dsppos_reg = DSPAPOS; | ||
781 | int pipesrc_reg = PIPEASRC; | ||
782 | u32 *pipeconf = &dev_priv->pipeconf[pipe]; | ||
783 | u32 *dspcntr = &dev_priv->dspcntr[pipe]; | ||
784 | int refclk = 0; | ||
785 | int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0, | ||
786 | clk_tmp = 0; | ||
787 | struct mrst_clock_t clock; | ||
788 | bool ok; | ||
789 | u32 dpll = 0, fp = 0; | ||
790 | bool is_crt = false, is_lvds = false, is_tv = false; | ||
791 | bool is_mipi = false, is_mipi2 = false, is_hdmi = false; | ||
792 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
793 | struct psb_intel_encoder *psb_intel_encoder = NULL; | ||
794 | uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; | ||
795 | struct drm_encoder *encoder; | ||
796 | struct drm_connector *connector; | ||
797 | int timeout = 0; | ||
798 | int ret; | ||
799 | |||
800 | dev_dbg(dev->dev, "pipe = 0x%x\n", pipe); | ||
801 | |||
802 | #if 0 | ||
803 | if (pipe == 1) { | ||
804 | if (!gma_power_begin(dev, true)) | ||
805 | return 0; | ||
806 | android_hdmi_crtc_mode_set(crtc, mode, adjusted_mode, | ||
807 | x, y, old_fb); | ||
808 | goto mrst_crtc_mode_set_exit; | ||
809 | } | ||
810 | #endif | ||
811 | |||
812 | switch (pipe) { | ||
813 | case 0: | ||
814 | break; | ||
815 | case 1: | ||
816 | fp_reg = FPB0; | ||
817 | dpll_reg = DPLL_B; | ||
818 | dspcntr_reg = DSPBCNTR; | ||
819 | pipeconf_reg = PIPEBCONF; | ||
820 | htot_reg = HTOTAL_B; | ||
821 | hblank_reg = HBLANK_B; | ||
822 | hsync_reg = HSYNC_B; | ||
823 | vtot_reg = VTOTAL_B; | ||
824 | vblank_reg = VBLANK_B; | ||
825 | vsync_reg = VSYNC_B; | ||
826 | dspsize_reg = DSPBSIZE; | ||
827 | dsppos_reg = DSPBPOS; | ||
828 | pipesrc_reg = PIPEBSRC; | ||
829 | fp_reg = MDFLD_DPLL_DIV0; | ||
830 | dpll_reg = MDFLD_DPLL_B; | ||
831 | break; | ||
832 | case 2: | ||
833 | dpll_reg = MRST_DPLL_A; | ||
834 | dspcntr_reg = DSPCCNTR; | ||
835 | pipeconf_reg = PIPECCONF; | ||
836 | htot_reg = HTOTAL_C; | ||
837 | hblank_reg = HBLANK_C; | ||
838 | hsync_reg = HSYNC_C; | ||
839 | vtot_reg = VTOTAL_C; | ||
840 | vblank_reg = VBLANK_C; | ||
841 | vsync_reg = VSYNC_C; | ||
842 | dspsize_reg = DSPCSIZE; | ||
843 | dsppos_reg = DSPCPOS; | ||
844 | pipesrc_reg = PIPECSRC; | ||
845 | break; | ||
846 | default: | ||
847 | DRM_ERROR("Illegal Pipe Number.\n"); | ||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | ret = check_fb(crtc->fb); | ||
852 | if (ret) | ||
853 | return ret; | ||
854 | |||
855 | dev_dbg(dev->dev, "adjusted_hdisplay = %d\n", | ||
856 | adjusted_mode->hdisplay); | ||
857 | dev_dbg(dev->dev, "adjusted_vdisplay = %d\n", | ||
858 | adjusted_mode->vdisplay); | ||
859 | dev_dbg(dev->dev, "adjusted_hsync_start = %d\n", | ||
860 | adjusted_mode->hsync_start); | ||
861 | dev_dbg(dev->dev, "adjusted_hsync_end = %d\n", | ||
862 | adjusted_mode->hsync_end); | ||
863 | dev_dbg(dev->dev, "adjusted_htotal = %d\n", | ||
864 | adjusted_mode->htotal); | ||
865 | dev_dbg(dev->dev, "adjusted_vsync_start = %d\n", | ||
866 | adjusted_mode->vsync_start); | ||
867 | dev_dbg(dev->dev, "adjusted_vsync_end = %d\n", | ||
868 | adjusted_mode->vsync_end); | ||
869 | dev_dbg(dev->dev, "adjusted_vtotal = %d\n", | ||
870 | adjusted_mode->vtotal); | ||
871 | dev_dbg(dev->dev, "adjusted_clock = %d\n", | ||
872 | adjusted_mode->clock); | ||
873 | dev_dbg(dev->dev, "hdisplay = %d\n", | ||
874 | mode->hdisplay); | ||
875 | dev_dbg(dev->dev, "vdisplay = %d\n", | ||
876 | mode->vdisplay); | ||
877 | |||
878 | if (!gma_power_begin(dev, true)) | ||
879 | return 0; | ||
880 | |||
881 | memcpy(&psb_intel_crtc->saved_mode, mode, | ||
882 | sizeof(struct drm_display_mode)); | ||
883 | memcpy(&psb_intel_crtc->saved_adjusted_mode, adjusted_mode, | ||
884 | sizeof(struct drm_display_mode)); | ||
885 | |||
886 | list_for_each_entry(connector, &mode_config->connector_list, head) { | ||
887 | if (!connector) | ||
888 | continue; | ||
889 | |||
890 | encoder = connector->encoder; | ||
891 | |||
892 | if (!encoder) | ||
893 | continue; | ||
894 | |||
895 | if (encoder->crtc != crtc) | ||
896 | continue; | ||
897 | |||
898 | psb_intel_encoder = psb_intel_attached_encoder(connector); | ||
899 | |||
900 | switch (psb_intel_encoder->type) { | ||
901 | case INTEL_OUTPUT_LVDS: | ||
902 | is_lvds = true; | ||
903 | break; | ||
904 | case INTEL_OUTPUT_TVOUT: | ||
905 | is_tv = true; | ||
906 | break; | ||
907 | case INTEL_OUTPUT_ANALOG: | ||
908 | is_crt = true; | ||
909 | break; | ||
910 | case INTEL_OUTPUT_MIPI: | ||
911 | is_mipi = true; | ||
912 | break; | ||
913 | case INTEL_OUTPUT_MIPI2: | ||
914 | is_mipi2 = true; | ||
915 | break; | ||
916 | case INTEL_OUTPUT_HDMI: | ||
917 | is_hdmi = true; | ||
918 | break; | ||
919 | } | ||
920 | } | ||
921 | |||
922 | /* Disable the VGA plane that we never use */ | ||
923 | REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
924 | |||
925 | /* Disable the panel fitter if it was on our pipe */ | ||
926 | if (psb_intel_panel_fitter_pipe(dev) == pipe) | ||
927 | REG_WRITE(PFIT_CONTROL, 0); | ||
928 | |||
929 | /* pipesrc and dspsize control the size that is scaled from, | ||
930 | * which should always be the user's requested size. | ||
931 | */ | ||
932 | if (pipe == 1) { | ||
933 | /* FIXME: To make HDMI display with 864x480 (TPO), 480x864 | ||
934 | * (PYR) or 480x854 (TMD), set the sprite width/height and | ||
935 | * souce image size registers with the adjusted mode for | ||
936 | * pipe B. | ||
937 | */ | ||
938 | |||
939 | /* | ||
940 | * The defined sprite rectangle must always be completely | ||
941 | * contained within the displayable area of the screen image | ||
942 | * (frame buffer). | ||
943 | */ | ||
944 | REG_WRITE(dspsize_reg, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16) | ||
945 | | (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1)); | ||
946 | /* Set the CRTC with encoder mode. */ | ||
947 | REG_WRITE(pipesrc_reg, ((mode->crtc_hdisplay - 1) << 16) | ||
948 | | (mode->crtc_vdisplay - 1)); | ||
949 | } else { | ||
950 | REG_WRITE(dspsize_reg, | ||
951 | ((mode->crtc_vdisplay - 1) << 16) | | ||
952 | (mode->crtc_hdisplay - 1)); | ||
953 | REG_WRITE(pipesrc_reg, | ||
954 | ((mode->crtc_hdisplay - 1) << 16) | | ||
955 | (mode->crtc_vdisplay - 1)); | ||
956 | } | ||
957 | |||
958 | REG_WRITE(dsppos_reg, 0); | ||
959 | |||
960 | if (psb_intel_encoder) | ||
961 | drm_connector_property_get_value(connector, | ||
962 | dev->mode_config.scaling_mode_property, &scalingType); | ||
963 | |||
964 | if (scalingType == DRM_MODE_SCALE_NO_SCALE) { | ||
965 | /* Medfield doesn't have register support for centering so we | ||
966 | * need to mess with the h/vblank and h/vsync start and ends | ||
967 | * to get centering | ||
968 | */ | ||
969 | int offsetX = 0, offsetY = 0; | ||
970 | |||
971 | offsetX = (adjusted_mode->crtc_hdisplay - | ||
972 | mode->crtc_hdisplay) / 2; | ||
973 | offsetY = (adjusted_mode->crtc_vdisplay - | ||
974 | mode->crtc_vdisplay) / 2; | ||
975 | |||
976 | REG_WRITE(htot_reg, (mode->crtc_hdisplay - 1) | | ||
977 | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
978 | REG_WRITE(vtot_reg, (mode->crtc_vdisplay - 1) | | ||
979 | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
980 | REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - | ||
981 | offsetX - 1) | | ||
982 | ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16)); | ||
983 | REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - | ||
984 | offsetX - 1) | | ||
985 | ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16)); | ||
986 | REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - | ||
987 | offsetY - 1) | | ||
988 | ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16)); | ||
989 | REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - | ||
990 | offsetY - 1) | | ||
991 | ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16)); | ||
992 | } else { | ||
993 | REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | | ||
994 | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
995 | REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | | ||
996 | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
997 | REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | | ||
998 | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
999 | REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | | ||
1000 | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
1001 | REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | | ||
1002 | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
1003 | REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | | ||
1004 | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
1005 | } | ||
1006 | |||
1007 | /* Flush the plane changes */ | ||
1008 | { | ||
1009 | struct drm_crtc_helper_funcs *crtc_funcs = | ||
1010 | crtc->helper_private; | ||
1011 | crtc_funcs->mode_set_base(crtc, x, y, old_fb); | ||
1012 | } | ||
1013 | |||
1014 | /* setup pipeconf */ | ||
1015 | *pipeconf = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */ | ||
1016 | |||
1017 | /* Set up the display plane register */ | ||
1018 | *dspcntr = REG_READ(dspcntr_reg); | ||
1019 | *dspcntr |= pipe << DISPPLANE_SEL_PIPE_POS; | ||
1020 | *dspcntr |= DISPLAY_PLANE_ENABLE; | ||
1021 | |||
1022 | if (is_mipi2) | ||
1023 | goto mrst_crtc_mode_set_exit; | ||
1024 | clk = adjusted_mode->clock; | ||
1025 | |||
1026 | if (is_hdmi) { | ||
1027 | if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) { | ||
1028 | refclk = 19200; | ||
1029 | |||
1030 | if (is_mipi || is_mipi2) | ||
1031 | clk_n = 1, clk_p2 = 8; | ||
1032 | else if (is_hdmi) | ||
1033 | clk_n = 1, clk_p2 = 10; | ||
1034 | } else if (ksel == KSEL_BYPASS_25) { | ||
1035 | refclk = 25000; | ||
1036 | |||
1037 | if (is_mipi || is_mipi2) | ||
1038 | clk_n = 1, clk_p2 = 8; | ||
1039 | else if (is_hdmi) | ||
1040 | clk_n = 1, clk_p2 = 10; | ||
1041 | } else if ((ksel == KSEL_BYPASS_83_100) && | ||
1042 | dev_priv->core_freq == 166) { | ||
1043 | refclk = 83000; | ||
1044 | |||
1045 | if (is_mipi || is_mipi2) | ||
1046 | clk_n = 4, clk_p2 = 8; | ||
1047 | else if (is_hdmi) | ||
1048 | clk_n = 4, clk_p2 = 10; | ||
1049 | } else if ((ksel == KSEL_BYPASS_83_100) && | ||
1050 | (dev_priv->core_freq == 100 || | ||
1051 | dev_priv->core_freq == 200)) { | ||
1052 | refclk = 100000; | ||
1053 | if (is_mipi || is_mipi2) | ||
1054 | clk_n = 4, clk_p2 = 8; | ||
1055 | else if (is_hdmi) | ||
1056 | clk_n = 4, clk_p2 = 10; | ||
1057 | } | ||
1058 | |||
1059 | if (is_mipi) | ||
1060 | clk_byte = dev_priv->bpp / 8; | ||
1061 | else if (is_mipi2) | ||
1062 | clk_byte = dev_priv->bpp2 / 8; | ||
1063 | |||
1064 | clk_tmp = clk * clk_n * clk_p2 * clk_byte; | ||
1065 | |||
1066 | dev_dbg(dev->dev, "clk = %d, clk_n = %d, clk_p2 = %d.\n", | ||
1067 | clk, clk_n, clk_p2); | ||
1068 | dev_dbg(dev->dev, "adjusted_mode->clock = %d, clk_tmp = %d.\n", | ||
1069 | adjusted_mode->clock, clk_tmp); | ||
1070 | |||
1071 | ok = mdfldFindBestPLL(crtc, clk_tmp, refclk, &clock); | ||
1072 | |||
1073 | if (!ok) { | ||
1074 | DRM_ERROR | ||
1075 | ("mdfldFindBestPLL fail in mdfld_crtc_mode_set.\n"); | ||
1076 | } else { | ||
1077 | m_conv = mdfld_m_converts[(clock.m - MDFLD_M_MIN)]; | ||
1078 | |||
1079 | dev_dbg(dev->dev, "dot clock = %d," | ||
1080 | "m = %d, p1 = %d, m_conv = %d.\n", | ||
1081 | clock.dot, clock.m, | ||
1082 | clock.p1, m_conv); | ||
1083 | } | ||
1084 | |||
1085 | dpll = REG_READ(dpll_reg); | ||
1086 | |||
1087 | if (dpll & DPLL_VCO_ENABLE) { | ||
1088 | dpll &= ~DPLL_VCO_ENABLE; | ||
1089 | REG_WRITE(dpll_reg, dpll); | ||
1090 | REG_READ(dpll_reg); | ||
1091 | |||
1092 | /* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */ | ||
1093 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | ||
1094 | udelay(500); | ||
1095 | |||
1096 | /* reset M1, N1 & P1 */ | ||
1097 | REG_WRITE(fp_reg, 0); | ||
1098 | dpll &= ~MDFLD_P1_MASK; | ||
1099 | REG_WRITE(dpll_reg, dpll); | ||
1100 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | ||
1101 | udelay(500); | ||
1102 | } | ||
1103 | |||
1104 | /* When ungating power of DPLL, needs to wait 0.5us before | ||
1105 | * enable the VCO */ | ||
1106 | if (dpll & MDFLD_PWR_GATE_EN) { | ||
1107 | dpll &= ~MDFLD_PWR_GATE_EN; | ||
1108 | REG_WRITE(dpll_reg, dpll); | ||
1109 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | ||
1110 | udelay(500); | ||
1111 | } | ||
1112 | dpll = 0; | ||
1113 | |||
1114 | #if 0 /* FIXME revisit later */ | ||
1115 | if (ksel == KSEL_CRYSTAL_19 || ksel == KSEL_BYPASS_19 || | ||
1116 | ksel == KSEL_BYPASS_25) | ||
1117 | dpll &= ~MDFLD_INPUT_REF_SEL; | ||
1118 | else if (ksel == KSEL_BYPASS_83_100) | ||
1119 | dpll |= MDFLD_INPUT_REF_SEL; | ||
1120 | #endif /* FIXME revisit later */ | ||
1121 | |||
1122 | if (is_hdmi) | ||
1123 | dpll |= MDFLD_VCO_SEL; | ||
1124 | |||
1125 | fp = (clk_n / 2) << 16; | ||
1126 | fp |= m_conv; | ||
1127 | |||
1128 | /* compute bitmask from p1 value */ | ||
1129 | dpll |= (1 << (clock.p1 - 2)) << 17; | ||
1130 | |||
1131 | #if 0 /* 1080p30 & 720p */ | ||
1132 | dpll = 0x00050000; | ||
1133 | fp = 0x000001be; | ||
1134 | #endif | ||
1135 | #if 0 /* 480p */ | ||
1136 | dpll = 0x02010000; | ||
1137 | fp = 0x000000d2; | ||
1138 | #endif | ||
1139 | } else { | ||
1140 | #if 0 /*DBI_TPO_480x864*/ | ||
1141 | dpll = 0x00020000; | ||
1142 | fp = 0x00000156; | ||
1143 | #endif /* DBI_TPO_480x864 */ /* get from spec. */ | ||
1144 | |||
1145 | dpll = 0x00800000; | ||
1146 | fp = 0x000000c1; | ||
1147 | } | ||
1148 | |||
1149 | REG_WRITE(fp_reg, fp); | ||
1150 | REG_WRITE(dpll_reg, dpll); | ||
1151 | /* FIXME_MDFLD PO - change 500 to 1 after PO */ | ||
1152 | udelay(500); | ||
1153 | |||
1154 | dpll |= DPLL_VCO_ENABLE; | ||
1155 | REG_WRITE(dpll_reg, dpll); | ||
1156 | REG_READ(dpll_reg); | ||
1157 | |||
1158 | /* wait for DSI PLL to lock */ | ||
1159 | while (timeout < 20000 && | ||
1160 | !(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) { | ||
1161 | udelay(150); | ||
1162 | timeout++; | ||
1163 | } | ||
1164 | |||
1165 | if (is_mipi) | ||
1166 | goto mrst_crtc_mode_set_exit; | ||
1167 | |||
1168 | dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi); | ||
1169 | |||
1170 | REG_WRITE(pipeconf_reg, *pipeconf); | ||
1171 | REG_READ(pipeconf_reg); | ||
1172 | |||
1173 | /* Wait for for the pipe enable to take effect. */ | ||
1174 | REG_WRITE(dspcntr_reg, *dspcntr); | ||
1175 | psb_intel_wait_for_vblank(dev); | ||
1176 | |||
1177 | mrst_crtc_mode_set_exit: | ||
1178 | |||
1179 | gma_power_end(dev); | ||
1180 | |||
1181 | return 0; | ||
1182 | } | ||
1183 | |||
1184 | const struct drm_crtc_helper_funcs mdfld_helper_funcs = { | ||
1185 | .dpms = mdfld_crtc_dpms, | ||
1186 | .mode_fixup = psb_intel_crtc_mode_fixup, | ||
1187 | .mode_set = mdfld_crtc_mode_set, | ||
1188 | .mode_set_base = mdfld__intel_pipe_set_base, | ||
1189 | .prepare = psb_intel_crtc_prepare, | ||
1190 | .commit = psb_intel_crtc_commit, | ||
1191 | }; | ||
1192 | |||
diff --git a/drivers/gpu/drm/gma500/mdfld_output.c b/drivers/gpu/drm/gma500/mdfld_output.c new file mode 100644 index 000000000000..de0ce0765738 --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_output.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicensen | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Thomas Eaton <thomas.g.eaton@intel.com> | ||
25 | * Scott Rowe <scott.m.rowe@intel.com> | ||
26 | */ | ||
27 | |||
28 | #include "mdfld_output.h" | ||
29 | #include "mdfld_dsi_dpi.h" | ||
30 | #include "mdfld_dsi_output.h" | ||
31 | |||
32 | #include "tc35876x-dsi-lvds.h" | ||
33 | |||
34 | int mdfld_get_panel_type(struct drm_device *dev, int pipe) | ||
35 | { | ||
36 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
37 | return dev_priv->mdfld_panel_id; | ||
38 | } | ||
39 | |||
40 | static void mdfld_init_panel(struct drm_device *dev, int mipi_pipe, | ||
41 | int p_type) | ||
42 | { | ||
43 | switch (p_type) { | ||
44 | case TPO_VID: | ||
45 | mdfld_dsi_output_init(dev, mipi_pipe, NULL, | ||
46 | &mdfld_tpo_vid_funcs); | ||
47 | break; | ||
48 | case TC35876X: | ||
49 | tc35876x_init(dev); | ||
50 | mdfld_dsi_output_init(dev, mipi_pipe, NULL, | ||
51 | &mdfld_tc35876x_funcs); | ||
52 | break; | ||
53 | case TMD_VID: | ||
54 | mdfld_dsi_output_init(dev, mipi_pipe, NULL, | ||
55 | &mdfld_tmd_vid_funcs); | ||
56 | break; | ||
57 | case HDMI: | ||
58 | /* if (dev_priv->mdfld_hdmi_present) | ||
59 | mdfld_hdmi_init(dev, &dev_priv->mode_dev); */ | ||
60 | break; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | |||
65 | int mdfld_output_init(struct drm_device *dev) | ||
66 | { | ||
67 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
68 | |||
69 | /* FIXME: hardcoded for now */ | ||
70 | dev_priv->mdfld_panel_id = TC35876X; | ||
71 | /* MIPI panel 1 */ | ||
72 | mdfld_init_panel(dev, 0, dev_priv->mdfld_panel_id); | ||
73 | /* HDMI panel */ | ||
74 | mdfld_init_panel(dev, 1, HDMI); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
diff --git a/drivers/gpu/drm/gma500/mdfld_output.h b/drivers/gpu/drm/gma500/mdfld_output.h new file mode 100644 index 000000000000..ab2b27c0f037 --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_output.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicensen | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Thomas Eaton <thomas.g.eaton@intel.com> | ||
25 | * Scott Rowe <scott.m.rowe@intel.com> | ||
26 | */ | ||
27 | |||
28 | #ifndef MDFLD_OUTPUT_H | ||
29 | #define MDFLD_OUTPUT_H | ||
30 | |||
31 | #include "psb_drv.h" | ||
32 | |||
33 | #define TPO_PANEL_WIDTH 84 | ||
34 | #define TPO_PANEL_HEIGHT 46 | ||
35 | #define TMD_PANEL_WIDTH 39 | ||
36 | #define TMD_PANEL_HEIGHT 71 | ||
37 | |||
38 | struct mdfld_dsi_config; | ||
39 | |||
40 | enum panel_type { | ||
41 | TPO_VID, | ||
42 | TMD_VID, | ||
43 | HDMI, | ||
44 | TC35876X, | ||
45 | }; | ||
46 | |||
47 | struct panel_info { | ||
48 | u32 width_mm; | ||
49 | u32 height_mm; | ||
50 | /* Other info */ | ||
51 | }; | ||
52 | |||
53 | struct panel_funcs { | ||
54 | const struct drm_encoder_funcs *encoder_funcs; | ||
55 | const struct drm_encoder_helper_funcs *encoder_helper_funcs; | ||
56 | struct drm_display_mode * (*get_config_mode)(struct drm_device *); | ||
57 | int (*get_panel_info)(struct drm_device *, int, struct panel_info *); | ||
58 | int (*reset)(int pipe); | ||
59 | void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe); | ||
60 | }; | ||
61 | |||
62 | int mdfld_output_init(struct drm_device *dev); | ||
63 | |||
64 | struct backlight_device *mdfld_get_backlight_device(void); | ||
65 | int mdfld_set_brightness(struct backlight_device *bd); | ||
66 | |||
67 | int mdfld_get_panel_type(struct drm_device *dev, int pipe); | ||
68 | |||
69 | extern const struct drm_crtc_helper_funcs mdfld_helper_funcs; | ||
70 | |||
71 | extern const struct panel_funcs mdfld_tmd_vid_funcs; | ||
72 | extern const struct panel_funcs mdfld_tpo_vid_funcs; | ||
73 | |||
74 | extern void mdfld_disable_crtc(struct drm_device *dev, int pipe); | ||
75 | extern void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe); | ||
76 | extern void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe); | ||
77 | #endif | ||
diff --git a/drivers/gpu/drm/gma500/mdfld_tmd_vid.c b/drivers/gpu/drm/gma500/mdfld_tmd_vid.c new file mode 100644 index 000000000000..dc0c6c3d3d29 --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_tmd_vid.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Jim Liu <jim.liu@intel.com> | ||
25 | * Jackie Li<yaodong.li@intel.com> | ||
26 | * Gideon Eaton <eaton. | ||
27 | * Scott Rowe <scott.m.rowe@intel.com> | ||
28 | */ | ||
29 | |||
30 | #include "mdfld_dsi_dpi.h" | ||
31 | #include "mdfld_dsi_pkg_sender.h" | ||
32 | |||
33 | static struct drm_display_mode *tmd_vid_get_config_mode(struct drm_device *dev) | ||
34 | { | ||
35 | struct drm_display_mode *mode; | ||
36 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
37 | struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; | ||
38 | bool use_gct = false; /*Disable GCT for now*/ | ||
39 | |||
40 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | ||
41 | if (!mode) | ||
42 | return NULL; | ||
43 | |||
44 | if (use_gct) { | ||
45 | mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; | ||
46 | mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; | ||
47 | mode->hsync_start = mode->hdisplay + \ | ||
48 | ((ti->hsync_offset_hi << 8) | \ | ||
49 | ti->hsync_offset_lo); | ||
50 | mode->hsync_end = mode->hsync_start + \ | ||
51 | ((ti->hsync_pulse_width_hi << 8) | \ | ||
52 | ti->hsync_pulse_width_lo); | ||
53 | mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \ | ||
54 | ti->hblank_lo); | ||
55 | mode->vsync_start = \ | ||
56 | mode->vdisplay + ((ti->vsync_offset_hi << 8) | \ | ||
57 | ti->vsync_offset_lo); | ||
58 | mode->vsync_end = \ | ||
59 | mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | \ | ||
60 | ti->vsync_pulse_width_lo); | ||
61 | mode->vtotal = mode->vdisplay + \ | ||
62 | ((ti->vblank_hi << 8) | ti->vblank_lo); | ||
63 | mode->clock = ti->pixel_clock * 10; | ||
64 | |||
65 | dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay); | ||
66 | dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay); | ||
67 | dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start); | ||
68 | dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end); | ||
69 | dev_dbg(dev->dev, "htotal is %d\n", mode->htotal); | ||
70 | dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start); | ||
71 | dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end); | ||
72 | dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal); | ||
73 | dev_dbg(dev->dev, "clock is %d\n", mode->clock); | ||
74 | } else { | ||
75 | mode->hdisplay = 480; | ||
76 | mode->vdisplay = 854; | ||
77 | mode->hsync_start = 487; | ||
78 | mode->hsync_end = 490; | ||
79 | mode->htotal = 499; | ||
80 | mode->vsync_start = 861; | ||
81 | mode->vsync_end = 865; | ||
82 | mode->vtotal = 873; | ||
83 | mode->clock = 33264; | ||
84 | } | ||
85 | |||
86 | drm_mode_set_name(mode); | ||
87 | drm_mode_set_crtcinfo(mode, 0); | ||
88 | |||
89 | mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
90 | |||
91 | return mode; | ||
92 | } | ||
93 | |||
94 | static int tmd_vid_get_panel_info(struct drm_device *dev, | ||
95 | int pipe, | ||
96 | struct panel_info *pi) | ||
97 | { | ||
98 | if (!dev || !pi) | ||
99 | return -EINVAL; | ||
100 | |||
101 | pi->width_mm = TMD_PANEL_WIDTH; | ||
102 | pi->height_mm = TMD_PANEL_HEIGHT; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | /* ************************************************************************* *\ | ||
108 | * FUNCTION: mdfld_init_TMD_MIPI | ||
109 | * | ||
110 | * DESCRIPTION: This function is called only by mrst_dsi_mode_set and | ||
111 | * restore_display_registers. since this function does not | ||
112 | * acquire the mutex, it is important that the calling function | ||
113 | * does! | ||
114 | \* ************************************************************************* */ | ||
115 | |||
116 | /* FIXME: make the below data u8 instead of u32; note byte order! */ | ||
117 | static u32 tmd_cmd_mcap_off[] = {0x000000b2}; | ||
118 | static u32 tmd_cmd_enable_lane_switch[] = {0x000101ef}; | ||
119 | static u32 tmd_cmd_set_lane_num[] = {0x006360ef}; | ||
120 | static u32 tmd_cmd_pushing_clock0[] = {0x00cc2fef}; | ||
121 | static u32 tmd_cmd_pushing_clock1[] = {0x00dd6eef}; | ||
122 | static u32 tmd_cmd_set_mode[] = {0x000000b3}; | ||
123 | static u32 tmd_cmd_set_sync_pulse_mode[] = {0x000961ef}; | ||
124 | static u32 tmd_cmd_set_column[] = {0x0100002a, 0x000000df}; | ||
125 | static u32 tmd_cmd_set_page[] = {0x0300002b, 0x00000055}; | ||
126 | static u32 tmd_cmd_set_video_mode[] = {0x00000153}; | ||
127 | /*no auto_bl,need add in furture*/ | ||
128 | static u32 tmd_cmd_enable_backlight[] = {0x00005ab4}; | ||
129 | static u32 tmd_cmd_set_backlight_dimming[] = {0x00000ebd}; | ||
130 | |||
131 | static void mdfld_dsi_tmd_drv_ic_init(struct mdfld_dsi_config *dsi_config, | ||
132 | int pipe) | ||
133 | { | ||
134 | struct mdfld_dsi_pkg_sender *sender | ||
135 | = mdfld_dsi_get_pkg_sender(dsi_config); | ||
136 | |||
137 | DRM_INFO("Enter mdfld init TMD MIPI display.\n"); | ||
138 | |||
139 | if (!sender) { | ||
140 | DRM_ERROR("Cannot get sender\n"); | ||
141 | return; | ||
142 | } | ||
143 | |||
144 | if (dsi_config->dvr_ic_inited) | ||
145 | return; | ||
146 | |||
147 | msleep(3); | ||
148 | |||
149 | /* FIXME: make the below data u8 instead of u32; note byte order! */ | ||
150 | |||
151 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_mcap_off, | ||
152 | sizeof(tmd_cmd_mcap_off), false); | ||
153 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_lane_switch, | ||
154 | sizeof(tmd_cmd_enable_lane_switch), false); | ||
155 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_lane_num, | ||
156 | sizeof(tmd_cmd_set_lane_num), false); | ||
157 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock0, | ||
158 | sizeof(tmd_cmd_pushing_clock0), false); | ||
159 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock1, | ||
160 | sizeof(tmd_cmd_pushing_clock1), false); | ||
161 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_mode, | ||
162 | sizeof(tmd_cmd_set_mode), false); | ||
163 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_sync_pulse_mode, | ||
164 | sizeof(tmd_cmd_set_sync_pulse_mode), false); | ||
165 | mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_column, | ||
166 | sizeof(tmd_cmd_set_column), false); | ||
167 | mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_page, | ||
168 | sizeof(tmd_cmd_set_page), false); | ||
169 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_video_mode, | ||
170 | sizeof(tmd_cmd_set_video_mode), false); | ||
171 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_backlight, | ||
172 | sizeof(tmd_cmd_enable_backlight), false); | ||
173 | mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_backlight_dimming, | ||
174 | sizeof(tmd_cmd_set_backlight_dimming), false); | ||
175 | |||
176 | dsi_config->dvr_ic_inited = 1; | ||
177 | } | ||
178 | |||
179 | /*TPO DPI encoder helper funcs*/ | ||
180 | static const struct drm_encoder_helper_funcs | ||
181 | mdfld_tpo_dpi_encoder_helper_funcs = { | ||
182 | .dpms = mdfld_dsi_dpi_dpms, | ||
183 | .mode_fixup = mdfld_dsi_dpi_mode_fixup, | ||
184 | .prepare = mdfld_dsi_dpi_prepare, | ||
185 | .mode_set = mdfld_dsi_dpi_mode_set, | ||
186 | .commit = mdfld_dsi_dpi_commit, | ||
187 | }; | ||
188 | |||
189 | /*TPO DPI encoder funcs*/ | ||
190 | static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = { | ||
191 | .destroy = drm_encoder_cleanup, | ||
192 | }; | ||
193 | |||
194 | const struct panel_funcs mdfld_tmd_vid_funcs = { | ||
195 | .encoder_funcs = &mdfld_tpo_dpi_encoder_funcs, | ||
196 | .encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs, | ||
197 | .get_config_mode = &tmd_vid_get_config_mode, | ||
198 | .get_panel_info = tmd_vid_get_panel_info, | ||
199 | .reset = mdfld_dsi_panel_reset, | ||
200 | .drv_ic_init = mdfld_dsi_tmd_drv_ic_init, | ||
201 | }; | ||
diff --git a/drivers/gpu/drm/gma500/mdfld_tpo_vid.c b/drivers/gpu/drm/gma500/mdfld_tpo_vid.c new file mode 100644 index 000000000000..d8d4170725b2 --- /dev/null +++ b/drivers/gpu/drm/gma500/mdfld_tpo_vid.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * Copyright © 2010 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * jim liu <jim.liu@intel.com> | ||
25 | * Jackie Li<yaodong.li@intel.com> | ||
26 | */ | ||
27 | |||
28 | #include "mdfld_dsi_dpi.h" | ||
29 | |||
30 | static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev) | ||
31 | { | ||
32 | struct drm_display_mode *mode; | ||
33 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
34 | struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; | ||
35 | bool use_gct = false; | ||
36 | |||
37 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | ||
38 | if (!mode) | ||
39 | return NULL; | ||
40 | |||
41 | if (use_gct) { | ||
42 | mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; | ||
43 | mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; | ||
44 | mode->hsync_start = mode->hdisplay + | ||
45 | ((ti->hsync_offset_hi << 8) | | ||
46 | ti->hsync_offset_lo); | ||
47 | mode->hsync_end = mode->hsync_start + | ||
48 | ((ti->hsync_pulse_width_hi << 8) | | ||
49 | ti->hsync_pulse_width_lo); | ||
50 | mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | | ||
51 | ti->hblank_lo); | ||
52 | mode->vsync_start = | ||
53 | mode->vdisplay + ((ti->vsync_offset_hi << 8) | | ||
54 | ti->vsync_offset_lo); | ||
55 | mode->vsync_end = | ||
56 | mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | | ||
57 | ti->vsync_pulse_width_lo); | ||
58 | mode->vtotal = mode->vdisplay + | ||
59 | ((ti->vblank_hi << 8) | ti->vblank_lo); | ||
60 | mode->clock = ti->pixel_clock * 10; | ||
61 | |||
62 | dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay); | ||
63 | dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay); | ||
64 | dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start); | ||
65 | dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end); | ||
66 | dev_dbg(dev->dev, "htotal is %d\n", mode->htotal); | ||
67 | dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start); | ||
68 | dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end); | ||
69 | dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal); | ||
70 | dev_dbg(dev->dev, "clock is %d\n", mode->clock); | ||
71 | } else { | ||
72 | mode->hdisplay = 864; | ||
73 | mode->vdisplay = 480; | ||
74 | mode->hsync_start = 873; | ||
75 | mode->hsync_end = 876; | ||
76 | mode->htotal = 887; | ||
77 | mode->vsync_start = 487; | ||
78 | mode->vsync_end = 490; | ||
79 | mode->vtotal = 499; | ||
80 | mode->clock = 33264; | ||
81 | } | ||
82 | |||
83 | drm_mode_set_name(mode); | ||
84 | drm_mode_set_crtcinfo(mode, 0); | ||
85 | |||
86 | mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
87 | |||
88 | return mode; | ||
89 | } | ||
90 | |||
91 | static int tpo_vid_get_panel_info(struct drm_device *dev, | ||
92 | int pipe, | ||
93 | struct panel_info *pi) | ||
94 | { | ||
95 | if (!dev || !pi) | ||
96 | return -EINVAL; | ||
97 | |||
98 | pi->width_mm = TPO_PANEL_WIDTH; | ||
99 | pi->height_mm = TPO_PANEL_HEIGHT; | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /*TPO DPI encoder helper funcs*/ | ||
105 | static const struct drm_encoder_helper_funcs | ||
106 | mdfld_tpo_dpi_encoder_helper_funcs = { | ||
107 | .dpms = mdfld_dsi_dpi_dpms, | ||
108 | .mode_fixup = mdfld_dsi_dpi_mode_fixup, | ||
109 | .prepare = mdfld_dsi_dpi_prepare, | ||
110 | .mode_set = mdfld_dsi_dpi_mode_set, | ||
111 | .commit = mdfld_dsi_dpi_commit, | ||
112 | }; | ||
113 | |||
114 | /*TPO DPI encoder funcs*/ | ||
115 | static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = { | ||
116 | .destroy = drm_encoder_cleanup, | ||
117 | }; | ||
118 | |||
119 | const struct panel_funcs mdfld_tpo_vid_funcs = { | ||
120 | .encoder_funcs = &mdfld_tpo_dpi_encoder_funcs, | ||
121 | .encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs, | ||
122 | .get_config_mode = &tpo_vid_get_config_mode, | ||
123 | .get_panel_info = tpo_vid_get_panel_info, | ||
124 | }; | ||
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 1f57aac2cf80..fc3293049fe7 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c | |||
@@ -60,6 +60,16 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { | |||
60 | /* Atom E620 */ | 60 | /* Atom E620 */ |
61 | { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, | 61 | { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, |
62 | #endif | 62 | #endif |
63 | #if defined(CONFIG_DRM_MEDFIELD) | ||
64 | {0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, | ||
65 | {0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, | ||
66 | {0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, | ||
67 | {0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, | ||
68 | {0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, | ||
69 | {0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, | ||
70 | {0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, | ||
71 | {0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, | ||
72 | #endif | ||
63 | #if defined(CONFIG_DRM_GMA3600) | 73 | #if defined(CONFIG_DRM_GMA3600) |
64 | { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | 74 | { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, |
65 | { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, | 75 | { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, |
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 3c0bf7be2738..af1c99752000 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h | |||
@@ -389,11 +389,79 @@ struct psb_state { | |||
389 | uint32_t savePWM_CONTROL_LOGIC; | 389 | uint32_t savePWM_CONTROL_LOGIC; |
390 | }; | 390 | }; |
391 | 391 | ||
392 | struct medfield_state { | ||
393 | uint32_t saveDPLL_A; | ||
394 | uint32_t saveFPA0; | ||
395 | uint32_t savePIPEACONF; | ||
396 | uint32_t saveHTOTAL_A; | ||
397 | uint32_t saveHBLANK_A; | ||
398 | uint32_t saveHSYNC_A; | ||
399 | uint32_t saveVTOTAL_A; | ||
400 | uint32_t saveVBLANK_A; | ||
401 | uint32_t saveVSYNC_A; | ||
402 | uint32_t savePIPEASRC; | ||
403 | uint32_t saveDSPASTRIDE; | ||
404 | uint32_t saveDSPALINOFF; | ||
405 | uint32_t saveDSPATILEOFF; | ||
406 | uint32_t saveDSPASIZE; | ||
407 | uint32_t saveDSPAPOS; | ||
408 | uint32_t saveDSPASURF; | ||
409 | uint32_t saveDSPACNTR; | ||
410 | uint32_t saveDSPASTATUS; | ||
411 | uint32_t save_palette_a[256]; | ||
412 | uint32_t saveMIPI; | ||
413 | |||
414 | uint32_t saveDPLL_B; | ||
415 | uint32_t saveFPB0; | ||
416 | uint32_t savePIPEBCONF; | ||
417 | uint32_t saveHTOTAL_B; | ||
418 | uint32_t saveHBLANK_B; | ||
419 | uint32_t saveHSYNC_B; | ||
420 | uint32_t saveVTOTAL_B; | ||
421 | uint32_t saveVBLANK_B; | ||
422 | uint32_t saveVSYNC_B; | ||
423 | uint32_t savePIPEBSRC; | ||
424 | uint32_t saveDSPBSTRIDE; | ||
425 | uint32_t saveDSPBLINOFF; | ||
426 | uint32_t saveDSPBTILEOFF; | ||
427 | uint32_t saveDSPBSIZE; | ||
428 | uint32_t saveDSPBPOS; | ||
429 | uint32_t saveDSPBSURF; | ||
430 | uint32_t saveDSPBCNTR; | ||
431 | uint32_t saveDSPBSTATUS; | ||
432 | uint32_t save_palette_b[256]; | ||
433 | |||
434 | uint32_t savePIPECCONF; | ||
435 | uint32_t saveHTOTAL_C; | ||
436 | uint32_t saveHBLANK_C; | ||
437 | uint32_t saveHSYNC_C; | ||
438 | uint32_t saveVTOTAL_C; | ||
439 | uint32_t saveVBLANK_C; | ||
440 | uint32_t saveVSYNC_C; | ||
441 | uint32_t savePIPECSRC; | ||
442 | uint32_t saveDSPCSTRIDE; | ||
443 | uint32_t saveDSPCLINOFF; | ||
444 | uint32_t saveDSPCTILEOFF; | ||
445 | uint32_t saveDSPCSIZE; | ||
446 | uint32_t saveDSPCPOS; | ||
447 | uint32_t saveDSPCSURF; | ||
448 | uint32_t saveDSPCCNTR; | ||
449 | uint32_t saveDSPCSTATUS; | ||
450 | uint32_t save_palette_c[256]; | ||
451 | uint32_t saveMIPI_C; | ||
452 | |||
453 | uint32_t savePFIT_CONTROL; | ||
454 | uint32_t savePFIT_PGM_RATIOS; | ||
455 | uint32_t saveHDMIPHYMISCCTL; | ||
456 | uint32_t saveHDMIB_CONTROL; | ||
457 | }; | ||
458 | |||
392 | struct psb_save_area { | 459 | struct psb_save_area { |
393 | uint32_t saveBSM; | 460 | uint32_t saveBSM; |
394 | uint32_t saveVBT; | 461 | uint32_t saveVBT; |
395 | union { | 462 | union { |
396 | struct psb_state psb; | 463 | struct psb_state psb; |
464 | struct medfield_state mdfld; | ||
397 | }; | 465 | }; |
398 | uint32_t saveBLC_PWM_CTL2; | 466 | uint32_t saveBLC_PWM_CTL2; |
399 | uint32_t saveBLC_PWM_CTL; | 467 | uint32_t saveBLC_PWM_CTL; |
@@ -563,6 +631,24 @@ struct drm_psb_private { | |||
563 | 631 | ||
564 | /* 2D acceleration */ | 632 | /* 2D acceleration */ |
565 | spinlock_t lock_2d; | 633 | spinlock_t lock_2d; |
634 | |||
635 | /* | ||
636 | * Panel brightness | ||
637 | */ | ||
638 | int brightness; | ||
639 | int brightness_adjusted; | ||
640 | |||
641 | bool dsr_enable; | ||
642 | u32 dsr_fb_update; | ||
643 | bool dpi_panel_on[3]; | ||
644 | void *dsi_configs[2]; | ||
645 | u32 bpp; | ||
646 | u32 bpp2; | ||
647 | |||
648 | u32 pipeconf[3]; | ||
649 | u32 dspcntr[3]; | ||
650 | |||
651 | int mdfld_panel_id; | ||
566 | }; | 652 | }; |
567 | 653 | ||
568 | 654 | ||
@@ -758,6 +844,9 @@ extern const struct psb_ops psb_chip_ops; | |||
758 | /* oaktrail_device.c */ | 844 | /* oaktrail_device.c */ |
759 | extern const struct psb_ops oaktrail_chip_ops; | 845 | extern const struct psb_ops oaktrail_chip_ops; |
760 | 846 | ||
847 | /* mdlfd_device.c */ | ||
848 | extern const struct psb_ops mdfld_chip_ops; | ||
849 | |||
761 | /* cdv_device.c */ | 850 | /* cdv_device.c */ |
762 | extern const struct psb_ops cdv_chip_ops; | 851 | extern const struct psb_ops cdv_chip_ops; |
763 | 852 | ||
diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index 7be802baceb5..a86fc3c4bf3a 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include "psb_reg.h" | 27 | #include "psb_reg.h" |
28 | #include "psb_intel_reg.h" | 28 | #include "psb_intel_reg.h" |
29 | #include "power.h" | 29 | #include "power.h" |
30 | #include "psb_irq.h" | ||
31 | #include "mdfld_output.h" | ||
30 | 32 | ||
31 | /* | 33 | /* |
32 | * inline functions | 34 | * inline functions |
@@ -453,6 +455,11 @@ int psb_enable_vblank(struct drm_device *dev, int pipe) | |||
453 | uint32_t reg_val = 0; | 455 | uint32_t reg_val = 0; |
454 | uint32_t pipeconf_reg = mid_pipeconf(pipe); | 456 | uint32_t pipeconf_reg = mid_pipeconf(pipe); |
455 | 457 | ||
458 | /* Medfield is different - we should perhaps extract out vblank | ||
459 | and blacklight etc ops */ | ||
460 | if (IS_MFLD(dev)) | ||
461 | return mdfld_enable_te(dev, pipe); | ||
462 | |||
456 | if (gma_power_begin(dev, false)) { | 463 | if (gma_power_begin(dev, false)) { |
457 | reg_val = REG_READ(pipeconf_reg); | 464 | reg_val = REG_READ(pipeconf_reg); |
458 | gma_power_end(dev); | 465 | gma_power_end(dev); |
@@ -485,6 +492,8 @@ void psb_disable_vblank(struct drm_device *dev, int pipe) | |||
485 | struct drm_psb_private *dev_priv = dev->dev_private; | 492 | struct drm_psb_private *dev_priv = dev->dev_private; |
486 | unsigned long irqflags; | 493 | unsigned long irqflags; |
487 | 494 | ||
495 | if (IS_MFLD(dev)) | ||
496 | mdfld_disable_te(dev, pipe); | ||
488 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | 497 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); |
489 | 498 | ||
490 | if (pipe == 0) | 499 | if (pipe == 0) |
@@ -499,6 +508,55 @@ void psb_disable_vblank(struct drm_device *dev, int pipe) | |||
499 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | 508 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); |
500 | } | 509 | } |
501 | 510 | ||
511 | /* | ||
512 | * It is used to enable TE interrupt | ||
513 | */ | ||
514 | int mdfld_enable_te(struct drm_device *dev, int pipe) | ||
515 | { | ||
516 | struct drm_psb_private *dev_priv = | ||
517 | (struct drm_psb_private *) dev->dev_private; | ||
518 | unsigned long irqflags; | ||
519 | uint32_t reg_val = 0; | ||
520 | uint32_t pipeconf_reg = mid_pipeconf(pipe); | ||
521 | |||
522 | if (gma_power_begin(dev, false)) { | ||
523 | reg_val = REG_READ(pipeconf_reg); | ||
524 | gma_power_end(dev); | ||
525 | } | ||
526 | |||
527 | if (!(reg_val & PIPEACONF_ENABLE)) | ||
528 | return -EINVAL; | ||
529 | |||
530 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
531 | |||
532 | mid_enable_pipe_event(dev_priv, pipe); | ||
533 | psb_enable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE); | ||
534 | |||
535 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | /* | ||
541 | * It is used to disable TE interrupt | ||
542 | */ | ||
543 | void mdfld_disable_te(struct drm_device *dev, int pipe) | ||
544 | { | ||
545 | struct drm_psb_private *dev_priv = | ||
546 | (struct drm_psb_private *) dev->dev_private; | ||
547 | unsigned long irqflags; | ||
548 | |||
549 | if (!dev_priv->dsr_enable) | ||
550 | return; | ||
551 | |||
552 | spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); | ||
553 | |||
554 | mid_disable_pipe_event(dev_priv, pipe); | ||
555 | psb_disable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE); | ||
556 | |||
557 | spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); | ||
558 | } | ||
559 | |||
502 | /* Called from drm generic code, passed a 'crtc', which | 560 | /* Called from drm generic code, passed a 'crtc', which |
503 | * we use as a pipe index | 561 | * we use as a pipe index |
504 | */ | 562 | */ |
diff --git a/drivers/gpu/drm/gma500/psb_irq.h b/drivers/gpu/drm/gma500/psb_irq.h index 216fda38b57d..603045bee58a 100644 --- a/drivers/gpu/drm/gma500/psb_irq.h +++ b/drivers/gpu/drm/gma500/psb_irq.h | |||
@@ -42,4 +42,6 @@ int psb_enable_vblank(struct drm_device *dev, int pipe); | |||
42 | void psb_disable_vblank(struct drm_device *dev, int pipe); | 42 | void psb_disable_vblank(struct drm_device *dev, int pipe); |
43 | u32 psb_get_vblank_counter(struct drm_device *dev, int pipe); | 43 | u32 psb_get_vblank_counter(struct drm_device *dev, int pipe); |
44 | 44 | ||
45 | int mdfld_enable_te(struct drm_device *dev, int pipe); | ||
46 | void mdfld_disable_te(struct drm_device *dev, int pipe); | ||
45 | #endif /* _SYSIRQ_H_ */ | 47 | #endif /* _SYSIRQ_H_ */ |
diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c new file mode 100644 index 000000000000..4a07ab596174 --- /dev/null +++ b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c | |||
@@ -0,0 +1,829 @@ | |||
1 | /* | ||
2 | * Copyright © 2011 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "mdfld_dsi_dpi.h" | ||
26 | #include "mdfld_output.h" | ||
27 | #include "mdfld_dsi_pkg_sender.h" | ||
28 | #include "tc35876x-dsi-lvds.h" | ||
29 | #include <linux/i2c/tc35876x.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <asm/intel_scu_ipc.h> | ||
33 | |||
34 | static struct i2c_client *tc35876x_client; | ||
35 | static struct i2c_client *cmi_lcd_i2c_client; | ||
36 | |||
37 | #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) | ||
38 | #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) | ||
39 | |||
40 | /* DSI D-PHY Layer Registers */ | ||
41 | #define D0W_DPHYCONTTX 0x0004 | ||
42 | #define CLW_DPHYCONTRX 0x0020 | ||
43 | #define D0W_DPHYCONTRX 0x0024 | ||
44 | #define D1W_DPHYCONTRX 0x0028 | ||
45 | #define D2W_DPHYCONTRX 0x002C | ||
46 | #define D3W_DPHYCONTRX 0x0030 | ||
47 | #define COM_DPHYCONTRX 0x0038 | ||
48 | #define CLW_CNTRL 0x0040 | ||
49 | #define D0W_CNTRL 0x0044 | ||
50 | #define D1W_CNTRL 0x0048 | ||
51 | #define D2W_CNTRL 0x004C | ||
52 | #define D3W_CNTRL 0x0050 | ||
53 | #define DFTMODE_CNTRL 0x0054 | ||
54 | |||
55 | /* DSI PPI Layer Registers */ | ||
56 | #define PPI_STARTPPI 0x0104 | ||
57 | #define PPI_BUSYPPI 0x0108 | ||
58 | #define PPI_LINEINITCNT 0x0110 | ||
59 | #define PPI_LPTXTIMECNT 0x0114 | ||
60 | #define PPI_LANEENABLE 0x0134 | ||
61 | #define PPI_TX_RX_TA 0x013C | ||
62 | #define PPI_CLS_ATMR 0x0140 | ||
63 | #define PPI_D0S_ATMR 0x0144 | ||
64 | #define PPI_D1S_ATMR 0x0148 | ||
65 | #define PPI_D2S_ATMR 0x014C | ||
66 | #define PPI_D3S_ATMR 0x0150 | ||
67 | #define PPI_D0S_CLRSIPOCOUNT 0x0164 | ||
68 | #define PPI_D1S_CLRSIPOCOUNT 0x0168 | ||
69 | #define PPI_D2S_CLRSIPOCOUNT 0x016C | ||
70 | #define PPI_D3S_CLRSIPOCOUNT 0x0170 | ||
71 | #define CLS_PRE 0x0180 | ||
72 | #define D0S_PRE 0x0184 | ||
73 | #define D1S_PRE 0x0188 | ||
74 | #define D2S_PRE 0x018C | ||
75 | #define D3S_PRE 0x0190 | ||
76 | #define CLS_PREP 0x01A0 | ||
77 | #define D0S_PREP 0x01A4 | ||
78 | #define D1S_PREP 0x01A8 | ||
79 | #define D2S_PREP 0x01AC | ||
80 | #define D3S_PREP 0x01B0 | ||
81 | #define CLS_ZERO 0x01C0 | ||
82 | #define D0S_ZERO 0x01C4 | ||
83 | #define D1S_ZERO 0x01C8 | ||
84 | #define D2S_ZERO 0x01CC | ||
85 | #define D3S_ZERO 0x01D0 | ||
86 | #define PPI_CLRFLG 0x01E0 | ||
87 | #define PPI_CLRSIPO 0x01E4 | ||
88 | #define HSTIMEOUT 0x01F0 | ||
89 | #define HSTIMEOUTENABLE 0x01F4 | ||
90 | |||
91 | /* DSI Protocol Layer Registers */ | ||
92 | #define DSI_STARTDSI 0x0204 | ||
93 | #define DSI_BUSYDSI 0x0208 | ||
94 | #define DSI_LANEENABLE 0x0210 | ||
95 | #define DSI_LANESTATUS0 0x0214 | ||
96 | #define DSI_LANESTATUS1 0x0218 | ||
97 | #define DSI_INTSTATUS 0x0220 | ||
98 | #define DSI_INTMASK 0x0224 | ||
99 | #define DSI_INTCLR 0x0228 | ||
100 | #define DSI_LPTXTO 0x0230 | ||
101 | |||
102 | /* DSI General Registers */ | ||
103 | #define DSIERRCNT 0x0300 | ||
104 | |||
105 | /* DSI Application Layer Registers */ | ||
106 | #define APLCTRL 0x0400 | ||
107 | #define RDPKTLN 0x0404 | ||
108 | |||
109 | /* Video Path Registers */ | ||
110 | #define VPCTRL 0x0450 | ||
111 | #define HTIM1 0x0454 | ||
112 | #define HTIM2 0x0458 | ||
113 | #define VTIM1 0x045C | ||
114 | #define VTIM2 0x0460 | ||
115 | #define VFUEN 0x0464 | ||
116 | |||
117 | /* LVDS Registers */ | ||
118 | #define LVMX0003 0x0480 | ||
119 | #define LVMX0407 0x0484 | ||
120 | #define LVMX0811 0x0488 | ||
121 | #define LVMX1215 0x048C | ||
122 | #define LVMX1619 0x0490 | ||
123 | #define LVMX2023 0x0494 | ||
124 | #define LVMX2427 0x0498 | ||
125 | #define LVCFG 0x049C | ||
126 | #define LVPHY0 0x04A0 | ||
127 | #define LVPHY1 0x04A4 | ||
128 | |||
129 | /* System Registers */ | ||
130 | #define SYSSTAT 0x0500 | ||
131 | #define SYSRST 0x0504 | ||
132 | |||
133 | /* GPIO Registers */ | ||
134 | /*#define GPIOC 0x0520*/ | ||
135 | #define GPIOO 0x0524 | ||
136 | #define GPIOI 0x0528 | ||
137 | |||
138 | /* I2C Registers */ | ||
139 | #define I2CTIMCTRL 0x0540 | ||
140 | #define I2CMADDR 0x0544 | ||
141 | #define WDATAQ 0x0548 | ||
142 | #define RDATAQ 0x054C | ||
143 | |||
144 | /* Chip/Rev Registers */ | ||
145 | #define IDREG 0x0580 | ||
146 | |||
147 | /* Debug Registers */ | ||
148 | #define DEBUG00 0x05A0 | ||
149 | #define DEBUG01 0x05A4 | ||
150 | |||
151 | /* Panel CABC registers */ | ||
152 | #define PANEL_PWM_CONTROL 0x90 | ||
153 | #define PANEL_FREQ_DIVIDER_HI 0x91 | ||
154 | #define PANEL_FREQ_DIVIDER_LO 0x92 | ||
155 | #define PANEL_DUTY_CONTROL 0x93 | ||
156 | #define PANEL_MODIFY_RGB 0x94 | ||
157 | #define PANEL_FRAMERATE_CONTROL 0x96 | ||
158 | #define PANEL_PWM_MIN 0x97 | ||
159 | #define PANEL_PWM_REF 0x98 | ||
160 | #define PANEL_PWM_MAX 0x99 | ||
161 | #define PANEL_ALLOW_DISTORT 0x9A | ||
162 | #define PANEL_BYPASS_PWMI 0x9B | ||
163 | |||
164 | /* Panel color management registers */ | ||
165 | #define PANEL_CM_ENABLE 0x700 | ||
166 | #define PANEL_CM_HUE 0x701 | ||
167 | #define PANEL_CM_SATURATION 0x702 | ||
168 | #define PANEL_CM_INTENSITY 0x703 | ||
169 | #define PANEL_CM_BRIGHTNESS 0x704 | ||
170 | #define PANEL_CM_CE_ENABLE 0x705 | ||
171 | #define PANEL_CM_PEAK_EN 0x710 | ||
172 | #define PANEL_CM_GAIN 0x711 | ||
173 | #define PANEL_CM_HUETABLE_START 0x730 | ||
174 | #define PANEL_CM_HUETABLE_END 0x747 /* inclusive */ | ||
175 | |||
176 | /* Input muxing for registers LVMX0003...LVMX2427 */ | ||
177 | enum { | ||
178 | INPUT_R0, /* 0 */ | ||
179 | INPUT_R1, | ||
180 | INPUT_R2, | ||
181 | INPUT_R3, | ||
182 | INPUT_R4, | ||
183 | INPUT_R5, | ||
184 | INPUT_R6, | ||
185 | INPUT_R7, | ||
186 | INPUT_G0, /* 8 */ | ||
187 | INPUT_G1, | ||
188 | INPUT_G2, | ||
189 | INPUT_G3, | ||
190 | INPUT_G4, | ||
191 | INPUT_G5, | ||
192 | INPUT_G6, | ||
193 | INPUT_G7, | ||
194 | INPUT_B0, /* 16 */ | ||
195 | INPUT_B1, | ||
196 | INPUT_B2, | ||
197 | INPUT_B3, | ||
198 | INPUT_B4, | ||
199 | INPUT_B5, | ||
200 | INPUT_B6, | ||
201 | INPUT_B7, | ||
202 | INPUT_HSYNC, /* 24 */ | ||
203 | INPUT_VSYNC, | ||
204 | INPUT_DE, | ||
205 | LOGIC_0, | ||
206 | /* 28...31 undefined */ | ||
207 | }; | ||
208 | |||
209 | #define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00) \ | ||
210 | (FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) | \ | ||
211 | FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0)) | ||
212 | |||
213 | /** | ||
214 | * tc35876x_regw - Write DSI-LVDS bridge register using I2C | ||
215 | * @client: struct i2c_client to use | ||
216 | * @reg: register address | ||
217 | * @value: value to write | ||
218 | * | ||
219 | * Returns 0 on success, or a negative error value. | ||
220 | */ | ||
221 | static int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value) | ||
222 | { | ||
223 | int r; | ||
224 | u8 tx_data[] = { | ||
225 | /* NOTE: Register address big-endian, data little-endian. */ | ||
226 | (reg >> 8) & 0xff, | ||
227 | reg & 0xff, | ||
228 | value & 0xff, | ||
229 | (value >> 8) & 0xff, | ||
230 | (value >> 16) & 0xff, | ||
231 | (value >> 24) & 0xff, | ||
232 | }; | ||
233 | struct i2c_msg msgs[] = { | ||
234 | { | ||
235 | .addr = client->addr, | ||
236 | .flags = 0, | ||
237 | .buf = tx_data, | ||
238 | .len = ARRAY_SIZE(tx_data), | ||
239 | }, | ||
240 | }; | ||
241 | |||
242 | r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
243 | if (r < 0) { | ||
244 | dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n", | ||
245 | __func__, reg, value, r); | ||
246 | return r; | ||
247 | } | ||
248 | |||
249 | if (r < ARRAY_SIZE(msgs)) { | ||
250 | dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n", | ||
251 | __func__, reg, value, r); | ||
252 | return -EAGAIN; | ||
253 | } | ||
254 | |||
255 | dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n", | ||
256 | __func__, reg, value); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * tc35876x_regr - Read DSI-LVDS bridge register using I2C | ||
263 | * @client: struct i2c_client to use | ||
264 | * @reg: register address | ||
265 | * @value: pointer for storing the value | ||
266 | * | ||
267 | * Returns 0 on success, or a negative error value. | ||
268 | */ | ||
269 | static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value) | ||
270 | { | ||
271 | int r; | ||
272 | u8 tx_data[] = { | ||
273 | (reg >> 8) & 0xff, | ||
274 | reg & 0xff, | ||
275 | }; | ||
276 | u8 rx_data[4]; | ||
277 | struct i2c_msg msgs[] = { | ||
278 | { | ||
279 | .addr = client->addr, | ||
280 | .flags = 0, | ||
281 | .buf = tx_data, | ||
282 | .len = ARRAY_SIZE(tx_data), | ||
283 | }, | ||
284 | { | ||
285 | .addr = client->addr, | ||
286 | .flags = I2C_M_RD, | ||
287 | .buf = rx_data, | ||
288 | .len = ARRAY_SIZE(rx_data), | ||
289 | }, | ||
290 | }; | ||
291 | |||
292 | r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
293 | if (r < 0) { | ||
294 | dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__, | ||
295 | reg, r); | ||
296 | return r; | ||
297 | } | ||
298 | |||
299 | if (r < ARRAY_SIZE(msgs)) { | ||
300 | dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__, | ||
301 | reg, r); | ||
302 | return -EAGAIN; | ||
303 | } | ||
304 | |||
305 | *value = rx_data[0] << 24 | rx_data[1] << 16 | | ||
306 | rx_data[2] << 8 | rx_data[3]; | ||
307 | |||
308 | dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__, | ||
309 | reg, *value); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state) | ||
315 | { | ||
316 | struct tc35876x_platform_data *pdata; | ||
317 | |||
318 | if (WARN(!tc35876x_client, "%s called before probe", __func__)) | ||
319 | return; | ||
320 | |||
321 | dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state); | ||
322 | |||
323 | pdata = dev_get_platdata(&tc35876x_client->dev); | ||
324 | |||
325 | if (pdata->gpio_bridge_reset == -1) | ||
326 | return; | ||
327 | |||
328 | if (state) { | ||
329 | gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); | ||
330 | mdelay(10); | ||
331 | } else { | ||
332 | /* Pull MIPI Bridge reset pin to Low */ | ||
333 | gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); | ||
334 | mdelay(20); | ||
335 | /* Pull MIPI Bridge reset pin to High */ | ||
336 | gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1); | ||
337 | mdelay(40); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | void tc35876x_configure_lvds_bridge(struct drm_device *dev) | ||
342 | { | ||
343 | struct i2c_client *i2c = tc35876x_client; | ||
344 | u32 ppi_lptxtimecnt; | ||
345 | u32 txtagocnt; | ||
346 | u32 txtasurecnt; | ||
347 | u32 id; | ||
348 | |||
349 | if (WARN(!tc35876x_client, "%s called before probe", __func__)) | ||
350 | return; | ||
351 | |||
352 | dev_dbg(&tc35876x_client->dev, "%s\n", __func__); | ||
353 | |||
354 | if (!tc35876x_regr(i2c, IDREG, &id)) | ||
355 | dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id); | ||
356 | else | ||
357 | dev_err(&tc35876x_client->dev, "Cannot read ID\n"); | ||
358 | |||
359 | ppi_lptxtimecnt = 4; | ||
360 | txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4; | ||
361 | txtasurecnt = 3 * ppi_lptxtimecnt / 2; | ||
362 | tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) | | ||
363 | FLD_VAL(txtasurecnt, 10, 0)); | ||
364 | tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0)); | ||
365 | |||
366 | tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); | ||
367 | tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); | ||
368 | tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); | ||
369 | tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); | ||
370 | |||
371 | /* Enabling MIPI & PPI lanes, Enable 4 lanes */ | ||
372 | tc35876x_regw(i2c, PPI_LANEENABLE, | ||
373 | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); | ||
374 | tc35876x_regw(i2c, DSI_LANEENABLE, | ||
375 | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); | ||
376 | tc35876x_regw(i2c, PPI_STARTPPI, BIT(0)); | ||
377 | tc35876x_regw(i2c, DSI_STARTDSI, BIT(0)); | ||
378 | |||
379 | /* Setting LVDS output frequency */ | ||
380 | tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) | | ||
381 | FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */ | ||
382 | |||
383 | /* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */ | ||
384 | tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5)); | ||
385 | |||
386 | /* Horizontal back porch and horizontal pulse width. 0x00280028 */ | ||
387 | tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0)); | ||
388 | |||
389 | /* Horizontal front porch and horizontal active video size. 0x00500500*/ | ||
390 | tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0)); | ||
391 | |||
392 | /* Vertical back porch and vertical sync pulse width. 0x000e000a */ | ||
393 | tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0)); | ||
394 | |||
395 | /* Vertical front porch and vertical display size. 0x000e0320 */ | ||
396 | tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0)); | ||
397 | |||
398 | /* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */ | ||
399 | tc35876x_regw(i2c, VFUEN, BIT(0)); | ||
400 | |||
401 | /* Soft reset LCD controller. */ | ||
402 | tc35876x_regw(i2c, SYSRST, BIT(2)); | ||
403 | |||
404 | /* LVDS-TX input muxing */ | ||
405 | tc35876x_regw(i2c, LVMX0003, | ||
406 | INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2)); | ||
407 | tc35876x_regw(i2c, LVMX0407, | ||
408 | INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6)); | ||
409 | tc35876x_regw(i2c, LVMX0811, | ||
410 | INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3)); | ||
411 | tc35876x_regw(i2c, LVMX1215, | ||
412 | INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5)); | ||
413 | tc35876x_regw(i2c, LVMX1619, | ||
414 | INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0)); | ||
415 | tc35876x_regw(i2c, LVMX2023, | ||
416 | INPUT_MUX(LOGIC_0, INPUT_B7, INPUT_B6, INPUT_B5)); | ||
417 | tc35876x_regw(i2c, LVMX2427, | ||
418 | INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC)); | ||
419 | |||
420 | /* Enable LVDS transmitter. */ | ||
421 | tc35876x_regw(i2c, LVCFG, BIT(0)); | ||
422 | |||
423 | /* Clear notifications. Don't write reserved bits. Was write 0xffffffff | ||
424 | * to 0x0288, must be in error?! */ | ||
425 | tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0)); | ||
426 | } | ||
427 | |||
428 | #define GPIOPWMCTRL 0x38F | ||
429 | #define PWM0CLKDIV0 0x62 /* low byte */ | ||
430 | #define PWM0CLKDIV1 0x61 /* high byte */ | ||
431 | |||
432 | #define SYSTEMCLK 19200000UL /* 19.2 MHz */ | ||
433 | #define PWM_FREQUENCY 9600 /* Hz */ | ||
434 | |||
435 | /* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */ | ||
436 | static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f) | ||
437 | { | ||
438 | return (baseclk - f) / f; | ||
439 | } | ||
440 | |||
441 | static void tc35876x_brightness_init(struct drm_device *dev) | ||
442 | { | ||
443 | int ret; | ||
444 | u8 pwmctrl; | ||
445 | u16 clkdiv; | ||
446 | |||
447 | /* Make sure the PWM reference is the 19.2 MHz system clock. Read first | ||
448 | * instead of setting directly to catch potential conflicts between PWM | ||
449 | * users. */ | ||
450 | ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl); | ||
451 | if (ret || pwmctrl != 0x01) { | ||
452 | if (ret) | ||
453 | dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n"); | ||
454 | else | ||
455 | dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl); | ||
456 | |||
457 | ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01); | ||
458 | if (ret) | ||
459 | dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n"); | ||
460 | } | ||
461 | |||
462 | clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY); | ||
463 | |||
464 | ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff); | ||
465 | if (!ret) | ||
466 | ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff); | ||
467 | |||
468 | if (ret) | ||
469 | dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n"); | ||
470 | else | ||
471 | dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n", | ||
472 | clkdiv, PWM_FREQUENCY); | ||
473 | } | ||
474 | |||
475 | #define PWM0DUTYCYCLE 0x67 | ||
476 | |||
477 | void tc35876x_brightness_control(struct drm_device *dev, int level) | ||
478 | { | ||
479 | int ret; | ||
480 | u8 duty_val; | ||
481 | u8 panel_duty_val; | ||
482 | |||
483 | level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); | ||
484 | |||
485 | /* PWM duty cycle 0x00...0x63 corresponds to 0...99% */ | ||
486 | duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL; | ||
487 | |||
488 | /* I won't pretend to understand this formula. The panel spec is quite | ||
489 | * bad engrish. | ||
490 | */ | ||
491 | panel_duty_val = (2 * level - 100) * 0xA9 / | ||
492 | MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56; | ||
493 | |||
494 | ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val); | ||
495 | if (ret) | ||
496 | dev_err(&tc35876x_client->dev, "%s: ipc write fail\n", | ||
497 | __func__); | ||
498 | |||
499 | if (cmi_lcd_i2c_client) { | ||
500 | ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, | ||
501 | PANEL_PWM_MAX, panel_duty_val); | ||
502 | if (ret < 0) | ||
503 | dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n", | ||
504 | __func__); | ||
505 | } | ||
506 | } | ||
507 | |||
508 | void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev) | ||
509 | { | ||
510 | struct tc35876x_platform_data *pdata; | ||
511 | |||
512 | if (WARN(!tc35876x_client, "%s called before probe", __func__)) | ||
513 | return; | ||
514 | |||
515 | dev_dbg(&tc35876x_client->dev, "%s\n", __func__); | ||
516 | |||
517 | pdata = dev_get_platdata(&tc35876x_client->dev); | ||
518 | |||
519 | if (pdata->gpio_panel_bl_en != -1) | ||
520 | gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0); | ||
521 | |||
522 | if (pdata->gpio_panel_vadd != -1) | ||
523 | gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0); | ||
524 | } | ||
525 | |||
526 | void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) | ||
527 | { | ||
528 | struct tc35876x_platform_data *pdata; | ||
529 | struct drm_psb_private *dev_priv = dev->dev_private; | ||
530 | |||
531 | if (WARN(!tc35876x_client, "%s called before probe", __func__)) | ||
532 | return; | ||
533 | |||
534 | dev_dbg(&tc35876x_client->dev, "%s\n", __func__); | ||
535 | |||
536 | pdata = dev_get_platdata(&tc35876x_client->dev); | ||
537 | |||
538 | if (pdata->gpio_panel_vadd != -1) { | ||
539 | gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1); | ||
540 | msleep(260); | ||
541 | } | ||
542 | |||
543 | if (cmi_lcd_i2c_client) { | ||
544 | int ret; | ||
545 | dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n"); | ||
546 | /* Bit 4 is average_saving. Setting it to 1, the brightness is | ||
547 | * referenced to the average of the frame content. 0 means | ||
548 | * reference to the maximum of frame contents. Bits 3:0 are | ||
549 | * allow_distort. When set to a nonzero value, all color values | ||
550 | * between 255-allow_distort*2 and 255 are mapped to the | ||
551 | * 255-allow_distort*2 value. | ||
552 | */ | ||
553 | ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, | ||
554 | PANEL_ALLOW_DISTORT, 0x10); | ||
555 | if (ret < 0) | ||
556 | dev_err(&cmi_lcd_i2c_client->dev, | ||
557 | "i2c write failed (%d)\n", ret); | ||
558 | ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, | ||
559 | PANEL_BYPASS_PWMI, 0); | ||
560 | if (ret < 0) | ||
561 | dev_err(&cmi_lcd_i2c_client->dev, | ||
562 | "i2c write failed (%d)\n", ret); | ||
563 | /* Set minimum brightness value - this is tunable */ | ||
564 | ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, | ||
565 | PANEL_PWM_MIN, 0x35); | ||
566 | if (ret < 0) | ||
567 | dev_err(&cmi_lcd_i2c_client->dev, | ||
568 | "i2c write failed (%d)\n", ret); | ||
569 | } | ||
570 | |||
571 | if (pdata->gpio_panel_bl_en != -1) | ||
572 | gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1); | ||
573 | |||
574 | tc35876x_brightness_control(dev, dev_priv->brightness_adjusted); | ||
575 | } | ||
576 | |||
577 | static struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev) | ||
578 | { | ||
579 | struct drm_display_mode *mode; | ||
580 | |||
581 | dev_dbg(&dev->pdev->dev, "%s\n", __func__); | ||
582 | |||
583 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | ||
584 | if (!mode) | ||
585 | return NULL; | ||
586 | |||
587 | /* FIXME: do this properly. */ | ||
588 | mode->hdisplay = 1280; | ||
589 | mode->vdisplay = 800; | ||
590 | mode->hsync_start = 1360; | ||
591 | mode->hsync_end = 1400; | ||
592 | mode->htotal = 1440; | ||
593 | mode->vsync_start = 814; | ||
594 | mode->vsync_end = 824; | ||
595 | mode->vtotal = 838; | ||
596 | mode->clock = 33324 << 1; | ||
597 | |||
598 | dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay); | ||
599 | dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay); | ||
600 | dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start); | ||
601 | dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end); | ||
602 | dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal); | ||
603 | dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start); | ||
604 | dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end); | ||
605 | dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal); | ||
606 | dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock); | ||
607 | |||
608 | drm_mode_set_name(mode); | ||
609 | drm_mode_set_crtcinfo(mode, 0); | ||
610 | |||
611 | mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
612 | |||
613 | return mode; | ||
614 | } | ||
615 | |||
616 | /* DV1 Active area 216.96 x 135.6 mm */ | ||
617 | #define DV1_PANEL_WIDTH 217 | ||
618 | #define DV1_PANEL_HEIGHT 136 | ||
619 | |||
620 | static int tc35876x_get_panel_info(struct drm_device *dev, int pipe, | ||
621 | struct panel_info *pi) | ||
622 | { | ||
623 | if (!dev || !pi) | ||
624 | return -EINVAL; | ||
625 | |||
626 | pi->width_mm = DV1_PANEL_WIDTH; | ||
627 | pi->height_mm = DV1_PANEL_HEIGHT; | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static int tc35876x_bridge_probe(struct i2c_client *client, | ||
633 | const struct i2c_device_id *id) | ||
634 | { | ||
635 | struct tc35876x_platform_data *pdata; | ||
636 | |||
637 | dev_info(&client->dev, "%s\n", __func__); | ||
638 | |||
639 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
640 | dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", | ||
641 | __func__); | ||
642 | return -ENODEV; | ||
643 | } | ||
644 | |||
645 | pdata = dev_get_platdata(&client->dev); | ||
646 | if (!pdata) { | ||
647 | dev_err(&client->dev, "%s: no platform data\n", __func__); | ||
648 | return -ENODEV; | ||
649 | } | ||
650 | |||
651 | if (pdata->gpio_bridge_reset != -1) { | ||
652 | gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset"); | ||
653 | gpio_direction_output(pdata->gpio_bridge_reset, 0); | ||
654 | } | ||
655 | |||
656 | if (pdata->gpio_panel_bl_en != -1) { | ||
657 | gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en"); | ||
658 | gpio_direction_output(pdata->gpio_panel_bl_en, 0); | ||
659 | } | ||
660 | |||
661 | if (pdata->gpio_panel_vadd != -1) { | ||
662 | gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd"); | ||
663 | gpio_direction_output(pdata->gpio_panel_vadd, 0); | ||
664 | } | ||
665 | |||
666 | tc35876x_client = client; | ||
667 | |||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static int tc35876x_bridge_remove(struct i2c_client *client) | ||
672 | { | ||
673 | struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev); | ||
674 | |||
675 | dev_dbg(&client->dev, "%s\n", __func__); | ||
676 | |||
677 | if (pdata->gpio_bridge_reset != -1) | ||
678 | gpio_free(pdata->gpio_bridge_reset); | ||
679 | |||
680 | if (pdata->gpio_panel_bl_en != -1) | ||
681 | gpio_free(pdata->gpio_panel_bl_en); | ||
682 | |||
683 | if (pdata->gpio_panel_vadd != -1) | ||
684 | gpio_free(pdata->gpio_panel_vadd); | ||
685 | |||
686 | tc35876x_client = NULL; | ||
687 | |||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static const struct i2c_device_id tc35876x_bridge_id[] = { | ||
692 | { "i2c_disp_brig", 0 }, | ||
693 | { } | ||
694 | }; | ||
695 | MODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id); | ||
696 | |||
697 | static struct i2c_driver tc35876x_bridge_i2c_driver = { | ||
698 | .driver = { | ||
699 | .name = "i2c_disp_brig", | ||
700 | }, | ||
701 | .id_table = tc35876x_bridge_id, | ||
702 | .probe = tc35876x_bridge_probe, | ||
703 | .remove = __devexit_p(tc35876x_bridge_remove), | ||
704 | }; | ||
705 | |||
706 | /* LCD panel I2C */ | ||
707 | static int cmi_lcd_i2c_probe(struct i2c_client *client, | ||
708 | const struct i2c_device_id *id) | ||
709 | { | ||
710 | dev_info(&client->dev, "%s\n", __func__); | ||
711 | |||
712 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
713 | dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", | ||
714 | __func__); | ||
715 | return -ENODEV; | ||
716 | } | ||
717 | |||
718 | cmi_lcd_i2c_client = client; | ||
719 | |||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static int cmi_lcd_i2c_remove(struct i2c_client *client) | ||
724 | { | ||
725 | dev_dbg(&client->dev, "%s\n", __func__); | ||
726 | |||
727 | cmi_lcd_i2c_client = NULL; | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static const struct i2c_device_id cmi_lcd_i2c_id[] = { | ||
733 | { "cmi-lcd", 0 }, | ||
734 | { } | ||
735 | }; | ||
736 | MODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id); | ||
737 | |||
738 | static struct i2c_driver cmi_lcd_i2c_driver = { | ||
739 | .driver = { | ||
740 | .name = "cmi-lcd", | ||
741 | }, | ||
742 | .id_table = cmi_lcd_i2c_id, | ||
743 | .probe = cmi_lcd_i2c_probe, | ||
744 | .remove = __devexit_p(cmi_lcd_i2c_remove), | ||
745 | }; | ||
746 | |||
747 | /* HACK to create I2C device while it's not created by platform code */ | ||
748 | #define CMI_LCD_I2C_ADAPTER 2 | ||
749 | #define CMI_LCD_I2C_ADDR 0x60 | ||
750 | |||
751 | static int cmi_lcd_hack_create_device(void) | ||
752 | { | ||
753 | struct i2c_adapter *adapter; | ||
754 | struct i2c_client *client; | ||
755 | struct i2c_board_info info = { | ||
756 | .type = "cmi-lcd", | ||
757 | .addr = CMI_LCD_I2C_ADDR, | ||
758 | }; | ||
759 | |||
760 | pr_debug("%s\n", __func__); | ||
761 | |||
762 | adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER); | ||
763 | if (!adapter) { | ||
764 | pr_err("%s: i2c_get_adapter(%d) failed\n", __func__, | ||
765 | CMI_LCD_I2C_ADAPTER); | ||
766 | return -EINVAL; | ||
767 | } | ||
768 | |||
769 | client = i2c_new_device(adapter, &info); | ||
770 | if (!client) { | ||
771 | pr_err("%s: i2c_new_device() failed\n", __func__); | ||
772 | i2c_put_adapter(adapter); | ||
773 | return -EINVAL; | ||
774 | } | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | static const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = { | ||
780 | .dpms = mdfld_dsi_dpi_dpms, | ||
781 | .mode_fixup = mdfld_dsi_dpi_mode_fixup, | ||
782 | .prepare = mdfld_dsi_dpi_prepare, | ||
783 | .mode_set = mdfld_dsi_dpi_mode_set, | ||
784 | .commit = mdfld_dsi_dpi_commit, | ||
785 | }; | ||
786 | |||
787 | static const struct drm_encoder_funcs tc35876x_encoder_funcs = { | ||
788 | .destroy = drm_encoder_cleanup, | ||
789 | }; | ||
790 | |||
791 | const struct panel_funcs mdfld_tc35876x_funcs = { | ||
792 | .encoder_funcs = &tc35876x_encoder_funcs, | ||
793 | .encoder_helper_funcs = &tc35876x_encoder_helper_funcs, | ||
794 | .get_config_mode = tc35876x_get_config_mode, | ||
795 | .get_panel_info = tc35876x_get_panel_info, | ||
796 | }; | ||
797 | |||
798 | void tc35876x_init(struct drm_device *dev) | ||
799 | { | ||
800 | int r; | ||
801 | |||
802 | dev_dbg(&dev->pdev->dev, "%s\n", __func__); | ||
803 | |||
804 | cmi_lcd_hack_create_device(); | ||
805 | |||
806 | r = i2c_add_driver(&cmi_lcd_i2c_driver); | ||
807 | if (r < 0) | ||
808 | dev_err(&dev->pdev->dev, | ||
809 | "%s: i2c_add_driver() for %s failed (%d)\n", | ||
810 | __func__, cmi_lcd_i2c_driver.driver.name, r); | ||
811 | |||
812 | r = i2c_add_driver(&tc35876x_bridge_i2c_driver); | ||
813 | if (r < 0) | ||
814 | dev_err(&dev->pdev->dev, | ||
815 | "%s: i2c_add_driver() for %s failed (%d)\n", | ||
816 | __func__, tc35876x_bridge_i2c_driver.driver.name, r); | ||
817 | |||
818 | tc35876x_brightness_init(dev); | ||
819 | } | ||
820 | |||
821 | void tc35876x_exit(void) | ||
822 | { | ||
823 | pr_debug("%s\n", __func__); | ||
824 | |||
825 | i2c_del_driver(&tc35876x_bridge_i2c_driver); | ||
826 | |||
827 | if (cmi_lcd_i2c_client) | ||
828 | i2c_del_driver(&cmi_lcd_i2c_driver); | ||
829 | } | ||
diff --git a/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h new file mode 100644 index 000000000000..b14b7f9e7d1e --- /dev/null +++ b/drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * Copyright © 2011 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __MDFLD_DSI_LVDS_BRIDGE_H__ | ||
26 | #define __MDFLD_DSI_LVDS_BRIDGE_H__ | ||
27 | |||
28 | void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state); | ||
29 | void tc35876x_configure_lvds_bridge(struct drm_device *dev); | ||
30 | void tc35876x_brightness_control(struct drm_device *dev, int level); | ||
31 | void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev); | ||
32 | void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev); | ||
33 | void tc35876x_init(struct drm_device *dev); | ||
34 | void tc35876x_exit(void); | ||
35 | |||
36 | extern const struct panel_funcs mdfld_tc35876x_funcs; | ||
37 | |||
38 | #endif /*__MDFLD_DSI_LVDS_BRIDGE_H__*/ | ||