16a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/**************************************************************************
26a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * Copyright (c) 2011, Intel Corporation.
36a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * All Rights Reserved.
46a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *
56a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * This program is free software; you can redistribute it and/or modify it
66a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * under the terms and conditions of the GNU General Public License,
76a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * version 2, as published by the Free Software Foundation.
86a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *
96a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * This program is distributed in the hope it will be useful, but WITHOUT
106a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * more details.
136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *
146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * You should have received a copy of the GNU General Public License along with
156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * this program; if not, write to the Free Software Foundation, Inc.,
166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *
186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox **************************************************************************/
196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include <linux/backlight.h>
216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include <drm/drmP.h>
226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include <drm/drm.h>
23838fa588a29331da012876623c3bc170d7d647c2Alan Cox#include "gma_drm.h"
246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "psb_drv.h"
256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "psb_reg.h"
266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "psb_intel_reg.h"
276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "intel_bios.h"
286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#include "cdv_device.h"
296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define VGA_SR_INDEX		0x3c4
316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define VGA_SR_DATA		0x3c5
326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_disable_vga(struct drm_device *dev)
346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
356a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	u8 sr1;
366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	u32 vga_reg;
376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	vga_reg = VGACNTRL;
396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	outb(1, VGA_SR_INDEX);
416a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	sr1 = inb(VGA_SR_DATA);
426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	outb(sr1 | 1<<5, VGA_SR_DATA);
436a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	udelay(300);
446a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	REG_WRITE(vga_reg, VGA_DISP_DISABLE);
466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	REG_READ(vga_reg);
476a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_output_init(struct drm_device *dev)
506a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
516a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	cdv_disable_vga(dev);
536a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
546a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	cdv_intel_crt_init(dev, &dev_priv->mode_dev);
556a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	cdv_intel_lvds_init(dev, &dev_priv->mode_dev);
566a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
576a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	/* These bits indicate HDMI not SDVO on CDV, but we don't yet support
586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	   the HDMI interface */
596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	if (REG_READ(SDVOB) & SDVO_DETECTED)
606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOB);
616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	if (REG_READ(SDVOC) & SDVO_DETECTED)
626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOC);
636a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return 0;
646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
666a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/*
696a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	Poulsbo Backlight Interfaces
706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */
716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
726a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define BLC_PWM_PRECISION_FACTOR 100	/* 10000000 */
736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define BLC_PWM_FREQ_CALC_CONSTANT 32
746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define MHz 1000000
756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BLC_PWM_PRECISION_FACTOR    10
776a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BLC_MAX_PWM_REG_FREQ        0xFFFE
786a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BLC_MIN_PWM_REG_FREQ        0x2
796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
806a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
816a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_BACKLIGHT_PWM_CTL_SHIFT	(16)
826a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_brightness;
846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic struct backlight_device *cdv_backlight_device;
856a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
866a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_get_brightness(struct backlight_device *bd)
876a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
886a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	/* return locally cached var instead of HW read (due to DPST etc.) */
896a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	/* FIXME: ideally return actual value in case firmware fiddled with
906a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	   it */
916a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return cdv_brightness;
926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
946a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_backlight_setup(struct drm_device *dev)
966a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
976a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	unsigned long core_clock;
996a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	/* u32 bl_max_freq; */
1006a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	/* unsigned long value; */
1016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	u16 bl_max_freq;
1026a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	uint32_t value;
1036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	uint32_t blc_pwm_precision_factor;
1046a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1056a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	/* get bl_max_freq and pol from dev_priv*/
1066a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	if (!dev_priv->lvds_bl) {
1076a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		dev_err(dev->dev, "Has no valid LVDS backlight info\n");
1086a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		return -ENOENT;
1096a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	}
1106a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	bl_max_freq = dev_priv->lvds_bl->freq;
1116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR;
1126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	core_clock = dev_priv->core_freq;
1146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT;
1166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	value *= blc_pwm_precision_factor;
1176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	value /= bl_max_freq;
1186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	value /= blc_pwm_precision_factor;
1196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ ||
1216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		 value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ)
1226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox				return -ERANGE;
1236a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	else {
1246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		/* FIXME */
1256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	}
1266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return 0;
1276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
1286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_set_brightness(struct backlight_device *bd)
1306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
1316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	int level = bd->props.brightness;
1326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	/* Percentage 1-100% being valid */
1346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	if (level < 1)
1356a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		level = 1;
1366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	/*cdv_intel_lvds_set_brightness(dev, level); FIXME */
1386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	cdv_brightness = level;
1396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return 0;
1406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
1416a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic const struct backlight_ops cdv_ops = {
1436a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.get_brightness = cdv_get_brightness,
1446a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.update_status  = cdv_set_brightness,
1456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox};
1466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1476a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_backlight_init(struct drm_device *dev)
1486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
1496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
1506a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	int ret;
1516a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	struct backlight_properties props;
1526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1536a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	memset(&props, 0, sizeof(struct backlight_properties));
1546a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	props.max_brightness = 100;
1556a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	props.type = BACKLIGHT_PLATFORM;
1566a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1576a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	cdv_backlight_device = backlight_device_register("psb-bl",
1586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox					NULL, (void *)dev, &cdv_ops, &props);
1596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	if (IS_ERR(cdv_backlight_device))
1606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		return PTR_ERR(cdv_backlight_device);
1616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	ret = cdv_backlight_setup(dev);
1636a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	if (ret < 0) {
1646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		backlight_device_unregister(cdv_backlight_device);
1656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		cdv_backlight_device = NULL;
1666a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		return ret;
1676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	}
1686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	cdv_backlight_device->props.brightness = 100;
1696a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	cdv_backlight_device->props.max_brightness = 100;
1706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	backlight_update_status(cdv_backlight_device);
1716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	dev_priv->backlight_device = cdv_backlight_device;
1726a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return 0;
1736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
1746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#endif
1766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1776a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/*
1786a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	Provide the Cedarview specific chip logic and low level methods
1796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	for power management
1806a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *
1816a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	FIXME: we need to implement the apm/ospm base management bits
1826a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	for this and the MID devices.
1836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */
1846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1856a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic inline u32 CDV_MSG_READ32(uint port, uint offset)
1866a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
1876a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	int mcr = (0x10<<24) | (port << 16) | (offset << 8);
1886a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	uint32_t ret_val = 0;
1896a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
1906a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pci_write_config_dword(pci_root, 0xD0, mcr);
1916a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pci_read_config_dword(pci_root, 0xD4, &ret_val);
1926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pci_dev_put(pci_root);
1936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return ret_val;
1946a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
1956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
1966a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic inline void CDV_MSG_WRITE32(uint port, uint offset, u32 value)
1976a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
1986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	int mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0;
1996a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
2006a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pci_write_config_dword(pci_root, 0xD4, value);
2016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pci_write_config_dword(pci_root, 0xD0, mcr);
2026a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pci_dev_put(pci_root);
2036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
2046a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
2056a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_PM_SSC			0x20
2066a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#define PSB_PM_SSS			0x30
20709016a11fc738e82ca1303e2332473b517bbd660Alan Cox#define PSB_PWRGT_GFX_ON		0x02
20809016a11fc738e82ca1303e2332473b517bbd660Alan Cox#define PSB_PWRGT_GFX_OFF		0x01
20909016a11fc738e82ca1303e2332473b517bbd660Alan Cox#define PSB_PWRGT_GFX_D0		0x00
21009016a11fc738e82ca1303e2332473b517bbd660Alan Cox#define PSB_PWRGT_GFX_D3		0x03
2116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
2126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_init_pm(struct drm_device *dev)
2136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
2146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
2156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	u32 pwr_cnt;
2166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	int i;
2176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
2186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	dev_priv->apm_base = CDV_MSG_READ32(PSB_PUNIT_PORT,
2196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox							PSB_APMBA) & 0xFFFF;
2206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT,
2216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox							PSB_OSPMBA) & 0xFFFF;
2226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
22309016a11fc738e82ca1303e2332473b517bbd660Alan Cox	/* Power status */
2246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
2256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
22609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	/* Enable the GPU */
22709016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
22809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_cnt |= PSB_PWRGT_GFX_ON;
2296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
23009016a11fc738e82ca1303e2332473b517bbd660Alan Cox
23109016a11fc738e82ca1303e2332473b517bbd660Alan Cox	/* Wait for the GPU power */
2326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	for (i = 0; i < 5; i++) {
2336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		u32 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
2346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		if ((pwr_sts & PSB_PWRGT_GFX_MASK) == 0)
23509016a11fc738e82ca1303e2332473b517bbd660Alan Cox			return;
2366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		udelay(10);
2376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	}
23809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	dev_err(dev->dev, "GPU: power management timed out.\n");
2396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
2406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
2416a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/**
2426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	cdv_save_display_registers	-	save registers lost on suspend
2436a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	@dev: our DRM device
2446a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *
2456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	Save the state we need in order to be able to restore the interface
2466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	upon resume from suspend
2476a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */
2486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_save_display_registers(struct drm_device *dev)
2496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
25009016a11fc738e82ca1303e2332473b517bbd660Alan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
25109016a11fc738e82ca1303e2332473b517bbd660Alan Cox	struct psb_save_area *regs = &dev_priv->regs;
25209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	struct drm_connector *connector;
25309016a11fc738e82ca1303e2332473b517bbd660Alan Cox
25409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	dev_info(dev->dev, "Saving GPU registers.\n");
25509016a11fc738e82ca1303e2332473b517bbd660Alan Cox
25609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pci_read_config_byte(dev->pdev, 0xF4, &regs->cdv.saveLBB);
25709016a11fc738e82ca1303e2332473b517bbd660Alan Cox
25809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveDSPCLK_GATE_D = REG_READ(DSPCLK_GATE_D);
25909016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveRAMCLK_GATE_D = REG_READ(RAMCLK_GATE_D);
26009016a11fc738e82ca1303e2332473b517bbd660Alan Cox
26109016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveDSPARB = REG_READ(DSPARB);
26209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveDSPFW[0] = REG_READ(DSPFW1);
26309016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveDSPFW[1] = REG_READ(DSPFW2);
26409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveDSPFW[2] = REG_READ(DSPFW3);
26509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveDSPFW[3] = REG_READ(DSPFW4);
26609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveDSPFW[4] = REG_READ(DSPFW5);
26709016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveDSPFW[5] = REG_READ(DSPFW6);
26809016a11fc738e82ca1303e2332473b517bbd660Alan Cox
26909016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveADPA = REG_READ(ADPA);
27009016a11fc738e82ca1303e2332473b517bbd660Alan Cox
27109016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.savePP_CONTROL = REG_READ(PP_CONTROL);
27209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
27309016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
27409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->saveBLC_PWM_CTL2 = REG_READ(BLC_PWM_CTL2);
27509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveLVDS = REG_READ(LVDS);
27609016a11fc738e82ca1303e2332473b517bbd660Alan Cox
27709016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.savePFIT_CONTROL = REG_READ(PFIT_CONTROL);
27809016a11fc738e82ca1303e2332473b517bbd660Alan Cox
27909016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.savePP_ON_DELAYS = REG_READ(PP_ON_DELAYS);
28009016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.savePP_OFF_DELAYS = REG_READ(PP_OFF_DELAYS);
28109016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.savePP_CYCLE = REG_READ(PP_CYCLE);
28209016a11fc738e82ca1303e2332473b517bbd660Alan Cox
28309016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveVGACNTRL = REG_READ(VGACNTRL);
28409016a11fc738e82ca1303e2332473b517bbd660Alan Cox
28509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveIER = REG_READ(PSB_INT_ENABLE_R);
28609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	regs->cdv.saveIMR = REG_READ(PSB_INT_MASK_R);
28709016a11fc738e82ca1303e2332473b517bbd660Alan Cox
28809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
28909016a11fc738e82ca1303e2332473b517bbd660Alan Cox		connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
29009016a11fc738e82ca1303e2332473b517bbd660Alan Cox
2916a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return 0;
2926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
2936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
2946a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/**
2956a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	cdv_restore_display_registers	-	restore lost register state
2966a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	@dev: our DRM device
2976a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *
2986a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	Restore register state that was lost during suspend and resume.
2996a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *
3006a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox *	FIXME: review
3016a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox */
3026a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_restore_display_registers(struct drm_device *dev)
3036a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
30409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
30509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	struct psb_save_area *regs = &dev_priv->regs;
30609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	struct drm_connector *connector;
30709016a11fc738e82ca1303e2332473b517bbd660Alan Cox	u32 temp;
30809016a11fc738e82ca1303e2332473b517bbd660Alan Cox
30909016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pci_write_config_byte(dev->pdev, 0xF4, regs->cdv.saveLBB);
31009016a11fc738e82ca1303e2332473b517bbd660Alan Cox
31109016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DSPCLK_GATE_D, regs->cdv.saveDSPCLK_GATE_D);
31209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(RAMCLK_GATE_D, regs->cdv.saveRAMCLK_GATE_D);
31309016a11fc738e82ca1303e2332473b517bbd660Alan Cox
31409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	/* BIOS does below anyway */
31509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DPIO_CFG, 0);
31609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DPIO_CFG, DPIO_MODE_SELECT_0 | DPIO_CMN_RESET_N);
31709016a11fc738e82ca1303e2332473b517bbd660Alan Cox
31809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	temp = REG_READ(DPLL_A);
31909016a11fc738e82ca1303e2332473b517bbd660Alan Cox	if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
32009016a11fc738e82ca1303e2332473b517bbd660Alan Cox		REG_WRITE(DPLL_A, temp | DPLL_SYNCLOCK_ENABLE);
32109016a11fc738e82ca1303e2332473b517bbd660Alan Cox		REG_READ(DPLL_A);
32209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	}
32309016a11fc738e82ca1303e2332473b517bbd660Alan Cox
32409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	temp = REG_READ(DPLL_B);
32509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
32609016a11fc738e82ca1303e2332473b517bbd660Alan Cox		REG_WRITE(DPLL_B, temp | DPLL_SYNCLOCK_ENABLE);
32709016a11fc738e82ca1303e2332473b517bbd660Alan Cox		REG_READ(DPLL_B);
32809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	}
32909016a11fc738e82ca1303e2332473b517bbd660Alan Cox
33009016a11fc738e82ca1303e2332473b517bbd660Alan Cox	udelay(500);
33109016a11fc738e82ca1303e2332473b517bbd660Alan Cox
33209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DSPFW1, regs->cdv.saveDSPFW[0]);
33309016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DSPFW2, regs->cdv.saveDSPFW[1]);
33409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DSPFW3, regs->cdv.saveDSPFW[2]);
33509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DSPFW4, regs->cdv.saveDSPFW[3]);
33609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DSPFW5, regs->cdv.saveDSPFW[4]);
33709016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DSPFW6, regs->cdv.saveDSPFW[5]);
33809016a11fc738e82ca1303e2332473b517bbd660Alan Cox
33909016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(DSPARB, regs->cdv.saveDSPARB);
34009016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(ADPA, regs->cdv.saveADPA);
34109016a11fc738e82ca1303e2332473b517bbd660Alan Cox
34209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(BLC_PWM_CTL2, regs->saveBLC_PWM_CTL2);
34309016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(LVDS, regs->cdv.saveLVDS);
34409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(PFIT_CONTROL, regs->cdv.savePFIT_CONTROL);
34509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(PFIT_PGM_RATIOS, regs->cdv.savePFIT_PGM_RATIOS);
34609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(BLC_PWM_CTL, regs->saveBLC_PWM_CTL);
34709016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(PP_ON_DELAYS, regs->cdv.savePP_ON_DELAYS);
34809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(PP_OFF_DELAYS, regs->cdv.savePP_OFF_DELAYS);
34909016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(PP_CYCLE, regs->cdv.savePP_CYCLE);
35009016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(PP_CONTROL, regs->cdv.savePP_CONTROL);
35109016a11fc738e82ca1303e2332473b517bbd660Alan Cox
35209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(VGACNTRL, regs->cdv.saveVGACNTRL);
35309016a11fc738e82ca1303e2332473b517bbd660Alan Cox
35409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(PSB_INT_ENABLE_R, regs->cdv.saveIER);
35509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	REG_WRITE(PSB_INT_MASK_R, regs->cdv.saveIMR);
35609016a11fc738e82ca1303e2332473b517bbd660Alan Cox
35709016a11fc738e82ca1303e2332473b517bbd660Alan Cox	/* Fix arbitration bug */
35809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	CDV_MSG_WRITE32(3, 0x30, 0x08027108);
35909016a11fc738e82ca1303e2332473b517bbd660Alan Cox
36009016a11fc738e82ca1303e2332473b517bbd660Alan Cox	drm_mode_config_reset(dev);
36109016a11fc738e82ca1303e2332473b517bbd660Alan Cox
36209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
36309016a11fc738e82ca1303e2332473b517bbd660Alan Cox		connector->funcs->dpms(connector, DRM_MODE_DPMS_ON);
36409016a11fc738e82ca1303e2332473b517bbd660Alan Cox
36509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	/* Resume the modeset for every activated CRTC */
36609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	drm_helper_resume_force_mode(dev);
3676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return 0;
3686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
3696a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
3706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_power_down(struct drm_device *dev)
3716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
37209016a11fc738e82ca1303e2332473b517bbd660Alan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
37309016a11fc738e82ca1303e2332473b517bbd660Alan Cox	u32 pwr_cnt, pwr_mask, pwr_sts;
37409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	int tries = 5;
37509016a11fc738e82ca1303e2332473b517bbd660Alan Cox
37609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
37709016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
37809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_cnt |= PSB_PWRGT_GFX_OFF;
37909016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_mask = PSB_PWRGT_GFX_MASK;
38009016a11fc738e82ca1303e2332473b517bbd660Alan Cox
38109016a11fc738e82ca1303e2332473b517bbd660Alan Cox	outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
38209016a11fc738e82ca1303e2332473b517bbd660Alan Cox
38309016a11fc738e82ca1303e2332473b517bbd660Alan Cox	while (tries--) {
38409016a11fc738e82ca1303e2332473b517bbd660Alan Cox		pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
38509016a11fc738e82ca1303e2332473b517bbd660Alan Cox		if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D3)
38609016a11fc738e82ca1303e2332473b517bbd660Alan Cox			return 0;
38709016a11fc738e82ca1303e2332473b517bbd660Alan Cox		udelay(10);
38809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	}
3896a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return 0;
3906a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
3916a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
3926a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_power_up(struct drm_device *dev)
3936a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
39409016a11fc738e82ca1303e2332473b517bbd660Alan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
39509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	u32 pwr_cnt, pwr_mask, pwr_sts;
39609016a11fc738e82ca1303e2332473b517bbd660Alan Cox	int tries = 5;
39709016a11fc738e82ca1303e2332473b517bbd660Alan Cox
39809016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
39909016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
40009016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_cnt |= PSB_PWRGT_GFX_ON;
40109016a11fc738e82ca1303e2332473b517bbd660Alan Cox	pwr_mask = PSB_PWRGT_GFX_MASK;
40209016a11fc738e82ca1303e2332473b517bbd660Alan Cox
40309016a11fc738e82ca1303e2332473b517bbd660Alan Cox	outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
40409016a11fc738e82ca1303e2332473b517bbd660Alan Cox
40509016a11fc738e82ca1303e2332473b517bbd660Alan Cox	while (tries--) {
40609016a11fc738e82ca1303e2332473b517bbd660Alan Cox		pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
40709016a11fc738e82ca1303e2332473b517bbd660Alan Cox		if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D0)
40809016a11fc738e82ca1303e2332473b517bbd660Alan Cox			return 0;
40909016a11fc738e82ca1303e2332473b517bbd660Alan Cox		udelay(10);
41009016a11fc738e82ca1303e2332473b517bbd660Alan Cox	}
4116a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return 0;
4126a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
4136a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4146a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/* FIXME ? - shared with Poulsbo */
4156a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic void cdv_get_core_freq(struct drm_device *dev)
4166a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
4176a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	uint32_t clock;
4186a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
4196a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	struct drm_psb_private *dev_priv = dev->dev_private;
4206a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4216a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pci_write_config_dword(pci_root, 0xD0, 0xD0050300);
4226a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pci_read_config_dword(pci_root, 0xD4, &clock);
4236a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	pci_dev_put(pci_root);
4246a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4256a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	switch (clock & 0x07) {
4266a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	case 0:
4276a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		dev_priv->core_freq = 100;
4286a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		break;
4296a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	case 1:
4306a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		dev_priv->core_freq = 133;
4316a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		break;
4326a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	case 2:
4336a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		dev_priv->core_freq = 150;
4346a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		break;
4356a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	case 3:
4366a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		dev_priv->core_freq = 178;
4376a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		break;
4386a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	case 4:
4396a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		dev_priv->core_freq = 200;
4406a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		break;
4416a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	case 5:
4426a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	case 6:
4436a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	case 7:
4446a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		dev_priv->core_freq = 266;
4456a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	default:
4466a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox		dev_priv->core_freq = 0;
4476a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	}
4486a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
4496a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4506a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxstatic int cdv_chip_setup(struct drm_device *dev)
4516a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox{
4526a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	cdv_get_core_freq(dev);
4536a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	gma_intel_opregion_init(dev);
4546a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	psb_intel_init_bios(dev);
455055bf38d3d6069707e2d555cffdde629b8404ff2Alan Cox	REG_WRITE(PORT_HOTPLUG_EN, 0);
456055bf38d3d6069707e2d555cffdde629b8404ff2Alan Cox	REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
4576a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	return 0;
4586a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox}
4596a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4606a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox/* CDV is much like Poulsbo but has MID like SGX offsets and PM */
4616a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4626a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Coxconst struct psb_ops cdv_chip_ops = {
463b6195aab9ca63a4f6911365f36eb091666fcb15aAlan Cox	.name = "GMA3600/3650",
4646a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.accel_2d = 0,
4656a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.pipes = 2,
466b6195aab9ca63a4f6911365f36eb091666fcb15aAlan Cox	.crtcs = 2,
4676a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.sgx_offset = MRST_SGX_OFFSET,
4686a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.chip_setup = cdv_chip_setup,
4696a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4706a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.crtc_helper = &cdv_intel_helper_funcs,
4716a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.crtc_funcs = &cdv_intel_crtc_funcs,
4726a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4736a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.output_init = cdv_output_init,
4746a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4756a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
4766a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.backlight_init = cdv_backlight_init,
4776a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox#endif
4786a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox
4796a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.init_pm = cdv_init_pm,
4806a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.save_regs = cdv_save_display_registers,
4816a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.restore_regs = cdv_restore_display_registers,
4826a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.power_down = cdv_power_down,
4836a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox	.power_up = cdv_power_up,
4846a227d5fd6c4abe6a9226a40f6981825e9da5fbeAlan Cox};
485