diff options
author | ms148562 <none@none> | 2008-07-18 15:31:07 -0700 |
---|---|---|
committer | ms148562 <none@none> | 2008-07-18 15:31:07 -0700 |
commit | 31c83a1b44505db718ee9088db1ce16bd9205d86 (patch) | |
tree | 46bfc366bcb160bea5ff35422964c41eda155e63 /usr/src | |
parent | a85084cae26f3fc328f0704c75464ad44d6fdeb3 (diff) | |
download | illumos-joyent-31c83a1b44505db718ee9088db1ce16bd9205d86.tar.gz |
6583859 Need S3 support for Intel graphics devices
6644080 agptarget needs to support S/R
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/io/drm/drmP.h | 5 | ||||
-rw-r--r-- | usr/src/uts/intel/io/agpgart/agptarget.c | 133 | ||||
-rw-r--r-- | usr/src/uts/intel/io/drm/i915_dma.c | 15 | ||||
-rw-r--r-- | usr/src/uts/intel/io/drm/i915_drv.c | 706 | ||||
-rw-r--r-- | usr/src/uts/intel/io/drm/i915_drv.h | 505 |
5 files changed, 1311 insertions, 53 deletions
diff --git a/usr/src/uts/common/io/drm/drmP.h b/usr/src/uts/common/io/drm/drmP.h index 72b682e945..49f92e773f 100644 --- a/usr/src/uts/common/io/drm/drmP.h +++ b/usr/src/uts/common/io/drm/drmP.h @@ -674,6 +674,11 @@ struct drm_device { u32 *drw_bitfield; unsigned int drw_info_length; drm_drawable_info_t **drw_info; + + /* + * Saving S3 context + */ + void *s3_private; }; /* Memory management support (drm_memory.c) */ diff --git a/usr/src/uts/intel/io/agpgart/agptarget.c b/usr/src/uts/intel/io/agpgart/agptarget.c index 712f237df3..3f1f806f5e 100644 --- a/usr/src/uts/intel/io/agpgart/agptarget.c +++ b/usr/src/uts/intel/io/agpgart/agptarget.c @@ -52,6 +52,8 @@ typedef struct agp_target_softstate { /* The offset of the ACAPID register */ off_t tsoft_acaptr; kmutex_t tsoft_lock; + int tsoft_gms_off; /* GMS offset in config */ + uint32_t tsoft_gms; }agp_target_softstate_t; /* @@ -79,6 +81,7 @@ is_64bit_aper(agp_target_softstate_t *softstate) { return (softstate->tsoft_devid == AMD_BR_8151); } + /* * Check if it is an intel bridge */ @@ -363,6 +366,21 @@ static gms_mode_t gms_modes[] = { {INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK, GMS_SIZE(gms_965GM), gms_965GM} }; +static int +get_chip_gms(uint32_t devid) +{ + int num_modes; + int i; + + num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t)); + + for (i = 0; i < num_modes; i++) { + if (gms_modes[i].gm_devid == devid) + break; + } + + return ((i == num_modes) ? -1 : i); +} /* Returns the size (kbytes) of pre-allocated graphics memory */ static size_t @@ -370,32 +388,26 @@ i8xx_biosmem_detect(agp_target_softstate_t *softstate) { uint8_t memval; size_t kbytes; - int i; - int num_modes; + int gms_off; kbytes = 0; - /* get GMS modes list entry */ - num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t)); - for (i = 0; i < num_modes; i++) { - if (gms_modes[i].gm_devid == softstate->tsoft_devid) - break; - } - if (i == num_modes) - goto done; + gms_off = softstate->tsoft_gms_off; + /* fetch the GMS value from DRAM controller */ memval = pci_config_get8(softstate->tsoft_pcihdl, - gms_modes[i].gm_regoff); + gms_modes[gms_off].gm_regoff); TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval)); - memval = (memval & gms_modes[i].gm_mask) >> GMS_SHIFT; + memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT; /* assuming zero byte for 0 or "reserved" GMS values */ - if (memval == 0 || memval > gms_modes[i].gm_num) { + if (memval == 0 || memval > gms_modes[gms_off].gm_num) { TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: " "devid = %x, GMS = %x. assuming zero byte of " - "pre-allocated memory", gms_modes[i].gm_devid, memval)); + "pre-allocated memory", + gms_modes[gms_off].gm_devid, memval)); goto done; } memval--; /* use (GMS_value - 1) as index */ - kbytes = (gms_modes[i].gm_vec)[memval]; + kbytes = (gms_modes[gms_off].gm_vec)[memval]; done: TARGETDB_PRINT2((CE_NOTE, @@ -439,45 +451,105 @@ static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, } static int +intel_br_resume(agp_target_softstate_t *softstate) +{ + int gms_off; + + gms_off = softstate->tsoft_gms_off; + + /* + * We recover the gmch graphics control register here + */ + pci_config_put16(softstate->tsoft_pcihdl, + gms_modes[gms_off].gm_regoff, softstate->tsoft_gms); + + return (DDI_SUCCESS); +} +static int +intel_br_suspend(agp_target_softstate_t *softstate) +{ + int gms_off; + + gms_off = softstate->tsoft_gms_off; + softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl, + gms_modes[gms_off].gm_regoff); + + return (DDI_SUCCESS); +} + +static int agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { agp_target_softstate_t *softstate; int instance; int status; - if (cmd != DDI_ATTACH) - return (DDI_FAILURE); - instance = ddi_get_instance(dip); - if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, instance) != - DDI_SUCCESS) + switch (cmd) { + case DDI_ATTACH: + break; + case DDI_RESUME: + softstate = + ddi_get_soft_state(agptarget_glob_soft_handle, instance); + return (intel_br_resume(softstate)); + default: + TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" + "only attach and resume ops are supported")); + return (DDI_FAILURE); + } + + if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, + instance) != DDI_SUCCESS) { + TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" + "soft state zalloc failed")); return (DDI_FAILURE); + } softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL); softstate->tsoft_dip = dip; status = pci_config_setup(dip, &softstate->tsoft_pcihdl); if (status != DDI_SUCCESS) { - ddi_soft_state_free(agptarget_glob_soft_handle, instance); + TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" + "pci config setup failed")); + ddi_soft_state_free(agptarget_glob_soft_handle, + instance); return (DDI_FAILURE); } softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl, PCI_CONF_VENID); + softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid); + if (softstate->tsoft_gms_off < 0) { + TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" + "read gms offset failed")); + pci_config_teardown(&softstate->tsoft_pcihdl); + ddi_soft_state_free(agptarget_glob_soft_handle, + instance); + return (DDI_FAILURE); + } softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl); if (softstate->tsoft_acaptr == 0) { /* Make a correction for some Intel chipsets */ if (is_intel_br(softstate)) softstate->tsoft_acaptr = AGP_CAP_OFF_DEF; - else + else { + TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" + "Not a supposed corretion")); + pci_config_teardown(&softstate->tsoft_pcihdl); + ddi_soft_state_free(agptarget_glob_soft_handle, + instance); return (DDI_FAILURE); + } } status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR, INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0); if (status != DDI_SUCCESS) { + TARGETDB_PRINT2((CE_WARN, "agp_target_attach:" + "Create minor node failed")); pci_config_teardown(&softstate->tsoft_pcihdl); ddi_soft_state_free(agptarget_glob_soft_handle, instance); return (DDI_FAILURE); @@ -493,13 +565,20 @@ agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) int instance; agp_target_softstate_t *softstate; - if (cmd != DDI_DETACH) - return (DDI_FAILURE); - instance = ddi_get_instance(dip); - softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance); + if (cmd == DDI_SUSPEND) { + /* get GMS modes list entry */ + return (intel_br_suspend(softstate)); + } + + if (cmd != DDI_DETACH) { + TARGETDB_PRINT2((CE_WARN, "agp_target_detach:" + "only detach and suspend ops are supported")); + return (DDI_FAILURE); + } + ddi_remove_minor_node(dip, AGPTARGET_NAME); pci_config_teardown(&softstate->tsoft_pcihdl); mutex_destroy(&softstate->tsoft_lock); @@ -785,7 +864,7 @@ static struct dev_ops agp_target_ops = { static struct modldrv modldrv = { &mod_driverops, - "AGP target driver v%I%", + "AGP target driver", &agp_target_ops, }; diff --git a/usr/src/uts/intel/io/drm/i915_dma.c b/usr/src/uts/intel/io/drm/i915_dma.c index 6918e18a31..cf1326a5da 100644 --- a/usr/src/uts/intel/io/drm/i915_dma.c +++ b/usr/src/uts/intel/io/drm/i915_dma.c @@ -40,17 +40,6 @@ #include "i915_drm.h" #include "i915_drv.h" -#define IS_I965G(dev) (dev->pci_device == 0x2972 || \ - dev->pci_device == 0x2982 || \ - dev->pci_device == 0x2992 || \ - dev->pci_device == 0x29A2 || \ - dev->pci_device == 0x2A02 || \ - dev->pci_device == 0x2A12) - -#define IS_G33(dev) (dev->pci_device == 0x29b2 || \ - dev->pci_device == 0x29c2 || \ - dev->pci_device == 0x29d2) - /* Really want an OS-independent resettable timer. Would like to have @@ -151,6 +140,10 @@ static int i915_initialize(drm_device_t * dev, return (EINVAL); } + /* + * mmio_map will be destoried after DMA clean up. We should not + * access mmio_map in suspend or resume process. + */ dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); if (!dev_priv->mmio_map) { dev->dev_private = (void *)dev_priv; diff --git a/usr/src/uts/intel/io/drm/i915_drv.c b/usr/src/uts/intel/io/drm/i915_drv.c index c111b34add..178e6685ff 100644 --- a/usr/src/uts/intel/io/drm/i915_drv.c +++ b/usr/src/uts/intel/io/drm/i915_drv.c @@ -58,6 +58,21 @@ #define i915_max_ioctl 0x20 /* changed from 15 */ +/* + * copied from vgasubr.h + */ + +struct vgaregmap { + uint8_t *addr; + ddi_acc_handle_t handle; + boolean_t mapped; +}; + +enum pipe { + PIPE_A = 0, + PIPE_B, +}; + /* * cb_ops entrypoint @@ -108,7 +123,7 @@ static struct dev_ops i915_dev_ops = { static struct modldrv modldrv = { &mod_driverops, /* drv_modops */ - "I915 DRM driver %I%", /* drv_linkinfo */ + "I915 DRM driver", /* drv_linkinfo */ &i915_dev_ops, /* drv_dev_ops */ }; @@ -116,6 +131,11 @@ static struct modlinkage modlinkage = { MODREV_1, (void *) &modldrv, NULL }; +static ddi_device_acc_attr_t s3_attr = { + DDI_DEVICE_ATTR_V0, + DDI_NEVERSWAP_ACC, + DDI_STRICTORDER_ACC /* must be DDI_STRICTORDER_ACC */ +}; /* * softstate head @@ -163,34 +183,666 @@ _info(struct modinfo *modinfop) } /* _info() */ +/* + * off range: 0x3b0 ~ 0x3ff + */ + +static void +vga_reg_put8(struct vgaregmap *regmap, uint16_t off, uint8_t val) +{ + ASSERT((off >= 0x3b0) && (off <= 0x3ff)); + + ddi_put8(regmap->handle, regmap->addr + off, val); +} + +/* + * off range: 0x3b0 ~ 0x3ff + */ +static uint8_t +vga_reg_get8(struct vgaregmap *regmap, uint16_t off) +{ + + ASSERT((off >= 0x3b0) && (off <= 0x3ff)); + + return (ddi_get8(regmap->handle, regmap->addr + off)); +} + +static void +i915_write_indexed(struct vgaregmap *regmap, + uint16_t index_port, uint16_t data_port, uint8_t index, uint8_t val) +{ + vga_reg_put8(regmap, index_port, index); + vga_reg_put8(regmap, data_port, val); +} + +static uint8_t +i915_read_indexed(struct vgaregmap *regmap, + uint16_t index_port, uint16_t data_port, uint8_t index) +{ + vga_reg_put8(regmap, index_port, index); + return (vga_reg_get8(regmap, data_port)); +} + +static void +i915_write_ar(struct vgaregmap *regmap, uint16_t st01, + uint8_t reg, uint8_t val, uint8_t palette_enable) +{ + (void) vga_reg_get8(regmap, st01); + vga_reg_put8(regmap, VGA_AR_INDEX, palette_enable | reg); + vga_reg_put8(regmap, VGA_AR_DATA_WRITE, val); +} + +static uint8_t +i915_read_ar(struct vgaregmap *regmap, uint16_t st01, + uint8_t index, uint8_t palette_enable) +{ + (void) vga_reg_get8(regmap, st01); + vga_reg_put8(regmap, VGA_AR_INDEX, index | palette_enable); + return (vga_reg_get8(regmap, VGA_AR_DATA_READ)); +} + +static int +i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) +{ + struct s3_i915_private *s3_priv = dev->s3_private; + + if (pipe == PIPE_A) + return (S3_READ(DPLL_A) & DPLL_VCO_ENABLE); + else + return (S3_READ(DPLL_B) & DPLL_VCO_ENABLE); +} + +static void +i915_save_palette(struct drm_device *dev, enum pipe pipe) +{ + struct s3_i915_private *s3_priv = dev->s3_private; + unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); + uint32_t *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (pipe == PIPE_A) + array = s3_priv->save_palette_a; + else + array = s3_priv->save_palette_b; + + for(i = 0; i < 256; i++) + array[i] = S3_READ(reg + (i << 2)); + +} + +static void +i915_restore_palette(struct drm_device *dev, enum pipe pipe) +{ + struct s3_i915_private *s3_priv = dev->s3_private; + unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); + uint32_t *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (pipe == PIPE_A) + array = s3_priv->save_palette_a; + else + array = s3_priv->save_palette_b; + + for(i = 0; i < 256; i++) + S3_WRITE(reg + (i << 2), array[i]); +} + +static void +i915_save_vga(struct drm_device *dev) +{ + struct s3_i915_private *s3_priv = dev->s3_private; + int i; + uint16_t cr_index, cr_data, st01; + struct vgaregmap regmap; + + regmap.addr = (uint8_t *)s3_priv->saveAddr; + regmap.handle = s3_priv->saveHandle; + + /* VGA color palette registers */ + s3_priv->saveDACMASK = vga_reg_get8(®map, VGA_DACMASK); + /* DACCRX automatically increments during read */ + vga_reg_put8(®map, VGA_DACRX, 0); + /* Read 3 bytes of color data from each index */ + for (i = 0; i < 256 * 3; i++) + s3_priv->saveDACDATA[i] = vga_reg_get8(®map, VGA_DACDATA); + + /* MSR bits */ + s3_priv->saveMSR = vga_reg_get8(®map, VGA_MSR_READ); + if (s3_priv->saveMSR & VGA_MSR_CGA_MODE) { + cr_index = VGA_CR_INDEX_CGA; + cr_data = VGA_CR_DATA_CGA; + st01 = VGA_ST01_CGA; + } else { + cr_index = VGA_CR_INDEX_MDA; + cr_data = VGA_CR_DATA_MDA; + st01 = VGA_ST01_MDA; + } + + /* CRT controller regs */ + i915_write_indexed(®map, cr_index, cr_data, 0x11, + i915_read_indexed(®map, cr_index, cr_data, 0x11) & (~0x80)); + for (i = 0; i < 0x24; i++) + s3_priv->saveCR[i] = + i915_read_indexed(®map, cr_index, cr_data, i); + /* Make sure we don't turn off CR group 0 writes */ + s3_priv->saveCR[0x11] &= ~0x80; + + /* Attribute controller registers */ + (void) vga_reg_get8(®map, st01); + s3_priv->saveAR_INDEX = vga_reg_get8(®map, VGA_AR_INDEX); + for (i = 0; i < 20; i++) + s3_priv->saveAR[i] = i915_read_ar(®map, st01, i, 0); + (void) vga_reg_get8(®map, st01); + vga_reg_put8(®map, VGA_AR_INDEX, s3_priv->saveAR_INDEX); + (void) vga_reg_get8(®map, st01); + + /* Graphics controller registers */ + for (i = 0; i < 9; i++) + s3_priv->saveGR[i] = + i915_read_indexed(®map, VGA_GR_INDEX, VGA_GR_DATA, i); + + s3_priv->saveGR[0x10] = + i915_read_indexed(®map, VGA_GR_INDEX, VGA_GR_DATA, 0x10); + s3_priv->saveGR[0x11] = + i915_read_indexed(®map, VGA_GR_INDEX, VGA_GR_DATA, 0x11); + s3_priv->saveGR[0x18] = + i915_read_indexed(®map, VGA_GR_INDEX, VGA_GR_DATA, 0x18); + + /* Sequencer registers */ + for (i = 0; i < 8; i++) + s3_priv->saveSR[i] = + i915_read_indexed(®map, VGA_SR_INDEX, VGA_SR_DATA, i); +} + +static void +i915_restore_vga(struct drm_device *dev) +{ + struct s3_i915_private *s3_priv = dev->s3_private; + int i; + uint16_t cr_index, cr_data, st01; + struct vgaregmap regmap; + + regmap.addr = (uint8_t *)s3_priv->saveAddr; + regmap.handle = s3_priv->saveHandle; + + /* + * I/O Address Select. This bit selects 3Bxh or 3Dxh as the + * I/O address for the CRT Controller registers, + * the Feature Control Register (FCR), and Input Status Register + * 1 (ST01). Presently ignored (whole range is claimed), but + * will "ignore" 3Bx for color configuration or 3Dx for monochrome. + * Note that it is typical in AGP chipsets to shadow this bit + * and properly steer I/O cycles to the proper bus for operation + * where a MDA exists on another bus such as ISA. + * 0 = Select 3Bxh I/O address (MDA emulation) (default). + * 1 = Select 3Dxh I/O address (CGA emulation). + */ + vga_reg_put8(®map, VGA_MSR_WRITE, s3_priv->saveMSR); + + if (s3_priv->saveMSR & VGA_MSR_CGA_MODE) { + cr_index = VGA_CR_INDEX_CGA; + cr_data = VGA_CR_DATA_CGA; + st01 = VGA_ST01_CGA; + } else { + cr_index = VGA_CR_INDEX_MDA; + cr_data = VGA_CR_DATA_MDA; + st01 = VGA_ST01_MDA; + } + + /* Sequencer registers, don't write SR07 */ + for (i = 0; i < 7; i++) + i915_write_indexed(®map, VGA_SR_INDEX, VGA_SR_DATA, i, + s3_priv->saveSR[i]); + /* CRT controller regs */ + /* Enable CR group 0 writes */ + i915_write_indexed(®map, cr_index, cr_data, + 0x11, s3_priv->saveCR[0x11]); + for (i = 0; i < 0x24; i++) + i915_write_indexed(®map, cr_index, + cr_data, i, s3_priv->saveCR[i]); + + /* Graphics controller regs */ + for (i = 0; i < 9; i++) + i915_write_indexed(®map, VGA_GR_INDEX, VGA_GR_DATA, i, + s3_priv->saveGR[i]); + + i915_write_indexed(®map, VGA_GR_INDEX, VGA_GR_DATA, 0x10, + s3_priv->saveGR[0x10]); + i915_write_indexed(®map, VGA_GR_INDEX, VGA_GR_DATA, 0x11, + s3_priv->saveGR[0x11]); + i915_write_indexed(®map, VGA_GR_INDEX, VGA_GR_DATA, 0x18, + s3_priv->saveGR[0x18]); + + /* Attribute controller registers */ + (void) vga_reg_get8(®map, st01); /* switch back to index mode */ + for (i = 0; i < 20; i++) + i915_write_ar(®map, st01, i, s3_priv->saveAR[i], 0); + (void) vga_reg_get8(®map, st01); /* switch back to index mode */ + vga_reg_put8(®map, VGA_AR_INDEX, s3_priv->saveAR_INDEX | 0x20); + (void) vga_reg_get8(®map, st01); /* switch back to index mode */ + + /* VGA color palette registers */ + vga_reg_put8(®map, VGA_DACMASK, s3_priv->saveDACMASK); + /* DACCRX automatically increments during read */ + vga_reg_put8(®map, VGA_DACWX, 0); + /* Read 3 bytes of color data from each index */ + for (i = 0; i < 256 * 3; i++) + vga_reg_put8(®map, VGA_DACDATA, s3_priv->saveDACDATA[i]); +} + +static int +i915_resume(struct drm_device *dev) +{ + ddi_acc_handle_t conf_hdl; + struct s3_i915_private *s3_priv = dev->s3_private; + int i; + + if (pci_config_setup(dev->dip, &conf_hdl) != DDI_SUCCESS) { + DRM_ERROR(("i915_resume: pci_config_setup fail")); + return (DDI_FAILURE); + } + /* + * Nexus driver will resume pci config space and set the power state + * for its children. So we needn't resume them explicitly here. + * see pci_pre_resume for detail. + */ + pci_config_put8(conf_hdl, LBB, s3_priv->saveLBB); + /* + * Pipe & plane A info + * Prime the clock + */ + if (s3_priv->saveDPLL_A & DPLL_VCO_ENABLE) { + S3_WRITE(DPLL_A, s3_priv->saveDPLL_A & + ~DPLL_VCO_ENABLE); + drv_usecwait(150); + } + S3_WRITE(FPA0, s3_priv->saveFPA0); + S3_WRITE(FPA1, s3_priv->saveFPA1); + /* Actually enable it */ + S3_WRITE(DPLL_A, s3_priv->saveDPLL_A); + drv_usecwait(150); + if (IS_I965G(dev)) + S3_WRITE(DPLL_A_MD, s3_priv->saveDPLL_A_MD); + drv_usecwait(150); + + /* Restore mode */ + S3_WRITE(HTOTAL_A, s3_priv->saveHTOTAL_A); + S3_WRITE(HBLANK_A, s3_priv->saveHBLANK_A); + S3_WRITE(HSYNC_A, s3_priv->saveHSYNC_A); + S3_WRITE(VTOTAL_A, s3_priv->saveVTOTAL_A); + S3_WRITE(VBLANK_A, s3_priv->saveVBLANK_A); + S3_WRITE(VSYNC_A, s3_priv->saveVSYNC_A); + S3_WRITE(BCLRPAT_A, s3_priv->saveBCLRPAT_A); + + /* Restore plane info */ + S3_WRITE(DSPASIZE, s3_priv->saveDSPASIZE); + S3_WRITE(DSPAPOS, s3_priv->saveDSPAPOS); + S3_WRITE(PIPEASRC, s3_priv->savePIPEASRC); + S3_WRITE(DSPABASE, s3_priv->saveDSPABASE); + S3_WRITE(DSPASTRIDE, s3_priv->saveDSPASTRIDE); + if (IS_I965G(dev)) { + S3_WRITE(DSPASURF, s3_priv->saveDSPASURF); + S3_WRITE(DSPATILEOFF, s3_priv->saveDSPATILEOFF); + } + S3_WRITE(PIPEACONF, s3_priv->savePIPEACONF); + i915_restore_palette(dev, PIPE_A); + /* Enable the plane */ + S3_WRITE(DSPACNTR, s3_priv->saveDSPACNTR); + S3_WRITE(DSPABASE, S3_READ(DSPABASE)); + + /* Pipe & plane B info */ + if (s3_priv->saveDPLL_B & DPLL_VCO_ENABLE) { + S3_WRITE(DPLL_B, s3_priv->saveDPLL_B & + ~DPLL_VCO_ENABLE); + drv_usecwait(150); + } + S3_WRITE(FPB0, s3_priv->saveFPB0); + S3_WRITE(FPB1, s3_priv->saveFPB1); + /* Actually enable it */ + S3_WRITE(DPLL_B, s3_priv->saveDPLL_B); + drv_usecwait(150); + if (IS_I965G(dev)) + S3_WRITE(DPLL_B_MD, s3_priv->saveDPLL_B_MD); + drv_usecwait(150); + + /* Restore mode */ + S3_WRITE(HTOTAL_B, s3_priv->saveHTOTAL_B); + S3_WRITE(HBLANK_B, s3_priv->saveHBLANK_B); + S3_WRITE(HSYNC_B, s3_priv->saveHSYNC_B); + S3_WRITE(VTOTAL_B, s3_priv->saveVTOTAL_B); + S3_WRITE(VBLANK_B, s3_priv->saveVBLANK_B); + S3_WRITE(VSYNC_B, s3_priv->saveVSYNC_B); + S3_WRITE(BCLRPAT_B, s3_priv->saveBCLRPAT_B); + + /* Restore plane info */ + S3_WRITE(DSPBSIZE, s3_priv->saveDSPBSIZE); + S3_WRITE(DSPBPOS, s3_priv->saveDSPBPOS); + S3_WRITE(PIPEBSRC, s3_priv->savePIPEBSRC); + S3_WRITE(DSPBBASE, s3_priv->saveDSPBBASE); + S3_WRITE(DSPBSTRIDE, s3_priv->saveDSPBSTRIDE); + if (IS_I965G(dev)) { + S3_WRITE(DSPBSURF, s3_priv->saveDSPBSURF); + S3_WRITE(DSPBTILEOFF, s3_priv->saveDSPBTILEOFF); + } + S3_WRITE(PIPEBCONF, s3_priv->savePIPEBCONF); + i915_restore_palette(dev, PIPE_B); + /* Enable the plane */ + S3_WRITE(DSPBCNTR, s3_priv->saveDSPBCNTR); + S3_WRITE(DSPBBASE, S3_READ(DSPBBASE)); + + /* CRT state */ + S3_WRITE(ADPA, s3_priv->saveADPA); + + /* LVDS state */ + if (IS_I965G(dev)) + S3_WRITE(BLC_PWM_CTL2, s3_priv->saveBLC_PWM_CTL2); + if (IS_MOBILE(dev) && !IS_I830(dev)) + S3_WRITE(LVDS, s3_priv->saveLVDS); + if (!IS_I830(dev) && !IS_845G(dev)) + S3_WRITE(PFIT_CONTROL, s3_priv->savePFIT_CONTROL); + + S3_WRITE(PFIT_PGM_RATIOS, s3_priv->savePFIT_PGM_RATIOS); + S3_WRITE(BLC_PWM_CTL, s3_priv->saveBLC_PWM_CTL); + S3_WRITE(LVDSPP_ON, s3_priv->saveLVDSPP_ON); + S3_WRITE(LVDSPP_OFF, s3_priv->saveLVDSPP_OFF); + S3_WRITE(PP_CYCLE, s3_priv->savePP_CYCLE); + S3_WRITE(PP_CONTROL, s3_priv->savePP_CONTROL); + + /* FIXME: restore TV & SDVO state */ + + /* FBC info */ + S3_WRITE(FBC_CFB_BASE, s3_priv->saveFBC_CFB_BASE); + S3_WRITE(FBC_LL_BASE, s3_priv->saveFBC_LL_BASE); + S3_WRITE(FBC_CONTROL2, s3_priv->saveFBC_CONTROL2); + S3_WRITE(FBC_CONTROL, s3_priv->saveFBC_CONTROL); + + /* VGA state */ + S3_WRITE(VGACNTRL, s3_priv->saveVGACNTRL); + S3_WRITE(VCLK_DIVISOR_VGA0, s3_priv->saveVCLK_DIVISOR_VGA0); + S3_WRITE(VCLK_DIVISOR_VGA1, s3_priv->saveVCLK_DIVISOR_VGA1); + S3_WRITE(VCLK_POST_DIV, s3_priv->saveVCLK_POST_DIV); + drv_usecwait(150); + + /* Clock gating state */ + S3_WRITE (DSPCLK_GATE_D, s3_priv->saveDSPCLK_GATE_D); + + /* Cache mode state */ + S3_WRITE (CACHE_MODE_0, s3_priv->saveCACHE_MODE_0 | 0xffff0000); + + /* Memory arbitration state */ + S3_WRITE (MI_ARB_STATE, s3_priv->saveMI_ARB_STATE | 0xffff0000); + + for (i = 0; i < 16; i++) { + S3_WRITE(SWF0 + (i << 2), s3_priv->saveSWF0[i]); + S3_WRITE(SWF10 + (i << 2), s3_priv->saveSWF1[i+7]); + } + for (i = 0; i < 3; i++) + S3_WRITE(SWF30 + (i << 2), s3_priv->saveSWF2[i]); + + i915_restore_vga(dev); + + S3_WRITE(I915REG_PGTBL_CTRL, s3_priv->pgtbl_ctl); + + (void) pci_config_teardown(&conf_hdl); + + return (DDI_SUCCESS); +} +static int +i915_suspend(struct drm_device *dev) +{ + ddi_acc_handle_t conf_hdl; + struct s3_i915_private *s3_priv = dev->s3_private; + int i; + + + if (pci_config_setup(dev->dip, &conf_hdl) != DDI_SUCCESS) { + DRM_ERROR(("i915_suspend: pci_config_setup fail")); + return (DDI_FAILURE); + } + + /* + * Nexus driver will resume pci config space for its children. + * So pci config registers are not saved here. + */ + s3_priv->saveLBB = pci_config_get8(conf_hdl, LBB); + + /* + * Pipe & plane A info. + */ + s3_priv->savePIPEACONF = S3_READ(PIPEACONF); + s3_priv->savePIPEASRC = S3_READ(PIPEASRC); + s3_priv->saveFPA0 = S3_READ(FPA0); + s3_priv->saveFPA1 = S3_READ(FPA1); + s3_priv->saveDPLL_A = S3_READ(DPLL_A); + if (IS_I965G(dev)) + s3_priv->saveDPLL_A_MD = S3_READ(DPLL_A_MD); + s3_priv->saveHTOTAL_A = S3_READ(HTOTAL_A); + s3_priv->saveHBLANK_A = S3_READ(HBLANK_A); + s3_priv->saveHSYNC_A = S3_READ(HSYNC_A); + s3_priv->saveVTOTAL_A = S3_READ(VTOTAL_A); + s3_priv->saveVBLANK_A = S3_READ(VBLANK_A); + s3_priv->saveVSYNC_A = S3_READ(VSYNC_A); + s3_priv->saveBCLRPAT_A = S3_READ(BCLRPAT_A); + + s3_priv->saveDSPACNTR = S3_READ(DSPACNTR); + s3_priv->saveDSPASTRIDE = S3_READ(DSPASTRIDE); + s3_priv->saveDSPASIZE = S3_READ(DSPASIZE); + s3_priv->saveDSPAPOS = S3_READ(DSPAPOS); + s3_priv->saveDSPABASE = S3_READ(DSPABASE); + if (IS_I965G(dev)) { + s3_priv->saveDSPASURF = S3_READ(DSPASURF); + s3_priv->saveDSPATILEOFF = S3_READ(DSPATILEOFF); + } + i915_save_palette(dev, PIPE_A); + s3_priv->savePIPEASTAT = S3_READ(I915REG_PIPEASTAT); + + /* + * Pipe & plane B info + */ + s3_priv->savePIPEBCONF = S3_READ(PIPEBCONF); + s3_priv->savePIPEBSRC = S3_READ(PIPEBSRC); + s3_priv->saveFPB0 = S3_READ(FPB0); + s3_priv->saveFPB1 = S3_READ(FPB1); + s3_priv->saveDPLL_B = S3_READ(DPLL_B); + if (IS_I965G(dev)) + s3_priv->saveDPLL_B_MD = S3_READ(DPLL_B_MD); + s3_priv->saveHTOTAL_B = S3_READ(HTOTAL_B); + s3_priv->saveHBLANK_B = S3_READ(HBLANK_B); + s3_priv->saveHSYNC_B = S3_READ(HSYNC_B); + s3_priv->saveVTOTAL_B = S3_READ(VTOTAL_B); + s3_priv->saveVBLANK_B = S3_READ(VBLANK_B); + s3_priv->saveVSYNC_B = S3_READ(VSYNC_B); + s3_priv->saveBCLRPAT_A = S3_READ(BCLRPAT_A); + + s3_priv->saveDSPBCNTR = S3_READ(DSPBCNTR); + s3_priv->saveDSPBSTRIDE = S3_READ(DSPBSTRIDE); + s3_priv->saveDSPBSIZE = S3_READ(DSPBSIZE); + s3_priv->saveDSPBPOS = S3_READ(DSPBPOS); + s3_priv->saveDSPBBASE = S3_READ(DSPBBASE); + if (IS_I965GM(dev) || IS_IGD_GM(dev)) { + s3_priv->saveDSPBSURF = S3_READ(DSPBSURF); + s3_priv->saveDSPBTILEOFF = S3_READ(DSPBTILEOFF); + } + i915_save_palette(dev, PIPE_B); + s3_priv->savePIPEBSTAT = S3_READ(I915REG_PIPEBSTAT); + + /* + * CRT state + */ + s3_priv->saveADPA = S3_READ(ADPA); + + /* + * LVDS state + */ + s3_priv->savePP_CONTROL = S3_READ(PP_CONTROL); + s3_priv->savePFIT_PGM_RATIOS = S3_READ(PFIT_PGM_RATIOS); + s3_priv->saveBLC_PWM_CTL = S3_READ(BLC_PWM_CTL); + if (IS_I965G(dev)) + s3_priv->saveBLC_PWM_CTL2 = S3_READ(BLC_PWM_CTL2); + if (IS_MOBILE(dev) && !IS_I830(dev)) + s3_priv->saveLVDS = S3_READ(LVDS); + if (!IS_I830(dev) && !IS_845G(dev)) + s3_priv->savePFIT_CONTROL = S3_READ(PFIT_CONTROL); + s3_priv->saveLVDSPP_ON = S3_READ(LVDSPP_ON); + s3_priv->saveLVDSPP_OFF = S3_READ(LVDSPP_OFF); + s3_priv->savePP_CYCLE = S3_READ(PP_CYCLE); + + /* FIXME: save TV & SDVO state */ + + /* FBC state */ + s3_priv->saveFBC_CFB_BASE = S3_READ(FBC_CFB_BASE); + s3_priv->saveFBC_LL_BASE = S3_READ(FBC_LL_BASE); + s3_priv->saveFBC_CONTROL2 = S3_READ(FBC_CONTROL2); + s3_priv->saveFBC_CONTROL = S3_READ(FBC_CONTROL); + + /* Interrupt state */ + s3_priv->saveIIR = S3_READ(I915REG_INT_IDENTITY_R); + s3_priv->saveIER = S3_READ(I915REG_INT_ENABLE_R); + s3_priv->saveIMR = S3_READ(I915REG_INT_MASK_R); + + /* VGA state */ + s3_priv->saveVCLK_DIVISOR_VGA0 = S3_READ(VCLK_DIVISOR_VGA0); + s3_priv->saveVCLK_DIVISOR_VGA1 = S3_READ(VCLK_DIVISOR_VGA1); + s3_priv->saveVCLK_POST_DIV = S3_READ(VCLK_POST_DIV); + s3_priv->saveVGACNTRL = S3_READ(VGACNTRL); + + /* Clock gating state */ + s3_priv->saveDSPCLK_GATE_D = S3_READ(DSPCLK_GATE_D); + + /* Cache mode state */ + s3_priv->saveCACHE_MODE_0 = S3_READ(CACHE_MODE_0); + + /* Memory Arbitration state */ + s3_priv->saveMI_ARB_STATE = S3_READ(MI_ARB_STATE); + + /* Scratch space */ + for (i = 0; i < 16; i++) { + s3_priv->saveSWF0[i] = S3_READ(SWF0 + (i << 2)); + s3_priv->saveSWF1[i] = S3_READ(SWF10 + (i << 2)); + } + for (i = 0; i < 3; i++) + s3_priv->saveSWF2[i] = S3_READ(SWF30 + (i << 2)); + + + i915_save_vga(dev); + /* + * Save page table control register + */ + s3_priv->pgtbl_ctl = S3_READ(I915REG_PGTBL_CTRL); + + (void) pci_config_teardown(&conf_hdl); + + return (DDI_SUCCESS); +} + +/* + * This funtion check the length of memory mapped IO space to get the right bar. * And There are two possibilities here. + * 1. The MMIO registers is in memory map IO bar with 1M size. The bottom half + * of the 1M space is the MMIO registers. + * 2. The MMIO register is in memory map IO with 512K size. The whole 512K + * space is the MMIO registers. + */ +static int +i915_map_regs(dev_info_t *dip, caddr_t *save_addr, ddi_acc_handle_t *handlep) +{ + int rnumber; + int nregs; + off_t size = 0; + + if (ddi_dev_nregs(dip, &nregs)) { + cmn_err(CE_WARN, "i915_map_regs: failed to get nregs"); + return (DDI_FAILURE); + } + + for (rnumber = 1; rnumber < nregs; rnumber++) { + (void) ddi_dev_regsize(dip, rnumber, &size); + if ((size == 0x80000) || + (size == 0x100000)) + break; + } + + if (rnumber >= nregs) { + cmn_err(CE_WARN, + "i915_map_regs: failed to find MMIO registers"); + return (DDI_FAILURE); + } + + if (ddi_regs_map_setup(dip, rnumber, save_addr, + 0, 0x80000, &s3_attr, handlep)) { + cmn_err(CE_WARN, + "i915_map_regs: failed to map bar %d", rnumber); + return (DDI_FAILURE); + } + + return (DDI_SUCCESS); +} +static void +i915_unmap_regs(ddi_acc_handle_t *handlep) +{ + ddi_regs_map_free(handlep); +} static int i915_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { drm_device_t *statep; + s3_i915_private_t *s3_private; void *handle; int unit; - if (cmd != DDI_ATTACH) { - DRM_ERROR("i915_attach: only attach op supported"); + unit = ddi_get_instance(dip); + switch (cmd) { + case DDI_ATTACH: + break; + case DDI_RESUME: + statep = ddi_get_soft_state(i915_statep, unit); + return (i915_resume(statep)); + default: + DRM_ERROR("i915_attach: attach and resume ops are supported"); return (DDI_FAILURE); + } - unit = ddi_get_instance(dip); if (ddi_soft_state_zalloc(i915_statep, unit) != DDI_SUCCESS) { - cmn_err(CE_WARN, "i915_attach: failed to alloc softstate"); - return (DDI_FAILURE); + cmn_err(CE_WARN, + "i915_attach: failed to alloc softstate"); + return (DDI_FAILURE); } statep = ddi_get_soft_state(i915_statep, unit); statep->dip = dip; statep->driver = &i915_driver; + statep->s3_private = drm_alloc(sizeof(s3_i915_private_t), + DRM_MEM_DRIVER); + + if (statep->s3_private == NULL) { + cmn_err(CE_WARN, "i915_attach: failed to allocate s3 priv"); + goto err_exit1; + } + + /* + * Map in the mmio register space for s3. + */ + s3_private = (s3_i915_private_t *)statep->s3_private; + + if (i915_map_regs(dip, &s3_private->saveAddr, + &s3_private->saveHandle)) { + cmn_err(CE_WARN, "i915_attach: failed to map MMIO"); + goto err_exit2; + } + /* * Call drm_supp_register to create minor nodes for us */ handle = drm_supp_register(dip, statep); if ( handle == NULL) { DRM_ERROR("i915_attach: drm_supp_register failed"); - goto err_exit1; + goto err_exit3; } statep->drm_handle = handle; @@ -198,24 +850,30 @@ i915_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) * After drm_supp_register, we can call drm_xxx routine */ statep->drm_supported = DRM_UNSUPPORT; - if (drm_probe(statep, i915_pciidlist) != DDI_SUCCESS) { + if ( + drm_probe(statep, i915_pciidlist) != DDI_SUCCESS) { DRM_ERROR("i915_open: " "DRM current don't support this graphics card"); - goto err_exit2; + goto err_exit4; } statep->drm_supported = DRM_SUPPORT; /* call common attach code */ if (drm_attach(statep) != DDI_SUCCESS) { DRM_ERROR("i915_attach: drm_attach failed"); - goto err_exit2; + goto err_exit4; } return (DDI_SUCCESS); - -err_exit2: +err_exit4: (void) drm_supp_unregister(handle); +err_exit3: + i915_unmap_regs(&s3_private->saveHandle); +err_exit2: + drm_free(statep->s3_private, sizeof(s3_i915_private_t), + DRM_MEM_DRIVER); err_exit1: (void) ddi_soft_state_free(i915_statep, unit); + return (DDI_FAILURE); } /* i915_attach() */ @@ -225,14 +883,32 @@ i915_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { drm_device_t *statep; int unit; + s3_i915_private_t *s3_private; - if (cmd != DDI_DETACH) - return (DDI_FAILURE); + if ((cmd != DDI_SUSPEND) && (cmd != DDI_DETACH)) { + DRM_ERROR("i915_detach: " + "only detach and resume ops are supported"); + return (DDI_FAILURE); + } unit = ddi_get_instance(dip); statep = ddi_get_soft_state(i915_statep, unit); - if (statep == NULL) + if (statep == NULL) { + DRM_ERROR("i915_detach: can not get soft state"); return (DDI_FAILURE); + } + + if (cmd == DDI_SUSPEND) + return (i915_suspend(statep)); + + s3_private = (s3_i915_private_t *)statep->s3_private; + ddi_regs_map_free(&s3_private->saveHandle); + + /* + * Free the struct for context saving in S3 + */ + drm_free(statep->s3_private, sizeof(s3_i915_private_t), + DRM_MEM_DRIVER); (void) drm_detach(statep); (void) drm_supp_unregister(statep->drm_handle); diff --git a/usr/src/uts/intel/io/drm/i915_drv.h b/usr/src/uts/intel/io/drm/i915_drv.h index 87493707ef..913bcc002e 100644 --- a/usr/src/uts/intel/io/drm/i915_drv.h +++ b/usr/src/uts/intel/io/drm/i915_drv.h @@ -95,6 +95,97 @@ typedef struct _drm_i915_vbl_swap { unsigned int sequence; } drm_i915_vbl_swap_t; +typedef struct s3_i915_private { + ddi_acc_handle_t saveHandle; + caddr_t saveAddr; + uint32_t pgtbl_ctl; + uint8_t saveLBB; + uint32_t saveDSPACNTR; + uint32_t saveDSPBCNTR; + uint32_t savePIPEACONF; + uint32_t savePIPEBCONF; + uint32_t savePIPEASRC; + uint32_t savePIPEBSRC; + uint32_t saveFPA0; + uint32_t saveFPA1; + uint32_t saveDPLL_A; + uint32_t saveDPLL_A_MD; + uint32_t saveHTOTAL_A; + uint32_t saveHBLANK_A; + uint32_t saveHSYNC_A; + uint32_t saveVTOTAL_A; + uint32_t saveVBLANK_A; + uint32_t saveVSYNC_A; + uint32_t saveBCLRPAT_A; + uint32_t saveDSPASTRIDE; + uint32_t saveDSPASIZE; + uint32_t saveDSPAPOS; + uint32_t saveDSPABASE; + uint32_t saveDSPASURF; + uint32_t saveDSPATILEOFF; + uint32_t savePFIT_PGM_RATIOS; + uint32_t saveBLC_PWM_CTL; + uint32_t saveBLC_PWM_CTL2; + uint32_t saveFPB0; + uint32_t saveFPB1; + uint32_t saveDPLL_B; + uint32_t saveDPLL_B_MD; + uint32_t saveHTOTAL_B; + uint32_t saveHBLANK_B; + uint32_t saveHSYNC_B; + uint32_t saveVTOTAL_B; + uint32_t saveVBLANK_B; + uint32_t saveVSYNC_B; + uint32_t saveBCLRPAT_B; + uint32_t saveDSPBSTRIDE; + uint32_t saveDSPBSIZE; + uint32_t saveDSPBPOS; + uint32_t saveDSPBBASE; + uint32_t saveDSPBSURF; + uint32_t saveDSPBTILEOFF; + uint32_t saveVCLK_DIVISOR_VGA0; + uint32_t saveVCLK_DIVISOR_VGA1; + uint32_t saveVCLK_POST_DIV; + uint32_t saveVGACNTRL; + uint32_t saveADPA; + uint32_t saveLVDS; + uint32_t saveLVDSPP_ON; + uint32_t saveLVDSPP_OFF; + uint32_t saveDVOA; + uint32_t saveDVOB; + uint32_t saveDVOC; + uint32_t savePP_ON; + uint32_t savePP_OFF; + uint32_t savePP_CONTROL; + uint32_t savePP_CYCLE; + uint32_t savePFIT_CONTROL; + uint32_t save_palette_a[256]; + uint32_t save_palette_b[256]; + uint32_t saveFBC_CFB_BASE; + uint32_t saveFBC_LL_BASE; + uint32_t saveFBC_CONTROL; + uint32_t saveFBC_CONTROL2; + uint32_t saveIER; + uint32_t saveIIR; + uint32_t saveIMR; + uint32_t saveDSPCLK_GATE_D; + uint32_t saveMI_ARB_STATE; + uint32_t savePIPEASTAT; + uint32_t savePIPEBSTAT; + uint32_t saveCACHE_MODE_0; + uint32_t saveSWF0[16]; + uint32_t saveSWF1[16]; + uint32_t saveSWF2[3]; + uint8_t saveMSR; + uint8_t saveSR[8]; + uint8_t saveGR[24]; + uint8_t saveAR_INDEX; + uint8_t saveAR[20]; + uint8_t saveDACMASK; + uint8_t saveDACDATA[256*3]; /* 256 3-byte colors */ + uint8_t saveCR[36]; +} s3_i915_private_t; + typedef struct drm_i915_private { drm_local_map_t *sarea; drm_local_map_t *mmio_map; @@ -143,6 +234,7 @@ typedef struct drm_i915_private { spinlock_t swaps_lock; drm_i915_vbl_swap_t vbl_swaps; unsigned int swaps_pending; + } drm_i915_private_t; enum intel_chip_family { @@ -224,6 +316,10 @@ extern int i915_move(drm_buffer_object_t *bo, int evict, #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) #define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, (reg)) #define I915_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, (reg), (val)) +#define S3_READ(reg) \ + *(uint32_t volatile *)((uintptr_t)s3_priv->saveAddr + (reg)) +#define S3_WRITE(reg, val) \ + *(uint32_t volatile *)((uintptr_t)s3_priv->saveAddr + (reg)) = (val) #define RING_LOCALS unsigned int outring, ringmask, outcount; \ volatile unsigned char *virt; @@ -252,6 +348,51 @@ extern int i915_move(drm_buffer_object_t *bo, int evict, extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); +/* Extended config space */ +#define LBB 0xf4 + +/* VGA stuff */ + +#define VGA_ST01_MDA 0x3ba +#define VGA_ST01_CGA 0x3da + +#define VGA_MSR_WRITE 0x3c2 +#define VGA_MSR_READ 0x3cc +#define VGA_MSR_MEM_EN (1<<1) +#define VGA_MSR_CGA_MODE (1<<0) + +#define VGA_SR_INDEX 0x3c4 +#define VGA_SR_DATA 0x3c5 + +#define VGA_AR_INDEX 0x3c0 +#define VGA_AR_VID_EN (1<<5) +#define VGA_AR_DATA_WRITE 0x3c0 +#define VGA_AR_DATA_READ 0x3c1 + +#define VGA_GR_INDEX 0x3ce +#define VGA_GR_DATA 0x3cf +/* GR05 */ +#define VGA_GR_MEM_READ_MODE_SHIFT 3 +#define VGA_GR_MEM_READ_MODE_PLANE 1 +/* GR06 */ +#define VGA_GR_MEM_MODE_MASK 0xc +#define VGA_GR_MEM_MODE_SHIFT 2 +#define VGA_GR_MEM_A0000_AFFFF 0 +#define VGA_GR_MEM_A0000_BFFFF 1 +#define VGA_GR_MEM_B0000_B7FFF 2 +#define VGA_GR_MEM_B0000_BFFFF 3 + +#define VGA_DACMASK 0x3c6 +#define VGA_DACRX 0x3c7 +#define VGA_DACWX 0x3c8 +#define VGA_DACDATA 0x3c9 + +#define VGA_CR_INDEX_MDA 0x3b4 +#define VGA_CR_DATA_MDA 0x3b5 +#define VGA_CR_INDEX_CGA 0x3d4 +#define VGA_CR_DATA_CGA 0x3d5 + + #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) #define CMD_REPORT_HEAD (7<<23) @@ -272,6 +413,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define BB1_UNPROTECTED (0<<0) #define BB2_END_ADDR_MASK (~0x7) +#define I915REG_PGTBL_CTRL 0x2020 #define I915REG_HWSTAM 0x02098 #define I915REG_INT_IDENTITY_R 0x020a4 #define I915REG_INT_MASK_R 0x020a8 @@ -375,4 +517,367 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) #define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) +/* + * add here for S3 support + */ +#define DPLL_A 0x06014 +#define DPLL_B 0x06018 +# define DPLL_VCO_ENABLE 0x80000000 /* (1 << 31) */ +# define DPLL_DVO_HIGH_SPEED (1 << 30) +# define DPLL_SYNCLOCK_ENABLE (1 << 29) +# define DPLL_VGA_MODE_DIS (1 << 28) +# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ +# define DPLLB_MODE_LVDS (2 << 26) /* i915 */ +# define DPLL_MODE_MASK (3 << 26) +# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ +# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ +# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ +# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ +# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ +# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ + +/** + * The i830 generation, in DAC/serial mode, defines p1 as two plus this + * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set. + */ +# define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 +/** + * The i830 generation, in LVDS mode, defines P1 as the bit number set within + * this field (only one bit may be set). + */ +# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 +# define DPLL_FPA01_P1_POST_DIV_SHIFT 16 +# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */ +# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ +# define PLL_REF_INPUT_DREFCLK (0 << 13) +# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ +# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ +# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) +# define PLL_REF_INPUT_MASK (3 << 13) +# define PLL_LOAD_PULSE_PHASE_SHIFT 9 +/* + * Parallel to Serial Load Pulse phase selection. + * Selects the phase for the 10X DPLL clock for the PCIe + * digital display port. The range is 4 to 13; 10 or more + * is just a flip delay. The default is 6 + */ +# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) +# define DISPLAY_RATE_SELECT_FPA1 (1 << 8) + +/** + * SDVO multiplier for 945G/GM. Not used on 965. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ +# define SDVO_MULTIPLIER_MASK 0x000000ff +# define SDVO_MULTIPLIER_SHIFT_HIRES 4 +# define SDVO_MULTIPLIER_SHIFT_VGA 0 + +/** @defgroup DPLL_MD + * @{ + */ +/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_A_MD 0x0601c +/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_B_MD 0x06020 +/** + * UDI pixel divider, controlling how many pixels are stuffed into a packet. + * + * Value is pixels minus 1. Must be set to 1 pixel for SDVO. + */ +# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 +# define DPLL_MD_UDI_DIVIDER_SHIFT 24 +/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ +# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 +# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +/** + * SDVO/UDI pixel multiplier. + * + * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus + * clock rate is 10 times the DPLL clock. At low resolution/refresh rate + * modes, the bus rate would be below the limits, so SDVO allows for stuffing + * dummy bytes in the datastream at an increased clock rate, with both sides of + * the link knowing how many bytes are fill. + * + * So, for a mode with a dotclock of 65Mhz, we would want to double the clock + * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be + * set to 130Mhz, and the SDVO multiplier set to 2x in this register and + * through an SDVO command. + * + * This register field has values of multiplication factor minus 1, with + * a maximum multiplier of 5 for SDVO. + */ +# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 +# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 +/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. + * This best be set to the default value (3) or the CRT won't work. No, + * I don't entirely understand what this does... + */ +# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f +# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 +/** @} */ + +#define DPLL_TEST 0x606c +# define DPLLB_TEST_SDVO_DIV_1 (0 << 22) +# define DPLLB_TEST_SDVO_DIV_2 (1 << 22) +# define DPLLB_TEST_SDVO_DIV_4 (2 << 22) +# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) +# define DPLLB_TEST_N_BYPASS (1 << 19) +# define DPLLB_TEST_M_BYPASS (1 << 18) +# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) +# define DPLLA_TEST_N_BYPASS (1 << 3) +# define DPLLA_TEST_M_BYPASS (1 << 2) +# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) + +/* + * Palette registers + */ +#define PALETTE_A 0x0a000 +#define PALETTE_B 0x0a800 + +#define FPA0 0x06040 +#define FPA1 0x06044 +#define FPB0 0x06048 +#define FPB1 0x0604c + +#define DSPCLK_GATE_D 0x6200 +#define MI_ARB_STATE 0x20e4 + +/* + * Cache mode 0 reg. + * - Manipulating render cache behaviour is central + * to the concept of zone rendering, tuning this reg can help avoid + * unnecessary render cache reads and even writes (for z/stencil) + * at beginning and end of scene. + * + * - To change a bit, write to this reg with a mask bit set and the + * bit of interest either set or cleared. EG: (BIT<<16) | BIT to set. + */ +#define CACHE_MODE_0 0x2120 + +/* I830 CRTC registers */ +#define HTOTAL_A 0x60000 +#define HBLANK_A 0x60004 +#define HSYNC_A 0x60008 +#define VTOTAL_A 0x6000c +#define VBLANK_A 0x60010 +#define VSYNC_A 0x60014 +#define PIPEASRC 0x6001c +#define BCLRPAT_A 0x60020 +#define VSYNCSHIFT_A 0x60028 + +#define HTOTAL_B 0x61000 +#define HBLANK_B 0x61004 +#define HSYNC_B 0x61008 +#define VTOTAL_B 0x6100c +#define VBLANK_B 0x61010 +#define VSYNC_B 0x61014 +#define PIPEBSRC 0x6101c +#define BCLRPAT_B 0x61020 +#define VSYNCSHIFT_B 0x61028 + +#define DSPACNTR 0x70180 +#define DSPBCNTR 0x71180 +#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_DISABLE 0 +#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_DISABLE 0 +#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_8BPP (0x2<<26) +#define DISPPLANE_15_16BPP (0x4<<26) +#define DISPPLANE_16BPP (0x5<<26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) +#define DISPPLANE_32BPP (0x7<<26) +#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define DISPPLANE_SEL_PIPE_A 0 +#define DISPPLANE_SEL_PIPE_B (1<<24) +#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SRC_KEY_DISABLE 0 +#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_NO_LINE_DOUBLE 0 +#define DISPPLANE_STEREO_POLARITY_FIRST 0 +#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) +/* plane B only */ +#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_DISABLE 0 +#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 +#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) + +#define DSPABASE 0x70184 +#define DSPASTRIDE 0x70188 + +#define DSPBBASE 0x71184 +#define DSPBADDR DSPBBASE +#define DSPBSTRIDE 0x71188 + +#define DSPAKEYVAL 0x70194 +#define DSPAKEYMASK 0x70198 + +#define DSPAPOS 0x7018C /* reserved */ +#define DSPASIZE 0x70190 +#define DSPBPOS 0x7118C +#define DSPBSIZE 0x71190 + +#define DSPASURF 0x7019C +#define DSPATILEOFF 0x701A4 + +#define DSPBSURF 0x7119C +#define DSPBTILEOFF 0x711A4 + +#define PIPEACONF 0x70008 +#define PIPEACONF_ENABLE (1<<31) +#define PIPEACONF_DISABLE 0 +#define PIPEACONF_DOUBLE_WIDE (1<<30) +#define I965_PIPECONF_ACTIVE (1<<30) +#define PIPEACONF_SINGLE_WIDE 0 +#define PIPEACONF_PIPE_UNLOCKED 0 +#define PIPEACONF_PIPE_LOCKED (1<<25) +#define PIPEACONF_PALETTE 0 +#define PIPEACONF_GAMMA (1<<24) +#define PIPECONF_FORCE_BORDER (1<<25) +#define PIPECONF_PROGRESSIVE (0 << 21) +#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) +#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) + +#define PIPEBCONF 0x71008 +#define PIPEBCONF_ENABLE (1<<31) +#define PIPEBCONF_DISABLE 0 +#define PIPEBCONF_DOUBLE_WIDE (1<<30) +#define PIPEBCONF_DISABLE 0 +#define PIPEBCONF_GAMMA (1<<24) +#define PIPEBCONF_PALETTE 0 + +#define BLC_PWM_CTL 0x61254 +#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) + +#define BLC_PWM_CTL2 0x61250 + +#define PFIT_CONTROL 0x61230 +#define PFIT_PGM_RATIOS 0x61234 + +/** + * Indicates that all dependencies of the panel are on: + * + * - PLL enabled + * - pipe enabled + * - LVDS/DVOB/DVOC on + */ +# define PP_READY (1 << 30) # define PP_SEQUENCE_NONE (0 << 28) +# define PP_SEQUENCE_ON (1 << 28) # define PP_SEQUENCE_OFF (2 << 28) +# define PP_SEQUENCE_MASK 0x30000000 +#define PP_CONTROL 0x61204 +# define POWER_TARGET_ON (1 << 0) + +#define LVDSPP_ON 0x61208 +#define LVDSPP_OFF 0x6120c +#define PP_CYCLE 0x61210 + +/* Framebuffer compression */ +#define FBC_CFB_BASE 0x03200 /* 4k page aligned */ +#define FBC_LL_BASE 0x03204 /* 4k page aligned */ +#define FBC_CONTROL 0x03208 + +#define VGACNTRL 0x71400 + +#define VCLK_DIVISOR_VGA0 0x6000 +#define VCLK_DIVISOR_VGA1 0x6004 +#define VCLK_POST_DIV 0x6010 + +/* Framebuffer compression */ +#define FBC_CFB_BASE 0x03200 /* 4k page aligned */ +#define FBC_LL_BASE 0x03204 /* 4k page aligned */ +#define FBC_CONTROL 0x03208 +#define FBC_CTL_EN (1<<31) +#define FBC_CTL_PERIODIC (1<<30) +#define FBC_CTL_INTERVAL_SHIFT (16) +#define FBC_CTL_UNCOMPRESSIBLE (1<<14) +#define FBC_CTL_STRIDE_SHIFT (5) +#define FBC_CTL_FENCENO (1<<0) #define FBC_COMMAND 0x0320c +#define FBC_CMD_COMPRESS (1<<0) #define FBC_STATUS 0x03210 +#define FBC_STAT_COMPRESSING (1<<31) +#define FBC_STAT_COMPRESSED (1<<30) +#define FBC_STAT_MODIFIED (1<<29) +#define FBC_STAT_CURRENT_LINE (1<<0) +#define FBC_CONTROL2 0x03214 +#define FBC_CTL_FENCE_DBL (0<<4) +#define FBC_CTL_IDLE_IMM (0<<2) +#define FBC_CTL_IDLE_FULL (1<<2) +#define FBC_CTL_IDLE_LINE (2<<2) +#define FBC_CTL_IDLE_DEBUG (3<<2) +#define FBC_CTL_CPU_FENCE (1<<1) +#define FBC_CTL_PLANEA (0<<0) +#define FBC_CTL_PLANEB (1<<0) +#define FBC_FENCE_OFF 0x0321b + +#define FBC_LL_SIZE (1536) +#define FBC_LL_PAD (32) + +/* + * Some BIOS scratch area registers. The 845 (and 830?) store the amount + * of video memory available to the BIOS in SWF1. + */ + +#define SWF0 0x71410 + +/* + * 855 scratch registers. + */ +#define SWF10 0x70410 + +#define SWF30 0x72414 + +#define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 +#define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562 +#define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582 +#define PCI_DEVICE_ID_INTEL_82865_IG 0x2572 +#define PCI_DEVICE_ID_INTEL_82915G_IG 0x2582 +#define PCI_DEVICE_ID_INTEL_82915GM_IG 0x2592 +#define PCI_DEVICE_ID_INTEL_82945G_IG 0x2772 +#define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27A2 +#define PCI_DEVICE_ID_INTEL_82946_GZ 0x2972 +#define PCI_DEVICE_ID_INTEL_82G35_IG 0x2982 +#define PCI_DEVICE_ID_INTEL_82Q963_IG 0x2992 +#define PCI_DEVICE_ID_INTEL_82G965_IG 0x29a2 +#define PCI_DEVICE_ID_INTEL_GM965_IG 0x2a02 +#define PCI_DEVICE_ID_INTEL_GME965_IG 0x2a12 +#define PCI_DEVICE_ID_INTEL_82G33_IG 0x29c2 +#define PCI_DEVICE_ID_INTEL_82Q35_IG 0x29b2 +#define PCI_DEVICE_ID_INTEL_82Q33_IG 0x29d2 +#define PCI_DEVICE_ID_INTEL_CANTIGA_IG 0x2a42 + + +#define IS_I830(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82830_CGC) +#define IS_845G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82845G_IG) +#define IS_I85X(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82855GM_IG) +#define IS_I855(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82855GM_IG) +#define IS_I865G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82865_IG) + +#define IS_I915G(dev) (dev->pci_device == PCI_DEVICE_ID_INTEL_82915G_IG) +#define IS_I915GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82915GM_IG) +#define IS_I945G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82945G_IG) +#define IS_I945GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82945GM_IG) + +#define IS_I965G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82946_GZ || \ + (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G35_IG || \ + (dev)->pci_device == PCI_DEVICE_ID_INTEL_82Q963_IG || \ + (dev)->pci_device == PCI_DEVICE_ID_INTEL_82G965_IG || \ + (dev)->pci_device == PCI_DEVICE_ID_INTEL_GM965_IG || \ + (dev)->pci_device == PCI_DEVICE_ID_INTEL_GME965_IG) + +#define IS_I965GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_GM965_IG) + +#define IS_G33(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82G33_IG || \ + (dev)->pci_device == PCI_DEVICE_ID_INTEL_82Q35_IG || \ + (dev)->pci_device == PCI_DEVICE_ID_INTEL_82Q33_IG) + +#define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \ + IS_I945GM(dev) || IS_I965G(dev)) + +#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ + IS_I945GM(dev) || IS_I965GM(dev)) + +#define IS_IGD_GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_CANTIGA_IG) + #endif /* _I915_DRV_H */ |