Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  psb_irq.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/**************************************************************************
 * Copyright (c) 2007, Intel Corporation.
 * All Rights Reserved.
 *
 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
 * develop this driver.
 *
 **************************************************************************/


#include <drm/drm_drv.h>
#include <drm/drm_vblank.h>

#include "power.h"
#include "psb_drv.h"
#include "psb_intel_reg.h"
#include "psb_irq.h"
#include "psb_reg.h"

/*
 * inline functions
 */


static inline u32 gma_pipestat(int pipe)
{
 if (pipe == 0)
  return PIPEASTAT;
 if (pipe == 1)
  return PIPEBSTAT;
 if (pipe == 2)
  return PIPECSTAT;
 BUG();
}

static inline u32 gma_pipeconf(int pipe)
{
 if (pipe == 0)
  return PIPEACONF;
 if (pipe == 1)
  return PIPEBCONF;
 if (pipe == 2)
  return PIPECCONF;
 BUG();
}

void gma_enable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
{
 if ((dev_priv->pipestat[pipe] & mask) != mask) {
  u32 reg = gma_pipestat(pipe);
  dev_priv->pipestat[pipe] |= mask;
  /* Enable the interrupt, clear any pending status */
  if (gma_power_begin(&dev_priv->dev, false)) {
   u32 writeVal = PSB_RVDC32(reg);
   writeVal |= (mask | (mask >> 16));
   PSB_WVDC32(writeVal, reg);
   (void) PSB_RVDC32(reg);
   gma_power_end(&dev_priv->dev);
  }
 }
}

void gma_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
{
 if ((dev_priv->pipestat[pipe] & mask) != 0) {
  u32 reg = gma_pipestat(pipe);
  dev_priv->pipestat[pipe] &= ~mask;
  if (gma_power_begin(&dev_priv->dev, false)) {
   u32 writeVal = PSB_RVDC32(reg);
   writeVal &= ~mask;
   PSB_WVDC32(writeVal, reg);
   (void) PSB_RVDC32(reg);
   gma_power_end(&dev_priv->dev);
  }
 }
}

/*
 * Display controller interrupt handler for pipe event.
 */

static void gma_pipe_event_handler(struct drm_device *dev, int pipe)
{
 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);

 uint32_t pipe_stat_val = 0;
 uint32_t pipe_stat_reg = gma_pipestat(pipe);
 uint32_t pipe_enable = dev_priv->pipestat[pipe];
 uint32_t pipe_status = dev_priv->pipestat[pipe] >> 16;
 uint32_t pipe_clear;
 uint32_t i = 0;

 spin_lock(&dev_priv->irqmask_lock);

 pipe_stat_val = PSB_RVDC32(pipe_stat_reg);
 pipe_stat_val &= pipe_enable | pipe_status;
 pipe_stat_val &= pipe_stat_val >> 16;

 spin_unlock(&dev_priv->irqmask_lock);

 /* Clear the 2nd level interrupt status bits
 * Sometimes the bits are very sticky so we repeat until they unstick */

 for (i = 0; i < 0xffff; i++) {
  PSB_WVDC32(PSB_RVDC32(pipe_stat_reg), pipe_stat_reg);
  pipe_clear = PSB_RVDC32(pipe_stat_reg) & pipe_status;

  if (pipe_clear == 0)
   break;
 }

 if (pipe_clear)
  dev_err(dev->dev,
  "%s, can't clear status bits for pipe %d, its value = 0x%x.\n",
  __func__, pipe, PSB_RVDC32(pipe_stat_reg));

 if (pipe_stat_val & PIPE_VBLANK_STATUS) {
  struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
  struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
  unsigned long flags;

  drm_handle_vblank(dev, pipe);

  spin_lock_irqsave(&dev->event_lock, flags);
  if (gma_crtc->page_flip_event) {
   drm_crtc_send_vblank_event(crtc,
         gma_crtc->page_flip_event);
   gma_crtc->page_flip_event = NULL;
   drm_crtc_vblank_put(crtc);
  }
  spin_unlock_irqrestore(&dev->event_lock, flags);
 }
}

