mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-29 10:01:25 +00:00
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:
parent
8736fe8153
commit
f5a954fed9
6 changed files with 92 additions and 2 deletions
|
@ -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 {
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
#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 @@
|
||||||
#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,
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
/* 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 {
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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,
|
||||||
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
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue