xref: /titanic_44/usr/src/uts/intel/io/drm/i915_drv.c (revision 2e6e901d9406e1a048063c872149376a6bf7cb63)
1ae115bc7Smrj /* BEGIN CSTYLED */
2ae115bc7Smrj 
3ae115bc7Smrj /*
4e92e3a86Szw161486  * i915_drv.c -- Intel i915 driver -*- linux-c -*-
5ae115bc7Smrj  * Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com
6ae115bc7Smrj  */
7ae115bc7Smrj 
8ae115bc7Smrj /*
9ae115bc7Smrj  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
10*0035d21cSmiao chen - Sun Microsystems - Beijing China  * Copyright (c) 2009, Intel Corporation.
11ae115bc7Smrj  * All Rights Reserved.
12ae115bc7Smrj  *
13ae115bc7Smrj  * Permission is hereby granted, free of charge, to any person obtaining a
14ae115bc7Smrj  * copy of this software and associated documentation files (the "Software"),
15ae115bc7Smrj  * to deal in the Software without restriction, including without limitation
16ae115bc7Smrj  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17ae115bc7Smrj  * and/or sell copies of the Software, and to permit persons to whom the
18ae115bc7Smrj  * Software is furnished to do so, subject to the following conditions:
19ae115bc7Smrj  *
20ae115bc7Smrj  * The above copyright notice and this permission notice (including the next
21ae115bc7Smrj  * paragraph) shall be included in all copies or substantial portions of the
22ae115bc7Smrj  * Software.
23ae115bc7Smrj  *
24ae115bc7Smrj  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25ae115bc7Smrj  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26ae115bc7Smrj  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
27ae115bc7Smrj  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
28ae115bc7Smrj  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
29ae115bc7Smrj  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30ae115bc7Smrj  * OTHER DEALINGS IN THE SOFTWARE.
31ae115bc7Smrj  *
32ae115bc7Smrj  * Authors:
33ae115bc7Smrj  *    Gareth Hughes <gareth@valinux.com>
34ae115bc7Smrj  *
35ae115bc7Smrj  */
36ae115bc7Smrj 
37e92e3a86Szw161486 /*
38d0231070Smiao chen - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
39e92e3a86Szw161486  * Use is subject to license terms.
40e92e3a86Szw161486  */
41e92e3a86Szw161486 
42d0538f66Scg149915 /*
43d0538f66Scg149915  * I915 DRM Driver for Solaris
44d0538f66Scg149915  *
45d0538f66Scg149915  * This driver provides the hardware 3D acceleration support for Intel
46d0538f66Scg149915  * integrated video devices (e.g. i8xx/i915/i945 series chipsets), under the
47d0538f66Scg149915  * DRI (Direct Rendering Infrastructure). DRM (Direct Rendering Manager) here
48d0538f66Scg149915  * means the kernel device driver in DRI.
49d0538f66Scg149915  *
50d0538f66Scg149915  * I915 driver is a device dependent driver only, it depends on a misc module
51d0538f66Scg149915  * named drm for generic DRM operations.
52d0538f66Scg149915  */
53ae115bc7Smrj 
54ae115bc7Smrj #include "drmP.h"
55ae115bc7Smrj #include "i915_drm.h"
56ae115bc7Smrj #include "i915_drv.h"
57ae115bc7Smrj #include "drm_pciids.h"
58ae115bc7Smrj 
5931c83a1bSms148562 /*
6031c83a1bSms148562  * copied from vgasubr.h
6131c83a1bSms148562  */
6231c83a1bSms148562 
6331c83a1bSms148562 struct vgaregmap {
6431c83a1bSms148562 	uint8_t			*addr;
6531c83a1bSms148562 	ddi_acc_handle_t	handle;
6631c83a1bSms148562 	boolean_t		mapped;
6731c83a1bSms148562 };
6831c83a1bSms148562 
6931c83a1bSms148562 enum pipe {
7031c83a1bSms148562 	PIPE_A = 0,
7131c83a1bSms148562 	PIPE_B,
7231c83a1bSms148562 };
7331c83a1bSms148562 
74d0538f66Scg149915 
75d0538f66Scg149915 /*
76d0538f66Scg149915  * cb_ops entrypoint
77d0538f66Scg149915  */
78d0538f66Scg149915 extern struct cb_ops drm_cb_ops;
79d0538f66Scg149915 
80d0538f66Scg149915 /*
81d0538f66Scg149915  * module entrypoint
82d0538f66Scg149915  */
83d0538f66Scg149915 static int i915_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
84d0538f66Scg149915 static int i915_attach(dev_info_t *, ddi_attach_cmd_t);
85d0538f66Scg149915 static int i915_detach(dev_info_t *, ddi_detach_cmd_t);
86d0538f66Scg149915 
87d0538f66Scg149915 
88d0538f66Scg149915 /* drv_PCI_IDs comes from drm_pciids.h */
89ae115bc7Smrj static drm_pci_id_list_t i915_pciidlist[] = {
90ae115bc7Smrj 	i915_PCI_IDS
91ae115bc7Smrj };
92ae115bc7Smrj 
93ae115bc7Smrj /*
94d0538f66Scg149915  * Local routines
95ae115bc7Smrj  */
96d0538f66Scg149915 static void i915_configure(drm_driver_t *);
974cde194bSEdward Shu static int i915_quiesce(dev_info_t *dip);
98ae115bc7Smrj 
99d0538f66Scg149915 /*
100d0538f66Scg149915  * DRM driver
101d0538f66Scg149915  */
102d0538f66Scg149915 static drm_driver_t	i915_driver = {0};
103ae115bc7Smrj 
104ae115bc7Smrj 
105d0538f66Scg149915 static struct dev_ops i915_dev_ops = {
106d0538f66Scg149915 	DEVO_REV,			/* devo_rev */
107d0538f66Scg149915 	0,				/* devo_refcnt */
108d0538f66Scg149915 	i915_info,			/* devo_getinfo */
109d0538f66Scg149915 	nulldev,			/* devo_identify */
110d0538f66Scg149915 	nulldev,			/* devo_probe */
111d0538f66Scg149915 	i915_attach,			/* devo_attach */
112d0538f66Scg149915 	i915_detach,			/* devo_detach */
113d0538f66Scg149915 	nodev,				/* devo_reset */
114d0538f66Scg149915 	&drm_cb_ops,			/* devo_cb_ops */
115d0538f66Scg149915 	NULL,				/* devo_bus_ops */
11619397407SSherry Moore 	NULL,				/* power */
1174cde194bSEdward Shu 	i915_quiesce,	/* devo_quiesce */
118d0538f66Scg149915 };
119ae115bc7Smrj 
120d0538f66Scg149915 static struct modldrv modldrv = {
121d0538f66Scg149915 	&mod_driverops,			/* drv_modops */
12231c83a1bSms148562 	"I915 DRM driver",	/* drv_linkinfo */
123d0538f66Scg149915 	&i915_dev_ops,			/* drv_dev_ops */
124d0538f66Scg149915 };
125ae115bc7Smrj 
126d0538f66Scg149915 static struct modlinkage modlinkage = {
127d0538f66Scg149915 	MODREV_1, (void *) &modldrv, NULL
128d0538f66Scg149915 };
129ae115bc7Smrj 
13031c83a1bSms148562 static ddi_device_acc_attr_t s3_attr = {
13131c83a1bSms148562         DDI_DEVICE_ATTR_V0,
13231c83a1bSms148562         DDI_NEVERSWAP_ACC,
13331c83a1bSms148562         DDI_STRICTORDER_ACC     /* must be DDI_STRICTORDER_ACC */
13431c83a1bSms148562 };
135ae115bc7Smrj 
136d0538f66Scg149915 /*
137d0538f66Scg149915  * softstate head
138d0538f66Scg149915  */
139d0538f66Scg149915 static void 	*i915_statep;
140ae115bc7Smrj 
141ae115bc7Smrj int
_init(void)142d0538f66Scg149915 _init(void)
143ae115bc7Smrj {
144d0538f66Scg149915 	int error;
145d0538f66Scg149915 
146d0538f66Scg149915 	i915_configure(&i915_driver);
147d0538f66Scg149915 
148d0538f66Scg149915 	if ((error = ddi_soft_state_init(&i915_statep,
149d0538f66Scg149915 	    sizeof (drm_device_t), DRM_MAX_INSTANCES)) != 0)
150d0538f66Scg149915 		return (error);
151d0538f66Scg149915 
152d0538f66Scg149915 	if ((error = mod_install(&modlinkage)) != 0) {
153d0538f66Scg149915 		ddi_soft_state_fini(&i915_statep);
154d0538f66Scg149915 		return (error);
155d0538f66Scg149915 	}
156d0538f66Scg149915 
157d0538f66Scg149915 	return (error);
158d0538f66Scg149915 
159d0538f66Scg149915 }	/* _init() */
160d0538f66Scg149915 
161d0538f66Scg149915 int
_fini(void)162d0538f66Scg149915 _fini(void)
163d0538f66Scg149915 {
164d0538f66Scg149915 	int error;
165d0538f66Scg149915 
166d0538f66Scg149915 	if ((error = mod_remove(&modlinkage)) != 0)
167d0538f66Scg149915 		return (error);
168d0538f66Scg149915 
169d0538f66Scg149915 	(void) ddi_soft_state_fini(&i915_statep);
170d0538f66Scg149915 
171d0538f66Scg149915 	return (0);
172d0538f66Scg149915 
173d0538f66Scg149915 }	/* _fini() */
174d0538f66Scg149915 
175d0538f66Scg149915 int
_info(struct modinfo * modinfop)176d0538f66Scg149915 _info(struct modinfo *modinfop)
177d0538f66Scg149915 {
178d0538f66Scg149915 	return (mod_info(&modlinkage, modinfop));
179d0538f66Scg149915 
180d0538f66Scg149915 }	/* _info() */
181d0538f66Scg149915 
18231c83a1bSms148562 /*
18331c83a1bSms148562  * off range: 0x3b0 ~ 0x3ff
18431c83a1bSms148562  */
18531c83a1bSms148562 
18631c83a1bSms148562 static void
vga_reg_put8(struct vgaregmap * regmap,uint16_t off,uint8_t val)18731c83a1bSms148562 vga_reg_put8(struct vgaregmap *regmap, uint16_t off, uint8_t val)
18831c83a1bSms148562 {
18931c83a1bSms148562 	ASSERT((off >= 0x3b0) && (off <= 0x3ff));
19031c83a1bSms148562 
19131c83a1bSms148562 	ddi_put8(regmap->handle, regmap->addr + off, val);
19231c83a1bSms148562 }
19331c83a1bSms148562 
19431c83a1bSms148562 /*
19531c83a1bSms148562  * off range: 0x3b0 ~ 0x3ff
19631c83a1bSms148562  */
19731c83a1bSms148562 static uint8_t
vga_reg_get8(struct vgaregmap * regmap,uint16_t off)19831c83a1bSms148562 vga_reg_get8(struct vgaregmap *regmap, uint16_t off)
19931c83a1bSms148562 {
20031c83a1bSms148562 
20131c83a1bSms148562 	ASSERT((off >= 0x3b0) && (off <= 0x3ff));
20231c83a1bSms148562 
20331c83a1bSms148562 	return (ddi_get8(regmap->handle, regmap->addr + off));
20431c83a1bSms148562 }
20531c83a1bSms148562 
20631c83a1bSms148562 static void
i915_write_indexed(struct vgaregmap * regmap,uint16_t index_port,uint16_t data_port,uint8_t index,uint8_t val)20731c83a1bSms148562 i915_write_indexed(struct vgaregmap *regmap,
20831c83a1bSms148562     uint16_t index_port, uint16_t data_port, uint8_t index, uint8_t val)
20931c83a1bSms148562 {
21031c83a1bSms148562 	vga_reg_put8(regmap, index_port, index);
21131c83a1bSms148562 	vga_reg_put8(regmap, data_port, val);
21231c83a1bSms148562 }
21331c83a1bSms148562 
21431c83a1bSms148562 static uint8_t
i915_read_indexed(struct vgaregmap * regmap,uint16_t index_port,uint16_t data_port,uint8_t index)21531c83a1bSms148562 i915_read_indexed(struct vgaregmap *regmap,
21631c83a1bSms148562     uint16_t index_port, uint16_t data_port, uint8_t index)
21731c83a1bSms148562 {
21831c83a1bSms148562 	vga_reg_put8(regmap, index_port, index);
21931c83a1bSms148562 	return (vga_reg_get8(regmap, data_port));
22031c83a1bSms148562 }
22131c83a1bSms148562 
22231c83a1bSms148562 static void
i915_write_ar(struct vgaregmap * regmap,uint16_t st01,uint8_t reg,uint8_t val,uint8_t palette_enable)22331c83a1bSms148562 i915_write_ar(struct vgaregmap *regmap, uint16_t st01,
22431c83a1bSms148562     uint8_t reg, uint8_t val, uint8_t palette_enable)
22531c83a1bSms148562 {
22631c83a1bSms148562 	(void) vga_reg_get8(regmap, st01);
22731c83a1bSms148562 	vga_reg_put8(regmap, VGA_AR_INDEX, palette_enable | reg);
22831c83a1bSms148562 	vga_reg_put8(regmap, VGA_AR_DATA_WRITE, val);
22931c83a1bSms148562 }
23031c83a1bSms148562 
23131c83a1bSms148562 static uint8_t
i915_read_ar(struct vgaregmap * regmap,uint16_t st01,uint8_t index,uint8_t palette_enable)23231c83a1bSms148562 i915_read_ar(struct vgaregmap *regmap, uint16_t st01,
23331c83a1bSms148562     uint8_t index, uint8_t palette_enable)
23431c83a1bSms148562 {
23531c83a1bSms148562 	(void) vga_reg_get8(regmap, st01);
23631c83a1bSms148562 	vga_reg_put8(regmap, VGA_AR_INDEX, index | palette_enable);
23731c83a1bSms148562 	return (vga_reg_get8(regmap, VGA_AR_DATA_READ));
23831c83a1bSms148562 }
23931c83a1bSms148562 
24031c83a1bSms148562 static int
i915_pipe_enabled(struct drm_device * dev,enum pipe pipe)24131c83a1bSms148562 i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
24231c83a1bSms148562 {
24331c83a1bSms148562 	struct s3_i915_private *s3_priv = dev->s3_private;
24431c83a1bSms148562 
24531c83a1bSms148562 	if (pipe == PIPE_A)
24631c83a1bSms148562 		return (S3_READ(DPLL_A) & DPLL_VCO_ENABLE);
24731c83a1bSms148562 	else
24831c83a1bSms148562 		return (S3_READ(DPLL_B) & DPLL_VCO_ENABLE);
24931c83a1bSms148562 }
25031c83a1bSms148562 
25131c83a1bSms148562 static void
i915_save_palette(struct drm_device * dev,enum pipe pipe)25231c83a1bSms148562 i915_save_palette(struct drm_device *dev, enum pipe pipe)
25331c83a1bSms148562 {
25431c83a1bSms148562 	struct s3_i915_private *s3_priv = dev->s3_private;
25531c83a1bSms148562 	unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
25631c83a1bSms148562 	uint32_t *array;
25731c83a1bSms148562 	int i;
25831c83a1bSms148562 
25931c83a1bSms148562 	if (!i915_pipe_enabled(dev, pipe))
26031c83a1bSms148562 		return;
26131c83a1bSms148562 
26231c83a1bSms148562 	if (pipe == PIPE_A)
26331c83a1bSms148562 		array = s3_priv->save_palette_a;
26431c83a1bSms148562 	else
26531c83a1bSms148562 		array = s3_priv->save_palette_b;
26631c83a1bSms148562 
26731c83a1bSms148562 	for(i = 0; i < 256; i++)
26831c83a1bSms148562 		array[i] = S3_READ(reg + (i << 2));
26931c83a1bSms148562 
27031c83a1bSms148562 }
27131c83a1bSms148562 
27231c83a1bSms148562 static void
i915_restore_palette(struct drm_device * dev,enum pipe pipe)27331c83a1bSms148562 i915_restore_palette(struct drm_device *dev, enum pipe pipe)
27431c83a1bSms148562 {
27531c83a1bSms148562 	struct s3_i915_private *s3_priv = dev->s3_private;
27631c83a1bSms148562 	unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B);
27731c83a1bSms148562 	uint32_t *array;
27831c83a1bSms148562 	int i;
27931c83a1bSms148562 
28031c83a1bSms148562 	if (!i915_pipe_enabled(dev, pipe))
28131c83a1bSms148562 		return;
28231c83a1bSms148562 
28331c83a1bSms148562 	if (pipe == PIPE_A)
28431c83a1bSms148562 		array = s3_priv->save_palette_a;
28531c83a1bSms148562 	else
28631c83a1bSms148562 		array = s3_priv->save_palette_b;
28731c83a1bSms148562 
28831c83a1bSms148562 	for(i = 0; i < 256; i++)
28931c83a1bSms148562 		S3_WRITE(reg + (i << 2), array[i]);
29031c83a1bSms148562 }
29131c83a1bSms148562 
29231c83a1bSms148562 static void
i915_save_vga(struct drm_device * dev)29331c83a1bSms148562 i915_save_vga(struct drm_device *dev)
29431c83a1bSms148562 {
29531c83a1bSms148562 	struct s3_i915_private *s3_priv = dev->s3_private;
29631c83a1bSms148562 	int i;
29731c83a1bSms148562 	uint16_t cr_index, cr_data, st01;
29831c83a1bSms148562 	struct vgaregmap regmap;
29931c83a1bSms148562 
30031c83a1bSms148562 	regmap.addr = (uint8_t *)s3_priv->saveAddr;
30131c83a1bSms148562 	regmap.handle = s3_priv->saveHandle;
30231c83a1bSms148562 
30331c83a1bSms148562 	/* VGA color palette registers */
30431c83a1bSms148562         s3_priv->saveDACMASK = vga_reg_get8(&regmap, VGA_DACMASK);
30531c83a1bSms148562 	/* DACCRX automatically increments during read */
30631c83a1bSms148562 	vga_reg_put8(&regmap, VGA_DACRX, 0);
30731c83a1bSms148562 	/* Read 3 bytes of color data from each index */
30831c83a1bSms148562 	for (i = 0; i < 256 * 3; i++)
30931c83a1bSms148562 		s3_priv->saveDACDATA[i] = vga_reg_get8(&regmap, VGA_DACDATA);
31031c83a1bSms148562 
31131c83a1bSms148562 	/* MSR bits */
31231c83a1bSms148562 	s3_priv->saveMSR = vga_reg_get8(&regmap, VGA_MSR_READ);
31331c83a1bSms148562 	if (s3_priv->saveMSR & VGA_MSR_CGA_MODE) {
31431c83a1bSms148562 		cr_index = VGA_CR_INDEX_CGA;
31531c83a1bSms148562 		cr_data = VGA_CR_DATA_CGA;
31631c83a1bSms148562 		st01 = VGA_ST01_CGA;
31731c83a1bSms148562 	} else {
31831c83a1bSms148562 		cr_index = VGA_CR_INDEX_MDA;
31931c83a1bSms148562 		cr_data = VGA_CR_DATA_MDA;
32031c83a1bSms148562 		st01 = VGA_ST01_MDA;
32131c83a1bSms148562 	}
32231c83a1bSms148562 
32331c83a1bSms148562 	/* CRT controller regs */
32431c83a1bSms148562 	i915_write_indexed(&regmap, cr_index, cr_data, 0x11,
32531c83a1bSms148562 	    i915_read_indexed(&regmap, cr_index, cr_data, 0x11) & (~0x80));
326fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	for (i = 0; i <= 0x24; i++)
32731c83a1bSms148562 		s3_priv->saveCR[i] =
32831c83a1bSms148562 		    i915_read_indexed(&regmap, cr_index, cr_data, i);
32931c83a1bSms148562 	/* Make sure we don't turn off CR group 0 writes */
33031c83a1bSms148562 	s3_priv->saveCR[0x11] &= ~0x80;
33131c83a1bSms148562 
33231c83a1bSms148562 	/* Attribute controller registers */
33331c83a1bSms148562 	(void) vga_reg_get8(&regmap, st01);
33431c83a1bSms148562 	s3_priv->saveAR_INDEX = vga_reg_get8(&regmap, VGA_AR_INDEX);
335fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	for (i = 0; i <= 0x14; i++)
33631c83a1bSms148562 		s3_priv->saveAR[i] = i915_read_ar(&regmap, st01, i, 0);
33731c83a1bSms148562 	(void) vga_reg_get8(&regmap, st01);
33831c83a1bSms148562 	vga_reg_put8(&regmap, VGA_AR_INDEX, s3_priv->saveAR_INDEX);
33931c83a1bSms148562 	(void) vga_reg_get8(&regmap, st01);
34031c83a1bSms148562 
34131c83a1bSms148562 	/* Graphics controller registers */
34231c83a1bSms148562 	for (i = 0; i < 9; i++)
34331c83a1bSms148562 		s3_priv->saveGR[i] =
34431c83a1bSms148562 		    i915_read_indexed(&regmap, VGA_GR_INDEX, VGA_GR_DATA, i);
34531c83a1bSms148562 
34631c83a1bSms148562 	s3_priv->saveGR[0x10] =
34731c83a1bSms148562 		i915_read_indexed(&regmap, VGA_GR_INDEX, VGA_GR_DATA, 0x10);
34831c83a1bSms148562 	s3_priv->saveGR[0x11] =
34931c83a1bSms148562 		i915_read_indexed(&regmap, VGA_GR_INDEX, VGA_GR_DATA, 0x11);
35031c83a1bSms148562 	s3_priv->saveGR[0x18] =
35131c83a1bSms148562 		i915_read_indexed(&regmap, VGA_GR_INDEX, VGA_GR_DATA, 0x18);
35231c83a1bSms148562 
35331c83a1bSms148562 	/* Sequencer registers */
35431c83a1bSms148562 	for (i = 0; i < 8; i++)
35531c83a1bSms148562 		s3_priv->saveSR[i] =
35631c83a1bSms148562 		    i915_read_indexed(&regmap, VGA_SR_INDEX, VGA_SR_DATA, i);
35731c83a1bSms148562 }
35831c83a1bSms148562 
35931c83a1bSms148562 static void
i915_restore_vga(struct drm_device * dev)36031c83a1bSms148562 i915_restore_vga(struct drm_device *dev)
36131c83a1bSms148562 {
36231c83a1bSms148562 	struct s3_i915_private *s3_priv = dev->s3_private;
36331c83a1bSms148562 	int i;
36431c83a1bSms148562 	uint16_t cr_index, cr_data, st01;
36531c83a1bSms148562 	struct vgaregmap regmap;
36631c83a1bSms148562 
36731c83a1bSms148562 	regmap.addr = (uint8_t *)s3_priv->saveAddr;
36831c83a1bSms148562 	regmap.handle = s3_priv->saveHandle;
36931c83a1bSms148562 
37031c83a1bSms148562 	/*
37131c83a1bSms148562 	 * I/O Address Select. This bit selects 3Bxh or 3Dxh as the
37231c83a1bSms148562 	 * I/O address for the CRT Controller registers,
37331c83a1bSms148562 	 * the Feature Control Register (FCR), and Input Status Register
37431c83a1bSms148562 	 * 1 (ST01). Presently ignored (whole range is claimed), but
37531c83a1bSms148562 	 * will "ignore" 3Bx for color configuration or 3Dx for monochrome.
37631c83a1bSms148562 	 * Note that it is typical in AGP chipsets to shadow this bit
37731c83a1bSms148562 	 * and properly steer I/O cycles to the proper bus for operation
37831c83a1bSms148562 	 * where a MDA exists on another bus such as ISA.
37931c83a1bSms148562 	 * 0 = Select 3Bxh I/O address (MDA emulation) (default).
38031c83a1bSms148562 	 * 1 = Select 3Dxh I/O address (CGA emulation).
38131c83a1bSms148562 	 */
38231c83a1bSms148562 	vga_reg_put8(&regmap, VGA_MSR_WRITE, s3_priv->saveMSR);
38331c83a1bSms148562 
38431c83a1bSms148562 	if (s3_priv->saveMSR & VGA_MSR_CGA_MODE) {
38531c83a1bSms148562 		cr_index = VGA_CR_INDEX_CGA;
38631c83a1bSms148562 		cr_data = VGA_CR_DATA_CGA;
38731c83a1bSms148562 		st01 = VGA_ST01_CGA;
38831c83a1bSms148562         } else {
38931c83a1bSms148562 		cr_index = VGA_CR_INDEX_MDA;
39031c83a1bSms148562 		cr_data = VGA_CR_DATA_MDA;
39131c83a1bSms148562 		st01 = VGA_ST01_MDA;
39231c83a1bSms148562         }
39331c83a1bSms148562 
39431c83a1bSms148562 	/* Sequencer registers, don't write SR07 */
39531c83a1bSms148562         for (i = 0; i < 7; i++)
39631c83a1bSms148562 		i915_write_indexed(&regmap, VGA_SR_INDEX, VGA_SR_DATA, i,
39731c83a1bSms148562 		    s3_priv->saveSR[i]);
39831c83a1bSms148562 	/* CRT controller regs */
39931c83a1bSms148562 	/* Enable CR group 0 writes */
40031c83a1bSms148562 	i915_write_indexed(&regmap, cr_index, cr_data,
40131c83a1bSms148562 	    0x11, s3_priv->saveCR[0x11]);
402fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	for (i = 0; i <= 0x24; i++)
40331c83a1bSms148562 		i915_write_indexed(&regmap, cr_index,
40431c83a1bSms148562 		    cr_data, i, s3_priv->saveCR[i]);
40531c83a1bSms148562 
40631c83a1bSms148562 	/* Graphics controller regs */
40731c83a1bSms148562 	for (i = 0; i < 9; i++)
40831c83a1bSms148562 		i915_write_indexed(&regmap, VGA_GR_INDEX, VGA_GR_DATA, i,
40931c83a1bSms148562 		    s3_priv->saveGR[i]);
41031c83a1bSms148562 
41131c83a1bSms148562 	i915_write_indexed(&regmap, VGA_GR_INDEX, VGA_GR_DATA, 0x10,
41231c83a1bSms148562 	    s3_priv->saveGR[0x10]);
41331c83a1bSms148562 	i915_write_indexed(&regmap, VGA_GR_INDEX, VGA_GR_DATA, 0x11,
41431c83a1bSms148562 	    s3_priv->saveGR[0x11]);
41531c83a1bSms148562 	i915_write_indexed(&regmap, VGA_GR_INDEX, VGA_GR_DATA, 0x18,
41631c83a1bSms148562 	    s3_priv->saveGR[0x18]);
41731c83a1bSms148562 
41831c83a1bSms148562 	/* Attribute controller registers */
41931c83a1bSms148562 	(void) vga_reg_get8(&regmap, st01); /* switch back to index mode */
420fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	for (i = 0; i <= 0x14; i++)
42131c83a1bSms148562 	    i915_write_ar(&regmap, st01, i, s3_priv->saveAR[i], 0);
42231c83a1bSms148562 	(void) vga_reg_get8(&regmap, st01); /* switch back to index mode */
42331c83a1bSms148562 	vga_reg_put8(&regmap, VGA_AR_INDEX, s3_priv->saveAR_INDEX | 0x20);
42431c83a1bSms148562 	(void) vga_reg_get8(&regmap, st01); /* switch back to index mode */
42531c83a1bSms148562 
42631c83a1bSms148562 	/* VGA color palette registers */
42731c83a1bSms148562 	vga_reg_put8(&regmap, VGA_DACMASK, s3_priv->saveDACMASK);
42831c83a1bSms148562 	/* DACCRX automatically increments during read */
42931c83a1bSms148562 	vga_reg_put8(&regmap, VGA_DACWX, 0);
43031c83a1bSms148562 	/* Read 3 bytes of color data from each index */
43131c83a1bSms148562 	for (i = 0; i < 256 * 3; i++)
43231c83a1bSms148562 		vga_reg_put8(&regmap, VGA_DACDATA, s3_priv->saveDACDATA[i]);
43331c83a1bSms148562 }
43431c83a1bSms148562 
435*0035d21cSmiao chen - Sun Microsystems - Beijing China /**
436*0035d21cSmiao chen - Sun Microsystems - Beijing China  * i915_save_display - save display & mode info
437*0035d21cSmiao chen - Sun Microsystems - Beijing China  * @dev: DRM device
438*0035d21cSmiao chen - Sun Microsystems - Beijing China  *
439*0035d21cSmiao chen - Sun Microsystems - Beijing China  * Save mode timings and display info.
44031c83a1bSms148562  */
i915_save_display(struct drm_device * dev)441*0035d21cSmiao chen - Sun Microsystems - Beijing China void i915_save_display(struct drm_device *dev)
442*0035d21cSmiao chen - Sun Microsystems - Beijing China {
443*0035d21cSmiao chen - Sun Microsystems - Beijing China 	struct s3_i915_private *s3_priv = dev->s3_private;
444*0035d21cSmiao chen - Sun Microsystems - Beijing China 
445*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/* Display arbitration control */
446*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPARB = S3_READ(DSPARB);
447*0035d21cSmiao chen - Sun Microsystems - Beijing China 
448*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/*
449*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 * Pipe & plane A info.
450*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 */
451*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->savePIPEACONF = S3_READ(PIPEACONF);
452*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->savePIPEASRC = S3_READ(PIPEASRC);
453*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveFPA0 = S3_READ(FPA0);
454*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveFPA1 = S3_READ(FPA1);
455*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDPLL_A = S3_READ(DPLL_A);
456*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_I965G(dev))
457*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->saveDPLL_A_MD = S3_READ(DPLL_A_MD);
458*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveHTOTAL_A = S3_READ(HTOTAL_A);
459*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveHBLANK_A = S3_READ(HBLANK_A);
460*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveHSYNC_A = S3_READ(HSYNC_A);
461*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVTOTAL_A = S3_READ(VTOTAL_A);
462*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVBLANK_A = S3_READ(VBLANK_A);
463*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVSYNC_A = S3_READ(VSYNC_A);
464*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveBCLRPAT_A = S3_READ(BCLRPAT_A);
465*0035d21cSmiao chen - Sun Microsystems - Beijing China 
466*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPACNTR = S3_READ(DSPACNTR);
467*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPASTRIDE = S3_READ(DSPASTRIDE);
468*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPASIZE = S3_READ(DSPASIZE);
469*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPAPOS = S3_READ(DSPAPOS);
470*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPABASE = S3_READ(DSPABASE);
471*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_I965G(dev)) {
472*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->saveDSPASURF = S3_READ(DSPASURF);
473*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->saveDSPATILEOFF = S3_READ(DSPATILEOFF);
474*0035d21cSmiao chen - Sun Microsystems - Beijing China 	}
475*0035d21cSmiao chen - Sun Microsystems - Beijing China 	i915_save_palette(dev, PIPE_A);
476*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->savePIPEASTAT = S3_READ(PIPEASTAT);
477*0035d21cSmiao chen - Sun Microsystems - Beijing China 
478*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/*
479*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 * Pipe & plane B info
480*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 */
481*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->savePIPEBCONF = S3_READ(PIPEBCONF);
482*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->savePIPEBSRC = S3_READ(PIPEBSRC);
483*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveFPB0 = S3_READ(FPB0);
484*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveFPB1 = S3_READ(FPB1);
485*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDPLL_B = S3_READ(DPLL_B);
486*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_I965G(dev))
487*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->saveDPLL_B_MD = S3_READ(DPLL_B_MD);
488*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveHTOTAL_B = S3_READ(HTOTAL_B);
489*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveHBLANK_B = S3_READ(HBLANK_B);
490*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveHSYNC_B = S3_READ(HSYNC_B);
491*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVTOTAL_B = S3_READ(VTOTAL_B);
492*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVBLANK_B = S3_READ(VBLANK_B);
493*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVSYNC_B = S3_READ(VSYNC_B);
494*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveBCLRPAT_A = S3_READ(BCLRPAT_A);
495*0035d21cSmiao chen - Sun Microsystems - Beijing China 
496*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPBCNTR = S3_READ(DSPBCNTR);
497*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPBSTRIDE = S3_READ(DSPBSTRIDE);
498*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPBSIZE = S3_READ(DSPBSIZE);
499*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPBPOS = S3_READ(DSPBPOS);
500*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveDSPBBASE = S3_READ(DSPBBASE);
501*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_I965GM(dev) || IS_GM45(dev)) {
502*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->saveDSPBSURF = S3_READ(DSPBSURF);
503*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->saveDSPBTILEOFF = S3_READ(DSPBTILEOFF);
504*0035d21cSmiao chen - Sun Microsystems - Beijing China 	}
505*0035d21cSmiao chen - Sun Microsystems - Beijing China 	i915_save_palette(dev, PIPE_B);
506*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->savePIPEBSTAT = S3_READ(PIPEBSTAT);
507*0035d21cSmiao chen - Sun Microsystems - Beijing China 
508*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/*
509*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 * CRT state
510*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 */
511*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveADPA = S3_READ(ADPA);
512*0035d21cSmiao chen - Sun Microsystems - Beijing China 
513*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/*
514*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 * LVDS state
515*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 */
516*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->savePP_CONTROL = S3_READ(PP_CONTROL);
517*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->savePFIT_PGM_RATIOS = S3_READ(PFIT_PGM_RATIOS);
518*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveBLC_PWM_CTL = S3_READ(BLC_PWM_CTL);
519*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_I965G(dev))
520*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->saveBLC_PWM_CTL2 = S3_READ(BLC_PWM_CTL2);
521*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_MOBILE(dev) && !IS_I830(dev))
522*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->saveLVDS = S3_READ(LVDS);
523*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (!IS_I830(dev) && !IS_845G(dev))
524*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->savePFIT_CONTROL = S3_READ(PFIT_CONTROL);
525*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveLVDSPP_ON = S3_READ(LVDSPP_ON);
526*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveLVDSPP_OFF = S3_READ(LVDSPP_OFF);
527*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->savePP_CYCLE = S3_READ(PP_CYCLE);
528*0035d21cSmiao chen - Sun Microsystems - Beijing China 
529*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/* FIXME: save TV & SDVO state */
530*0035d21cSmiao chen - Sun Microsystems - Beijing China 
531*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/* FBC state */
532*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveFBC_CFB_BASE = S3_READ(FBC_CFB_BASE);
533*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveFBC_LL_BASE = S3_READ(FBC_LL_BASE);
534*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveFBC_CONTROL2 = S3_READ(FBC_CONTROL2);
535*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveFBC_CONTROL = S3_READ(FBC_CONTROL);
536*0035d21cSmiao chen - Sun Microsystems - Beijing China 
537*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/* VGA state */
538*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVCLK_DIVISOR_VGA0 = S3_READ(VCLK_DIVISOR_VGA0);
539*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVCLK_DIVISOR_VGA1 = S3_READ(VCLK_DIVISOR_VGA1);
540*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVCLK_POST_DIV = S3_READ(VCLK_POST_DIV);
541*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveVGACNTRL = S3_READ(VGACNTRL);
542*0035d21cSmiao chen - Sun Microsystems - Beijing China 
543*0035d21cSmiao chen - Sun Microsystems - Beijing China 	i915_save_vga(dev);
544*0035d21cSmiao chen - Sun Microsystems - Beijing China }
545*0035d21cSmiao chen - Sun Microsystems - Beijing China 
i915_restore_display(struct drm_device * dev)546*0035d21cSmiao chen - Sun Microsystems - Beijing China void i915_restore_display(struct drm_device *dev)
547*0035d21cSmiao chen - Sun Microsystems - Beijing China {
548*0035d21cSmiao chen - Sun Microsystems - Beijing China         struct s3_i915_private *s3_priv = dev->s3_private;
549fc6df3bdSmiao chen - Sun Microsystems - Beijing China 
550fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	S3_WRITE(DSPARB, s3_priv->saveDSPARB);
551fc6df3bdSmiao chen - Sun Microsystems - Beijing China 
55231c83a1bSms148562 	/*
55331c83a1bSms148562 	 * Pipe & plane A info
55431c83a1bSms148562 	 * Prime the clock
55531c83a1bSms148562 	 */
55631c83a1bSms148562 	if (s3_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
55731c83a1bSms148562 		S3_WRITE(DPLL_A, s3_priv->saveDPLL_A &
55831c83a1bSms148562 		    ~DPLL_VCO_ENABLE);
55931c83a1bSms148562 		drv_usecwait(150);
56031c83a1bSms148562         }
56131c83a1bSms148562 	S3_WRITE(FPA0, s3_priv->saveFPA0);
56231c83a1bSms148562 	S3_WRITE(FPA1, s3_priv->saveFPA1);
56331c83a1bSms148562 	/* Actually enable it */
56431c83a1bSms148562 	S3_WRITE(DPLL_A, s3_priv->saveDPLL_A);
56531c83a1bSms148562 	drv_usecwait(150);
56631c83a1bSms148562 	if (IS_I965G(dev))
56731c83a1bSms148562 		S3_WRITE(DPLL_A_MD, s3_priv->saveDPLL_A_MD);
56831c83a1bSms148562 	drv_usecwait(150);
56931c83a1bSms148562 
57031c83a1bSms148562 	/* Restore mode */
57131c83a1bSms148562 	S3_WRITE(HTOTAL_A, s3_priv->saveHTOTAL_A);
57231c83a1bSms148562 	S3_WRITE(HBLANK_A, s3_priv->saveHBLANK_A);
57331c83a1bSms148562 	S3_WRITE(HSYNC_A, s3_priv->saveHSYNC_A);
57431c83a1bSms148562 	S3_WRITE(VTOTAL_A, s3_priv->saveVTOTAL_A);
57531c83a1bSms148562 	S3_WRITE(VBLANK_A, s3_priv->saveVBLANK_A);
57631c83a1bSms148562 	S3_WRITE(VSYNC_A, s3_priv->saveVSYNC_A);
57731c83a1bSms148562 	S3_WRITE(BCLRPAT_A, s3_priv->saveBCLRPAT_A);
57831c83a1bSms148562 
57931c83a1bSms148562 	/* Restore plane info */
58031c83a1bSms148562 	S3_WRITE(DSPASIZE, s3_priv->saveDSPASIZE);
58131c83a1bSms148562 	S3_WRITE(DSPAPOS, s3_priv->saveDSPAPOS);
58231c83a1bSms148562 	S3_WRITE(PIPEASRC, s3_priv->savePIPEASRC);
58331c83a1bSms148562 	S3_WRITE(DSPABASE, s3_priv->saveDSPABASE);
58431c83a1bSms148562 	S3_WRITE(DSPASTRIDE, s3_priv->saveDSPASTRIDE);
58531c83a1bSms148562 	if (IS_I965G(dev)) {
58631c83a1bSms148562 		S3_WRITE(DSPASURF, s3_priv->saveDSPASURF);
58731c83a1bSms148562 		S3_WRITE(DSPATILEOFF, s3_priv->saveDSPATILEOFF);
58831c83a1bSms148562 	}
58931c83a1bSms148562 	S3_WRITE(PIPEACONF, s3_priv->savePIPEACONF);
59031c83a1bSms148562 	i915_restore_palette(dev, PIPE_A);
59131c83a1bSms148562 	/* Enable the plane */
59231c83a1bSms148562 	S3_WRITE(DSPACNTR, s3_priv->saveDSPACNTR);
59331c83a1bSms148562 	S3_WRITE(DSPABASE, S3_READ(DSPABASE));
59431c83a1bSms148562 
59531c83a1bSms148562 	/* Pipe & plane B info */
59631c83a1bSms148562 	if (s3_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
59731c83a1bSms148562 		S3_WRITE(DPLL_B, s3_priv->saveDPLL_B &
59831c83a1bSms148562 		    ~DPLL_VCO_ENABLE);
59931c83a1bSms148562 		drv_usecwait(150);
60031c83a1bSms148562 	}
60131c83a1bSms148562 	S3_WRITE(FPB0, s3_priv->saveFPB0);
60231c83a1bSms148562 	S3_WRITE(FPB1, s3_priv->saveFPB1);
60331c83a1bSms148562 	/* Actually enable it */
60431c83a1bSms148562 	S3_WRITE(DPLL_B, s3_priv->saveDPLL_B);
60531c83a1bSms148562 	drv_usecwait(150);
60631c83a1bSms148562 	if (IS_I965G(dev))
60731c83a1bSms148562 		S3_WRITE(DPLL_B_MD, s3_priv->saveDPLL_B_MD);
60831c83a1bSms148562 	drv_usecwait(150);
60931c83a1bSms148562 
61031c83a1bSms148562 	/* Restore mode */
61131c83a1bSms148562 	S3_WRITE(HTOTAL_B, s3_priv->saveHTOTAL_B);
61231c83a1bSms148562 	S3_WRITE(HBLANK_B, s3_priv->saveHBLANK_B);
61331c83a1bSms148562 	S3_WRITE(HSYNC_B, s3_priv->saveHSYNC_B);
61431c83a1bSms148562 	S3_WRITE(VTOTAL_B, s3_priv->saveVTOTAL_B);
61531c83a1bSms148562 	S3_WRITE(VBLANK_B, s3_priv->saveVBLANK_B);
61631c83a1bSms148562 	S3_WRITE(VSYNC_B, s3_priv->saveVSYNC_B);
61731c83a1bSms148562 	S3_WRITE(BCLRPAT_B, s3_priv->saveBCLRPAT_B);
61831c83a1bSms148562 
61931c83a1bSms148562 	/* Restore plane info */
62031c83a1bSms148562 	S3_WRITE(DSPBSIZE, s3_priv->saveDSPBSIZE);
62131c83a1bSms148562 	S3_WRITE(DSPBPOS, s3_priv->saveDSPBPOS);
62231c83a1bSms148562 	S3_WRITE(PIPEBSRC, s3_priv->savePIPEBSRC);
62331c83a1bSms148562 	S3_WRITE(DSPBBASE, s3_priv->saveDSPBBASE);
62431c83a1bSms148562 	S3_WRITE(DSPBSTRIDE, s3_priv->saveDSPBSTRIDE);
62531c83a1bSms148562 	if (IS_I965G(dev)) {
62631c83a1bSms148562 		S3_WRITE(DSPBSURF, s3_priv->saveDSPBSURF);
62731c83a1bSms148562 		S3_WRITE(DSPBTILEOFF, s3_priv->saveDSPBTILEOFF);
62831c83a1bSms148562         }
62931c83a1bSms148562 	S3_WRITE(PIPEBCONF, s3_priv->savePIPEBCONF);
63031c83a1bSms148562 	i915_restore_palette(dev, PIPE_B);
63131c83a1bSms148562 	/* Enable the plane */
63231c83a1bSms148562 	S3_WRITE(DSPBCNTR, s3_priv->saveDSPBCNTR);
63331c83a1bSms148562         S3_WRITE(DSPBBASE, S3_READ(DSPBBASE));
63431c83a1bSms148562 
63531c83a1bSms148562 	/* CRT state */
63631c83a1bSms148562 	S3_WRITE(ADPA, s3_priv->saveADPA);
63731c83a1bSms148562 
63831c83a1bSms148562 	/* LVDS state */
63931c83a1bSms148562 	if (IS_I965G(dev))
64031c83a1bSms148562 		S3_WRITE(BLC_PWM_CTL2, s3_priv->saveBLC_PWM_CTL2);
64131c83a1bSms148562 	if (IS_MOBILE(dev) && !IS_I830(dev))
64231c83a1bSms148562 		S3_WRITE(LVDS, s3_priv->saveLVDS);
64331c83a1bSms148562 	if (!IS_I830(dev) && !IS_845G(dev))
64431c83a1bSms148562 		S3_WRITE(PFIT_CONTROL, s3_priv->savePFIT_CONTROL);
64531c83a1bSms148562 
64631c83a1bSms148562 	S3_WRITE(PFIT_PGM_RATIOS, s3_priv->savePFIT_PGM_RATIOS);
64731c83a1bSms148562 	S3_WRITE(BLC_PWM_CTL, s3_priv->saveBLC_PWM_CTL);
64831c83a1bSms148562         S3_WRITE(LVDSPP_ON, s3_priv->saveLVDSPP_ON);
64931c83a1bSms148562         S3_WRITE(LVDSPP_OFF, s3_priv->saveLVDSPP_OFF);
65031c83a1bSms148562         S3_WRITE(PP_CYCLE, s3_priv->savePP_CYCLE);
65131c83a1bSms148562         S3_WRITE(PP_CONTROL, s3_priv->savePP_CONTROL);
65231c83a1bSms148562 
65331c83a1bSms148562 	/* FIXME: restore TV & SDVO state */
65431c83a1bSms148562 
65531c83a1bSms148562 	/* FBC info */
65631c83a1bSms148562 	S3_WRITE(FBC_CFB_BASE, s3_priv->saveFBC_CFB_BASE);
65731c83a1bSms148562 	S3_WRITE(FBC_LL_BASE, s3_priv->saveFBC_LL_BASE);
65831c83a1bSms148562 	S3_WRITE(FBC_CONTROL2, s3_priv->saveFBC_CONTROL2);
65931c83a1bSms148562 	S3_WRITE(FBC_CONTROL, s3_priv->saveFBC_CONTROL);
66031c83a1bSms148562 
66131c83a1bSms148562 	/* VGA state */
66231c83a1bSms148562 	S3_WRITE(VGACNTRL, s3_priv->saveVGACNTRL);
66331c83a1bSms148562 	S3_WRITE(VCLK_DIVISOR_VGA0, s3_priv->saveVCLK_DIVISOR_VGA0);
66431c83a1bSms148562 	S3_WRITE(VCLK_DIVISOR_VGA1, s3_priv->saveVCLK_DIVISOR_VGA1);
66531c83a1bSms148562 	S3_WRITE(VCLK_POST_DIV, s3_priv->saveVCLK_POST_DIV);
66631c83a1bSms148562 	drv_usecwait(150);
66731c83a1bSms148562 
668*0035d21cSmiao chen - Sun Microsystems - Beijing China 	i915_restore_vga(dev);
669*0035d21cSmiao chen - Sun Microsystems - Beijing China }
670*0035d21cSmiao chen - Sun Microsystems - Beijing China static int
i915_resume(struct drm_device * dev)671*0035d21cSmiao chen - Sun Microsystems - Beijing China i915_resume(struct drm_device *dev)
672*0035d21cSmiao chen - Sun Microsystems - Beijing China {
673*0035d21cSmiao chen - Sun Microsystems - Beijing China 	ddi_acc_handle_t conf_hdl;
674*0035d21cSmiao chen - Sun Microsystems - Beijing China 	struct s3_i915_private *s3_priv = dev->s3_private;
675*0035d21cSmiao chen - Sun Microsystems - Beijing China 	int i;
676*0035d21cSmiao chen - Sun Microsystems - Beijing China 
677*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (pci_config_setup(dev->dip, &conf_hdl) != DDI_SUCCESS) {
678*0035d21cSmiao chen - Sun Microsystems - Beijing China 		DRM_ERROR(("i915_resume: pci_config_setup fail"));
679*0035d21cSmiao chen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
680*0035d21cSmiao chen - Sun Microsystems - Beijing China 	}
681*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/*
682*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 * Nexus driver will resume pci config space and set the power state
683*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 * for its children. So we needn't resume them explicitly here.
684*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 * see pci_pre_resume for detail.
685*0035d21cSmiao chen - Sun Microsystems - Beijing China 	 */
686*0035d21cSmiao chen - Sun Microsystems - Beijing China 	pci_config_put8(conf_hdl, LBB, s3_priv->saveLBB);
687*0035d21cSmiao chen - Sun Microsystems - Beijing China 
688*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_I965G(dev) && IS_MOBILE(dev))
689*0035d21cSmiao chen - Sun Microsystems - Beijing China 		S3_WRITE(MCHBAR_RENDER_STANDBY, s3_priv->saveRENDERSTANDBY);
690*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_I965GM(dev))
691*0035d21cSmiao chen - Sun Microsystems - Beijing China 		(void) S3_READ(MCHBAR_RENDER_STANDBY);
692*0035d21cSmiao chen - Sun Microsystems - Beijing China 
693*0035d21cSmiao chen - Sun Microsystems - Beijing China 	S3_WRITE(HWS_PGA, s3_priv->saveHWS);
694*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_I965GM(dev))
695*0035d21cSmiao chen - Sun Microsystems - Beijing China 		(void) S3_READ(HWS_PGA);
696*0035d21cSmiao chen - Sun Microsystems - Beijing China 
697*0035d21cSmiao chen - Sun Microsystems - Beijing China 	i915_restore_display(dev);
698*0035d21cSmiao chen - Sun Microsystems - Beijing China 
69931c83a1bSms148562 	 /* Clock gating state */
700fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	S3_WRITE (D_STATE, s3_priv->saveD_STATE);
701fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	S3_WRITE (CG_2D_DIS, s3_priv->saveCG_2D_DIS);
70231c83a1bSms148562 
70331c83a1bSms148562 	/* Cache mode state */
70431c83a1bSms148562 	S3_WRITE (CACHE_MODE_0, s3_priv->saveCACHE_MODE_0 | 0xffff0000);
70531c83a1bSms148562 
70631c83a1bSms148562 	/* Memory arbitration state */
70731c83a1bSms148562 	S3_WRITE (MI_ARB_STATE, s3_priv->saveMI_ARB_STATE | 0xffff0000);
70831c83a1bSms148562 
70931c83a1bSms148562 	for (i = 0; i < 16; i++) {
71031c83a1bSms148562 		S3_WRITE(SWF0 + (i << 2), s3_priv->saveSWF0[i]);
71131c83a1bSms148562 		S3_WRITE(SWF10 + (i << 2), s3_priv->saveSWF1[i+7]);
71231c83a1bSms148562         }
71331c83a1bSms148562 	for (i = 0; i < 3; i++)
71431c83a1bSms148562 		S3_WRITE(SWF30 + (i << 2), s3_priv->saveSWF2[i]);
71531c83a1bSms148562 
71631c83a1bSms148562 	S3_WRITE(I915REG_PGTBL_CTRL, s3_priv->pgtbl_ctl);
71731c83a1bSms148562 
71831c83a1bSms148562 	(void) pci_config_teardown(&conf_hdl);
71931c83a1bSms148562 
720*0035d21cSmiao chen - Sun Microsystems - Beijing China 	drm_agp_rebind(dev);
721*0035d21cSmiao chen - Sun Microsystems - Beijing China 
72231c83a1bSms148562 	return (DDI_SUCCESS);
72331c83a1bSms148562 }
724*0035d21cSmiao chen - Sun Microsystems - Beijing China 
72531c83a1bSms148562 static int
i915_suspend(struct drm_device * dev)72631c83a1bSms148562 i915_suspend(struct drm_device *dev)
72731c83a1bSms148562 {
72831c83a1bSms148562 	ddi_acc_handle_t conf_hdl;
72931c83a1bSms148562 	struct s3_i915_private *s3_priv = dev->s3_private;
73031c83a1bSms148562 	int i;
73131c83a1bSms148562 
73231c83a1bSms148562 	if (pci_config_setup(dev->dip, &conf_hdl) != DDI_SUCCESS) {
73331c83a1bSms148562 		DRM_ERROR(("i915_suspend: pci_config_setup fail"));
73431c83a1bSms148562 		return (DDI_FAILURE);
73531c83a1bSms148562 	}
73631c83a1bSms148562 
73731c83a1bSms148562 	/*
73831c83a1bSms148562 	 * Nexus driver will resume pci config space for its children.
73931c83a1bSms148562 	 * So pci config registers are not saved here.
74031c83a1bSms148562 	 */
74131c83a1bSms148562 	s3_priv->saveLBB = pci_config_get8(conf_hdl, LBB);
74231c83a1bSms148562 
743*0035d21cSmiao chen - Sun Microsystems - Beijing China 	if (IS_I965G(dev) && IS_MOBILE(dev))
744*0035d21cSmiao chen - Sun Microsystems - Beijing China 		s3_priv->saveRENDERSTANDBY = S3_READ(MCHBAR_RENDER_STANDBY);
745fc6df3bdSmiao chen - Sun Microsystems - Beijing China 
746*0035d21cSmiao chen - Sun Microsystems - Beijing China 	/* Hardware status page */
747*0035d21cSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveHWS = S3_READ(HWS_PGA);
74831c83a1bSms148562 
749*0035d21cSmiao chen - Sun Microsystems - Beijing China 	i915_save_display(dev);
75031c83a1bSms148562 
75131c83a1bSms148562 	/* Interrupt state */
752d0231070Smiao chen - Sun Microsystems - Beijing China 	s3_priv->saveIIR = S3_READ(IIR);
753d0231070Smiao chen - Sun Microsystems - Beijing China 	s3_priv->saveIER = S3_READ(IER);
754d0231070Smiao chen - Sun Microsystems - Beijing China 	s3_priv->saveIMR = S3_READ(IMR);
75531c83a1bSms148562 
75631c83a1bSms148562 	/* Clock gating state */
757fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveD_STATE = S3_READ(D_STATE);
758fc6df3bdSmiao chen - Sun Microsystems - Beijing China 	s3_priv->saveCG_2D_DIS = S3_READ(CG_2D_DIS);
75931c83a1bSms148562 
76031c83a1bSms148562 	/* Cache mode state */
76131c83a1bSms148562 	s3_priv->saveCACHE_MODE_0 = S3_READ(CACHE_MODE_0);
76231c83a1bSms148562 
76331c83a1bSms148562 	/* Memory Arbitration state */
76431c83a1bSms148562 	s3_priv->saveMI_ARB_STATE = S3_READ(MI_ARB_STATE);
76531c83a1bSms148562 
76631c83a1bSms148562 	/* Scratch space */
76731c83a1bSms148562 	for (i = 0; i < 16; i++) {
76831c83a1bSms148562 		s3_priv->saveSWF0[i] = S3_READ(SWF0 + (i << 2));
76931c83a1bSms148562 		s3_priv->saveSWF1[i] = S3_READ(SWF10 + (i << 2));
77031c83a1bSms148562 	}
77131c83a1bSms148562 	for (i = 0; i < 3; i++)
77231c83a1bSms148562 		s3_priv->saveSWF2[i] = S3_READ(SWF30 + (i << 2));
77331c83a1bSms148562 
77431c83a1bSms148562 	/*
77531c83a1bSms148562 	 * Save page table control register
77631c83a1bSms148562 	 */
77731c83a1bSms148562 	s3_priv->pgtbl_ctl = S3_READ(I915REG_PGTBL_CTRL);
77831c83a1bSms148562 
77931c83a1bSms148562 	(void) pci_config_teardown(&conf_hdl);
78031c83a1bSms148562 
78131c83a1bSms148562 	return (DDI_SUCCESS);
78231c83a1bSms148562 }
78331c83a1bSms148562 
78431c83a1bSms148562 /*
78531c83a1bSms148562  * This funtion check the length of memory mapped IO space to get the right bar. * And There are two possibilities here.
78631c83a1bSms148562  * 1. The MMIO registers is in memory map IO bar with 1M size. The bottom half
78731c83a1bSms148562  *    of the 1M space is the MMIO registers.
78831c83a1bSms148562  * 2. The MMIO register is in memory map IO with 512K size. The whole 512K
78931c83a1bSms148562  *    space is the MMIO registers.
79031c83a1bSms148562  */
79131c83a1bSms148562 static int
i915_map_regs(dev_info_t * dip,caddr_t * save_addr,ddi_acc_handle_t * handlep)79231c83a1bSms148562 i915_map_regs(dev_info_t *dip, caddr_t *save_addr, ddi_acc_handle_t *handlep)
79331c83a1bSms148562 {
79431c83a1bSms148562 	int	rnumber;
79531c83a1bSms148562 	int	nregs;
79631c83a1bSms148562 	off_t	size = 0;
79731c83a1bSms148562 
79831c83a1bSms148562 	if (ddi_dev_nregs(dip, &nregs)) {
79931c83a1bSms148562 		cmn_err(CE_WARN, "i915_map_regs: failed to get nregs");
80031c83a1bSms148562 		return (DDI_FAILURE);
80131c83a1bSms148562 	}
80231c83a1bSms148562 
80331c83a1bSms148562 	for (rnumber = 1; rnumber < nregs; rnumber++) {
80431c83a1bSms148562 		(void) ddi_dev_regsize(dip, rnumber, &size);
80531c83a1bSms148562 		if ((size == 0x80000) ||
806fc6df3bdSmiao chen - Sun Microsystems - Beijing China 		    (size == 0x100000) ||
807fc6df3bdSmiao chen - Sun Microsystems - Beijing China 		    (size == 0x400000))
80831c83a1bSms148562 			break;
80931c83a1bSms148562 	}
81031c83a1bSms148562 
81131c83a1bSms148562 	if (rnumber >= nregs) {
81231c83a1bSms148562 		cmn_err(CE_WARN,
81331c83a1bSms148562 		    "i915_map_regs: failed to find MMIO registers");
81431c83a1bSms148562 		return (DDI_FAILURE);
81531c83a1bSms148562 	}
81631c83a1bSms148562 
81731c83a1bSms148562 	if (ddi_regs_map_setup(dip, rnumber, save_addr,
81831c83a1bSms148562 	    0, 0x80000, &s3_attr, handlep)) {
81931c83a1bSms148562 		cmn_err(CE_WARN,
82031c83a1bSms148562 		    "i915_map_regs: failed to map bar %d", rnumber);
82131c83a1bSms148562 		return (DDI_FAILURE);
82231c83a1bSms148562 	}
82331c83a1bSms148562 
82431c83a1bSms148562 	return (DDI_SUCCESS);
82531c83a1bSms148562 }
82631c83a1bSms148562 static void
i915_unmap_regs(ddi_acc_handle_t * handlep)82731c83a1bSms148562 i915_unmap_regs(ddi_acc_handle_t *handlep)
82831c83a1bSms148562 {
82931c83a1bSms148562 	ddi_regs_map_free(handlep);
83031c83a1bSms148562 }
831d0538f66Scg149915 static int
i915_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)832d0538f66Scg149915 i915_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
833d0538f66Scg149915 {
834d0538f66Scg149915 	drm_device_t		*statep;
83531c83a1bSms148562 	s3_i915_private_t	*s3_private;
836d0538f66Scg149915 	void		*handle;
837d0538f66Scg149915 	int			unit;
838ae115bc7Smrj 
83931c83a1bSms148562 	unit =  ddi_get_instance(dip);
84031c83a1bSms148562 	switch (cmd) {
84131c83a1bSms148562 	case DDI_ATTACH:
84231c83a1bSms148562 		break;
84331c83a1bSms148562 	case DDI_RESUME:
84431c83a1bSms148562 		statep = ddi_get_soft_state(i915_statep, unit);
84531c83a1bSms148562 		return (i915_resume(statep));
84631c83a1bSms148562 	default:
84731c83a1bSms148562 		DRM_ERROR("i915_attach: attach and resume ops are supported");
848ae115bc7Smrj 		return (DDI_FAILURE);
84931c83a1bSms148562 
850ae115bc7Smrj 	}
851ae115bc7Smrj 
852d0538f66Scg149915 	if (ddi_soft_state_zalloc(i915_statep, unit) != DDI_SUCCESS) {
85331c83a1bSms148562 			cmn_err(CE_WARN,
85431c83a1bSms148562 			    "i915_attach: failed to alloc softstate");
855d0538f66Scg149915 			return (DDI_FAILURE);
856d0538f66Scg149915 	}
857d0538f66Scg149915 	statep = ddi_get_soft_state(i915_statep, unit);
858d0538f66Scg149915 	statep->dip = dip;
859d0538f66Scg149915 	statep->driver = &i915_driver;
860ae115bc7Smrj 
86131c83a1bSms148562 	statep->s3_private = drm_alloc(sizeof(s3_i915_private_t),
86231c83a1bSms148562 	    DRM_MEM_DRIVER);
86331c83a1bSms148562 
86431c83a1bSms148562 	if (statep->s3_private == NULL) {
86531c83a1bSms148562 		cmn_err(CE_WARN, "i915_attach: failed to allocate s3 priv");
86631c83a1bSms148562 		goto err_exit1;
86731c83a1bSms148562 	}
86831c83a1bSms148562 
86931c83a1bSms148562 	/*
87031c83a1bSms148562 	 * Map in the mmio register space for s3.
87131c83a1bSms148562 	 */
87231c83a1bSms148562 	s3_private = (s3_i915_private_t *)statep->s3_private;
87331c83a1bSms148562 
87431c83a1bSms148562 	if (i915_map_regs(dip, &s3_private->saveAddr,
87531c83a1bSms148562 	    &s3_private->saveHandle)) {
87631c83a1bSms148562 		cmn_err(CE_WARN, "i915_attach: failed to map MMIO");
87731c83a1bSms148562 		goto err_exit2;
87831c83a1bSms148562 	}
87931c83a1bSms148562 
880d0538f66Scg149915 	/*
881d0538f66Scg149915 	 * Call drm_supp_register to create minor nodes for us
882d0538f66Scg149915 	 */
883d0538f66Scg149915 	handle = drm_supp_register(dip, statep);
884d0538f66Scg149915 	if ( handle == NULL) {
885d0538f66Scg149915 		DRM_ERROR("i915_attach: drm_supp_register failed");
88631c83a1bSms148562 		goto err_exit3;
887d0538f66Scg149915 	}
888d0538f66Scg149915 	statep->drm_handle = handle;
889d0538f66Scg149915 
890d0538f66Scg149915 	/*
891d0538f66Scg149915 	 * After drm_supp_register, we can call drm_xxx routine
892d0538f66Scg149915 	 */
893d0538f66Scg149915 	statep->drm_supported = DRM_UNSUPPORT;
89431c83a1bSms148562 	if (
89531c83a1bSms148562 		    drm_probe(statep, i915_pciidlist) != DDI_SUCCESS) {
896d0538f66Scg149915 		DRM_ERROR("i915_open: "
897d0538f66Scg149915 		    "DRM current don't support this graphics card");
89831c83a1bSms148562 		goto err_exit4;
899d0538f66Scg149915 	}
900d0538f66Scg149915 	statep->drm_supported = DRM_SUPPORT;
901ae115bc7Smrj 
902ae115bc7Smrj 	/* call common attach code */
903d0538f66Scg149915 	if (drm_attach(statep) != DDI_SUCCESS) {
904d0538f66Scg149915 		DRM_ERROR("i915_attach: drm_attach failed");
90531c83a1bSms148562 		goto err_exit4;
906ae115bc7Smrj 	}
907ae115bc7Smrj 	return (DDI_SUCCESS);
90831c83a1bSms148562 err_exit4:
909d0538f66Scg149915 	(void) drm_supp_unregister(handle);
91031c83a1bSms148562 err_exit3:
91131c83a1bSms148562 	i915_unmap_regs(&s3_private->saveHandle);
91231c83a1bSms148562 err_exit2:
91331c83a1bSms148562 	drm_free(statep->s3_private, sizeof(s3_i915_private_t),
91431c83a1bSms148562 	    DRM_MEM_DRIVER);
915d0538f66Scg149915 err_exit1:
916d0538f66Scg149915 	(void) ddi_soft_state_free(i915_statep, unit);
91731c83a1bSms148562 
918ae115bc7Smrj 	return (DDI_FAILURE);
919ae115bc7Smrj 
920d0538f66Scg149915 }	/* i915_attach() */
921ae115bc7Smrj 
922d0538f66Scg149915 static int
i915_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)923d0538f66Scg149915 i915_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
924ae115bc7Smrj {
925d0538f66Scg149915 	drm_device_t		*statep;
926d0538f66Scg149915 	int		unit;
92731c83a1bSms148562 	s3_i915_private_t	*s3_private;
928ae115bc7Smrj 
92931c83a1bSms148562 	if ((cmd != DDI_SUSPEND) && (cmd != DDI_DETACH)) {
93031c83a1bSms148562 			DRM_ERROR("i915_detach: "
93131c83a1bSms148562 			    "only detach and resume ops are supported");
932ae115bc7Smrj 			return (DDI_FAILURE);
93331c83a1bSms148562 	}
934ae115bc7Smrj 
935d0538f66Scg149915 	unit =  ddi_get_instance(dip);
936d0538f66Scg149915 	statep = ddi_get_soft_state(i915_statep, unit);
93731c83a1bSms148562 	if (statep == NULL) {
93831c83a1bSms148562 		DRM_ERROR("i915_detach: can not get soft state");
939d0538f66Scg149915 		return (DDI_FAILURE);
94031c83a1bSms148562 	}
94131c83a1bSms148562 
94231c83a1bSms148562 	if (cmd == DDI_SUSPEND)
94331c83a1bSms148562 			return (i915_suspend(statep));
94431c83a1bSms148562 
94531c83a1bSms148562 	s3_private = (s3_i915_private_t *)statep->s3_private;
94631c83a1bSms148562 	ddi_regs_map_free(&s3_private->saveHandle);
94731c83a1bSms148562 
94831c83a1bSms148562 	/*
94931c83a1bSms148562 	 * Free the struct for context saving in S3
95031c83a1bSms148562 	 */
95131c83a1bSms148562 	drm_free(statep->s3_private, sizeof(s3_i915_private_t),
95231c83a1bSms148562 	    DRM_MEM_DRIVER);
953ae115bc7Smrj 
954d0538f66Scg149915 	(void) drm_detach(statep);
955d0538f66Scg149915 	(void) drm_supp_unregister(statep->drm_handle);
956d0538f66Scg149915 	(void) ddi_soft_state_free(i915_statep, unit);
957ae115bc7Smrj 
958ae115bc7Smrj 	return (DDI_SUCCESS);
959d0538f66Scg149915 
960d0538f66Scg149915 }	/* i915_detach() */
961d0538f66Scg149915 
962d0538f66Scg149915 
963d0538f66Scg149915 /*ARGSUSED*/
964d0538f66Scg149915 static int
i915_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)965d0538f66Scg149915 i915_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
966d0538f66Scg149915 {
967d0538f66Scg149915 	drm_device_t		*statep;
968d0538f66Scg149915 	int 	error = DDI_SUCCESS;
969d0538f66Scg149915 	int 	unit;
970d0538f66Scg149915 
971d0538f66Scg149915 	unit = drm_dev_to_instance((dev_t)arg);
972d0538f66Scg149915 	switch (infocmd) {
973d0538f66Scg149915 	case DDI_INFO_DEVT2DEVINFO:
974d0538f66Scg149915 		statep = ddi_get_soft_state(i915_statep, unit);
975d0538f66Scg149915 		if (statep == NULL || statep->dip == NULL) {
976d0538f66Scg149915 			error = DDI_FAILURE;
977d0538f66Scg149915 		} else {
978d0538f66Scg149915 			*result = (void *) statep->dip;
979d0538f66Scg149915 			error = DDI_SUCCESS;
980d0538f66Scg149915 		}
981d0538f66Scg149915 		break;
982d0538f66Scg149915 	case DDI_INFO_DEVT2INSTANCE:
983d0538f66Scg149915 		*result = (void *)(uintptr_t)unit;
984d0538f66Scg149915 		error = DDI_SUCCESS;
985d0538f66Scg149915 		break;
986d0538f66Scg149915 	default:
987d0538f66Scg149915 		error = DDI_FAILURE;
988d0538f66Scg149915 		break;
989d0538f66Scg149915 	}
990d0538f66Scg149915 	return (error);
991d0538f66Scg149915 
992d0538f66Scg149915 }	/* i915_info() */
993d0538f66Scg149915 
994d0538f66Scg149915 
i915_configure(drm_driver_t * driver)995d0538f66Scg149915 static void i915_configure(drm_driver_t *driver)
996d0538f66Scg149915 {
997d0538f66Scg149915 	driver->buf_priv_size	=	1;	/* No dev_priv */
998d0538f66Scg149915 	driver->load	=	i915_driver_load;
99991fae470Scg149915 	driver->unload	=	i915_driver_unload;
1000*0035d21cSmiao chen - Sun Microsystems - Beijing China 	driver->open	=	i915_driver_open;
1001d0538f66Scg149915 	driver->preclose	=	i915_driver_preclose;
1002*0035d21cSmiao chen - Sun Microsystems - Beijing China 	driver->postclose	=	i915_driver_postclose;
1003d0538f66Scg149915 	driver->lastclose	=	i915_driver_lastclose;
1004d0538f66Scg149915 	driver->device_is_agp	=	i915_driver_device_is_agp;
1005d0231070Smiao chen - Sun Microsystems - Beijing China 	driver->enable_vblank	= 	i915_enable_vblank;
1006d0231070Smiao chen - Sun Microsystems - Beijing China 	driver->disable_vblank	= 	i915_disable_vblank;
1007d0538f66Scg149915 	driver->irq_preinstall	=	i915_driver_irq_preinstall;
1008d0538f66Scg149915 	driver->irq_postinstall	=	i915_driver_irq_postinstall;
1009d0538f66Scg149915 	driver->irq_uninstall	=	i915_driver_irq_uninstall;
1010d0538f66Scg149915 	driver->irq_handler 	=	i915_driver_irq_handler;
1011d0538f66Scg149915 
1012*0035d21cSmiao chen - Sun Microsystems - Beijing China 	driver->gem_init_object = 	i915_gem_init_object;
1013*0035d21cSmiao chen - Sun Microsystems - Beijing China 	driver->gem_free_object = 	i915_gem_free_object;
1014*0035d21cSmiao chen - Sun Microsystems - Beijing China 
1015d0538f66Scg149915 	driver->driver_ioctls	=	i915_ioctls;
1016d0538f66Scg149915 	driver->max_driver_ioctl	=	i915_max_ioctl;
1017d0538f66Scg149915 
1018d0538f66Scg149915 	driver->driver_name	=	DRIVER_NAME;
1019d0538f66Scg149915 	driver->driver_desc	=	DRIVER_DESC;
1020d0538f66Scg149915 	driver->driver_date	=	DRIVER_DATE;
1021d0538f66Scg149915 	driver->driver_major	=	DRIVER_MAJOR;
1022d0538f66Scg149915 	driver->driver_minor	=	DRIVER_MINOR;
1023d0538f66Scg149915 	driver->driver_patchlevel	=	DRIVER_PATCHLEVEL;
1024d0538f66Scg149915 
1025d0538f66Scg149915 	driver->use_agp	=	1;
1026d0538f66Scg149915 	driver->require_agp	=	1;
1027d0538f66Scg149915 	driver->use_irq	=	1;
1028ae115bc7Smrj }
10294cde194bSEdward Shu 
i915_quiesce(dev_info_t * dip)10304cde194bSEdward Shu static int i915_quiesce(dev_info_t *dip)
10314cde194bSEdward Shu {
10324cde194bSEdward Shu 	drm_device_t		*statep;
10334cde194bSEdward Shu 	int		unit;
10344cde194bSEdward Shu 
10354cde194bSEdward Shu 	unit =  ddi_get_instance(dip);
10364cde194bSEdward Shu 	statep = ddi_get_soft_state(i915_statep, unit);
10374cde194bSEdward Shu 	if (statep == NULL) {
10384cde194bSEdward Shu 		return (DDI_FAILURE);
10394cde194bSEdward Shu 	}
10404cde194bSEdward Shu 	i915_driver_irq_uninstall(statep);
10414cde194bSEdward Shu 
10424cde194bSEdward Shu 	return (DDI_SUCCESS);
10434cde194bSEdward Shu }
1044