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: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
Arto Merilainen 2013-10-14 15:21:53 +03:00 коммит произвёл Thierry Reding
Родитель 8736fe8153
Коммит f5a954fed9
6 изменённых файлов: 92 добавлений и 2 удалений

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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,20 +336,30 @@ 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;
syncpt = devm_kzalloc(host->dev, sizeof(*syncpt) * host->info->nb_pts,
GFP_KERNEL);
GFP_KERNEL);
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;
}

Просмотреть файл

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

Просмотреть файл

@ -125,7 +125,9 @@ static inline void host1x_bo_kunmap(struct host1x_bo *bo,
*/
#define HOST1X_SYNCPT_CLIENT_MANAGED (1 << 0)
#define HOST1X_SYNCPT_HAS_BASE (1 << 1)
struct host1x_syncpt_base;
struct host1x_syncpt;
struct host1x;
@ -140,6 +142,9 @@ struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
unsigned long flags);
void host1x_syncpt_free(struct host1x_syncpt *sp);
struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp);
u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base);
/*
* host1x channel
*/