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