/*
 * Display controller interrupt handler.
 */

static void gma_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat)
{
 if (vdc_stat & _PSB_IRQ_ASLE)
  psb_intel_opregion_asle_intr(dev);

 if (vdc_stat & _PSB_VSYNC_PIPEA_FLAG)
  gma_pipe_event_handler(dev, 0);

 if (vdc_stat & _PSB_VSYNC_PIPEB_FLAG)
  gma_pipe_event_handler(dev, 1);
}

/*
 * SGX interrupt handler
 */

static void gma_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2)
{
 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 u32 val, addr;

 if (stat_1 & _PSB_CE_TWOD_COMPLETE)
  val = PSB_RSGX32(PSB_CR_2D_BLIT_STATUS);

 if (stat_2 & _PSB_CE2_BIF_REQUESTER_FAULT) {
  val = PSB_RSGX32(PSB_CR_BIF_INT_STAT);
  addr = PSB_RSGX32(PSB_CR_BIF_FAULT);
  if (val) {
   if (val & _PSB_CBI_STAT_PF_N_RW)
    DRM_ERROR("SGX MMU page fault:");
   else
    DRM_ERROR("SGX MMU read / write protection fault:");

   if (val & _PSB_CBI_STAT_FAULT_CACHE)
    DRM_ERROR("\tCache requestor");
   if (val & _PSB_CBI_STAT_FAULT_TA)
    DRM_ERROR("\tTA requestor");
   if (val & _PSB_CBI_STAT_FAULT_VDM)
    DRM_ERROR("\tVDM requestor");
   if (val & _PSB_CBI_STAT_FAULT_2D)
    DRM_ERROR("\t2D requestor");
   if (val & _PSB_CBI_STAT_FAULT_PBE)
    DRM_ERROR("\tPBE requestor");
   if (val & _PSB_CBI_STAT_FAULT_TSP)
    DRM_ERROR("\tTSP requestor");
   if (val & _PSB_CBI_STAT_FAULT_ISP)
    DRM_ERROR("\tISP requestor");
   if (val & _PSB_CBI_STAT_FAULT_USSEPDS)
    DRM_ERROR("\tUSSEPDS requestor");
   if (val & _PSB_CBI_STAT_FAULT_HOST)
    DRM_ERROR("\tHost requestor");

   DRM_ERROR("\tMMU failing address is 0x%08x.\n",
      (unsigned int)addr);
  }
 }

 /* Clear bits */
 PSB_WSGX32(stat_1, PSB_CR_EVENT_HOST_CLEAR);
 PSB_WSGX32(stat_2, PSB_CR_EVENT_HOST_CLEAR2);
 PSB_RSGX32(PSB_CR_EVENT_HOST_CLEAR2);
}

static irqreturn_t gma_irq_handler(int irq, void *arg)
{
 struct drm_device *dev = arg;
 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 uint32_t vdc_stat, dsp_int = 0, sgx_int = 0, hotplug_int = 0;
 u32 sgx_stat_1, sgx_stat_2;
 int handled = 0;

 spin_lock(&dev_priv->irqmask_lock);

 vdc_stat = PSB_RVDC32(PSB_INT_IDENTITY_R);

 if (vdc_stat & (_PSB_PIPE_EVENT_FLAG|_PSB_IRQ_ASLE))
  dsp_int = 1;

 if (vdc_stat & _PSB_IRQ_SGX_FLAG)
  sgx_int = 1;
 if (vdc_stat & _PSB_IRQ_DISP_HOTSYNC)
  hotplug_int = 1;

 vdc_stat &= dev_priv->vdc_irq_mask;
 spin_unlock(&dev_priv->irqmask_lock);

 if (dsp_int) {
  gma_vdc_interrupt(dev, vdc_stat);
  handled = 1;
 }

 if (sgx_int) {
  sgx_stat_1 = PSB_RSGX32(PSB_CR_EVENT_STATUS);
  sgx_stat_2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2);
  gma_sgx_interrupt(dev, sgx_stat_1, sgx_stat_2);
  handled = 1;
 }

 /* Note: this bit has other meanings on some devices, so we will
   need to address that later if it ever matters */

 if (hotplug_int && dev_priv->ops->hotplug) {
  handled = dev_priv->ops->hotplug(dev);
  REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
 }

 PSB_WVDC32(vdc_stat, PSB_INT_IDENTITY_R);
 (void) PSB_RVDC32(PSB_INT_IDENTITY_R);
 rmb();

 if (!handled)
  return IRQ_NONE;

 return IRQ_HANDLED;
}

