1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /**************************************************************************
3*4882a593Smuzhiyun * Copyright (c) 2011, Intel Corporation.
4*4882a593Smuzhiyun * All Rights Reserved.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun **************************************************************************/
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun #include <linux/gpio/machine.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <asm/intel_scu_ipc.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include "mdfld_dsi_output.h"
14*4882a593Smuzhiyun #include "mdfld_output.h"
15*4882a593Smuzhiyun #include "mid_bios.h"
16*4882a593Smuzhiyun #include "psb_drv.h"
17*4882a593Smuzhiyun #include "tc35876x-dsi-lvds.h"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF
22*4882a593Smuzhiyun #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */
23*4882a593Smuzhiyun #define BLC_PWM_FREQ_CALC_CONSTANT 32
24*4882a593Smuzhiyun #define MHz 1000000
25*4882a593Smuzhiyun #define BRIGHTNESS_MIN_LEVEL 1
26*4882a593Smuzhiyun #define BRIGHTNESS_MAX_LEVEL 100
27*4882a593Smuzhiyun #define BRIGHTNESS_MASK 0xFF
28*4882a593Smuzhiyun #define BLC_POLARITY_NORMAL 0
29*4882a593Smuzhiyun #define BLC_POLARITY_INVERSE 1
30*4882a593Smuzhiyun #define BLC_ADJUSTMENT_MAX 100
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define MDFLD_BLC_PWM_PRECISION_FACTOR 10
33*4882a593Smuzhiyun #define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE
34*4882a593Smuzhiyun #define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
37*4882a593Smuzhiyun #define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16)
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun static struct backlight_device *mdfld_backlight_device;
40*4882a593Smuzhiyun
mdfld_set_brightness(struct backlight_device * bd)41*4882a593Smuzhiyun int mdfld_set_brightness(struct backlight_device *bd)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun struct drm_device *dev =
44*4882a593Smuzhiyun (struct drm_device *)bl_get_data(mdfld_backlight_device);
45*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
46*4882a593Smuzhiyun int level = bd->props.brightness;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun DRM_DEBUG_DRIVER("backlight level set to %d\n", level);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* Perform value bounds checking */
51*4882a593Smuzhiyun if (level < BRIGHTNESS_MIN_LEVEL)
52*4882a593Smuzhiyun level = BRIGHTNESS_MIN_LEVEL;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun if (gma_power_begin(dev, false)) {
55*4882a593Smuzhiyun u32 adjusted_level = 0;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /*
58*4882a593Smuzhiyun * Adjust the backlight level with the percent in
59*4882a593Smuzhiyun * dev_priv->blc_adj2
60*4882a593Smuzhiyun */
61*4882a593Smuzhiyun adjusted_level = level * dev_priv->blc_adj2;
62*4882a593Smuzhiyun adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX;
63*4882a593Smuzhiyun dev_priv->brightness_adjusted = adjusted_level;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (mdfld_get_panel_type(dev, 0) == TC35876X) {
66*4882a593Smuzhiyun if (dev_priv->dpi_panel_on[0] ||
67*4882a593Smuzhiyun dev_priv->dpi_panel_on[2])
68*4882a593Smuzhiyun tc35876x_brightness_control(dev,
69*4882a593Smuzhiyun dev_priv->brightness_adjusted);
70*4882a593Smuzhiyun } else {
71*4882a593Smuzhiyun if (dev_priv->dpi_panel_on[0])
72*4882a593Smuzhiyun mdfld_dsi_brightness_control(dev, 0,
73*4882a593Smuzhiyun dev_priv->brightness_adjusted);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun if (dev_priv->dpi_panel_on[2])
77*4882a593Smuzhiyun mdfld_dsi_brightness_control(dev, 2,
78*4882a593Smuzhiyun dev_priv->brightness_adjusted);
79*4882a593Smuzhiyun gma_power_end(dev);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /* cache the brightness for later use */
83*4882a593Smuzhiyun dev_priv->brightness = level;
84*4882a593Smuzhiyun return 0;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
mdfld_get_brightness(struct backlight_device * bd)87*4882a593Smuzhiyun static int mdfld_get_brightness(struct backlight_device *bd)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun struct drm_device *dev =
90*4882a593Smuzhiyun (struct drm_device *)bl_get_data(mdfld_backlight_device);
91*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* return locally cached var instead of HW read (due to DPST etc.) */
96*4882a593Smuzhiyun return dev_priv->brightness;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun static const struct backlight_ops mdfld_ops = {
100*4882a593Smuzhiyun .get_brightness = mdfld_get_brightness,
101*4882a593Smuzhiyun .update_status = mdfld_set_brightness,
102*4882a593Smuzhiyun };
103*4882a593Smuzhiyun
device_backlight_init(struct drm_device * dev)104*4882a593Smuzhiyun static int device_backlight_init(struct drm_device *dev)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun struct drm_psb_private *dev_priv = (struct drm_psb_private *)
107*4882a593Smuzhiyun dev->dev_private;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;
110*4882a593Smuzhiyun dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun return 0;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
mdfld_backlight_init(struct drm_device * dev)115*4882a593Smuzhiyun static int mdfld_backlight_init(struct drm_device *dev)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun struct backlight_properties props;
118*4882a593Smuzhiyun int ret = 0;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun memset(&props, 0, sizeof(struct backlight_properties));
121*4882a593Smuzhiyun props.max_brightness = BRIGHTNESS_MAX_LEVEL;
122*4882a593Smuzhiyun props.type = BACKLIGHT_PLATFORM;
123*4882a593Smuzhiyun mdfld_backlight_device = backlight_device_register("mdfld-bl",
124*4882a593Smuzhiyun NULL, (void *)dev, &mdfld_ops, &props);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun if (IS_ERR(mdfld_backlight_device))
127*4882a593Smuzhiyun return PTR_ERR(mdfld_backlight_device);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun ret = device_backlight_init(dev);
130*4882a593Smuzhiyun if (ret)
131*4882a593Smuzhiyun return ret;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL;
134*4882a593Smuzhiyun mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL;
135*4882a593Smuzhiyun backlight_update_status(mdfld_backlight_device);
136*4882a593Smuzhiyun return 0;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun #endif
139*4882a593Smuzhiyun
mdfld_get_backlight_device(void)140*4882a593Smuzhiyun struct backlight_device *mdfld_get_backlight_device(void)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
143*4882a593Smuzhiyun return mdfld_backlight_device;
144*4882a593Smuzhiyun #else
145*4882a593Smuzhiyun return NULL;
146*4882a593Smuzhiyun #endif
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /*
150*4882a593Smuzhiyun * mdfld_save_display_registers
151*4882a593Smuzhiyun *
152*4882a593Smuzhiyun * Description: We are going to suspend so save current display
153*4882a593Smuzhiyun * register state.
154*4882a593Smuzhiyun *
155*4882a593Smuzhiyun * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
156*4882a593Smuzhiyun */
mdfld_save_display_registers(struct drm_device * dev,int pipenum)157*4882a593Smuzhiyun static int mdfld_save_display_registers(struct drm_device *dev, int pipenum)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
160*4882a593Smuzhiyun struct medfield_state *regs = &dev_priv->regs.mdfld;
161*4882a593Smuzhiyun struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
162*4882a593Smuzhiyun const struct psb_offset *map = &dev_priv->regmap[pipenum];
163*4882a593Smuzhiyun int i;
164*4882a593Smuzhiyun u32 *mipi_val;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /* register */
167*4882a593Smuzhiyun u32 mipi_reg = MIPI;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun switch (pipenum) {
170*4882a593Smuzhiyun case 0:
171*4882a593Smuzhiyun mipi_val = ®s->saveMIPI;
172*4882a593Smuzhiyun break;
173*4882a593Smuzhiyun case 1:
174*4882a593Smuzhiyun mipi_val = ®s->saveMIPI;
175*4882a593Smuzhiyun break;
176*4882a593Smuzhiyun case 2:
177*4882a593Smuzhiyun /* register */
178*4882a593Smuzhiyun mipi_reg = MIPI_C;
179*4882a593Smuzhiyun /* pointer to values */
180*4882a593Smuzhiyun mipi_val = ®s->saveMIPI_C;
181*4882a593Smuzhiyun break;
182*4882a593Smuzhiyun default:
183*4882a593Smuzhiyun DRM_ERROR("%s, invalid pipe number.\n", __func__);
184*4882a593Smuzhiyun return -EINVAL;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /* Pipe & plane A info */
188*4882a593Smuzhiyun pipe->dpll = PSB_RVDC32(map->dpll);
189*4882a593Smuzhiyun pipe->fp0 = PSB_RVDC32(map->fp0);
190*4882a593Smuzhiyun pipe->conf = PSB_RVDC32(map->conf);
191*4882a593Smuzhiyun pipe->htotal = PSB_RVDC32(map->htotal);
192*4882a593Smuzhiyun pipe->hblank = PSB_RVDC32(map->hblank);
193*4882a593Smuzhiyun pipe->hsync = PSB_RVDC32(map->hsync);
194*4882a593Smuzhiyun pipe->vtotal = PSB_RVDC32(map->vtotal);
195*4882a593Smuzhiyun pipe->vblank = PSB_RVDC32(map->vblank);
196*4882a593Smuzhiyun pipe->vsync = PSB_RVDC32(map->vsync);
197*4882a593Smuzhiyun pipe->src = PSB_RVDC32(map->src);
198*4882a593Smuzhiyun pipe->stride = PSB_RVDC32(map->stride);
199*4882a593Smuzhiyun pipe->linoff = PSB_RVDC32(map->linoff);
200*4882a593Smuzhiyun pipe->tileoff = PSB_RVDC32(map->tileoff);
201*4882a593Smuzhiyun pipe->size = PSB_RVDC32(map->size);
202*4882a593Smuzhiyun pipe->pos = PSB_RVDC32(map->pos);
203*4882a593Smuzhiyun pipe->surf = PSB_RVDC32(map->surf);
204*4882a593Smuzhiyun pipe->cntr = PSB_RVDC32(map->cntr);
205*4882a593Smuzhiyun pipe->status = PSB_RVDC32(map->status);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /*save palette (gamma) */
208*4882a593Smuzhiyun for (i = 0; i < 256; i++)
209*4882a593Smuzhiyun pipe->palette[i] = PSB_RVDC32(map->palette + (i << 2));
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (pipenum == 1) {
212*4882a593Smuzhiyun regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
213*4882a593Smuzhiyun regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
216*4882a593Smuzhiyun regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
217*4882a593Smuzhiyun return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun *mipi_val = PSB_RVDC32(mipi_reg);
221*4882a593Smuzhiyun return 0;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /*
225*4882a593Smuzhiyun * mdfld_restore_display_registers
226*4882a593Smuzhiyun *
227*4882a593Smuzhiyun * Description: We are going to resume so restore display register state.
228*4882a593Smuzhiyun *
229*4882a593Smuzhiyun * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
230*4882a593Smuzhiyun */
mdfld_restore_display_registers(struct drm_device * dev,int pipenum)231*4882a593Smuzhiyun static int mdfld_restore_display_registers(struct drm_device *dev, int pipenum)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun /* To get panel out of ULPS mode. */
234*4882a593Smuzhiyun u32 temp = 0;
235*4882a593Smuzhiyun u32 device_ready_reg = DEVICE_READY_REG;
236*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
237*4882a593Smuzhiyun struct mdfld_dsi_config *dsi_config = NULL;
238*4882a593Smuzhiyun struct medfield_state *regs = &dev_priv->regs.mdfld;
239*4882a593Smuzhiyun struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
240*4882a593Smuzhiyun const struct psb_offset *map = &dev_priv->regmap[pipenum];
241*4882a593Smuzhiyun u32 i;
242*4882a593Smuzhiyun u32 dpll;
243*4882a593Smuzhiyun u32 timeout = 0;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun /* register */
246*4882a593Smuzhiyun u32 mipi_reg = MIPI;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun /* values */
249*4882a593Smuzhiyun u32 dpll_val = pipe->dpll;
250*4882a593Smuzhiyun u32 mipi_val = regs->saveMIPI;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun switch (pipenum) {
253*4882a593Smuzhiyun case 0:
254*4882a593Smuzhiyun dpll_val &= ~DPLL_VCO_ENABLE;
255*4882a593Smuzhiyun dsi_config = dev_priv->dsi_configs[0];
256*4882a593Smuzhiyun break;
257*4882a593Smuzhiyun case 1:
258*4882a593Smuzhiyun dpll_val &= ~DPLL_VCO_ENABLE;
259*4882a593Smuzhiyun break;
260*4882a593Smuzhiyun case 2:
261*4882a593Smuzhiyun mipi_reg = MIPI_C;
262*4882a593Smuzhiyun mipi_val = regs->saveMIPI_C;
263*4882a593Smuzhiyun dsi_config = dev_priv->dsi_configs[1];
264*4882a593Smuzhiyun break;
265*4882a593Smuzhiyun default:
266*4882a593Smuzhiyun DRM_ERROR("%s, invalid pipe number.\n", __func__);
267*4882a593Smuzhiyun return -EINVAL;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /*make sure VGA plane is off. it initializes to on after reset!*/
271*4882a593Smuzhiyun PSB_WVDC32(0x80000000, VGACNTRL);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun if (pipenum == 1) {
274*4882a593Smuzhiyun PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, map->dpll);
275*4882a593Smuzhiyun PSB_RVDC32(map->dpll);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun PSB_WVDC32(pipe->fp0, map->fp0);
278*4882a593Smuzhiyun } else {
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun dpll = PSB_RVDC32(map->dpll);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if (!(dpll & DPLL_VCO_ENABLE)) {
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* When ungating power of DPLL, needs to wait 0.5us
285*4882a593Smuzhiyun before enable the VCO */
286*4882a593Smuzhiyun if (dpll & MDFLD_PWR_GATE_EN) {
287*4882a593Smuzhiyun dpll &= ~MDFLD_PWR_GATE_EN;
288*4882a593Smuzhiyun PSB_WVDC32(dpll, map->dpll);
289*4882a593Smuzhiyun /* FIXME_MDFLD PO - change 500 to 1 after PO */
290*4882a593Smuzhiyun udelay(500);
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun PSB_WVDC32(pipe->fp0, map->fp0);
294*4882a593Smuzhiyun PSB_WVDC32(dpll_val, map->dpll);
295*4882a593Smuzhiyun /* FIXME_MDFLD PO - change 500 to 1 after PO */
296*4882a593Smuzhiyun udelay(500);
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun dpll_val |= DPLL_VCO_ENABLE;
299*4882a593Smuzhiyun PSB_WVDC32(dpll_val, map->dpll);
300*4882a593Smuzhiyun PSB_RVDC32(map->dpll);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* wait for DSI PLL to lock */
303*4882a593Smuzhiyun while (timeout < 20000 &&
304*4882a593Smuzhiyun !(PSB_RVDC32(map->conf) & PIPECONF_DSIPLL_LOCK)) {
305*4882a593Smuzhiyun udelay(150);
306*4882a593Smuzhiyun timeout++;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun if (timeout == 20000) {
310*4882a593Smuzhiyun DRM_ERROR("%s, can't lock DSIPLL.\n",
311*4882a593Smuzhiyun __func__);
312*4882a593Smuzhiyun return -EINVAL;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun /* Restore mode */
317*4882a593Smuzhiyun PSB_WVDC32(pipe->htotal, map->htotal);
318*4882a593Smuzhiyun PSB_WVDC32(pipe->hblank, map->hblank);
319*4882a593Smuzhiyun PSB_WVDC32(pipe->hsync, map->hsync);
320*4882a593Smuzhiyun PSB_WVDC32(pipe->vtotal, map->vtotal);
321*4882a593Smuzhiyun PSB_WVDC32(pipe->vblank, map->vblank);
322*4882a593Smuzhiyun PSB_WVDC32(pipe->vsync, map->vsync);
323*4882a593Smuzhiyun PSB_WVDC32(pipe->src, map->src);
324*4882a593Smuzhiyun PSB_WVDC32(pipe->status, map->status);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /*set up the plane*/
327*4882a593Smuzhiyun PSB_WVDC32(pipe->stride, map->stride);
328*4882a593Smuzhiyun PSB_WVDC32(pipe->linoff, map->linoff);
329*4882a593Smuzhiyun PSB_WVDC32(pipe->tileoff, map->tileoff);
330*4882a593Smuzhiyun PSB_WVDC32(pipe->size, map->size);
331*4882a593Smuzhiyun PSB_WVDC32(pipe->pos, map->pos);
332*4882a593Smuzhiyun PSB_WVDC32(pipe->surf, map->surf);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun if (pipenum == 1) {
335*4882a593Smuzhiyun /* restore palette (gamma) */
336*4882a593Smuzhiyun /* udelay(50000); */
337*4882a593Smuzhiyun for (i = 0; i < 256; i++)
338*4882a593Smuzhiyun PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
341*4882a593Smuzhiyun PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun /*TODO: resume HDMI port */
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun /*TODO: resume pipe*/
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /*enable the plane*/
348*4882a593Smuzhiyun PSB_WVDC32(pipe->cntr & ~DISPLAY_PLANE_ENABLE, map->cntr);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun return 0;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /*set up pipe related registers*/
354*4882a593Smuzhiyun PSB_WVDC32(mipi_val, mipi_reg);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /*setup MIPI adapter + MIPI IP registers*/
357*4882a593Smuzhiyun if (dsi_config)
358*4882a593Smuzhiyun mdfld_dsi_controller_init(dsi_config, pipenum);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun if (in_atomic() || in_interrupt())
361*4882a593Smuzhiyun mdelay(20);
362*4882a593Smuzhiyun else
363*4882a593Smuzhiyun msleep(20);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun /*enable the plane*/
366*4882a593Smuzhiyun PSB_WVDC32(pipe->cntr, map->cntr);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (in_atomic() || in_interrupt())
369*4882a593Smuzhiyun mdelay(20);
370*4882a593Smuzhiyun else
371*4882a593Smuzhiyun msleep(20);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun /* LP Hold Release */
374*4882a593Smuzhiyun temp = REG_READ(mipi_reg);
375*4882a593Smuzhiyun temp |= LP_OUTPUT_HOLD_RELEASE;
376*4882a593Smuzhiyun REG_WRITE(mipi_reg, temp);
377*4882a593Smuzhiyun mdelay(1);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* Set DSI host to exit from Utra Low Power State */
381*4882a593Smuzhiyun temp = REG_READ(device_ready_reg);
382*4882a593Smuzhiyun temp &= ~ULPS_MASK;
383*4882a593Smuzhiyun temp |= 0x3;
384*4882a593Smuzhiyun temp |= EXIT_ULPS_DEV_READY;
385*4882a593Smuzhiyun REG_WRITE(device_ready_reg, temp);
386*4882a593Smuzhiyun mdelay(1);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun temp = REG_READ(device_ready_reg);
389*4882a593Smuzhiyun temp &= ~ULPS_MASK;
390*4882a593Smuzhiyun temp |= EXITING_ULPS;
391*4882a593Smuzhiyun REG_WRITE(device_ready_reg, temp);
392*4882a593Smuzhiyun mdelay(1);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun /*enable the pipe*/
395*4882a593Smuzhiyun PSB_WVDC32(pipe->conf, map->conf);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun /* restore palette (gamma) */
398*4882a593Smuzhiyun /* udelay(50000); */
399*4882a593Smuzhiyun for (i = 0; i < 256; i++)
400*4882a593Smuzhiyun PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun return 0;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
mdfld_save_registers(struct drm_device * dev)405*4882a593Smuzhiyun static int mdfld_save_registers(struct drm_device *dev)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun /* mdfld_save_cursor_overlay_registers(dev); */
408*4882a593Smuzhiyun mdfld_save_display_registers(dev, 0);
409*4882a593Smuzhiyun mdfld_save_display_registers(dev, 2);
410*4882a593Smuzhiyun mdfld_disable_crtc(dev, 0);
411*4882a593Smuzhiyun mdfld_disable_crtc(dev, 2);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun return 0;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
mdfld_restore_registers(struct drm_device * dev)416*4882a593Smuzhiyun static int mdfld_restore_registers(struct drm_device *dev)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun mdfld_restore_display_registers(dev, 2);
419*4882a593Smuzhiyun mdfld_restore_display_registers(dev, 0);
420*4882a593Smuzhiyun /* mdfld_restore_cursor_overlay_registers(dev); */
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun return 0;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
mdfld_power_down(struct drm_device * dev)425*4882a593Smuzhiyun static int mdfld_power_down(struct drm_device *dev)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun /* FIXME */
428*4882a593Smuzhiyun return 0;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
mdfld_power_up(struct drm_device * dev)431*4882a593Smuzhiyun static int mdfld_power_up(struct drm_device *dev)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun /* FIXME */
434*4882a593Smuzhiyun return 0;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* Medfield */
438*4882a593Smuzhiyun static const struct psb_offset mdfld_regmap[3] = {
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun .fp0 = MRST_FPA0,
441*4882a593Smuzhiyun .fp1 = MRST_FPA1,
442*4882a593Smuzhiyun .cntr = DSPACNTR,
443*4882a593Smuzhiyun .conf = PIPEACONF,
444*4882a593Smuzhiyun .src = PIPEASRC,
445*4882a593Smuzhiyun .dpll = MRST_DPLL_A,
446*4882a593Smuzhiyun .htotal = HTOTAL_A,
447*4882a593Smuzhiyun .hblank = HBLANK_A,
448*4882a593Smuzhiyun .hsync = HSYNC_A,
449*4882a593Smuzhiyun .vtotal = VTOTAL_A,
450*4882a593Smuzhiyun .vblank = VBLANK_A,
451*4882a593Smuzhiyun .vsync = VSYNC_A,
452*4882a593Smuzhiyun .stride = DSPASTRIDE,
453*4882a593Smuzhiyun .size = DSPASIZE,
454*4882a593Smuzhiyun .pos = DSPAPOS,
455*4882a593Smuzhiyun .surf = DSPASURF,
456*4882a593Smuzhiyun .addr = MRST_DSPABASE,
457*4882a593Smuzhiyun .status = PIPEASTAT,
458*4882a593Smuzhiyun .linoff = DSPALINOFF,
459*4882a593Smuzhiyun .tileoff = DSPATILEOFF,
460*4882a593Smuzhiyun .palette = PALETTE_A,
461*4882a593Smuzhiyun },
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun .fp0 = MDFLD_DPLL_DIV0,
464*4882a593Smuzhiyun .cntr = DSPBCNTR,
465*4882a593Smuzhiyun .conf = PIPEBCONF,
466*4882a593Smuzhiyun .src = PIPEBSRC,
467*4882a593Smuzhiyun .dpll = MDFLD_DPLL_B,
468*4882a593Smuzhiyun .htotal = HTOTAL_B,
469*4882a593Smuzhiyun .hblank = HBLANK_B,
470*4882a593Smuzhiyun .hsync = HSYNC_B,
471*4882a593Smuzhiyun .vtotal = VTOTAL_B,
472*4882a593Smuzhiyun .vblank = VBLANK_B,
473*4882a593Smuzhiyun .vsync = VSYNC_B,
474*4882a593Smuzhiyun .stride = DSPBSTRIDE,
475*4882a593Smuzhiyun .size = DSPBSIZE,
476*4882a593Smuzhiyun .pos = DSPBPOS,
477*4882a593Smuzhiyun .surf = DSPBSURF,
478*4882a593Smuzhiyun .addr = MRST_DSPBBASE,
479*4882a593Smuzhiyun .status = PIPEBSTAT,
480*4882a593Smuzhiyun .linoff = DSPBLINOFF,
481*4882a593Smuzhiyun .tileoff = DSPBTILEOFF,
482*4882a593Smuzhiyun .palette = PALETTE_B,
483*4882a593Smuzhiyun },
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun .fp0 = MRST_FPA0, /* This is what the old code did ?? */
486*4882a593Smuzhiyun .cntr = DSPCCNTR,
487*4882a593Smuzhiyun .conf = PIPECCONF,
488*4882a593Smuzhiyun .src = PIPECSRC,
489*4882a593Smuzhiyun /* No DPLL_C */
490*4882a593Smuzhiyun .dpll = MRST_DPLL_A,
491*4882a593Smuzhiyun .htotal = HTOTAL_C,
492*4882a593Smuzhiyun .hblank = HBLANK_C,
493*4882a593Smuzhiyun .hsync = HSYNC_C,
494*4882a593Smuzhiyun .vtotal = VTOTAL_C,
495*4882a593Smuzhiyun .vblank = VBLANK_C,
496*4882a593Smuzhiyun .vsync = VSYNC_C,
497*4882a593Smuzhiyun .stride = DSPCSTRIDE,
498*4882a593Smuzhiyun .size = DSPBSIZE,
499*4882a593Smuzhiyun .pos = DSPCPOS,
500*4882a593Smuzhiyun .surf = DSPCSURF,
501*4882a593Smuzhiyun .addr = MDFLD_DSPCBASE,
502*4882a593Smuzhiyun .status = PIPECSTAT,
503*4882a593Smuzhiyun .linoff = DSPCLINOFF,
504*4882a593Smuzhiyun .tileoff = DSPCTILEOFF,
505*4882a593Smuzhiyun .palette = PALETTE_C,
506*4882a593Smuzhiyun },
507*4882a593Smuzhiyun };
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun /*
510*4882a593Smuzhiyun * The GPIO lines for resetting DSI pipe 0 and 2 are available in the
511*4882a593Smuzhiyun * PCI device 0000:00:0c.0 on the Medfield.
512*4882a593Smuzhiyun */
513*4882a593Smuzhiyun static struct gpiod_lookup_table mdfld_dsi_pipe_gpio_table = {
514*4882a593Smuzhiyun .table = {
515*4882a593Smuzhiyun GPIO_LOOKUP("0000:00:0c.0", 128, "dsi-pipe0-reset",
516*4882a593Smuzhiyun GPIO_ACTIVE_HIGH),
517*4882a593Smuzhiyun GPIO_LOOKUP("0000:00:0c.0", 34, "dsi-pipe2-reset",
518*4882a593Smuzhiyun GPIO_ACTIVE_HIGH),
519*4882a593Smuzhiyun { },
520*4882a593Smuzhiyun },
521*4882a593Smuzhiyun };
522*4882a593Smuzhiyun
mdfld_chip_setup(struct drm_device * dev)523*4882a593Smuzhiyun static int mdfld_chip_setup(struct drm_device *dev)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun struct drm_psb_private *dev_priv = dev->dev_private;
526*4882a593Smuzhiyun if (pci_enable_msi(dev->pdev))
527*4882a593Smuzhiyun dev_warn(dev->dev, "Enabling MSI failed!\n");
528*4882a593Smuzhiyun dev_priv->regmap = mdfld_regmap;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* Associate the GPIO lines with the DRM device */
531*4882a593Smuzhiyun mdfld_dsi_pipe_gpio_table.dev_id = dev_name(dev->dev);
532*4882a593Smuzhiyun gpiod_add_lookup_table(&mdfld_dsi_pipe_gpio_table);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun return mid_chip_setup(dev);
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun const struct psb_ops mdfld_chip_ops = {
538*4882a593Smuzhiyun .name = "mdfld",
539*4882a593Smuzhiyun .accel_2d = 0,
540*4882a593Smuzhiyun .pipes = 3,
541*4882a593Smuzhiyun .crtcs = 3,
542*4882a593Smuzhiyun .lvds_mask = (1 << 1),
543*4882a593Smuzhiyun .hdmi_mask = (1 << 1),
544*4882a593Smuzhiyun .cursor_needs_phys = 0,
545*4882a593Smuzhiyun .sgx_offset = MRST_SGX_OFFSET,
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun .chip_setup = mdfld_chip_setup,
548*4882a593Smuzhiyun .crtc_helper = &mdfld_helper_funcs,
549*4882a593Smuzhiyun .crtc_funcs = &psb_intel_crtc_funcs,
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun .output_init = mdfld_output_init,
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
554*4882a593Smuzhiyun .backlight_init = mdfld_backlight_init,
555*4882a593Smuzhiyun #endif
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun .save_regs = mdfld_save_registers,
558*4882a593Smuzhiyun .restore_regs = mdfld_restore_registers,
559*4882a593Smuzhiyun .save_crtc = gma_crtc_save,
560*4882a593Smuzhiyun .restore_crtc = gma_crtc_restore,
561*4882a593Smuzhiyun .power_down = mdfld_power_down,
562*4882a593Smuzhiyun .power_up = mdfld_power_up,
563*4882a593Smuzhiyun };
564