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