drivers/gpu/drm/panthor/panthor_pwr.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/panthor/panthor_pwr.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/panthor/panthor_pwr.c
Extension
.c
Size
16241 bytes
Lines
577
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

struct panthor_pwr {
	/** @iomem: CPU mapping of PWR_CONTROL iomem region */
	void __iomem *iomem;

	/** @irq: PWR irq. */
	struct panthor_irq irq;

	/** @reqs_lock: Lock protecting access to pending_reqs. */
	spinlock_t reqs_lock;

	/** @pending_reqs: Pending PWR requests. */
	u32 pending_reqs;

	/** @reqs_acked: PWR request wait queue. */
	wait_queue_head_t reqs_acked;
};

static void panthor_pwr_irq_handler(struct panthor_device *ptdev, u32 status)
{
	struct panthor_pwr *pwr = ptdev->pwr;

	spin_lock(&ptdev->pwr->reqs_lock);
	gpu_write(pwr->irq.iomem, INT_CLEAR, status);

	if (unlikely(status & PWR_IRQ_COMMAND_NOT_ALLOWED))
		drm_err(&ptdev->base, "PWR_IRQ: COMMAND_NOT_ALLOWED");

	if (unlikely(status & PWR_IRQ_COMMAND_INVALID))
		drm_err(&ptdev->base, "PWR_IRQ: COMMAND_INVALID");

	if (status & ptdev->pwr->pending_reqs) {
		ptdev->pwr->pending_reqs &= ~status;
		wake_up_all(&ptdev->pwr->reqs_acked);
	}
	spin_unlock(&ptdev->pwr->reqs_lock);
}
PANTHOR_IRQ_HANDLER(pwr, panthor_pwr_irq_handler);

static void panthor_pwr_write_command(struct panthor_device *ptdev, u32 command, u64 args)
{
	struct panthor_pwr *pwr = ptdev->pwr;

	if (args)
		gpu_write64(pwr->iomem, PWR_CMDARG, args);

	gpu_write(pwr->iomem, PWR_COMMAND, command);
}

static bool reset_irq_raised(struct panthor_device *ptdev)
{
	struct panthor_pwr *pwr = ptdev->pwr;

	return gpu_read(pwr->irq.iomem, INT_RAWSTAT) & PWR_IRQ_RESET_COMPLETED;
}

static bool reset_pending(struct panthor_device *ptdev)
{
	return (ptdev->pwr->pending_reqs & PWR_IRQ_RESET_COMPLETED);
}

static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd)
{
	struct panthor_pwr *pwr = ptdev->pwr;

	scoped_guard(spinlock_irqsave, &ptdev->pwr->reqs_lock) {
		if (reset_pending(ptdev)) {
			drm_WARN(&ptdev->base, 1, "Reset already pending");
		} else {
			ptdev->pwr->pending_reqs |= PWR_IRQ_RESET_COMPLETED;
			gpu_write(pwr->irq.iomem, INT_CLEAR, PWR_IRQ_RESET_COMPLETED);
			panthor_pwr_write_command(ptdev, reset_cmd, 0);
		}
	}

	if (!wait_event_timeout(ptdev->pwr->reqs_acked, !reset_pending(ptdev),
				msecs_to_jiffies(PWR_RESET_TIMEOUT_MS))) {
		guard(spinlock_irqsave)(&ptdev->pwr->reqs_lock);

		if (reset_pending(ptdev) && !reset_irq_raised(ptdev)) {
			drm_err(&ptdev->base, "RESET timed out (0x%x)", reset_cmd);
			return -ETIMEDOUT;
		}

		ptdev->pwr->pending_reqs &= ~PWR_IRQ_RESET_COMPLETED;
	}

	return 0;
}

static const char *get_domain_name(u8 domain)

Annotation

Implementation Notes