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

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
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "job.h" #include "job.h"
struct host1x_syncpt; struct host1x_syncpt;
struct host1x_syncpt_base;
struct host1x_channel; struct host1x_channel;
struct host1x_cdma; struct host1x_cdma;
struct host1x_job; struct host1x_job;
...@@ -102,6 +103,7 @@ struct host1x { ...@@ -102,6 +103,7 @@ struct host1x {
void __iomem *regs; void __iomem *regs;
struct host1x_syncpt *syncpt; struct host1x_syncpt *syncpt;
struct host1x_syncpt_base *bases;
struct device *dev; struct device *dev;
struct clk *clk; struct clk *clk;
......
...@@ -67,6 +67,22 @@ static void submit_gathers(struct host1x_job *job) ...@@ -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) static int channel_submit(struct host1x_job *job)
{ {
struct host1x_channel *ch = job->channel; struct host1x_channel *ch = job->channel;
...@@ -118,6 +134,10 @@ static int channel_submit(struct host1x_job *job) ...@@ -118,6 +134,10 @@ static int channel_submit(struct host1x_job *job)
host1x_syncpt_read_max(sp))); 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); syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs);
job->syncpt_end = syncval; job->syncpt_end = syncval;
......
...@@ -111,6 +111,12 @@ static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v) ...@@ -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) \ #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
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) static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
{ {
return (v & 0xff) << 24; return (v & 0xff) << 24;
......
...@@ -30,6 +30,29 @@ ...@@ -30,6 +30,29 @@
#define SYNCPT_CHECK_PERIOD (2 * HZ) #define SYNCPT_CHECK_PERIOD (2 * HZ)
#define MAX_STUCK_CHECK_COUNT 15 #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, static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
struct device *dev, struct device *dev,
unsigned long flags) unsigned long flags)
...@@ -44,6 +67,12 @@ static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, ...@@ -44,6 +67,12 @@ static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
if (i >= host->info->nb_pts) if (i >= host->info->nb_pts)
return NULL; 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, name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id,
dev ? dev_name(dev) : NULL); dev ? dev_name(dev) : NULL);
if (!name) if (!name)
...@@ -307,6 +336,7 @@ int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) ...@@ -307,6 +336,7 @@ int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr)
int host1x_syncpt_init(struct host1x *host) int host1x_syncpt_init(struct host1x *host)
{ {
struct host1x_syncpt_base *bases;
struct host1x_syncpt *syncpt; struct host1x_syncpt *syncpt;
int i; int i;
...@@ -315,12 +345,21 @@ int host1x_syncpt_init(struct host1x *host) ...@@ -315,12 +345,21 @@ int host1x_syncpt_init(struct host1x *host)
if (!syncpt) if (!syncpt)
return -ENOMEM; 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].id = i;
syncpt[i].host = host; syncpt[i].host = host;
} }
for (i = 0; i < host->info->nb_bases; i++)
bases[i].id = i;
host->syncpt = syncpt; host->syncpt = syncpt;
host->bases = bases;
host1x_syncpt_restore(host); host1x_syncpt_restore(host);
...@@ -344,7 +383,9 @@ void host1x_syncpt_free(struct host1x_syncpt *sp) ...@@ -344,7 +383,9 @@ void host1x_syncpt_free(struct host1x_syncpt *sp)
if (!sp) if (!sp)
return; return;
host1x_syncpt_base_free(sp->base);
kfree(sp->name); kfree(sp->name);
sp->base = NULL;
sp->dev = NULL; sp->dev = NULL;
sp->name = NULL; sp->name = NULL;
sp->client_managed = false; sp->client_managed = false;
...@@ -398,3 +439,13 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id) ...@@ -398,3 +439,13 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id)
return NULL; return NULL;
return host->syncpt + id; 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; ...@@ -31,6 +31,11 @@ struct host1x;
/* Reserved for replacing an expired wait with a NOP */ /* Reserved for replacing an expired wait with a NOP */
#define HOST1X_SYNCPT_RESERVED 0 #define HOST1X_SYNCPT_RESERVED 0
struct host1x_syncpt_base {
unsigned int id;
bool requested;
};
struct host1x_syncpt { struct host1x_syncpt {
int id; int id;
atomic_t min_val; atomic_t min_val;
...@@ -40,6 +45,7 @@ struct host1x_syncpt { ...@@ -40,6 +45,7 @@ struct host1x_syncpt {
bool client_managed; bool client_managed;
struct host1x *host; struct host1x *host;
struct device *dev; struct device *dev;
struct host1x_syncpt_base *base;
/* interrupt data */ /* interrupt data */
struct host1x_syncpt_intr intr; struct host1x_syncpt_intr intr;
......
...@@ -125,7 +125,9 @@ static inline void host1x_bo_kunmap(struct host1x_bo *bo, ...@@ -125,7 +125,9 @@ static inline void host1x_bo_kunmap(struct host1x_bo *bo,
*/ */
#define HOST1X_SYNCPT_CLIENT_MANAGED (1 << 0) #define HOST1X_SYNCPT_CLIENT_MANAGED (1 << 0)
#define HOST1X_SYNCPT_HAS_BASE (1 << 1)
struct host1x_syncpt_base;
struct host1x_syncpt; struct host1x_syncpt;
struct host1x; struct host1x;
...@@ -140,6 +142,9 @@ struct host1x_syncpt *host1x_syncpt_request(struct device *dev, ...@@ -140,6 +142,9 @@ struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
unsigned long flags); unsigned long flags);
void host1x_syncpt_free(struct host1x_syncpt *sp); 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 * host1x channel
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment