0,0 → 1,441 |
/* i915_dma.c -- DMA support for the I915 -*- linux-c -*- |
*/ |
/* |
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. |
* All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the |
* "Software"), to deal in the Software without restriction, including |
* without limitation the rights to use, copy, modify, merge, publish, |
* distribute, sub license, and/or sell copies of the Software, and to |
* permit persons to whom the Software is furnished to do so, subject to |
* the following conditions: |
* |
* The above copyright notice and this permission notice (including the |
* next paragraph) shall be included in all copies or substantial portions |
* of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
*/ |
|
#include "drmP.h" |
#include "drm.h" |
#include "drm_crtc_helper.h" |
#include "drm_fb_helper.h" |
#include "intel_drv.h" |
//#include "i915_drm.h" |
#include "i915_drv.h" |
#include <drm/intel-gtt.h> |
//#include "i915_trace.h" |
//#include "../../../platform/x86/intel_ips.h" |
#include <linux/pci.h> |
//#include <linux/vgaarb.h> |
//#include <linux/acpi.h> |
//#include <linux/pnp.h> |
//#include <linux/vga_switcheroo.h> |
//#include <linux/slab.h> |
//#include <acpi/video.h> |
|
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen); |
|
static void i915_write_hws_pga(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
u32 addr; |
|
addr = dev_priv->status_page_dmah->busaddr; |
if (INTEL_INFO(dev)->gen >= 4) |
addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0; |
I915_WRITE(HWS_PGA, addr); |
} |
|
|
/** |
* Sets up the hardware status page for devices that need a physical address |
* in the register. |
*/ |
static int i915_init_phys_hws(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
|
/* Program Hardware Status Page */ |
dev_priv->status_page_dmah = |
drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE); |
|
if (!dev_priv->status_page_dmah) { |
DRM_ERROR("Can not allocate hardware status page\n"); |
return -ENOMEM; |
} |
|
i915_write_hws_pga(dev); |
|
dbgprintf("Enabled hardware status page\n"); |
return 0; |
} |
|
static void i915_pineview_get_mem_freq(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
u32 tmp; |
|
tmp = I915_READ(CLKCFG); |
|
switch (tmp & CLKCFG_FSB_MASK) { |
case CLKCFG_FSB_533: |
dev_priv->fsb_freq = 533; /* 133*4 */ |
break; |
case CLKCFG_FSB_800: |
dev_priv->fsb_freq = 800; /* 200*4 */ |
break; |
case CLKCFG_FSB_667: |
dev_priv->fsb_freq = 667; /* 167*4 */ |
break; |
case CLKCFG_FSB_400: |
dev_priv->fsb_freq = 400; /* 100*4 */ |
break; |
} |
|
switch (tmp & CLKCFG_MEM_MASK) { |
case CLKCFG_MEM_533: |
dev_priv->mem_freq = 533; |
break; |
case CLKCFG_MEM_667: |
dev_priv->mem_freq = 667; |
break; |
case CLKCFG_MEM_800: |
dev_priv->mem_freq = 800; |
break; |
} |
|
/* detect pineview DDR3 setting */ |
tmp = I915_READ(CSHRDDR3CTL); |
dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0; |
} |
|
static void i915_ironlake_get_mem_freq(struct drm_device *dev) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
u16 ddrpll, csipll; |
|
ddrpll = I915_READ16(DDRMPLL1); |
csipll = I915_READ16(CSIPLL0); |
|
switch (ddrpll & 0xff) { |
case 0xc: |
dev_priv->mem_freq = 800; |
break; |
case 0x10: |
dev_priv->mem_freq = 1066; |
break; |
case 0x14: |
dev_priv->mem_freq = 1333; |
break; |
case 0x18: |
dev_priv->mem_freq = 1600; |
break; |
default: |
DRM_DEBUG_DRIVER("unknown memory frequency 0x%02x\n", |
ddrpll & 0xff); |
dev_priv->mem_freq = 0; |
break; |
} |
|
dev_priv->r_t = dev_priv->mem_freq; |
|
switch (csipll & 0x3ff) { |
case 0x00c: |
dev_priv->fsb_freq = 3200; |
break; |
case 0x00e: |
dev_priv->fsb_freq = 3733; |
break; |
case 0x010: |
dev_priv->fsb_freq = 4266; |
break; |
case 0x012: |
dev_priv->fsb_freq = 4800; |
break; |
case 0x014: |
dev_priv->fsb_freq = 5333; |
break; |
case 0x016: |
dev_priv->fsb_freq = 5866; |
break; |
case 0x018: |
dev_priv->fsb_freq = 6400; |
break; |
default: |
DRM_DEBUG_DRIVER("unknown fsb frequency 0x%04x\n", |
csipll & 0x3ff); |
dev_priv->fsb_freq = 0; |
break; |
} |
|
if (dev_priv->fsb_freq == 3200) { |
dev_priv->c_m = 0; |
} else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) { |
dev_priv->c_m = 1; |
} else { |
dev_priv->c_m = 2; |
} |
} |
|
static int i915_get_bridge_dev(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
dev_priv->bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); |
if (!dev_priv->bridge_dev) { |
DRM_ERROR("bridge device not found\n"); |
return -1; |
} |
return 0; |
} |
|
|
/* Global for IPS driver to get at the current i915 device */ |
static struct drm_i915_private *i915_mch_dev; |
/* |
* Lock protecting IPS related data structures |
* - i915_mch_dev |
* - dev_priv->max_delay |
* - dev_priv->min_delay |
* - dev_priv->fmax |
* - dev_priv->gpu_busy |
*/ |
static DEFINE_SPINLOCK(mchdev_lock); |
|
|
/** |
* i915_driver_load - setup chip and create an initial config |
* @dev: DRM device |
* @flags: startup flags |
* |
* The driver load routine has to do several things: |
* - drive output discovery via intel_modeset_init() |
* - initialize the memory manager |
* - allocate initial config memory |
* - setup the DRM framebuffer with the allocated memory |
*/ |
int i915_driver_load(struct drm_device *dev, unsigned long flags) |
{ |
struct drm_i915_private *dev_priv; |
int ret = 0, mmio_bar; |
uint32_t agp_size; |
|
ENTER(); |
|
dev_priv = kzalloc(sizeof(drm_i915_private_t), GFP_KERNEL); |
if (dev_priv == NULL) |
return -ENOMEM; |
|
dev->dev_private = (void *)dev_priv; |
dev_priv->dev = dev; |
dev_priv->info = (struct intel_device_info *) flags; |
|
if (i915_get_bridge_dev(dev)) { |
ret = -EIO; |
goto free_priv; |
} |
|
/* overlay on gen2 is broken and can't address above 1G */ |
// if (IS_GEN2(dev)) |
// dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30)); |
|
/* 965GM sometimes incorrectly writes to hardware status page (HWS) |
* using 32bit addressing, overwriting memory if HWS is located |
* above 4GB. |
* |
* The documentation also mentions an issue with undefined |
* behaviour if any general state is accessed within a page above 4GB, |
* which also needs to be handled carefully. |
*/ |
// if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) |
// dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32)); |
|
mmio_bar = IS_GEN2(dev) ? 1 : 0; |
dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0); |
if (!dev_priv->regs) { |
DRM_ERROR("failed to map registers\n"); |
ret = -EIO; |
goto put_bridge; |
} |
|
dev_priv->mm.gtt = intel_gtt_get(); |
if (!dev_priv->mm.gtt) { |
DRM_ERROR("Failed to initialize GTT\n"); |
ret = -ENODEV; |
goto out_rmmap; |
} |
|
// agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; |
|
/* agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; */ |
|
// dev_priv->mm.gtt_mapping = |
// io_mapping_create_wc(dev->agp->base, agp_size); |
// if (dev_priv->mm.gtt_mapping == NULL) { |
// ret = -EIO; |
// goto out_rmmap; |
// } |
|
/* Set up a WC MTRR for non-PAT systems. This is more common than |
* one would think, because the kernel disables PAT on first |
* generation Core chips because WC PAT gets overridden by a UC |
* MTRR if present. Even if a UC MTRR isn't present. |
*/ |
// dev_priv->mm.gtt_mtrr = mtrr_add(dev->agp->base, |
// agp_size, |
// MTRR_TYPE_WRCOMB, 1); |
// if (dev_priv->mm.gtt_mtrr < 0) { |
// DRM_INFO("MTRR allocation failed. Graphics " |
// "performance may suffer.\n"); |
// } |
|
/* The i915 workqueue is primarily used for batched retirement of |
* requests (and thus managing bo) once the task has been completed |
* by the GPU. i915_gem_retire_requests() is called directly when we |
* need high-priority retirement, such as waiting for an explicit |
* bo. |
* |
* It is also used for periodic low-priority events, such as |
* idle-timers and recording error state. |
* |
* All tasks on the workqueue are expected to acquire the dev mutex |
* so there is no point in running more than one instance of the |
* workqueue at any time: max_active = 1 and NON_REENTRANT. |
*/ |
|
// dev_priv->wq = alloc_workqueue("i915", |
// WQ_UNBOUND | WQ_NON_REENTRANT, |
// 1); |
// if (dev_priv->wq == NULL) { |
// DRM_ERROR("Failed to create our workqueue.\n"); |
// ret = -ENOMEM; |
// goto out_mtrrfree; |
// } |
|
/* enable GEM by default */ |
dev_priv->has_gem = 1; |
|
|
// intel_irq_init(dev); |
|
/* Try to make sure MCHBAR is enabled before poking at it */ |
// intel_setup_mchbar(dev); |
intel_setup_gmbus(dev); |
|
// intel_opregion_setup(dev); |
|
/* Make sure the bios did its job and set up vital registers */ |
// intel_setup_bios(dev); |
|
i915_gem_load(dev); |
|
/* Init HWS */ |
if (!I915_NEED_GFX_HWS(dev)) { |
ret = i915_init_phys_hws(dev); |
if (ret) |
goto out_gem_unload; |
} |
|
if (IS_PINEVIEW(dev)) |
i915_pineview_get_mem_freq(dev); |
else if (IS_GEN5(dev)) |
i915_ironlake_get_mem_freq(dev); |
|
/* On the 945G/GM, the chipset reports the MSI capability on the |
* integrated graphics even though the support isn't actually there |
* according to the published specs. It doesn't appear to function |
* correctly in testing on 945G. |
* This may be a side effect of MSI having been made available for PEG |
* and the registers being closely associated. |
* |
* According to chipset errata, on the 965GM, MSI interrupts may |
* be lost or delayed, but we use them anyways to avoid |
* stuck interrupts on some machines. |
*/ |
// if (!IS_I945G(dev) && !IS_I945GM(dev)) |
// pci_enable_msi(dev->pdev); |
|
spin_lock_init(&dev_priv->irq_lock); |
spin_lock_init(&dev_priv->error_lock); |
spin_lock_init(&dev_priv->rps_lock); |
|
if (IS_MOBILE(dev) || !IS_GEN2(dev)) |
dev_priv->num_pipe = 2; |
else |
dev_priv->num_pipe = 1; |
|
// ret = drm_vblank_init(dev, dev_priv->num_pipe); |
// if (ret) |
// goto out_gem_unload; |
|
/* Start out suspended */ |
dev_priv->mm.suspended = 1; |
|
intel_detect_pch(dev); |
|
|
// if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
// ret = i915_load_modeset_init(dev); |
// if (ret < 0) { |
// DRM_ERROR("failed to init modeset\n"); |
// goto out_gem_unload; |
// } |
// } |
|
/* Must be done after probing outputs */ |
// intel_opregion_init(dev); |
// acpi_video_register(); |
|
// setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, |
// (unsigned long) dev); |
|
spin_lock(&mchdev_lock); |
i915_mch_dev = dev_priv; |
dev_priv->mchdev_lock = &mchdev_lock; |
spin_unlock(&mchdev_lock); |
|
// ips_ping_for_i915_load(); |
|
LEAVE(); |
|
return 0; |
|
out_gem_unload: |
// if (dev_priv->mm.inactive_shrinker.shrink) |
// unregister_shrinker(&dev_priv->mm.inactive_shrinker); |
|
// if (dev->pdev->msi_enabled) |
// pci_disable_msi(dev->pdev); |
|
// intel_teardown_gmbus(dev); |
// intel_teardown_mchbar(dev); |
// destroy_workqueue(dev_priv->wq); |
out_mtrrfree: |
// if (dev_priv->mm.gtt_mtrr >= 0) { |
// mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base, |
// dev->agp->agp_info.aper_size * 1024 * 1024); |
// dev_priv->mm.gtt_mtrr = -1; |
// } |
// io_mapping_free(dev_priv->mm.gtt_mapping); |
|
out_rmmap: |
pci_iounmap(dev->pdev, dev_priv->regs); |
|
put_bridge: |
// pci_dev_put(dev_priv->bridge_dev); |
free_priv: |
kfree(dev_priv); |
return ret; |
} |
|