void gma_irq_preinstall(struct drm_device *dev)
{
 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 unsigned long irqflags;

 spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);

 PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
 PSB_WVDC32(0x00000000, PSB_INT_MASK_R);
 PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R);
 PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE);
 PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE);

 if (dev->vblank[0].enabled)
  dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG;
 if (dev->vblank[1].enabled)
  dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEB_FLAG;

 /* Revisit this area - want per device masks ? */
 if (dev_priv->ops->hotplug)
  dev_priv->vdc_irq_mask |= _PSB_IRQ_DISP_HOTSYNC;
 dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE | _PSB_IRQ_SGX_FLAG;

 /* This register is safe even if display island is off */
 PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
 spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
}

void gma_irq_postinstall(struct drm_device *dev)
{
 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 unsigned long irqflags;
 unsigned int i;

 spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);

 /* Enable 2D and MMU fault interrupts */
 PSB_WSGX32(_PSB_CE2_BIF_REQUESTER_FAULT, PSB_CR_EVENT_HOST_ENABLE2);
 PSB_WSGX32(_PSB_CE_TWOD_COMPLETE, PSB_CR_EVENT_HOST_ENABLE);
 PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); /* Post */

 /* This register is safe even if display island is off */
 PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
 PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);

 for (i = 0; i < dev->num_crtcs; ++i) {
  if (dev->vblank[i].enabled)
   gma_enable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
  else
   gma_disable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
 }

 if (dev_priv->ops->hotplug_enable)
  dev_priv->ops->hotplug_enable(dev, true);

 spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
}

int gma_irq_install(struct drm_device *dev)
{
 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 struct pci_dev *pdev = to_pci_dev(dev->dev);
 int ret;

 if (dev_priv->use_msi && pci_enable_msi(pdev)) {
  dev_warn(dev->dev, "Enabling MSI failed!\n");
  dev_priv->use_msi = false;
 }

 if (pdev->irq == IRQ_NOTCONNECTED)
  return -ENOTCONN;

 gma_irq_preinstall(dev);

 /* PCI devices require shared interrupts. */
 ret = request_irq(pdev->irq, gma_irq_handler, IRQF_SHARED, dev->driver->name, dev);
 if (ret)
  return ret;

 gma_irq_postinstall(dev);

 dev_priv->irq_enabled = true;

 return 0;
}

void gma_irq_uninstall(struct drm_device *dev)
{
 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 struct pci_dev *pdev = to_pci_dev(dev->dev);
 unsigned long irqflags;
 unsigned int i;

 if (!dev_priv->irq_enabled)
  return;

 spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);

 if (dev_priv->ops->hotplug_enable)
  dev_priv->ops->hotplug_enable(dev, false);

 PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);

 for (i = 0; i < dev->num_crtcs; ++i) {
  if (dev->vblank[i].enabled)
   gma_disable_pipestat(dev_priv, i, PIPE_VBLANK_INTERRUPT_ENABLE);
 }

 dev_priv->vdc_irq_mask &= _PSB_IRQ_SGX_FLAG |
      _PSB_IRQ_MSVDX_FLAG |
      _LNC_IRQ_TOPAZ_FLAG;

 /* These two registers are safe even if display island is off */
 PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
 PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);

 wmb();

 /* This register is safe even if display island is off */
 PSB_WVDC32(PSB_RVDC32(PSB_INT_IDENTITY_R), PSB_INT_IDENTITY_R);
 spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);

 free_irq(pdev->irq, dev);
 if (dev_priv->use_msi)
  pci_disable_msi(pdev);
}

