Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f5a954fe authored by Arto Merilainen's avatar Arto Merilainen Committed by Thierry Reding
Browse files

gpu: host1x: Add syncpoint base support



This patch adds support for hardware syncpoint bases. This creates
a simple mechanism to stall the command FIFO until an operation is
completed.

Signed-off-by: default avatarArto Merilainen <amerilainen@nvidia.com>
Reviewed-by: default avatarTerje Bergstrom <tbergstrom@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 8736fe81
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "job.h"

struct host1x_syncpt;
struct host1x_syncpt_base;
struct host1x_channel;
struct host1x_cdma;
struct host1x_job;
@@ -102,6 +103,7 @@ struct host1x {

	void __iomem *regs;
	struct host1x_syncpt *syncpt;
	struct host1x_syncpt_base *bases;
	struct device *dev;
	struct clk *clk;

+20 −0
Original line number Diff line number Diff line
@@ -67,6 +67,22 @@ static void submit_gathers(struct host1x_job *job)
	}
}

static inline void synchronize_syncpt_base(struct host1x_job *job)
{
	struct host1x *host = dev_get_drvdata(job->channel->dev->parent);
	struct host1x_syncpt *sp = host->syncpt + job->syncpt_id;
	u32 id, value;

	value = host1x_syncpt_read_max(sp);
	id = sp->base->id;

	host1x_cdma_push(&job->channel->cdma,
			 host1x_opcode_setclass(HOST1X_CLASS_HOST1X,
				HOST1X_UCLASS_LOAD_SYNCPT_BASE, 1),
			 HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(id) |
			 HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(value));
}

static int channel_submit(struct host1x_job *job)
{
	struct host1x_channel *ch = job->channel;
@@ -118,6 +134,10 @@ static int channel_submit(struct host1x_job *job)
					host1x_syncpt_read_max(sp)));
	}

	/* Synchronize base register to allow using it for relative waiting */
	if (sp->base)
		synchronize_syncpt_base(job);

	syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs);

	job->syncpt_end = syncval;
+6 −0
Original line number Diff line number Diff line
@@ -111,6 +111,12 @@ static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v)
}
#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
	host1x_uclass_wait_syncpt_base_offset_f(v)
static inline u32 host1x_uclass_load_syncpt_base_r(void)
{
	return 0xb;
}
#define HOST1X_UCLASS_LOAD_SYNCPT_BASE \
	host1x_uclass_load_syncpt_base_r()
static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
{
	return (v & 0xff) << 24;
+53 −2
Original line number Diff line number Diff line
@@ -30,6 +30,29 @@
#define SYNCPT_CHECK_PERIOD (2 * HZ)
#define MAX_STUCK_CHECK_COUNT 15

static struct host1x_syncpt_base *
host1x_syncpt_base_request(struct host1x *host)
{
	struct host1x_syncpt_base *bases = host->bases;
	unsigned int i;

	for (i = 0; i < host->info->nb_bases; i++)
		if (!bases[i].requested)
			break;

	if (i >= host->info->nb_bases)
		return NULL;

	bases[i].requested = true;
	return &bases[i];
}

static void host1x_syncpt_base_free(struct host1x_syncpt_base *base)
{
	if (base)
		base->requested = false;
}

static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
						 struct device *dev,
						 unsigned long flags)
@@ -44,6 +67,12 @@ static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
	if (i >= host->info->nb_pts)
		return NULL;

	if (flags & HOST1X_SYNCPT_HAS_BASE) {
		sp->base = host1x_syncpt_base_request(host);
		if (!sp->base)
			return NULL;
	}

	name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id,
			dev ? dev_name(dev) : NULL);
	if (!name)
@@ -307,6 +336,7 @@ int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr)

int host1x_syncpt_init(struct host1x *host)
{
	struct host1x_syncpt_base *bases;
	struct host1x_syncpt *syncpt;
	int i;

@@ -315,12 +345,21 @@ int host1x_syncpt_init(struct host1x *host)
	if (!syncpt)
		return -ENOMEM;

	for (i = 0; i < host->info->nb_pts; ++i) {
	bases = devm_kzalloc(host->dev, sizeof(*bases) * host->info->nb_bases,
			     GFP_KERNEL);
	if (!bases)
		return -ENOMEM;

	for (i = 0; i < host->info->nb_pts; i++) {
		syncpt[i].id = i;
		syncpt[i].host = host;
	}

	for (i = 0; i < host->info->nb_bases; i++)
		bases[i].id = i;

	host->syncpt = syncpt;
	host->bases = bases;

	host1x_syncpt_restore(host);

@@ -344,7 +383,9 @@ void host1x_syncpt_free(struct host1x_syncpt *sp)
	if (!sp)
		return;

	host1x_syncpt_base_free(sp->base);
	kfree(sp->name);
	sp->base = NULL;
	sp->dev = NULL;
	sp->name = NULL;
	sp->client_managed = false;
@@ -398,3 +439,13 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id)
		return NULL;
	return host->syncpt + id;
}

struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp)
{
	return sp ? sp->base : NULL;
}

u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base)
{
	return base->id;
}
+6 −0
Original line number Diff line number Diff line
@@ -31,6 +31,11 @@ struct host1x;
/* Reserved for replacing an expired wait with a NOP */
#define HOST1X_SYNCPT_RESERVED			0

struct host1x_syncpt_base {
	unsigned int id;
	bool requested;
};

struct host1x_syncpt {
	int id;
	atomic_t min_val;
@@ -40,6 +45,7 @@ struct host1x_syncpt {
	bool client_managed;
	struct host1x *host;
	struct device *dev;
	struct host1x_syncpt_base *base;

	/* interrupt data */
	struct host1x_syncpt_intr intr;
Loading