189c78134cc54dff016c83367912eb055637fa50cAlan Cox/*
289c78134cc54dff016c83367912eb055637fa50cAlan Cox * Copyright © 2006-2011 Intel Corporation
389c78134cc54dff016c83367912eb055637fa50cAlan Cox *
489c78134cc54dff016c83367912eb055637fa50cAlan Cox * This program is free software; you can redistribute it and/or modify it
589c78134cc54dff016c83367912eb055637fa50cAlan Cox * under the terms and conditions of the GNU General Public License,
689c78134cc54dff016c83367912eb055637fa50cAlan Cox * version 2, as published by the Free Software Foundation.
789c78134cc54dff016c83367912eb055637fa50cAlan Cox *
889c78134cc54dff016c83367912eb055637fa50cAlan Cox * This program is distributed in the hope it will be useful, but WITHOUT
989c78134cc54dff016c83367912eb055637fa50cAlan Cox * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1089c78134cc54dff016c83367912eb055637fa50cAlan Cox * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1189c78134cc54dff016c83367912eb055637fa50cAlan Cox * more details.
1289c78134cc54dff016c83367912eb055637fa50cAlan Cox *
1389c78134cc54dff016c83367912eb055637fa50cAlan Cox * You should have received a copy of the GNU General Public License along with
1489c78134cc54dff016c83367912eb055637fa50cAlan Cox * this program; if not, write to the Free Software Foundation, Inc.,
1589c78134cc54dff016c83367912eb055637fa50cAlan Cox * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
1689c78134cc54dff016c83367912eb055637fa50cAlan Cox *
1789c78134cc54dff016c83367912eb055637fa50cAlan Cox * Authors:
1889c78134cc54dff016c83367912eb055637fa50cAlan Cox *	Eric Anholt <eric@anholt.net>
1989c78134cc54dff016c83367912eb055637fa50cAlan Cox */
2089c78134cc54dff016c83367912eb055637fa50cAlan Cox
2189c78134cc54dff016c83367912eb055637fa50cAlan Cox#include <linux/i2c.h>
2289c78134cc54dff016c83367912eb055637fa50cAlan Cox#include <linux/pm_runtime.h>
2389c78134cc54dff016c83367912eb055637fa50cAlan Cox
2489c78134cc54dff016c83367912eb055637fa50cAlan Cox#include <drm/drmP.h>
2589c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "framebuffer.h"
2689c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "psb_drv.h"
2789c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "psb_intel_drv.h"
2889c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "psb_intel_reg.h"
2989c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "psb_intel_display.h"
3089c78134cc54dff016c83367912eb055637fa50cAlan Cox#include "power.h"
3189c78134cc54dff016c83367912eb055637fa50cAlan Cox
3289c78134cc54dff016c83367912eb055637fa50cAlan Coxstruct psb_intel_clock_t {
3389c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* given values */
3489c78134cc54dff016c83367912eb055637fa50cAlan Cox	int n;
3589c78134cc54dff016c83367912eb055637fa50cAlan Cox	int m1, m2;
3689c78134cc54dff016c83367912eb055637fa50cAlan Cox	int p1, p2;
3789c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* derived values */
3889c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dot;
3989c78134cc54dff016c83367912eb055637fa50cAlan Cox	int vco;
4089c78134cc54dff016c83367912eb055637fa50cAlan Cox	int m;
4189c78134cc54dff016c83367912eb055637fa50cAlan Cox	int p;
4289c78134cc54dff016c83367912eb055637fa50cAlan Cox};
4389c78134cc54dff016c83367912eb055637fa50cAlan Cox
4489c78134cc54dff016c83367912eb055637fa50cAlan Coxstruct psb_intel_range_t {
4589c78134cc54dff016c83367912eb055637fa50cAlan Cox	int min, max;
4689c78134cc54dff016c83367912eb055637fa50cAlan Cox};
4789c78134cc54dff016c83367912eb055637fa50cAlan Cox
4889c78134cc54dff016c83367912eb055637fa50cAlan Coxstruct psb_intel_p2_t {
4989c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dot_limit;
5089c78134cc54dff016c83367912eb055637fa50cAlan Cox	int p2_slow, p2_fast;
5189c78134cc54dff016c83367912eb055637fa50cAlan Cox};
5289c78134cc54dff016c83367912eb055637fa50cAlan Cox
5389c78134cc54dff016c83367912eb055637fa50cAlan Cox#define INTEL_P2_NUM		      2
5489c78134cc54dff016c83367912eb055637fa50cAlan Cox
5589c78134cc54dff016c83367912eb055637fa50cAlan Coxstruct psb_intel_limit_t {
5689c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_range_t dot, vco, n, m, m1, m2, p, p1;
5789c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_p2_t p2;
5889c78134cc54dff016c83367912eb055637fa50cAlan Cox};
5989c78134cc54dff016c83367912eb055637fa50cAlan Cox
6089c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_DOT_MIN		  25000
6189c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_DOT_MAX		 350000
6289c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_VCO_MIN		 930000
6389c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_VCO_MAX		1400000
6489c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_N_MIN		      3
6589c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_N_MAX		     16
6689c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_M_MIN		     96
6789c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_M_MAX		    140
6889c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_M1_MIN		     18
6989c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_M1_MAX		     26
7089c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_M2_MIN		      6
7189c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_M2_MAX		     16
7289c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P_MIN		      4
7389c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P_MAX		    128
7489c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P1_MIN		      2
7589c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P1_MAX		     33
7689c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P1_LVDS_MIN	      1
7789c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P1_LVDS_MAX	      6
7889c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P2_SLOW		      4
7989c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P2_FAST		      2
8089c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P2_LVDS_SLOW	      14
8189c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P2_LVDS_FAST	      14	/* No fast option */
8289c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I8XX_P2_SLOW_LIMIT	 165000
8389c78134cc54dff016c83367912eb055637fa50cAlan Cox
8489c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_DOT_MIN		  20000
8589c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_DOT_MAX		 400000
8689c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_VCO_MIN		1400000
8789c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_VCO_MAX		2800000
8889c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_N_MIN		      3
8989c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_N_MAX		      8
9089c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_M_MIN		     70
9189c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_M_MAX		    120
9289c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_M1_MIN		     10
9389c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_M1_MAX		     20
9489c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_M2_MIN		      5
9589c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_M2_MAX		      9
9689c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P_SDVO_DAC_MIN	      5
9789c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P_SDVO_DAC_MAX	     80
9889c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P_LVDS_MIN		      7
9989c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P_LVDS_MAX		     98
10089c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P1_MIN		      1
10189c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P1_MAX		      8
10289c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P2_SDVO_DAC_SLOW		     10
10389c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P2_SDVO_DAC_FAST		      5
10489c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P2_SDVO_DAC_SLOW_LIMIT	 200000
10589c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P2_LVDS_SLOW		     14
10689c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P2_LVDS_FAST		      7
10789c78134cc54dff016c83367912eb055637fa50cAlan Cox#define I9XX_P2_LVDS_SLOW_LIMIT		 112000
10889c78134cc54dff016c83367912eb055637fa50cAlan Cox
10989c78134cc54dff016c83367912eb055637fa50cAlan Cox#define INTEL_LIMIT_I8XX_DVO_DAC    0
11089c78134cc54dff016c83367912eb055637fa50cAlan Cox#define INTEL_LIMIT_I8XX_LVDS	    1
11189c78134cc54dff016c83367912eb055637fa50cAlan Cox#define INTEL_LIMIT_I9XX_SDVO_DAC   2
11289c78134cc54dff016c83367912eb055637fa50cAlan Cox#define INTEL_LIMIT_I9XX_LVDS	    3
11389c78134cc54dff016c83367912eb055637fa50cAlan Cox
11489c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic const struct psb_intel_limit_t psb_intel_limits[] = {
11589c78134cc54dff016c83367912eb055637fa50cAlan Cox	{			/* INTEL_LIMIT_I8XX_DVO_DAC */
11689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .dot = {.min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX},
11789c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .vco = {.min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX},
11889c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .n = {.min = I8XX_N_MIN, .max = I8XX_N_MAX},
11989c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m = {.min = I8XX_M_MIN, .max = I8XX_M_MAX},
12089c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m1 = {.min = I8XX_M1_MIN, .max = I8XX_M1_MAX},
12189c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m2 = {.min = I8XX_M2_MIN, .max = I8XX_M2_MAX},
12289c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p = {.min = I8XX_P_MIN, .max = I8XX_P_MAX},
12389c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p1 = {.min = I8XX_P1_MIN, .max = I8XX_P1_MAX},
12489c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p2 = {.dot_limit = I8XX_P2_SLOW_LIMIT,
12589c78134cc54dff016c83367912eb055637fa50cAlan Cox		.p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST},
12689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 },
12789c78134cc54dff016c83367912eb055637fa50cAlan Cox	{			/* INTEL_LIMIT_I8XX_LVDS */
12889c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .dot = {.min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX},
12989c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .vco = {.min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX},
13089c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .n = {.min = I8XX_N_MIN, .max = I8XX_N_MAX},
13189c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m = {.min = I8XX_M_MIN, .max = I8XX_M_MAX},
13289c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m1 = {.min = I8XX_M1_MIN, .max = I8XX_M1_MAX},
13389c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m2 = {.min = I8XX_M2_MIN, .max = I8XX_M2_MAX},
13489c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p = {.min = I8XX_P_MIN, .max = I8XX_P_MAX},
13589c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p1 = {.min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX},
13689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p2 = {.dot_limit = I8XX_P2_SLOW_LIMIT,
13789c78134cc54dff016c83367912eb055637fa50cAlan Cox		.p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST},
13889c78134cc54dff016c83367912eb055637fa50cAlan Cox	 },
13989c78134cc54dff016c83367912eb055637fa50cAlan Cox	{			/* INTEL_LIMIT_I9XX_SDVO_DAC */
14089c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
14189c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX},
14289c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX},
14389c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX},
14489c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX},
14589c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX},
14689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p = {.min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX},
14789c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX},
14889c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p2 = {.dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
14989c78134cc54dff016c83367912eb055637fa50cAlan Cox		.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast =
15089c78134cc54dff016c83367912eb055637fa50cAlan Cox		I9XX_P2_SDVO_DAC_FAST},
15189c78134cc54dff016c83367912eb055637fa50cAlan Cox	 },
15289c78134cc54dff016c83367912eb055637fa50cAlan Cox	{			/* INTEL_LIMIT_I9XX_LVDS */
15389c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
15489c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX},
15589c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX},
15689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX},
15789c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX},
15889c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX},
15989c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p = {.min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX},
16089c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX},
16189c78134cc54dff016c83367912eb055637fa50cAlan Cox	 /* The single-channel range is 25-112Mhz, and dual-channel
16289c78134cc54dff016c83367912eb055637fa50cAlan Cox	  * is 80-224Mhz.  Prefer single channel as much as possible.
16389c78134cc54dff016c83367912eb055637fa50cAlan Cox	  */
16489c78134cc54dff016c83367912eb055637fa50cAlan Cox	 .p2 = {.dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
16589c78134cc54dff016c83367912eb055637fa50cAlan Cox		.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST},
16689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 },
16789c78134cc54dff016c83367912eb055637fa50cAlan Cox};
16889c78134cc54dff016c83367912eb055637fa50cAlan Cox
16989c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic const struct psb_intel_limit_t *psb_intel_limit(struct drm_crtc *crtc)
17089c78134cc54dff016c83367912eb055637fa50cAlan Cox{
17189c78134cc54dff016c83367912eb055637fa50cAlan Cox	const struct psb_intel_limit_t *limit;
17289c78134cc54dff016c83367912eb055637fa50cAlan Cox
17389c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
17489c78134cc54dff016c83367912eb055637fa50cAlan Cox		limit = &psb_intel_limits[INTEL_LIMIT_I9XX_LVDS];
17589c78134cc54dff016c83367912eb055637fa50cAlan Cox	else
17689c78134cc54dff016c83367912eb055637fa50cAlan Cox		limit = &psb_intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
17789c78134cc54dff016c83367912eb055637fa50cAlan Cox	return limit;
17889c78134cc54dff016c83367912eb055637fa50cAlan Cox}
17989c78134cc54dff016c83367912eb055637fa50cAlan Cox
18089c78134cc54dff016c83367912eb055637fa50cAlan Cox/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
18189c78134cc54dff016c83367912eb055637fa50cAlan Cox
18289c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void i8xx_clock(int refclk, struct psb_intel_clock_t *clock)
18389c78134cc54dff016c83367912eb055637fa50cAlan Cox{
18489c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
18589c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock->p = clock->p1 * clock->p2;
18689c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock->vco = refclk * clock->m / (clock->n + 2);
18789c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock->dot = clock->vco / clock->p;
18889c78134cc54dff016c83367912eb055637fa50cAlan Cox}
18989c78134cc54dff016c83367912eb055637fa50cAlan Cox
19089c78134cc54dff016c83367912eb055637fa50cAlan Cox/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */
19189c78134cc54dff016c83367912eb055637fa50cAlan Cox
19289c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void i9xx_clock(int refclk, struct psb_intel_clock_t *clock)
19389c78134cc54dff016c83367912eb055637fa50cAlan Cox{
19489c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
19589c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock->p = clock->p1 * clock->p2;
19689c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock->vco = refclk * clock->m / (clock->n + 2);
19789c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock->dot = clock->vco / clock->p;
19889c78134cc54dff016c83367912eb055637fa50cAlan Cox}
19989c78134cc54dff016c83367912eb055637fa50cAlan Cox
20089c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_clock(struct drm_device *dev, int refclk,
20189c78134cc54dff016c83367912eb055637fa50cAlan Cox			struct psb_intel_clock_t *clock)
20289c78134cc54dff016c83367912eb055637fa50cAlan Cox{
20389c78134cc54dff016c83367912eb055637fa50cAlan Cox	return i9xx_clock(refclk, clock);
20489c78134cc54dff016c83367912eb055637fa50cAlan Cox}
20589c78134cc54dff016c83367912eb055637fa50cAlan Cox
20689c78134cc54dff016c83367912eb055637fa50cAlan Cox/**
20789c78134cc54dff016c83367912eb055637fa50cAlan Cox * Returns whether any output on the specified pipe is of the specified type
20889c78134cc54dff016c83367912eb055637fa50cAlan Cox */
20989c78134cc54dff016c83367912eb055637fa50cAlan Coxbool psb_intel_pipe_has_type(struct drm_crtc *crtc, int type)
21089c78134cc54dff016c83367912eb055637fa50cAlan Cox{
21189c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
21289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_mode_config *mode_config = &dev->mode_config;
21389c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_connector *l_entry;
21489c78134cc54dff016c83367912eb055637fa50cAlan Cox
21589c78134cc54dff016c83367912eb055637fa50cAlan Cox	list_for_each_entry(l_entry, &mode_config->connector_list, head) {
21689c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (l_entry->encoder && l_entry->encoder->crtc == crtc) {
2171730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson			struct psb_intel_encoder *psb_intel_encoder =
2181730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson					psb_intel_attached_encoder(l_entry);
2191730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson			if (psb_intel_encoder->type == type)
22089c78134cc54dff016c83367912eb055637fa50cAlan Cox				return true;
22189c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
22289c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
22389c78134cc54dff016c83367912eb055637fa50cAlan Cox	return false;
22489c78134cc54dff016c83367912eb055637fa50cAlan Cox}
22589c78134cc54dff016c83367912eb055637fa50cAlan Cox
22689c78134cc54dff016c83367912eb055637fa50cAlan Cox#define INTELPllInvalid(s)   { /* ErrorF (s) */; return false; }
22789c78134cc54dff016c83367912eb055637fa50cAlan Cox/**
22889c78134cc54dff016c83367912eb055637fa50cAlan Cox * Returns whether the given set of divisors are valid for a given refclk with
22989c78134cc54dff016c83367912eb055637fa50cAlan Cox * the given connectors.
23089c78134cc54dff016c83367912eb055637fa50cAlan Cox */
23189c78134cc54dff016c83367912eb055637fa50cAlan Cox
23289c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic bool psb_intel_PLL_is_valid(struct drm_crtc *crtc,
23389c78134cc54dff016c83367912eb055637fa50cAlan Cox			       struct psb_intel_clock_t *clock)
23489c78134cc54dff016c83367912eb055637fa50cAlan Cox{
23589c78134cc54dff016c83367912eb055637fa50cAlan Cox	const struct psb_intel_limit_t *limit = psb_intel_limit(crtc);
23689c78134cc54dff016c83367912eb055637fa50cAlan Cox
23789c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
23889c78134cc54dff016c83367912eb055637fa50cAlan Cox		INTELPllInvalid("p1 out of range\n");
23989c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (clock->p < limit->p.min || limit->p.max < clock->p)
24089c78134cc54dff016c83367912eb055637fa50cAlan Cox		INTELPllInvalid("p out of range\n");
24189c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2)
24289c78134cc54dff016c83367912eb055637fa50cAlan Cox		INTELPllInvalid("m2 out of range\n");
24389c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
24489c78134cc54dff016c83367912eb055637fa50cAlan Cox		INTELPllInvalid("m1 out of range\n");
24589c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (clock->m1 <= clock->m2)
24689c78134cc54dff016c83367912eb055637fa50cAlan Cox		INTELPllInvalid("m1 <= m2\n");
24789c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (clock->m < limit->m.min || limit->m.max < clock->m)
24889c78134cc54dff016c83367912eb055637fa50cAlan Cox		INTELPllInvalid("m out of range\n");
24989c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (clock->n < limit->n.min || limit->n.max < clock->n)
25089c78134cc54dff016c83367912eb055637fa50cAlan Cox		INTELPllInvalid("n out of range\n");
25189c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
25289c78134cc54dff016c83367912eb055637fa50cAlan Cox		INTELPllInvalid("vco out of range\n");
25389c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* XXX: We may need to be checking "Dot clock"
25489c78134cc54dff016c83367912eb055637fa50cAlan Cox	 * depending on the multiplier, connector, etc.,
25589c78134cc54dff016c83367912eb055637fa50cAlan Cox	 * rather than just a single range.
25689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 */
25789c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
25889c78134cc54dff016c83367912eb055637fa50cAlan Cox		INTELPllInvalid("dot out of range\n");
25989c78134cc54dff016c83367912eb055637fa50cAlan Cox
26089c78134cc54dff016c83367912eb055637fa50cAlan Cox	return true;
26189c78134cc54dff016c83367912eb055637fa50cAlan Cox}
26289c78134cc54dff016c83367912eb055637fa50cAlan Cox
26389c78134cc54dff016c83367912eb055637fa50cAlan Cox/**
26489c78134cc54dff016c83367912eb055637fa50cAlan Cox * Returns a set of divisors for the desired target clock with the given
26589c78134cc54dff016c83367912eb055637fa50cAlan Cox * refclk, or FALSE.  The returned values represent the clock equation:
26689c78134cc54dff016c83367912eb055637fa50cAlan Cox * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
26789c78134cc54dff016c83367912eb055637fa50cAlan Cox */
26889c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic bool psb_intel_find_best_PLL(struct drm_crtc *crtc, int target,
26989c78134cc54dff016c83367912eb055637fa50cAlan Cox				int refclk,
27089c78134cc54dff016c83367912eb055637fa50cAlan Cox				struct psb_intel_clock_t *best_clock)
27189c78134cc54dff016c83367912eb055637fa50cAlan Cox{
27289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
27389c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_clock_t clock;
27489c78134cc54dff016c83367912eb055637fa50cAlan Cox	const struct psb_intel_limit_t *limit = psb_intel_limit(crtc);
27589c78134cc54dff016c83367912eb055637fa50cAlan Cox	int err = target;
27689c78134cc54dff016c83367912eb055637fa50cAlan Cox
27789c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
27889c78134cc54dff016c83367912eb055637fa50cAlan Cox	    (REG_READ(LVDS) & LVDS_PORT_EN) != 0) {
27989c78134cc54dff016c83367912eb055637fa50cAlan Cox		/*
28089c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * For LVDS, if the panel is on, just rely on its current
28189c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * settings for dual-channel.  We haven't figured out how to
28289c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * reliably set up different single/dual channel state, if we
28389c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * even can.
28489c78134cc54dff016c83367912eb055637fa50cAlan Cox		 */
28589c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((REG_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
28689c78134cc54dff016c83367912eb055637fa50cAlan Cox		    LVDS_CLKB_POWER_UP)
28789c78134cc54dff016c83367912eb055637fa50cAlan Cox			clock.p2 = limit->p2.p2_fast;
28889c78134cc54dff016c83367912eb055637fa50cAlan Cox		else
28989c78134cc54dff016c83367912eb055637fa50cAlan Cox			clock.p2 = limit->p2.p2_slow;
29089c78134cc54dff016c83367912eb055637fa50cAlan Cox	} else {
29189c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (target < limit->p2.dot_limit)
29289c78134cc54dff016c83367912eb055637fa50cAlan Cox			clock.p2 = limit->p2.p2_slow;
29389c78134cc54dff016c83367912eb055637fa50cAlan Cox		else
29489c78134cc54dff016c83367912eb055637fa50cAlan Cox			clock.p2 = limit->p2.p2_fast;
29589c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
29689c78134cc54dff016c83367912eb055637fa50cAlan Cox
29789c78134cc54dff016c83367912eb055637fa50cAlan Cox	memset(best_clock, 0, sizeof(*best_clock));
29889c78134cc54dff016c83367912eb055637fa50cAlan Cox
29989c78134cc54dff016c83367912eb055637fa50cAlan Cox	for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
30089c78134cc54dff016c83367912eb055637fa50cAlan Cox	     clock.m1++) {
30189c78134cc54dff016c83367912eb055637fa50cAlan Cox		for (clock.m2 = limit->m2.min;
30289c78134cc54dff016c83367912eb055637fa50cAlan Cox		     clock.m2 < clock.m1 && clock.m2 <= limit->m2.max;
30389c78134cc54dff016c83367912eb055637fa50cAlan Cox		     clock.m2++) {
30489c78134cc54dff016c83367912eb055637fa50cAlan Cox			for (clock.n = limit->n.min;
30589c78134cc54dff016c83367912eb055637fa50cAlan Cox			     clock.n <= limit->n.max; clock.n++) {
30689c78134cc54dff016c83367912eb055637fa50cAlan Cox				for (clock.p1 = limit->p1.min;
30789c78134cc54dff016c83367912eb055637fa50cAlan Cox				     clock.p1 <= limit->p1.max;
30889c78134cc54dff016c83367912eb055637fa50cAlan Cox				     clock.p1++) {
30989c78134cc54dff016c83367912eb055637fa50cAlan Cox					int this_err;
31089c78134cc54dff016c83367912eb055637fa50cAlan Cox
31189c78134cc54dff016c83367912eb055637fa50cAlan Cox					psb_intel_clock(dev, refclk, &clock);
31289c78134cc54dff016c83367912eb055637fa50cAlan Cox
31389c78134cc54dff016c83367912eb055637fa50cAlan Cox					if (!psb_intel_PLL_is_valid
31489c78134cc54dff016c83367912eb055637fa50cAlan Cox					    (crtc, &clock))
31589c78134cc54dff016c83367912eb055637fa50cAlan Cox						continue;
31689c78134cc54dff016c83367912eb055637fa50cAlan Cox
31789c78134cc54dff016c83367912eb055637fa50cAlan Cox					this_err = abs(clock.dot - target);
31889c78134cc54dff016c83367912eb055637fa50cAlan Cox					if (this_err < err) {
31989c78134cc54dff016c83367912eb055637fa50cAlan Cox						*best_clock = clock;
32089c78134cc54dff016c83367912eb055637fa50cAlan Cox						err = this_err;
32189c78134cc54dff016c83367912eb055637fa50cAlan Cox					}
32289c78134cc54dff016c83367912eb055637fa50cAlan Cox				}
32389c78134cc54dff016c83367912eb055637fa50cAlan Cox			}
32489c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
32589c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
32689c78134cc54dff016c83367912eb055637fa50cAlan Cox
32789c78134cc54dff016c83367912eb055637fa50cAlan Cox	return err != target;
32889c78134cc54dff016c83367912eb055637fa50cAlan Cox}
32989c78134cc54dff016c83367912eb055637fa50cAlan Cox
33089c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_wait_for_vblank(struct drm_device *dev)
33189c78134cc54dff016c83367912eb055637fa50cAlan Cox{
33289c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Wait for 20ms, i.e. one cycle at 50hz. */
33389c78134cc54dff016c83367912eb055637fa50cAlan Cox	mdelay(20);
33489c78134cc54dff016c83367912eb055637fa50cAlan Cox}
33589c78134cc54dff016c83367912eb055637fa50cAlan Cox
3363c1d08d7af81b4dbd77530cb4f21f28cd4035f40Kirill A. Shutemovstatic int psb_intel_pipe_set_base(struct drm_crtc *crtc,
33789c78134cc54dff016c83367912eb055637fa50cAlan Cox			    int x, int y, struct drm_framebuffer *old_fb)
33889c78134cc54dff016c83367912eb055637fa50cAlan Cox{
33989c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
34089c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* struct drm_i915_master_private *master_priv; */
34189c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
34289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
34389c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipe = psb_intel_crtc->pipe;
34489c78134cc54dff016c83367912eb055637fa50cAlan Cox	unsigned long start, offset;
34589c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE);
34689c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
34789c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
34889c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
34989c78134cc54dff016c83367912eb055637fa50cAlan Cox	u32 dspcntr;
35089c78134cc54dff016c83367912eb055637fa50cAlan Cox	int ret = 0;
35189c78134cc54dff016c83367912eb055637fa50cAlan Cox
35289c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!gma_power_begin(dev, true))
35389c78134cc54dff016c83367912eb055637fa50cAlan Cox		return 0;
35489c78134cc54dff016c83367912eb055637fa50cAlan Cox
35589c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* no fb bound */
35689c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!crtc->fb) {
35789c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_dbg(dev->dev, "No FB bound\n");
35889c78134cc54dff016c83367912eb055637fa50cAlan Cox		goto psb_intel_pipe_cleaner;
35989c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
36089c78134cc54dff016c83367912eb055637fa50cAlan Cox
36189c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* We are displaying this buffer, make sure it is actually loaded
36289c78134cc54dff016c83367912eb055637fa50cAlan Cox	   into the GTT */
36389c78134cc54dff016c83367912eb055637fa50cAlan Cox	ret = psb_gtt_pin(psbfb->gtt);
36489c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (ret < 0)
36589c78134cc54dff016c83367912eb055637fa50cAlan Cox		goto psb_intel_pipe_set_base_exit;
36689c78134cc54dff016c83367912eb055637fa50cAlan Cox	start = psbfb->gtt->offset;
36789c78134cc54dff016c83367912eb055637fa50cAlan Cox
36801f2c7730e188077026c5f766f85f329c7000c54Ville Syrjälä	offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
36989c78134cc54dff016c83367912eb055637fa50cAlan Cox
37001f2c7730e188077026c5f766f85f329c7000c54Ville Syrjälä	REG_WRITE(dspstride, crtc->fb->pitches[0]);
37189c78134cc54dff016c83367912eb055637fa50cAlan Cox
37289c78134cc54dff016c83367912eb055637fa50cAlan Cox	dspcntr = REG_READ(dspcntr_reg);
37389c78134cc54dff016c83367912eb055637fa50cAlan Cox	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
37489c78134cc54dff016c83367912eb055637fa50cAlan Cox
37589c78134cc54dff016c83367912eb055637fa50cAlan Cox	switch (crtc->fb->bits_per_pixel) {
37689c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 8:
37789c78134cc54dff016c83367912eb055637fa50cAlan Cox		dspcntr |= DISPPLANE_8BPP;
37889c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
37989c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 16:
38089c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (crtc->fb->depth == 15)
38189c78134cc54dff016c83367912eb055637fa50cAlan Cox			dspcntr |= DISPPLANE_15_16BPP;
38289c78134cc54dff016c83367912eb055637fa50cAlan Cox		else
38389c78134cc54dff016c83367912eb055637fa50cAlan Cox			dspcntr |= DISPPLANE_16BPP;
38489c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
38589c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 24:
38689c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 32:
38789c78134cc54dff016c83367912eb055637fa50cAlan Cox		dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
38889c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
38989c78134cc54dff016c83367912eb055637fa50cAlan Cox	default:
39089c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_err(dev->dev, "Unknown color depth\n");
39189c78134cc54dff016c83367912eb055637fa50cAlan Cox		ret = -EINVAL;
39289c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_gtt_unpin(psbfb->gtt);
39389c78134cc54dff016c83367912eb055637fa50cAlan Cox		goto psb_intel_pipe_set_base_exit;
39489c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
39589c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(dspcntr_reg, dspcntr);
39689c78134cc54dff016c83367912eb055637fa50cAlan Cox
39789c78134cc54dff016c83367912eb055637fa50cAlan Cox
39889c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (0 /* FIXMEAC - check what PSB needs */) {
39989c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(dspbase, offset);
40089c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_READ(dspbase);
40189c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(dspsurf, start);
40289c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_READ(dspsurf);
40389c78134cc54dff016c83367912eb055637fa50cAlan Cox	} else {
40489c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(dspbase, start + offset);
40589c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_READ(dspbase);
40689c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
40789c78134cc54dff016c83367912eb055637fa50cAlan Cox
40889c78134cc54dff016c83367912eb055637fa50cAlan Coxpsb_intel_pipe_cleaner:
40989c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* If there was a previous display we can now unpin it */
41089c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (old_fb)
41189c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_gtt_unpin(to_psb_fb(old_fb)->gtt);
41289c78134cc54dff016c83367912eb055637fa50cAlan Cox
41389c78134cc54dff016c83367912eb055637fa50cAlan Coxpsb_intel_pipe_set_base_exit:
41489c78134cc54dff016c83367912eb055637fa50cAlan Cox	gma_power_end(dev);
41589c78134cc54dff016c83367912eb055637fa50cAlan Cox	return ret;
41689c78134cc54dff016c83367912eb055637fa50cAlan Cox}
41789c78134cc54dff016c83367912eb055637fa50cAlan Cox
41889c78134cc54dff016c83367912eb055637fa50cAlan Cox/**
41989c78134cc54dff016c83367912eb055637fa50cAlan Cox * Sets the power management mode of the pipe and plane.
42089c78134cc54dff016c83367912eb055637fa50cAlan Cox *
42189c78134cc54dff016c83367912eb055637fa50cAlan Cox * This code should probably grow support for turning the cursor off and back
42289c78134cc54dff016c83367912eb055637fa50cAlan Cox * on appropriately at the same time as we're turning the pipe off/on.
42389c78134cc54dff016c83367912eb055637fa50cAlan Cox */
42489c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
42589c78134cc54dff016c83367912eb055637fa50cAlan Cox{
42689c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
42789c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* struct drm_i915_master_private *master_priv; */
42889c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* struct drm_i915_private *dev_priv = dev->dev_private; */
42989c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
43089c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipe = psb_intel_crtc->pipe;
43189c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
43289c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
43389c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
43489c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
43589c78134cc54dff016c83367912eb055637fa50cAlan Cox	u32 temp;
43689c78134cc54dff016c83367912eb055637fa50cAlan Cox
43789c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* XXX: When our outputs are all unaware of DPMS modes other than off
43889c78134cc54dff016c83367912eb055637fa50cAlan Cox	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
43989c78134cc54dff016c83367912eb055637fa50cAlan Cox	 */
44089c78134cc54dff016c83367912eb055637fa50cAlan Cox	switch (mode) {
44189c78134cc54dff016c83367912eb055637fa50cAlan Cox	case DRM_MODE_DPMS_ON:
44289c78134cc54dff016c83367912eb055637fa50cAlan Cox	case DRM_MODE_DPMS_STANDBY:
44389c78134cc54dff016c83367912eb055637fa50cAlan Cox	case DRM_MODE_DPMS_SUSPEND:
44489c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Enable the DPLL */
44589c78134cc54dff016c83367912eb055637fa50cAlan Cox		temp = REG_READ(dpll_reg);
44689c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((temp & DPLL_VCO_ENABLE) == 0) {
44789c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(dpll_reg, temp);
44889c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_READ(dpll_reg);
44989c78134cc54dff016c83367912eb055637fa50cAlan Cox			/* Wait for the clocks to stabilize. */
45089c78134cc54dff016c83367912eb055637fa50cAlan Cox			udelay(150);
45189c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
45289c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_READ(dpll_reg);
45389c78134cc54dff016c83367912eb055637fa50cAlan Cox			/* Wait for the clocks to stabilize. */
45489c78134cc54dff016c83367912eb055637fa50cAlan Cox			udelay(150);
45589c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
45689c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_READ(dpll_reg);
45789c78134cc54dff016c83367912eb055637fa50cAlan Cox			/* Wait for the clocks to stabilize. */
45889c78134cc54dff016c83367912eb055637fa50cAlan Cox			udelay(150);
45989c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
46089c78134cc54dff016c83367912eb055637fa50cAlan Cox
46189c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Enable the pipe */
46289c78134cc54dff016c83367912eb055637fa50cAlan Cox		temp = REG_READ(pipeconf_reg);
46389c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((temp & PIPEACONF_ENABLE) == 0)
46489c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
46589c78134cc54dff016c83367912eb055637fa50cAlan Cox
46689c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Enable the plane */
46789c78134cc54dff016c83367912eb055637fa50cAlan Cox		temp = REG_READ(dspcntr_reg);
46889c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
46989c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(dspcntr_reg,
47089c78134cc54dff016c83367912eb055637fa50cAlan Cox				  temp | DISPLAY_PLANE_ENABLE);
47189c78134cc54dff016c83367912eb055637fa50cAlan Cox			/* Flush the plane changes */
47289c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
47389c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
47489c78134cc54dff016c83367912eb055637fa50cAlan Cox
47589c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc_load_lut(crtc);
47689c78134cc54dff016c83367912eb055637fa50cAlan Cox
47789c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Give the overlay scaler a chance to enable
47889c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * if it's on this pipe */
47989c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* psb_intel_crtc_dpms_video(crtc, true); TODO */
48089c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
48189c78134cc54dff016c83367912eb055637fa50cAlan Cox	case DRM_MODE_DPMS_OFF:
48289c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Give the overlay scaler a chance to disable
48389c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * if it's on this pipe */
48489c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
48589c78134cc54dff016c83367912eb055637fa50cAlan Cox
48689c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Disable the VGA plane that we never use */
48789c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
48889c78134cc54dff016c83367912eb055637fa50cAlan Cox
48989c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Disable display plane */
49089c78134cc54dff016c83367912eb055637fa50cAlan Cox		temp = REG_READ(dspcntr_reg);
49189c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
49289c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(dspcntr_reg,
49389c78134cc54dff016c83367912eb055637fa50cAlan Cox				  temp & ~DISPLAY_PLANE_ENABLE);
49489c78134cc54dff016c83367912eb055637fa50cAlan Cox			/* Flush the plane changes */
49589c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
49689c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_READ(dspbase_reg);
49789c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
49889c78134cc54dff016c83367912eb055637fa50cAlan Cox
49989c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Next, disable display pipes */
50089c78134cc54dff016c83367912eb055637fa50cAlan Cox		temp = REG_READ(pipeconf_reg);
50189c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((temp & PIPEACONF_ENABLE) != 0) {
50289c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
50389c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_READ(pipeconf_reg);
50489c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
50589c78134cc54dff016c83367912eb055637fa50cAlan Cox
50689c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Wait for vblank for the disable to take effect. */
50789c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_wait_for_vblank(dev);
50889c78134cc54dff016c83367912eb055637fa50cAlan Cox
50989c78134cc54dff016c83367912eb055637fa50cAlan Cox		temp = REG_READ(dpll_reg);
51089c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((temp & DPLL_VCO_ENABLE) != 0) {
51189c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
51289c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_READ(dpll_reg);
51389c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
51489c78134cc54dff016c83367912eb055637fa50cAlan Cox
51589c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Wait for the clocks to turn off. */
51689c78134cc54dff016c83367912eb055637fa50cAlan Cox		udelay(150);
51789c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
51889c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
51989c78134cc54dff016c83367912eb055637fa50cAlan Cox
52089c78134cc54dff016c83367912eb055637fa50cAlan Cox	/*Set FIFO Watermarks*/
52189c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(DSPARB, 0x3F3E);
52289c78134cc54dff016c83367912eb055637fa50cAlan Cox}
52389c78134cc54dff016c83367912eb055637fa50cAlan Cox
52489c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_crtc_prepare(struct drm_crtc *crtc)
52589c78134cc54dff016c83367912eb055637fa50cAlan Cox{
52689c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
52789c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
52889c78134cc54dff016c83367912eb055637fa50cAlan Cox}
52989c78134cc54dff016c83367912eb055637fa50cAlan Cox
53089c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_crtc_commit(struct drm_crtc *crtc)
53189c78134cc54dff016c83367912eb055637fa50cAlan Cox{
53289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
53389c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
53489c78134cc54dff016c83367912eb055637fa50cAlan Cox}
53589c78134cc54dff016c83367912eb055637fa50cAlan Cox
53689c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_encoder_prepare(struct drm_encoder *encoder)
53789c78134cc54dff016c83367912eb055637fa50cAlan Cox{
53889c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_encoder_helper_funcs *encoder_funcs =
53989c78134cc54dff016c83367912eb055637fa50cAlan Cox	    encoder->helper_private;
54089c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* lvds has its own version of prepare see psb_intel_lvds_prepare */
54189c78134cc54dff016c83367912eb055637fa50cAlan Cox	encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
54289c78134cc54dff016c83367912eb055637fa50cAlan Cox}
54389c78134cc54dff016c83367912eb055637fa50cAlan Cox
54489c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_encoder_commit(struct drm_encoder *encoder)
54589c78134cc54dff016c83367912eb055637fa50cAlan Cox{
54689c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_encoder_helper_funcs *encoder_funcs =
54789c78134cc54dff016c83367912eb055637fa50cAlan Cox	    encoder->helper_private;
54889c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* lvds has its own version of commit see psb_intel_lvds_commit */
54989c78134cc54dff016c83367912eb055637fa50cAlan Cox	encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
55089c78134cc54dff016c83367912eb055637fa50cAlan Cox}
55189c78134cc54dff016c83367912eb055637fa50cAlan Cox
5525736995b473b8853d5ee048c7dfb9c1d20ebf0eaPatrik Jakobssonvoid psb_intel_encoder_destroy(struct drm_encoder *encoder)
5535736995b473b8853d5ee048c7dfb9c1d20ebf0eaPatrik Jakobsson{
5545736995b473b8853d5ee048c7dfb9c1d20ebf0eaPatrik Jakobsson	struct psb_intel_encoder *intel_encoder = to_psb_intel_encoder(encoder);
5555736995b473b8853d5ee048c7dfb9c1d20ebf0eaPatrik Jakobsson
5565736995b473b8853d5ee048c7dfb9c1d20ebf0eaPatrik Jakobsson	drm_encoder_cleanup(encoder);
5575736995b473b8853d5ee048c7dfb9c1d20ebf0eaPatrik Jakobsson	kfree(intel_encoder);
5585736995b473b8853d5ee048c7dfb9c1d20ebf0eaPatrik Jakobsson}
5595736995b473b8853d5ee048c7dfb9c1d20ebf0eaPatrik Jakobsson
56089c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic bool psb_intel_crtc_mode_fixup(struct drm_crtc *crtc,
56189c78134cc54dff016c83367912eb055637fa50cAlan Cox				  struct drm_display_mode *mode,
56289c78134cc54dff016c83367912eb055637fa50cAlan Cox				  struct drm_display_mode *adjusted_mode)
56389c78134cc54dff016c83367912eb055637fa50cAlan Cox{
56489c78134cc54dff016c83367912eb055637fa50cAlan Cox	return true;
56589c78134cc54dff016c83367912eb055637fa50cAlan Cox}
56689c78134cc54dff016c83367912eb055637fa50cAlan Cox
56789c78134cc54dff016c83367912eb055637fa50cAlan Cox
56889c78134cc54dff016c83367912eb055637fa50cAlan Cox/**
56989c78134cc54dff016c83367912eb055637fa50cAlan Cox * Return the pipe currently connected to the panel fitter,
57089c78134cc54dff016c83367912eb055637fa50cAlan Cox * or -1 if the panel fitter is not present or not in use
57189c78134cc54dff016c83367912eb055637fa50cAlan Cox */
57289c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic int psb_intel_panel_fitter_pipe(struct drm_device *dev)
57389c78134cc54dff016c83367912eb055637fa50cAlan Cox{
57489c78134cc54dff016c83367912eb055637fa50cAlan Cox	u32 pfit_control;
57589c78134cc54dff016c83367912eb055637fa50cAlan Cox
57689c78134cc54dff016c83367912eb055637fa50cAlan Cox	pfit_control = REG_READ(PFIT_CONTROL);
57789c78134cc54dff016c83367912eb055637fa50cAlan Cox
57889c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* See if the panel fitter is in use */
57989c78134cc54dff016c83367912eb055637fa50cAlan Cox	if ((pfit_control & PFIT_ENABLE) == 0)
58089c78134cc54dff016c83367912eb055637fa50cAlan Cox		return -1;
58189c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Must be on PIPE 1 for PSB */
58289c78134cc54dff016c83367912eb055637fa50cAlan Cox	return 1;
58389c78134cc54dff016c83367912eb055637fa50cAlan Cox}
58489c78134cc54dff016c83367912eb055637fa50cAlan Cox
58589c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
58689c78134cc54dff016c83367912eb055637fa50cAlan Cox			       struct drm_display_mode *mode,
58789c78134cc54dff016c83367912eb055637fa50cAlan Cox			       struct drm_display_mode *adjusted_mode,
58889c78134cc54dff016c83367912eb055637fa50cAlan Cox			       int x, int y,
58989c78134cc54dff016c83367912eb055637fa50cAlan Cox			       struct drm_framebuffer *old_fb)
59089c78134cc54dff016c83367912eb055637fa50cAlan Cox{
59189c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
59289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
59389c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
59489c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipe = psb_intel_crtc->pipe;
59589c78134cc54dff016c83367912eb055637fa50cAlan Cox	int fp_reg = (pipe == 0) ? FPA0 : FPB0;
59689c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
59789c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
59889c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
59989c78134cc54dff016c83367912eb055637fa50cAlan Cox	int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
60089c78134cc54dff016c83367912eb055637fa50cAlan Cox	int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
60189c78134cc54dff016c83367912eb055637fa50cAlan Cox	int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
60289c78134cc54dff016c83367912eb055637fa50cAlan Cox	int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
60389c78134cc54dff016c83367912eb055637fa50cAlan Cox	int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
60489c78134cc54dff016c83367912eb055637fa50cAlan Cox	int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
60589c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
60689c78134cc54dff016c83367912eb055637fa50cAlan Cox	int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
60789c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
60889c78134cc54dff016c83367912eb055637fa50cAlan Cox	int refclk;
60989c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_clock_t clock;
61089c78134cc54dff016c83367912eb055637fa50cAlan Cox	u32 dpll = 0, fp = 0, dspcntr, pipeconf;
6112e33d6b92ff3298c06e87661040c5401e1099ea5Kirill A. Shutemov	bool ok, is_sdvo = false;
6122e33d6b92ff3298c06e87661040c5401e1099ea5Kirill A. Shutemov	bool is_lvds = false, is_tv = false;
61389c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_mode_config *mode_config = &dev->mode_config;
61489c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_connector *connector;
61589c78134cc54dff016c83367912eb055637fa50cAlan Cox
61689c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* No scan out no play */
61789c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (crtc->fb == NULL) {
61889c78134cc54dff016c83367912eb055637fa50cAlan Cox		crtc_funcs->mode_set_base(crtc, x, y, old_fb);
61989c78134cc54dff016c83367912eb055637fa50cAlan Cox		return 0;
62089c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
62189c78134cc54dff016c83367912eb055637fa50cAlan Cox
62289c78134cc54dff016c83367912eb055637fa50cAlan Cox	list_for_each_entry(connector, &mode_config->connector_list, head) {
6231730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson		struct psb_intel_encoder *psb_intel_encoder =
6241730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson					psb_intel_attached_encoder(connector);
62589c78134cc54dff016c83367912eb055637fa50cAlan Cox
62689c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (!connector->encoder
62789c78134cc54dff016c83367912eb055637fa50cAlan Cox		    || connector->encoder->crtc != crtc)
62889c78134cc54dff016c83367912eb055637fa50cAlan Cox			continue;
62989c78134cc54dff016c83367912eb055637fa50cAlan Cox
6301730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson		switch (psb_intel_encoder->type) {
63189c78134cc54dff016c83367912eb055637fa50cAlan Cox		case INTEL_OUTPUT_LVDS:
63289c78134cc54dff016c83367912eb055637fa50cAlan Cox			is_lvds = true;
63389c78134cc54dff016c83367912eb055637fa50cAlan Cox			break;
63489c78134cc54dff016c83367912eb055637fa50cAlan Cox		case INTEL_OUTPUT_SDVO:
63589c78134cc54dff016c83367912eb055637fa50cAlan Cox			is_sdvo = true;
63689c78134cc54dff016c83367912eb055637fa50cAlan Cox			break;
63789c78134cc54dff016c83367912eb055637fa50cAlan Cox		case INTEL_OUTPUT_TVOUT:
63889c78134cc54dff016c83367912eb055637fa50cAlan Cox			is_tv = true;
63989c78134cc54dff016c83367912eb055637fa50cAlan Cox			break;
64089c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
64189c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
64289c78134cc54dff016c83367912eb055637fa50cAlan Cox
64389c78134cc54dff016c83367912eb055637fa50cAlan Cox	refclk = 96000;
64489c78134cc54dff016c83367912eb055637fa50cAlan Cox
64589c78134cc54dff016c83367912eb055637fa50cAlan Cox	ok = psb_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk,
64689c78134cc54dff016c83367912eb055637fa50cAlan Cox				 &clock);
64789c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!ok) {
64889c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_err(dev->dev, "Couldn't find PLL settings for mode!\n");
64989c78134cc54dff016c83367912eb055637fa50cAlan Cox		return 0;
65089c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
65189c78134cc54dff016c83367912eb055637fa50cAlan Cox
65289c78134cc54dff016c83367912eb055637fa50cAlan Cox	fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
65389c78134cc54dff016c83367912eb055637fa50cAlan Cox
65489c78134cc54dff016c83367912eb055637fa50cAlan Cox	dpll = DPLL_VGA_MODE_DIS;
65589c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (is_lvds) {
65689c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |= DPLLB_MODE_LVDS;
65789c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |= DPLL_DVO_HIGH_SPEED;
65889c78134cc54dff016c83367912eb055637fa50cAlan Cox	} else
65989c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |= DPLLB_MODE_DAC_SERIAL;
66089c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (is_sdvo) {
66189c78134cc54dff016c83367912eb055637fa50cAlan Cox		int sdvo_pixel_multiply =
66289c78134cc54dff016c83367912eb055637fa50cAlan Cox			    adjusted_mode->clock / mode->clock;
66389c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |= DPLL_DVO_HIGH_SPEED;
66489c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |=
66589c78134cc54dff016c83367912eb055637fa50cAlan Cox		    (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
66689c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
66789c78134cc54dff016c83367912eb055637fa50cAlan Cox
66889c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* compute bitmask from p1 value */
66989c78134cc54dff016c83367912eb055637fa50cAlan Cox	dpll |= (1 << (clock.p1 - 1)) << 16;
67089c78134cc54dff016c83367912eb055637fa50cAlan Cox	switch (clock.p2) {
67189c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 5:
67289c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
67389c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
67489c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 7:
67589c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
67689c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
67789c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 10:
67889c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
67989c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
68089c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 14:
68189c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
68289c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
68389c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
68489c78134cc54dff016c83367912eb055637fa50cAlan Cox
68589c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (is_tv) {
68689c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* XXX: just matching BIOS for now */
68789c78134cc54dff016c83367912eb055637fa50cAlan Cox/*	dpll |= PLL_REF_INPUT_TVCLKINBC; */
68889c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll |= 3;
68989c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
69089c78134cc54dff016c83367912eb055637fa50cAlan Cox	dpll |= PLL_REF_INPUT_DREFCLK;
69189c78134cc54dff016c83367912eb055637fa50cAlan Cox
69289c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* setup pipeconf */
69389c78134cc54dff016c83367912eb055637fa50cAlan Cox	pipeconf = REG_READ(pipeconf_reg);
69489c78134cc54dff016c83367912eb055637fa50cAlan Cox
69589c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Set up the display plane register */
69689c78134cc54dff016c83367912eb055637fa50cAlan Cox	dspcntr = DISPPLANE_GAMMA_ENABLE;
69789c78134cc54dff016c83367912eb055637fa50cAlan Cox
69889c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (pipe == 0)
69989c78134cc54dff016c83367912eb055637fa50cAlan Cox		dspcntr |= DISPPLANE_SEL_PIPE_A;
70089c78134cc54dff016c83367912eb055637fa50cAlan Cox	else
70189c78134cc54dff016c83367912eb055637fa50cAlan Cox		dspcntr |= DISPPLANE_SEL_PIPE_B;
70289c78134cc54dff016c83367912eb055637fa50cAlan Cox
70389c78134cc54dff016c83367912eb055637fa50cAlan Cox	dspcntr |= DISPLAY_PLANE_ENABLE;
70489c78134cc54dff016c83367912eb055637fa50cAlan Cox	pipeconf |= PIPEACONF_ENABLE;
70589c78134cc54dff016c83367912eb055637fa50cAlan Cox	dpll |= DPLL_VCO_ENABLE;
70689c78134cc54dff016c83367912eb055637fa50cAlan Cox
70789c78134cc54dff016c83367912eb055637fa50cAlan Cox
70889c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Disable the panel fitter if it was on our pipe */
70989c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (psb_intel_panel_fitter_pipe(dev) == pipe)
71089c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(PFIT_CONTROL, 0);
71189c78134cc54dff016c83367912eb055637fa50cAlan Cox
71289c78134cc54dff016c83367912eb055637fa50cAlan Cox	drm_mode_debug_printmodeline(mode);
71389c78134cc54dff016c83367912eb055637fa50cAlan Cox
71489c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (dpll & DPLL_VCO_ENABLE) {
71589c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(fp_reg, fp);
71689c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
71789c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_READ(dpll_reg);
71889c78134cc54dff016c83367912eb055637fa50cAlan Cox		udelay(150);
71989c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
72089c78134cc54dff016c83367912eb055637fa50cAlan Cox
72189c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* The LVDS pin pair needs to be on before the DPLLs are enabled.
72289c78134cc54dff016c83367912eb055637fa50cAlan Cox	 * This is an exception to the general rule that mode_set doesn't turn
72389c78134cc54dff016c83367912eb055637fa50cAlan Cox	 * things on.
72489c78134cc54dff016c83367912eb055637fa50cAlan Cox	 */
72589c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (is_lvds) {
72689c78134cc54dff016c83367912eb055637fa50cAlan Cox		u32 lvds = REG_READ(LVDS);
72789c78134cc54dff016c83367912eb055637fa50cAlan Cox
72889c78134cc54dff016c83367912eb055637fa50cAlan Cox		lvds &= ~LVDS_PIPEB_SELECT;
72989c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (pipe == 1)
73089c78134cc54dff016c83367912eb055637fa50cAlan Cox			lvds |= LVDS_PIPEB_SELECT;
73189c78134cc54dff016c83367912eb055637fa50cAlan Cox
73289c78134cc54dff016c83367912eb055637fa50cAlan Cox		lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
73389c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Set the B0-B3 data pairs corresponding to
73489c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * whether we're going to
73589c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * set the DPLLs for dual-channel mode or not.
73689c78134cc54dff016c83367912eb055637fa50cAlan Cox		 */
73789c78134cc54dff016c83367912eb055637fa50cAlan Cox		lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
73889c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (clock.p2 == 7)
73989c78134cc54dff016c83367912eb055637fa50cAlan Cox			lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
74089c78134cc54dff016c83367912eb055637fa50cAlan Cox
74189c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
74289c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * appropriately here, but we need to look more
74389c78134cc54dff016c83367912eb055637fa50cAlan Cox		 * thoroughly into how panels behave in the two modes.
74489c78134cc54dff016c83367912eb055637fa50cAlan Cox		 */
74589c78134cc54dff016c83367912eb055637fa50cAlan Cox
74689c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(LVDS, lvds);
74789c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_READ(LVDS);
74889c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
74989c78134cc54dff016c83367912eb055637fa50cAlan Cox
75089c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(fp_reg, fp);
75189c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(dpll_reg, dpll);
75289c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_READ(dpll_reg);
75389c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Wait for the clocks to stabilize. */
75489c78134cc54dff016c83367912eb055637fa50cAlan Cox	udelay(150);
75589c78134cc54dff016c83367912eb055637fa50cAlan Cox
75689c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* write it again -- the BIOS does, after all */
75789c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(dpll_reg, dpll);
75889c78134cc54dff016c83367912eb055637fa50cAlan Cox
75989c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_READ(dpll_reg);
76089c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Wait for the clocks to stabilize. */
76189c78134cc54dff016c83367912eb055637fa50cAlan Cox	udelay(150);
76289c78134cc54dff016c83367912eb055637fa50cAlan Cox
76389c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
76489c78134cc54dff016c83367912eb055637fa50cAlan Cox		  ((adjusted_mode->crtc_htotal - 1) << 16));
76589c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
76689c78134cc54dff016c83367912eb055637fa50cAlan Cox		  ((adjusted_mode->crtc_hblank_end - 1) << 16));
76789c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
76889c78134cc54dff016c83367912eb055637fa50cAlan Cox		  ((adjusted_mode->crtc_hsync_end - 1) << 16));
76989c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
77089c78134cc54dff016c83367912eb055637fa50cAlan Cox		  ((adjusted_mode->crtc_vtotal - 1) << 16));
77189c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
77289c78134cc54dff016c83367912eb055637fa50cAlan Cox		  ((adjusted_mode->crtc_vblank_end - 1) << 16));
77389c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
77489c78134cc54dff016c83367912eb055637fa50cAlan Cox		  ((adjusted_mode->crtc_vsync_end - 1) << 16));
77589c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* pipesrc and dspsize control the size that is scaled from,
77689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 * which should always be the user's requested size.
77789c78134cc54dff016c83367912eb055637fa50cAlan Cox	 */
77889c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(dspsize_reg,
77989c78134cc54dff016c83367912eb055637fa50cAlan Cox		  ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
78089c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(dsppos_reg, 0);
78189c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipesrc_reg,
78289c78134cc54dff016c83367912eb055637fa50cAlan Cox		  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
78389c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeconf_reg, pipeconf);
78489c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_READ(pipeconf_reg);
78589c78134cc54dff016c83367912eb055637fa50cAlan Cox
78689c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_wait_for_vblank(dev);
78789c78134cc54dff016c83367912eb055637fa50cAlan Cox
78889c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(dspcntr_reg, dspcntr);
78989c78134cc54dff016c83367912eb055637fa50cAlan Cox
79089c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Flush the plane changes */
79189c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_funcs->mode_set_base(crtc, x, y, old_fb);
79289c78134cc54dff016c83367912eb055637fa50cAlan Cox
79389c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_wait_for_vblank(dev);
79489c78134cc54dff016c83367912eb055637fa50cAlan Cox
79589c78134cc54dff016c83367912eb055637fa50cAlan Cox	return 0;
79689c78134cc54dff016c83367912eb055637fa50cAlan Cox}
79789c78134cc54dff016c83367912eb055637fa50cAlan Cox
79889c78134cc54dff016c83367912eb055637fa50cAlan Cox/** Loads the palette/gamma unit for the CRTC with the prepared values */
79989c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_crtc_load_lut(struct drm_crtc *crtc)
80089c78134cc54dff016c83367912eb055637fa50cAlan Cox{
80189c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
80289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_psb_private *dev_priv =
80389c78134cc54dff016c83367912eb055637fa50cAlan Cox				(struct drm_psb_private *)dev->dev_private;
80489c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
80589c78134cc54dff016c83367912eb055637fa50cAlan Cox	int palreg = PALETTE_A;
80689c78134cc54dff016c83367912eb055637fa50cAlan Cox	int i;
80789c78134cc54dff016c83367912eb055637fa50cAlan Cox
80889c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* The clocks have to be on to load the palette. */
80989c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!crtc->enabled)
81089c78134cc54dff016c83367912eb055637fa50cAlan Cox		return;
81189c78134cc54dff016c83367912eb055637fa50cAlan Cox
81289c78134cc54dff016c83367912eb055637fa50cAlan Cox	switch (psb_intel_crtc->pipe) {
81389c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 0:
81489c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
81589c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 1:
81689c78134cc54dff016c83367912eb055637fa50cAlan Cox		palreg = PALETTE_B;
81789c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
81889c78134cc54dff016c83367912eb055637fa50cAlan Cox	case 2:
81989c78134cc54dff016c83367912eb055637fa50cAlan Cox		palreg = PALETTE_C;
82089c78134cc54dff016c83367912eb055637fa50cAlan Cox		break;
82189c78134cc54dff016c83367912eb055637fa50cAlan Cox	default:
82289c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_err(dev->dev, "Illegal Pipe Number.\n");
82389c78134cc54dff016c83367912eb055637fa50cAlan Cox		return;
82489c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
82589c78134cc54dff016c83367912eb055637fa50cAlan Cox
82689c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (gma_power_begin(dev, false)) {
82789c78134cc54dff016c83367912eb055637fa50cAlan Cox		for (i = 0; i < 256; i++) {
82889c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(palreg + 4 * i,
82989c78134cc54dff016c83367912eb055637fa50cAlan Cox				  ((psb_intel_crtc->lut_r[i] +
83089c78134cc54dff016c83367912eb055637fa50cAlan Cox				  psb_intel_crtc->lut_adj[i]) << 16) |
83189c78134cc54dff016c83367912eb055637fa50cAlan Cox				  ((psb_intel_crtc->lut_g[i] +
83289c78134cc54dff016c83367912eb055637fa50cAlan Cox				  psb_intel_crtc->lut_adj[i]) << 8) |
83389c78134cc54dff016c83367912eb055637fa50cAlan Cox				  (psb_intel_crtc->lut_b[i] +
83489c78134cc54dff016c83367912eb055637fa50cAlan Cox				  psb_intel_crtc->lut_adj[i]));
83589c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
83689c78134cc54dff016c83367912eb055637fa50cAlan Cox		gma_power_end(dev);
83789c78134cc54dff016c83367912eb055637fa50cAlan Cox	} else {
83889c78134cc54dff016c83367912eb055637fa50cAlan Cox		for (i = 0; i < 256; i++) {
839c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.save_palette_a[i] =
84089c78134cc54dff016c83367912eb055637fa50cAlan Cox				  ((psb_intel_crtc->lut_r[i] +
84189c78134cc54dff016c83367912eb055637fa50cAlan Cox				  psb_intel_crtc->lut_adj[i]) << 16) |
84289c78134cc54dff016c83367912eb055637fa50cAlan Cox				  ((psb_intel_crtc->lut_g[i] +
84389c78134cc54dff016c83367912eb055637fa50cAlan Cox				  psb_intel_crtc->lut_adj[i]) << 8) |
84489c78134cc54dff016c83367912eb055637fa50cAlan Cox				  (psb_intel_crtc->lut_b[i] +
84589c78134cc54dff016c83367912eb055637fa50cAlan Cox				  psb_intel_crtc->lut_adj[i]);
84689c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
84789c78134cc54dff016c83367912eb055637fa50cAlan Cox
84889c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
84989c78134cc54dff016c83367912eb055637fa50cAlan Cox}
85089c78134cc54dff016c83367912eb055637fa50cAlan Cox
85189c78134cc54dff016c83367912eb055637fa50cAlan Cox/**
85289c78134cc54dff016c83367912eb055637fa50cAlan Cox * Save HW states of giving crtc
85389c78134cc54dff016c83367912eb055637fa50cAlan Cox */
85489c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_crtc_save(struct drm_crtc *crtc)
85589c78134cc54dff016c83367912eb055637fa50cAlan Cox{
85689c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
85789c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* struct drm_psb_private *dev_priv =
85889c78134cc54dff016c83367912eb055637fa50cAlan Cox			(struct drm_psb_private *)dev->dev_private; */
85989c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
86089c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state;
86189c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipeA = (psb_intel_crtc->pipe == 0);
86289c78134cc54dff016c83367912eb055637fa50cAlan Cox	uint32_t paletteReg;
86389c78134cc54dff016c83367912eb055637fa50cAlan Cox	int i;
86489c78134cc54dff016c83367912eb055637fa50cAlan Cox
86589c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!crtc_state) {
86689c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_err(dev->dev, "No CRTC state found\n");
86789c78134cc54dff016c83367912eb055637fa50cAlan Cox		return;
86889c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
86989c78134cc54dff016c83367912eb055637fa50cAlan Cox
87089c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveDSPCNTR = REG_READ(pipeA ? DSPACNTR : DSPBCNTR);
87189c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->savePIPECONF = REG_READ(pipeA ? PIPEACONF : PIPEBCONF);
87289c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->savePIPESRC = REG_READ(pipeA ? PIPEASRC : PIPEBSRC);
87389c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveFP0 = REG_READ(pipeA ? FPA0 : FPB0);
87489c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveFP1 = REG_READ(pipeA ? FPA1 : FPB1);
87589c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveDPLL = REG_READ(pipeA ? DPLL_A : DPLL_B);
87689c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveHTOTAL = REG_READ(pipeA ? HTOTAL_A : HTOTAL_B);
87789c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveHBLANK = REG_READ(pipeA ? HBLANK_A : HBLANK_B);
87889c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveHSYNC = REG_READ(pipeA ? HSYNC_A : HSYNC_B);
87989c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveVTOTAL = REG_READ(pipeA ? VTOTAL_A : VTOTAL_B);
88089c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveVBLANK = REG_READ(pipeA ? VBLANK_A : VBLANK_B);
88189c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveVSYNC = REG_READ(pipeA ? VSYNC_A : VSYNC_B);
88289c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveDSPSTRIDE = REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE);
88389c78134cc54dff016c83367912eb055637fa50cAlan Cox
88489c78134cc54dff016c83367912eb055637fa50cAlan Cox	/*NOTE: DSPSIZE DSPPOS only for psb*/
88589c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveDSPSIZE = REG_READ(pipeA ? DSPASIZE : DSPBSIZE);
88689c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveDSPPOS = REG_READ(pipeA ? DSPAPOS : DSPBPOS);
88789c78134cc54dff016c83367912eb055637fa50cAlan Cox
88889c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc_state->saveDSPBASE = REG_READ(pipeA ? DSPABASE : DSPBBASE);
88989c78134cc54dff016c83367912eb055637fa50cAlan Cox
89089c78134cc54dff016c83367912eb055637fa50cAlan Cox	paletteReg = pipeA ? PALETTE_A : PALETTE_B;
89189c78134cc54dff016c83367912eb055637fa50cAlan Cox	for (i = 0; i < 256; ++i)
89289c78134cc54dff016c83367912eb055637fa50cAlan Cox		crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2));
89389c78134cc54dff016c83367912eb055637fa50cAlan Cox}
89489c78134cc54dff016c83367912eb055637fa50cAlan Cox
89589c78134cc54dff016c83367912eb055637fa50cAlan Cox/**
89689c78134cc54dff016c83367912eb055637fa50cAlan Cox * Restore HW states of giving crtc
89789c78134cc54dff016c83367912eb055637fa50cAlan Cox */
89889c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_crtc_restore(struct drm_crtc *crtc)
89989c78134cc54dff016c83367912eb055637fa50cAlan Cox{
90089c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
90189c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* struct drm_psb_private * dev_priv =
90289c78134cc54dff016c83367912eb055637fa50cAlan Cox				(struct drm_psb_private *)dev->dev_private; */
90389c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc =  to_psb_intel_crtc(crtc);
90489c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state;
90589c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* struct drm_crtc_helper_funcs * crtc_funcs = crtc->helper_private; */
90689c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipeA = (psb_intel_crtc->pipe == 0);
90789c78134cc54dff016c83367912eb055637fa50cAlan Cox	uint32_t paletteReg;
90889c78134cc54dff016c83367912eb055637fa50cAlan Cox	int i;
90989c78134cc54dff016c83367912eb055637fa50cAlan Cox
91089c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!crtc_state) {
91189c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_err(dev->dev, "No crtc state\n");
91289c78134cc54dff016c83367912eb055637fa50cAlan Cox		return;
91389c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
91489c78134cc54dff016c83367912eb055637fa50cAlan Cox
91589c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) {
91689c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(pipeA ? DPLL_A : DPLL_B,
91789c78134cc54dff016c83367912eb055637fa50cAlan Cox			crtc_state->saveDPLL & ~DPLL_VCO_ENABLE);
91889c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_READ(pipeA ? DPLL_A : DPLL_B);
91989c78134cc54dff016c83367912eb055637fa50cAlan Cox		udelay(150);
92089c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
92189c78134cc54dff016c83367912eb055637fa50cAlan Cox
92289c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? FPA0 : FPB0, crtc_state->saveFP0);
92389c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_READ(pipeA ? FPA0 : FPB0);
92489c78134cc54dff016c83367912eb055637fa50cAlan Cox
92589c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? FPA1 : FPB1, crtc_state->saveFP1);
92689c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_READ(pipeA ? FPA1 : FPB1);
92789c78134cc54dff016c83367912eb055637fa50cAlan Cox
92889c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? DPLL_A : DPLL_B, crtc_state->saveDPLL);
92989c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_READ(pipeA ? DPLL_A : DPLL_B);
93089c78134cc54dff016c83367912eb055637fa50cAlan Cox	udelay(150);
93189c78134cc54dff016c83367912eb055637fa50cAlan Cox
93289c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? HTOTAL_A : HTOTAL_B, crtc_state->saveHTOTAL);
93389c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? HBLANK_A : HBLANK_B, crtc_state->saveHBLANK);
93489c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? HSYNC_A : HSYNC_B, crtc_state->saveHSYNC);
93589c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? VTOTAL_A : VTOTAL_B, crtc_state->saveVTOTAL);
93689c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? VBLANK_A : VBLANK_B, crtc_state->saveVBLANK);
93789c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? VSYNC_A : VSYNC_B, crtc_state->saveVSYNC);
93889c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? DSPASTRIDE : DSPBSTRIDE, crtc_state->saveDSPSTRIDE);
93989c78134cc54dff016c83367912eb055637fa50cAlan Cox
94089c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? DSPASIZE : DSPBSIZE, crtc_state->saveDSPSIZE);
94189c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? DSPAPOS : DSPBPOS, crtc_state->saveDSPPOS);
94289c78134cc54dff016c83367912eb055637fa50cAlan Cox
94389c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? PIPEASRC : PIPEBSRC, crtc_state->savePIPESRC);
94489c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE);
94589c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? PIPEACONF : PIPEBCONF, crtc_state->savePIPECONF);
94689c78134cc54dff016c83367912eb055637fa50cAlan Cox
94789c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_wait_for_vblank(dev);
94889c78134cc54dff016c83367912eb055637fa50cAlan Cox
94989c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? DSPACNTR : DSPBCNTR, crtc_state->saveDSPCNTR);
95089c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE);
95189c78134cc54dff016c83367912eb055637fa50cAlan Cox
95289c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_wait_for_vblank(dev);
95389c78134cc54dff016c83367912eb055637fa50cAlan Cox
95489c78134cc54dff016c83367912eb055637fa50cAlan Cox	paletteReg = pipeA ? PALETTE_A : PALETTE_B;
95589c78134cc54dff016c83367912eb055637fa50cAlan Cox	for (i = 0; i < 256; ++i)
95689c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(paletteReg + (i << 2), crtc_state->savePalette[i]);
95789c78134cc54dff016c83367912eb055637fa50cAlan Cox}
95889c78134cc54dff016c83367912eb055637fa50cAlan Cox
95989c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
96089c78134cc54dff016c83367912eb055637fa50cAlan Cox				 struct drm_file *file_priv,
96189c78134cc54dff016c83367912eb055637fa50cAlan Cox				 uint32_t handle,
96289c78134cc54dff016c83367912eb055637fa50cAlan Cox				 uint32_t width, uint32_t height)
96389c78134cc54dff016c83367912eb055637fa50cAlan Cox{
96489c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
96589c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
96689c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipe = psb_intel_crtc->pipe;
96789c78134cc54dff016c83367912eb055637fa50cAlan Cox	uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
96889c78134cc54dff016c83367912eb055637fa50cAlan Cox	uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
96989c78134cc54dff016c83367912eb055637fa50cAlan Cox	uint32_t temp;
97089c78134cc54dff016c83367912eb055637fa50cAlan Cox	size_t addr = 0;
97189c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct gtt_range *gt;
97289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_gem_object *obj;
97389c78134cc54dff016c83367912eb055637fa50cAlan Cox	int ret;
97489c78134cc54dff016c83367912eb055637fa50cAlan Cox
97589c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* if we want to turn of the cursor ignore width and height */
97689c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!handle) {
97789c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* turn off the cursor */
97889c78134cc54dff016c83367912eb055637fa50cAlan Cox		temp = CURSOR_MODE_DISABLE;
97989c78134cc54dff016c83367912eb055637fa50cAlan Cox
98089c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (gma_power_begin(dev, false)) {
98189c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(control, temp);
98289c78134cc54dff016c83367912eb055637fa50cAlan Cox			REG_WRITE(base, 0);
98389c78134cc54dff016c83367912eb055637fa50cAlan Cox			gma_power_end(dev);
98489c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
98589c78134cc54dff016c83367912eb055637fa50cAlan Cox
98689c78134cc54dff016c83367912eb055637fa50cAlan Cox		/* Unpin the old GEM object */
98789c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (psb_intel_crtc->cursor_obj) {
98889c78134cc54dff016c83367912eb055637fa50cAlan Cox			gt = container_of(psb_intel_crtc->cursor_obj,
98989c78134cc54dff016c83367912eb055637fa50cAlan Cox							struct gtt_range, gem);
99089c78134cc54dff016c83367912eb055637fa50cAlan Cox			psb_gtt_unpin(gt);
99189c78134cc54dff016c83367912eb055637fa50cAlan Cox			drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
99289c78134cc54dff016c83367912eb055637fa50cAlan Cox			psb_intel_crtc->cursor_obj = NULL;
99389c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
99489c78134cc54dff016c83367912eb055637fa50cAlan Cox
99589c78134cc54dff016c83367912eb055637fa50cAlan Cox		return 0;
99689c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
99789c78134cc54dff016c83367912eb055637fa50cAlan Cox
99889c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Currently we only support 64x64 cursors */
99989c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (width != 64 || height != 64) {
100089c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_dbg(dev->dev, "we currently only support 64x64 cursors\n");
100189c78134cc54dff016c83367912eb055637fa50cAlan Cox		return -EINVAL;
100289c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
100389c78134cc54dff016c83367912eb055637fa50cAlan Cox
100489c78134cc54dff016c83367912eb055637fa50cAlan Cox	obj = drm_gem_object_lookup(dev, file_priv, handle);
100589c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!obj)
100689c78134cc54dff016c83367912eb055637fa50cAlan Cox		return -ENOENT;
100789c78134cc54dff016c83367912eb055637fa50cAlan Cox
100889c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (obj->size < width * height * 4) {
100989c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_dbg(dev->dev, "buffer is to small\n");
101089c78134cc54dff016c83367912eb055637fa50cAlan Cox		return -ENOMEM;
101189c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
101289c78134cc54dff016c83367912eb055637fa50cAlan Cox
101389c78134cc54dff016c83367912eb055637fa50cAlan Cox	gt = container_of(obj, struct gtt_range, gem);
101489c78134cc54dff016c83367912eb055637fa50cAlan Cox
101589c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Pin the memory into the GTT */
101689c78134cc54dff016c83367912eb055637fa50cAlan Cox	ret = psb_gtt_pin(gt);
101789c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (ret) {
101889c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle);
101989c78134cc54dff016c83367912eb055637fa50cAlan Cox		return ret;
102089c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
102189c78134cc54dff016c83367912eb055637fa50cAlan Cox
102289c78134cc54dff016c83367912eb055637fa50cAlan Cox
102389c78134cc54dff016c83367912eb055637fa50cAlan Cox	addr = gt->offset;	/* Or resource.start ??? */
102489c78134cc54dff016c83367912eb055637fa50cAlan Cox
102589c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc->cursor_addr = addr;
102689c78134cc54dff016c83367912eb055637fa50cAlan Cox
102789c78134cc54dff016c83367912eb055637fa50cAlan Cox	temp = 0;
102889c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* set the pipe for the cursor */
102989c78134cc54dff016c83367912eb055637fa50cAlan Cox	temp |= (pipe << 28);
103089c78134cc54dff016c83367912eb055637fa50cAlan Cox	temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
103189c78134cc54dff016c83367912eb055637fa50cAlan Cox
103289c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (gma_power_begin(dev, false)) {
103389c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(control, temp);
103489c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE(base, addr);
103589c78134cc54dff016c83367912eb055637fa50cAlan Cox		gma_power_end(dev);
103689c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
103789c78134cc54dff016c83367912eb055637fa50cAlan Cox
103889c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* unpin the old bo */
103989c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (psb_intel_crtc->cursor_obj) {
104089c78134cc54dff016c83367912eb055637fa50cAlan Cox		gt = container_of(psb_intel_crtc->cursor_obj,
104189c78134cc54dff016c83367912eb055637fa50cAlan Cox							struct gtt_range, gem);
104289c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_gtt_unpin(gt);
104389c78134cc54dff016c83367912eb055637fa50cAlan Cox		drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
104489c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc->cursor_obj = obj;
104589c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
104689c78134cc54dff016c83367912eb055637fa50cAlan Cox	return 0;
104789c78134cc54dff016c83367912eb055637fa50cAlan Cox}
104889c78134cc54dff016c83367912eb055637fa50cAlan Cox
104989c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic int psb_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
105089c78134cc54dff016c83367912eb055637fa50cAlan Cox{
105189c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = crtc->dev;
105289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
105389c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipe = psb_intel_crtc->pipe;
105489c78134cc54dff016c83367912eb055637fa50cAlan Cox	uint32_t temp = 0;
105589c78134cc54dff016c83367912eb055637fa50cAlan Cox	uint32_t addr;
105689c78134cc54dff016c83367912eb055637fa50cAlan Cox
105789c78134cc54dff016c83367912eb055637fa50cAlan Cox
105889c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (x < 0) {
105989c78134cc54dff016c83367912eb055637fa50cAlan Cox		temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
106089c78134cc54dff016c83367912eb055637fa50cAlan Cox		x = -x;
106189c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
106289c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (y < 0) {
106389c78134cc54dff016c83367912eb055637fa50cAlan Cox		temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
106489c78134cc54dff016c83367912eb055637fa50cAlan Cox		y = -y;
106589c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
106689c78134cc54dff016c83367912eb055637fa50cAlan Cox
106789c78134cc54dff016c83367912eb055637fa50cAlan Cox	temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
106889c78134cc54dff016c83367912eb055637fa50cAlan Cox	temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
106989c78134cc54dff016c83367912eb055637fa50cAlan Cox
107089c78134cc54dff016c83367912eb055637fa50cAlan Cox	addr = psb_intel_crtc->cursor_addr;
107189c78134cc54dff016c83367912eb055637fa50cAlan Cox
107289c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (gma_power_begin(dev, false)) {
107389c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
107489c78134cc54dff016c83367912eb055637fa50cAlan Cox		REG_WRITE((pipe == 0) ? CURABASE : CURBBASE, addr);
107589c78134cc54dff016c83367912eb055637fa50cAlan Cox		gma_power_end(dev);
107689c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
107789c78134cc54dff016c83367912eb055637fa50cAlan Cox	return 0;
107889c78134cc54dff016c83367912eb055637fa50cAlan Cox}
107989c78134cc54dff016c83367912eb055637fa50cAlan Cox
108089c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red,
108189c78134cc54dff016c83367912eb055637fa50cAlan Cox			 u16 *green, u16 *blue, uint32_t type, uint32_t size)
108289c78134cc54dff016c83367912eb055637fa50cAlan Cox{
108389c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
108489c78134cc54dff016c83367912eb055637fa50cAlan Cox	int i;
108589c78134cc54dff016c83367912eb055637fa50cAlan Cox
108689c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (size != 256)
108789c78134cc54dff016c83367912eb055637fa50cAlan Cox		return;
108889c78134cc54dff016c83367912eb055637fa50cAlan Cox
108989c78134cc54dff016c83367912eb055637fa50cAlan Cox	for (i = 0; i < 256; i++) {
109089c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc->lut_r[i] = red[i] >> 8;
109189c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc->lut_g[i] = green[i] >> 8;
109289c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc->lut_b[i] = blue[i] >> 8;
109389c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
109489c78134cc54dff016c83367912eb055637fa50cAlan Cox
109589c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc_load_lut(crtc);
109689c78134cc54dff016c83367912eb055637fa50cAlan Cox}
109789c78134cc54dff016c83367912eb055637fa50cAlan Cox
109889c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic int psb_crtc_set_config(struct drm_mode_set *set)
109989c78134cc54dff016c83367912eb055637fa50cAlan Cox{
110089c78134cc54dff016c83367912eb055637fa50cAlan Cox	int ret;
110189c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_device *dev = set->crtc->dev;
110289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
110389c78134cc54dff016c83367912eb055637fa50cAlan Cox
110489c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!dev_priv->rpm_enabled)
110589c78134cc54dff016c83367912eb055637fa50cAlan Cox		return drm_crtc_helper_set_config(set);
110689c78134cc54dff016c83367912eb055637fa50cAlan Cox
110789c78134cc54dff016c83367912eb055637fa50cAlan Cox	pm_runtime_forbid(&dev->pdev->dev);
110889c78134cc54dff016c83367912eb055637fa50cAlan Cox	ret = drm_crtc_helper_set_config(set);
110989c78134cc54dff016c83367912eb055637fa50cAlan Cox	pm_runtime_allow(&dev->pdev->dev);
111089c78134cc54dff016c83367912eb055637fa50cAlan Cox	return ret;
111189c78134cc54dff016c83367912eb055637fa50cAlan Cox}
111289c78134cc54dff016c83367912eb055637fa50cAlan Cox
111389c78134cc54dff016c83367912eb055637fa50cAlan Cox/* Returns the clock of the currently programmed mode of the given pipe. */
111489c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic int psb_intel_crtc_clock_get(struct drm_device *dev,
111589c78134cc54dff016c83367912eb055637fa50cAlan Cox				struct drm_crtc *crtc)
111689c78134cc54dff016c83367912eb055637fa50cAlan Cox{
111789c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
111889c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipe = psb_intel_crtc->pipe;
111989c78134cc54dff016c83367912eb055637fa50cAlan Cox	u32 dpll;
112089c78134cc54dff016c83367912eb055637fa50cAlan Cox	u32 fp;
112189c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_clock_t clock;
112289c78134cc54dff016c83367912eb055637fa50cAlan Cox	bool is_lvds;
112389c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
112489c78134cc54dff016c83367912eb055637fa50cAlan Cox
112589c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (gma_power_begin(dev, false)) {
112689c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll = REG_READ((pipe == 0) ? DPLL_A : DPLL_B);
112789c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
112889c78134cc54dff016c83367912eb055637fa50cAlan Cox			fp = REG_READ((pipe == 0) ? FPA0 : FPB0);
112989c78134cc54dff016c83367912eb055637fa50cAlan Cox		else
113089c78134cc54dff016c83367912eb055637fa50cAlan Cox			fp = REG_READ((pipe == 0) ? FPA1 : FPB1);
113189c78134cc54dff016c83367912eb055637fa50cAlan Cox		is_lvds = (pipe == 1) && (REG_READ(LVDS) & LVDS_PORT_EN);
113289c78134cc54dff016c83367912eb055637fa50cAlan Cox		gma_power_end(dev);
113389c78134cc54dff016c83367912eb055637fa50cAlan Cox	} else {
113489c78134cc54dff016c83367912eb055637fa50cAlan Cox		dpll = (pipe == 0) ?
1135c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveDPLL_A :
1136c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveDPLL_B;
113789c78134cc54dff016c83367912eb055637fa50cAlan Cox
113889c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
113989c78134cc54dff016c83367912eb055637fa50cAlan Cox			fp = (pipe == 0) ?
1140c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox				dev_priv->regs.psb.saveFPA0 :
1141c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox				dev_priv->regs.psb.saveFPB0;
114289c78134cc54dff016c83367912eb055637fa50cAlan Cox		else
114389c78134cc54dff016c83367912eb055637fa50cAlan Cox			fp = (pipe == 0) ?
1144c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox				dev_priv->regs.psb.saveFPA1 :
1145c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox				dev_priv->regs.psb.saveFPB1;
114689c78134cc54dff016c83367912eb055637fa50cAlan Cox
1147c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox		is_lvds = (pipe == 1) && (dev_priv->regs.psb.saveLVDS &
1148648a8e342c5a754bdc62f003d3af90507c1abfdeAlan Cox								LVDS_PORT_EN);
114989c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
115089c78134cc54dff016c83367912eb055637fa50cAlan Cox
115189c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
115289c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
115389c78134cc54dff016c83367912eb055637fa50cAlan Cox	clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
115489c78134cc54dff016c83367912eb055637fa50cAlan Cox
115589c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (is_lvds) {
115689c78134cc54dff016c83367912eb055637fa50cAlan Cox		clock.p1 =
115789c78134cc54dff016c83367912eb055637fa50cAlan Cox		    ffs((dpll &
115889c78134cc54dff016c83367912eb055637fa50cAlan Cox			 DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
115989c78134cc54dff016c83367912eb055637fa50cAlan Cox			DPLL_FPA01_P1_POST_DIV_SHIFT);
116089c78134cc54dff016c83367912eb055637fa50cAlan Cox		clock.p2 = 14;
116189c78134cc54dff016c83367912eb055637fa50cAlan Cox
116289c78134cc54dff016c83367912eb055637fa50cAlan Cox		if ((dpll & PLL_REF_INPUT_MASK) ==
116389c78134cc54dff016c83367912eb055637fa50cAlan Cox		    PLLB_REF_INPUT_SPREADSPECTRUMIN) {
116489c78134cc54dff016c83367912eb055637fa50cAlan Cox			/* XXX: might not be 66MHz */
116589c78134cc54dff016c83367912eb055637fa50cAlan Cox			i8xx_clock(66000, &clock);
116689c78134cc54dff016c83367912eb055637fa50cAlan Cox		} else
116789c78134cc54dff016c83367912eb055637fa50cAlan Cox			i8xx_clock(48000, &clock);
116889c78134cc54dff016c83367912eb055637fa50cAlan Cox	} else {
116989c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (dpll & PLL_P1_DIVIDE_BY_TWO)
117089c78134cc54dff016c83367912eb055637fa50cAlan Cox			clock.p1 = 2;
117189c78134cc54dff016c83367912eb055637fa50cAlan Cox		else {
117289c78134cc54dff016c83367912eb055637fa50cAlan Cox			clock.p1 =
117389c78134cc54dff016c83367912eb055637fa50cAlan Cox			    ((dpll &
117489c78134cc54dff016c83367912eb055637fa50cAlan Cox			      DPLL_FPA01_P1_POST_DIV_MASK_I830) >>
117589c78134cc54dff016c83367912eb055637fa50cAlan Cox			     DPLL_FPA01_P1_POST_DIV_SHIFT) + 2;
117689c78134cc54dff016c83367912eb055637fa50cAlan Cox		}
117789c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (dpll & PLL_P2_DIVIDE_BY_4)
117889c78134cc54dff016c83367912eb055637fa50cAlan Cox			clock.p2 = 4;
117989c78134cc54dff016c83367912eb055637fa50cAlan Cox		else
118089c78134cc54dff016c83367912eb055637fa50cAlan Cox			clock.p2 = 2;
118189c78134cc54dff016c83367912eb055637fa50cAlan Cox
118289c78134cc54dff016c83367912eb055637fa50cAlan Cox		i8xx_clock(48000, &clock);
118389c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
118489c78134cc54dff016c83367912eb055637fa50cAlan Cox
118589c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* XXX: It would be nice to validate the clocks, but we can't reuse
118689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 * i830PllIsValid() because it relies on the xf86_config connector
118789c78134cc54dff016c83367912eb055637fa50cAlan Cox	 * configuration being accurate, which it isn't necessarily.
118889c78134cc54dff016c83367912eb055637fa50cAlan Cox	 */
118989c78134cc54dff016c83367912eb055637fa50cAlan Cox
119089c78134cc54dff016c83367912eb055637fa50cAlan Cox	return clock.dot;
119189c78134cc54dff016c83367912eb055637fa50cAlan Cox}
119289c78134cc54dff016c83367912eb055637fa50cAlan Cox
119389c78134cc54dff016c83367912eb055637fa50cAlan Cox/** Returns the currently programmed mode of the given pipe. */
119489c78134cc54dff016c83367912eb055637fa50cAlan Coxstruct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
119589c78134cc54dff016c83367912eb055637fa50cAlan Cox					     struct drm_crtc *crtc)
119689c78134cc54dff016c83367912eb055637fa50cAlan Cox{
119789c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
119889c78134cc54dff016c83367912eb055637fa50cAlan Cox	int pipe = psb_intel_crtc->pipe;
119989c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_display_mode *mode;
120089c78134cc54dff016c83367912eb055637fa50cAlan Cox	int htot;
120189c78134cc54dff016c83367912eb055637fa50cAlan Cox	int hsync;
120289c78134cc54dff016c83367912eb055637fa50cAlan Cox	int vtot;
120389c78134cc54dff016c83367912eb055637fa50cAlan Cox	int vsync;
120489c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
120589c78134cc54dff016c83367912eb055637fa50cAlan Cox
120689c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (gma_power_begin(dev, false)) {
120789c78134cc54dff016c83367912eb055637fa50cAlan Cox		htot = REG_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B);
120889c78134cc54dff016c83367912eb055637fa50cAlan Cox		hsync = REG_READ((pipe == 0) ? HSYNC_A : HSYNC_B);
120989c78134cc54dff016c83367912eb055637fa50cAlan Cox		vtot = REG_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B);
121089c78134cc54dff016c83367912eb055637fa50cAlan Cox		vsync = REG_READ((pipe == 0) ? VSYNC_A : VSYNC_B);
121189c78134cc54dff016c83367912eb055637fa50cAlan Cox		gma_power_end(dev);
121289c78134cc54dff016c83367912eb055637fa50cAlan Cox	} else {
121389c78134cc54dff016c83367912eb055637fa50cAlan Cox		htot = (pipe == 0) ?
1214c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveHTOTAL_A :
1215c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveHTOTAL_B;
121689c78134cc54dff016c83367912eb055637fa50cAlan Cox		hsync = (pipe == 0) ?
1217c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveHSYNC_A :
1218c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveHSYNC_B;
121989c78134cc54dff016c83367912eb055637fa50cAlan Cox		vtot = (pipe == 0) ?
1220c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveVTOTAL_A :
1221c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveVTOTAL_B;
122289c78134cc54dff016c83367912eb055637fa50cAlan Cox		vsync = (pipe == 0) ?
1223c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveVSYNC_A :
1224c6265ff593467d472814aa9f16f89f6c1dc90a5dAlan Cox			dev_priv->regs.psb.saveVSYNC_B;
122589c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
122689c78134cc54dff016c83367912eb055637fa50cAlan Cox
122789c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
122889c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!mode)
122989c78134cc54dff016c83367912eb055637fa50cAlan Cox		return NULL;
123089c78134cc54dff016c83367912eb055637fa50cAlan Cox
123189c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode->clock = psb_intel_crtc_clock_get(dev, crtc);
123289c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode->hdisplay = (htot & 0xffff) + 1;
123389c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
123489c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode->hsync_start = (hsync & 0xffff) + 1;
123589c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1;
123689c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode->vdisplay = (vtot & 0xffff) + 1;
123789c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1;
123889c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode->vsync_start = (vsync & 0xffff) + 1;
123989c78134cc54dff016c83367912eb055637fa50cAlan Cox	mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
124089c78134cc54dff016c83367912eb055637fa50cAlan Cox
124189c78134cc54dff016c83367912eb055637fa50cAlan Cox	drm_mode_set_name(mode);
124289c78134cc54dff016c83367912eb055637fa50cAlan Cox	drm_mode_set_crtcinfo(mode, 0);
124389c78134cc54dff016c83367912eb055637fa50cAlan Cox
124489c78134cc54dff016c83367912eb055637fa50cAlan Cox	return mode;
124589c78134cc54dff016c83367912eb055637fa50cAlan Cox}
124689c78134cc54dff016c83367912eb055637fa50cAlan Cox
124789c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_crtc_destroy(struct drm_crtc *crtc)
124889c78134cc54dff016c83367912eb055637fa50cAlan Cox{
124989c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
125089c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct gtt_range *gt;
125189c78134cc54dff016c83367912eb055637fa50cAlan Cox
125289c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Unpin the old GEM object */
125389c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (psb_intel_crtc->cursor_obj) {
125489c78134cc54dff016c83367912eb055637fa50cAlan Cox		gt = container_of(psb_intel_crtc->cursor_obj,
125589c78134cc54dff016c83367912eb055637fa50cAlan Cox						struct gtt_range, gem);
125689c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_gtt_unpin(gt);
125789c78134cc54dff016c83367912eb055637fa50cAlan Cox		drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
125889c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc->cursor_obj = NULL;
125989c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
126089c78134cc54dff016c83367912eb055637fa50cAlan Cox	kfree(psb_intel_crtc->crtc_state);
126189c78134cc54dff016c83367912eb055637fa50cAlan Cox	drm_crtc_cleanup(crtc);
126289c78134cc54dff016c83367912eb055637fa50cAlan Cox	kfree(psb_intel_crtc);
126389c78134cc54dff016c83367912eb055637fa50cAlan Cox}
126489c78134cc54dff016c83367912eb055637fa50cAlan Cox
126589c78134cc54dff016c83367912eb055637fa50cAlan Coxconst struct drm_crtc_helper_funcs psb_intel_helper_funcs = {
126689c78134cc54dff016c83367912eb055637fa50cAlan Cox	.dpms = psb_intel_crtc_dpms,
126789c78134cc54dff016c83367912eb055637fa50cAlan Cox	.mode_fixup = psb_intel_crtc_mode_fixup,
126889c78134cc54dff016c83367912eb055637fa50cAlan Cox	.mode_set = psb_intel_crtc_mode_set,
126989c78134cc54dff016c83367912eb055637fa50cAlan Cox	.mode_set_base = psb_intel_pipe_set_base,
127089c78134cc54dff016c83367912eb055637fa50cAlan Cox	.prepare = psb_intel_crtc_prepare,
127189c78134cc54dff016c83367912eb055637fa50cAlan Cox	.commit = psb_intel_crtc_commit,
127289c78134cc54dff016c83367912eb055637fa50cAlan Cox};
127389c78134cc54dff016c83367912eb055637fa50cAlan Cox
127489c78134cc54dff016c83367912eb055637fa50cAlan Coxconst struct drm_crtc_funcs psb_intel_crtc_funcs = {
127589c78134cc54dff016c83367912eb055637fa50cAlan Cox	.save = psb_intel_crtc_save,
127689c78134cc54dff016c83367912eb055637fa50cAlan Cox	.restore = psb_intel_crtc_restore,
127789c78134cc54dff016c83367912eb055637fa50cAlan Cox	.cursor_set = psb_intel_crtc_cursor_set,
127889c78134cc54dff016c83367912eb055637fa50cAlan Cox	.cursor_move = psb_intel_crtc_cursor_move,
127989c78134cc54dff016c83367912eb055637fa50cAlan Cox	.gamma_set = psb_intel_crtc_gamma_set,
128089c78134cc54dff016c83367912eb055637fa50cAlan Cox	.set_config = psb_crtc_set_config,
128189c78134cc54dff016c83367912eb055637fa50cAlan Cox	.destroy = psb_intel_crtc_destroy,
128289c78134cc54dff016c83367912eb055637fa50cAlan Cox};
128389c78134cc54dff016c83367912eb055637fa50cAlan Cox
128489c78134cc54dff016c83367912eb055637fa50cAlan Cox/*
128589c78134cc54dff016c83367912eb055637fa50cAlan Cox * Set the default value of cursor control and base register
128689c78134cc54dff016c83367912eb055637fa50cAlan Cox * to zero. This is a workaround for h/w defect on Oaktrail
128789c78134cc54dff016c83367912eb055637fa50cAlan Cox */
128889c78134cc54dff016c83367912eb055637fa50cAlan Coxstatic void psb_intel_cursor_init(struct drm_device *dev, int pipe)
128989c78134cc54dff016c83367912eb055637fa50cAlan Cox{
129089c78134cc54dff016c83367912eb055637fa50cAlan Cox	u32 control[3] = { CURACNTR, CURBCNTR, CURCCNTR };
129189c78134cc54dff016c83367912eb055637fa50cAlan Cox	u32 base[3] = { CURABASE, CURBBASE, CURCBASE };
129289c78134cc54dff016c83367912eb055637fa50cAlan Cox
129389c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(control[pipe], 0);
129489c78134cc54dff016c83367912eb055637fa50cAlan Cox	REG_WRITE(base[pipe], 0);
129589c78134cc54dff016c83367912eb055637fa50cAlan Cox}
129689c78134cc54dff016c83367912eb055637fa50cAlan Cox
129789c78134cc54dff016c83367912eb055637fa50cAlan Coxvoid psb_intel_crtc_init(struct drm_device *dev, int pipe,
129889c78134cc54dff016c83367912eb055637fa50cAlan Cox		     struct psb_intel_mode_device *mode_dev)
129989c78134cc54dff016c83367912eb055637fa50cAlan Cox{
130089c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
130189c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *psb_intel_crtc;
130289c78134cc54dff016c83367912eb055637fa50cAlan Cox	int i;
130389c78134cc54dff016c83367912eb055637fa50cAlan Cox	uint16_t *r_base, *g_base, *b_base;
130489c78134cc54dff016c83367912eb055637fa50cAlan Cox
130589c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* We allocate a extra array of drm_connector pointers
130689c78134cc54dff016c83367912eb055637fa50cAlan Cox	 * for fbdev after the crtc */
130789c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc =
130889c78134cc54dff016c83367912eb055637fa50cAlan Cox	    kzalloc(sizeof(struct psb_intel_crtc) +
130989c78134cc54dff016c83367912eb055637fa50cAlan Cox		    (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)),
131089c78134cc54dff016c83367912eb055637fa50cAlan Cox		    GFP_KERNEL);
131189c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (psb_intel_crtc == NULL)
131289c78134cc54dff016c83367912eb055637fa50cAlan Cox		return;
131389c78134cc54dff016c83367912eb055637fa50cAlan Cox
131489c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc->crtc_state =
131589c78134cc54dff016c83367912eb055637fa50cAlan Cox		kzalloc(sizeof(struct psb_intel_crtc_state), GFP_KERNEL);
131689c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!psb_intel_crtc->crtc_state) {
131789c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_err(dev->dev, "Crtc state error: No memory\n");
131889c78134cc54dff016c83367912eb055637fa50cAlan Cox		kfree(psb_intel_crtc);
131989c78134cc54dff016c83367912eb055637fa50cAlan Cox		return;
132089c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
132189c78134cc54dff016c83367912eb055637fa50cAlan Cox
132289c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Set the CRTC operations from the chip specific data */
132389c78134cc54dff016c83367912eb055637fa50cAlan Cox	drm_crtc_init(dev, &psb_intel_crtc->base, dev_priv->ops->crtc_funcs);
132489c78134cc54dff016c83367912eb055637fa50cAlan Cox
132589c78134cc54dff016c83367912eb055637fa50cAlan Cox	drm_mode_crtc_set_gamma_size(&psb_intel_crtc->base, 256);
132689c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc->pipe = pipe;
132789c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc->plane = pipe;
132889c78134cc54dff016c83367912eb055637fa50cAlan Cox
132989c78134cc54dff016c83367912eb055637fa50cAlan Cox	r_base = psb_intel_crtc->base.gamma_store;
133089c78134cc54dff016c83367912eb055637fa50cAlan Cox	g_base = r_base + 256;
133189c78134cc54dff016c83367912eb055637fa50cAlan Cox	b_base = g_base + 256;
133289c78134cc54dff016c83367912eb055637fa50cAlan Cox	for (i = 0; i < 256; i++) {
133389c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc->lut_r[i] = i;
133489c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc->lut_g[i] = i;
133589c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc->lut_b[i] = i;
133689c78134cc54dff016c83367912eb055637fa50cAlan Cox		r_base[i] = i << 8;
133789c78134cc54dff016c83367912eb055637fa50cAlan Cox		g_base[i] = i << 8;
133889c78134cc54dff016c83367912eb055637fa50cAlan Cox		b_base[i] = i << 8;
133989c78134cc54dff016c83367912eb055637fa50cAlan Cox
134089c78134cc54dff016c83367912eb055637fa50cAlan Cox		psb_intel_crtc->lut_adj[i] = 0;
134189c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
134289c78134cc54dff016c83367912eb055637fa50cAlan Cox
134389c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc->mode_dev = mode_dev;
134489c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc->cursor_addr = 0;
134589c78134cc54dff016c83367912eb055637fa50cAlan Cox
134689c78134cc54dff016c83367912eb055637fa50cAlan Cox	drm_crtc_helper_add(&psb_intel_crtc->base,
134789c78134cc54dff016c83367912eb055637fa50cAlan Cox						dev_priv->ops->crtc_helper);
134889c78134cc54dff016c83367912eb055637fa50cAlan Cox
134989c78134cc54dff016c83367912eb055637fa50cAlan Cox	/* Setup the array of drm_connector pointer array */
135089c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc->mode_set.crtc = &psb_intel_crtc->base;
135189c78134cc54dff016c83367912eb055637fa50cAlan Cox	BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
135289c78134cc54dff016c83367912eb055637fa50cAlan Cox	       dev_priv->plane_to_crtc_mapping[psb_intel_crtc->plane] != NULL);
135389c78134cc54dff016c83367912eb055637fa50cAlan Cox	dev_priv->plane_to_crtc_mapping[psb_intel_crtc->plane] =
135489c78134cc54dff016c83367912eb055637fa50cAlan Cox							&psb_intel_crtc->base;
135589c78134cc54dff016c83367912eb055637fa50cAlan Cox	dev_priv->pipe_to_crtc_mapping[psb_intel_crtc->pipe] =
135689c78134cc54dff016c83367912eb055637fa50cAlan Cox							&psb_intel_crtc->base;
135789c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc->mode_set.connectors =
135889c78134cc54dff016c83367912eb055637fa50cAlan Cox	    (struct drm_connector **) (psb_intel_crtc + 1);
135989c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_crtc->mode_set.num_connectors = 0;
136089c78134cc54dff016c83367912eb055637fa50cAlan Cox	psb_intel_cursor_init(dev, pipe);
136189c78134cc54dff016c83367912eb055637fa50cAlan Cox}
136289c78134cc54dff016c83367912eb055637fa50cAlan Cox
136389c78134cc54dff016c83367912eb055637fa50cAlan Coxint psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
136489c78134cc54dff016c83367912eb055637fa50cAlan Cox				struct drm_file *file_priv)
136589c78134cc54dff016c83367912eb055637fa50cAlan Cox{
136689c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
136789c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_psb_get_pipe_from_crtc_id_arg *pipe_from_crtc_id = data;
136889c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_mode_object *drmmode_obj;
136989c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct psb_intel_crtc *crtc;
137089c78134cc54dff016c83367912eb055637fa50cAlan Cox
137189c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!dev_priv) {
137289c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_err(dev->dev, "called with no initialization\n");
137389c78134cc54dff016c83367912eb055637fa50cAlan Cox		return -EINVAL;
137489c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
137589c78134cc54dff016c83367912eb055637fa50cAlan Cox
137689c78134cc54dff016c83367912eb055637fa50cAlan Cox	drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id,
137789c78134cc54dff016c83367912eb055637fa50cAlan Cox			DRM_MODE_OBJECT_CRTC);
137889c78134cc54dff016c83367912eb055637fa50cAlan Cox
137989c78134cc54dff016c83367912eb055637fa50cAlan Cox	if (!drmmode_obj) {
138089c78134cc54dff016c83367912eb055637fa50cAlan Cox		dev_err(dev->dev, "no such CRTC id\n");
138189c78134cc54dff016c83367912eb055637fa50cAlan Cox		return -EINVAL;
138289c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
138389c78134cc54dff016c83367912eb055637fa50cAlan Cox
138489c78134cc54dff016c83367912eb055637fa50cAlan Cox	crtc = to_psb_intel_crtc(obj_to_crtc(drmmode_obj));
138589c78134cc54dff016c83367912eb055637fa50cAlan Cox	pipe_from_crtc_id->pipe = crtc->pipe;
138689c78134cc54dff016c83367912eb055637fa50cAlan Cox
138789c78134cc54dff016c83367912eb055637fa50cAlan Cox	return 0;
138889c78134cc54dff016c83367912eb055637fa50cAlan Cox}
138989c78134cc54dff016c83367912eb055637fa50cAlan Cox
139089c78134cc54dff016c83367912eb055637fa50cAlan Coxstruct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
139189c78134cc54dff016c83367912eb055637fa50cAlan Cox{
139289c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_crtc *crtc = NULL;
139389c78134cc54dff016c83367912eb055637fa50cAlan Cox
139489c78134cc54dff016c83367912eb055637fa50cAlan Cox	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
139589c78134cc54dff016c83367912eb055637fa50cAlan Cox		struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
139689c78134cc54dff016c83367912eb055637fa50cAlan Cox		if (psb_intel_crtc->pipe == pipe)
139789c78134cc54dff016c83367912eb055637fa50cAlan Cox			break;
139889c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
139989c78134cc54dff016c83367912eb055637fa50cAlan Cox	return crtc;
140089c78134cc54dff016c83367912eb055637fa50cAlan Cox}
140189c78134cc54dff016c83367912eb055637fa50cAlan Cox
140289c78134cc54dff016c83367912eb055637fa50cAlan Coxint psb_intel_connector_clones(struct drm_device *dev, int type_mask)
140389c78134cc54dff016c83367912eb055637fa50cAlan Cox{
140489c78134cc54dff016c83367912eb055637fa50cAlan Cox	int index_mask = 0;
140589c78134cc54dff016c83367912eb055637fa50cAlan Cox	struct drm_connector *connector;
140689c78134cc54dff016c83367912eb055637fa50cAlan Cox	int entry = 0;
140789c78134cc54dff016c83367912eb055637fa50cAlan Cox
140889c78134cc54dff016c83367912eb055637fa50cAlan Cox	list_for_each_entry(connector, &dev->mode_config.connector_list,
140989c78134cc54dff016c83367912eb055637fa50cAlan Cox			    head) {
14101730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson		struct psb_intel_encoder *psb_intel_encoder =
14111730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson					psb_intel_attached_encoder(connector);
14121730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson		if (type_mask & (1 << psb_intel_encoder->type))
141389c78134cc54dff016c83367912eb055637fa50cAlan Cox			index_mask |= (1 << entry);
141489c78134cc54dff016c83367912eb055637fa50cAlan Cox		entry++;
141589c78134cc54dff016c83367912eb055637fa50cAlan Cox	}
141689c78134cc54dff016c83367912eb055637fa50cAlan Cox	return index_mask;
141789c78134cc54dff016c83367912eb055637fa50cAlan Cox}
141889c78134cc54dff016c83367912eb055637fa50cAlan Cox
141989c78134cc54dff016c83367912eb055637fa50cAlan Cox/* current intel driver doesn't take advantage of encoders
142089c78134cc54dff016c83367912eb055637fa50cAlan Cox   always give back the encoder for the connector
142189c78134cc54dff016c83367912eb055637fa50cAlan Cox*/
142289c78134cc54dff016c83367912eb055637fa50cAlan Coxstruct drm_encoder *psb_intel_best_encoder(struct drm_connector *connector)
142389c78134cc54dff016c83367912eb055637fa50cAlan Cox{
14241730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson	struct psb_intel_encoder *psb_intel_encoder =
14251730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson					psb_intel_attached_encoder(connector);
142689c78134cc54dff016c83367912eb055637fa50cAlan Cox
14271730f89bfcff353484672cdcefbef13b2f374176Patrik Jakobsson	return &psb_intel_encoder->base;
142889c78134cc54dff016c83367912eb055637fa50cAlan Cox}
142989c78134cc54dff016c83367912eb055637fa50cAlan Cox
143075e9d019d5625032b708576e02e025c79e04ae44Patrik Jakobssonvoid psb_intel_connector_attach_encoder(struct psb_intel_connector *connector,
143175e9d019d5625032b708576e02e025c79e04ae44Patrik Jakobsson					struct psb_intel_encoder *encoder)
143275e9d019d5625032b708576e02e025c79e04ae44Patrik Jakobsson{
143375e9d019d5625032b708576e02e025c79e04ae44Patrik Jakobsson	connector->encoder = encoder;
143475e9d019d5625032b708576e02e025c79e04ae44Patrik Jakobsson	drm_mode_connector_attach_encoder(&connector->base,
143575e9d019d5625032b708576e02e025c79e04ae44Patrik Jakobsson					  &encoder->base);
143675e9d019d5625032b708576e02e025c79e04ae44Patrik Jakobsson}
1437