drivers/gpu/host1x/hw/cdma_hw.c

Source file repositories/reference/linux-study-clean/drivers/gpu/host1x/hw/cdma_hw.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/host1x/hw/cdma_hw.c
Extension
.c
Size
9910 bytes
Lines
378
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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Tegra host1x Command DMA
 *
 * Copyright (c) 2010-2013, NVIDIA Corporation.
 */

#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>

#include "../cdma.h"
#include "../channel.h"
#include "../dev.h"
#include "../debug.h"

/*
 * Put the restart at the end of pushbuffer memory
 */
static void push_buffer_init(struct push_buffer *pb)
{
	*(u32 *)(pb->mapped + pb->size) = host1x_opcode_restart(0);
}

/*
 * Increment timedout buffer's syncpt via CPU.
 */
static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr,
				u32 syncpt_incrs, u32 syncval, u32 nr_slots)
{
	unsigned int i;

	for (i = 0; i < syncpt_incrs; i++)
		host1x_syncpt_incr(cdma->timeout.syncpt);

	/* after CPU incr, ensure shadow is up to date */
	host1x_syncpt_load(cdma->timeout.syncpt);
}

/*
 * Start channel DMA
 */
static void cdma_start(struct host1x_cdma *cdma)
{
	struct host1x_channel *ch = cdma_to_channel(cdma);
	u64 start, end;

	if (cdma->running)
		return;

	cdma->last_pos = cdma->push_buffer.pos;
	start = cdma->push_buffer.dma;
	end = cdma->push_buffer.size + 4;

	host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP,
			 HOST1X_CHANNEL_DMACTRL);

	/* set base, put and end pointer */
	host1x_ch_writel(ch, lower_32_bits(start), HOST1X_CHANNEL_DMASTART);
#if HOST1X_HW >= 6
	host1x_ch_writel(ch, upper_32_bits(start), HOST1X_CHANNEL_DMASTART_HI);
#endif
	host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT);
#if HOST1X_HW >= 6
	host1x_ch_writel(ch, 0, HOST1X_CHANNEL_DMAPUT_HI);
#endif
	host1x_ch_writel(ch, lower_32_bits(end), HOST1X_CHANNEL_DMAEND);
#if HOST1X_HW >= 6
	host1x_ch_writel(ch, upper_32_bits(end), HOST1X_CHANNEL_DMAEND_HI);
#endif

	/* reset GET */
	host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP |
			 HOST1X_CHANNEL_DMACTRL_DMAGETRST |
			 HOST1X_CHANNEL_DMACTRL_DMAINITGET,
			 HOST1X_CHANNEL_DMACTRL);

	/* start the command DMA */
	host1x_ch_writel(ch, 0, HOST1X_CHANNEL_DMACTRL);

	cdma->running = true;
}

/*
 * Similar to cdma_start(), but rather than starting from an idle
 * state (where DMA GET is set to DMA PUT), on a timeout we restore
 * DMA GET from an explicit value (so DMA may again be pending).
 */
static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr)
{

Annotation

Implementation Notes