drivers/gpu/drm/gma500/psb_irq.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/gma500/psb_irq.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/gma500/psb_irq.c
Extension
.c
Size
13054 bytes
Lines
495
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

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);

Annotation

Implementation Notes