int gma_crtc_enable_vblank(struct drm_crtc *crtc)
{
 struct drm_device *dev = crtc->dev;
 unsigned int pipe = crtc->index;
 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 unsigned long irqflags;
 uint32_t reg_val = 0;
 uint32_t pipeconf_reg = gma_pipeconf(pipe);

 if (gma_power_begin(dev, false)) {
  reg_val = REG_READ(pipeconf_reg);
  gma_power_end(dev);
 }

 if (!(reg_val & PIPEACONF_ENABLE))
  return -EINVAL;

 spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);

 if (pipe == 0)
  dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG;
 else if (pipe == 1)
  dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEB_FLAG;

 PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
 PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
 gma_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE);

 spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);

 return 0;
}

void gma_crtc_disable_vblank(struct drm_crtc *crtc)
{
 struct drm_device *dev = crtc->dev;
 unsigned int pipe = crtc->index;
 struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 unsigned long irqflags;

 spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);

 if (pipe == 0)
  dev_priv->vdc_irq_mask &= ~_PSB_VSYNC_PIPEA_FLAG;
 else if (pipe == 1)
  dev_priv->vdc_irq_mask &= ~_PSB_VSYNC_PIPEB_FLAG;

 PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
 PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
 gma_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE);

 spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
}

/* Called from drm generic code, passed a 'crtc', which
 * we use as a pipe index
 */

u32 gma_crtc_get_vblank_counter(struct drm_crtc *crtc)
{
 struct drm_device *dev = crtc->dev;
 unsigned int pipe = crtc->index;
 uint32_t high_frame = PIPEAFRAMEHIGH;
 uint32_t low_frame = PIPEAFRAMEPIXEL;
 uint32_t pipeconf_reg = PIPEACONF;
 uint32_t reg_val = 0;
 uint32_t high1 = 0, high2 = 0, low = 0, count = 0;

 switch (pipe) {
 case 0:
  break;
 case 1:
  high_frame = PIPEBFRAMEHIGH;
  low_frame = PIPEBFRAMEPIXEL;
  pipeconf_reg = PIPEBCONF;
  break;
 case 2:
  high_frame = PIPECFRAMEHIGH;
  low_frame = PIPECFRAMEPIXEL;
  pipeconf_reg = PIPECCONF;
  break;
 default:
  dev_err(dev->dev, "%s, invalid pipe.\n", __func__);
  return 0;
 }

 if (!gma_power_begin(dev, false))
  return 0;

 reg_val = REG_READ(pipeconf_reg);

 if (!(reg_val & PIPEACONF_ENABLE)) {
  dev_err(dev->dev, "trying to get vblank count for disabled pipe %u\n",
   pipe);
  goto err_gma_power_end;
 }

 /*
 * High & low register fields aren't synchronized, so make sure
 * we get a low value that's stable across two reads of the high
 * register.
 */

 do {
  high1 = ((REG_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
    PIPE_FRAME_HIGH_SHIFT);
  low =  ((REG_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
   PIPE_FRAME_LOW_SHIFT);
  high2 = ((REG_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
    PIPE_FRAME_HIGH_SHIFT);
 } while (high1 != high2);

 count = (high1 << 8) | low;

err_gma_power_end:
 gma_power_end(dev);

 return count;
}


Messung V0.5
C=96 H=97 G=96

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge