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>
#include "job.h"
struct host1x_syncpt;
#include "job.h"
struct host1x_syncpt;
+struct host1x_syncpt_base;
struct host1x_channel;
struct host1x_cdma;
struct host1x_job;
struct host1x_channel;
struct host1x_cdma;
struct host1x_job;
void __iomem *regs;
struct host1x_syncpt *syncpt;
void __iomem *regs;
struct host1x_syncpt *syncpt;
+ struct host1x_syncpt_base *bases;
struct device *dev;
struct clk *clk;
struct device *dev;
struct clk *clk;
+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;
static int channel_submit(struct host1x_job *job)
{
struct host1x_channel *ch = job->channel;
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);
job->syncpt_end = syncval;
syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs);
job->syncpt_end = syncval;
}
#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
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)
+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;
static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
{
return (v & 0xff) << 24;
#define SYNCPT_CHECK_PERIOD (2 * HZ)
#define MAX_STUCK_CHECK_COUNT 15
#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)
static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
struct device *dev,
unsigned long flags)
if (i >= host->info->nb_pts)
return NULL;
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)
name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id,
dev ? dev_name(dev) : NULL);
if (!name)
int host1x_syncpt_init(struct host1x *host)
{
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,
struct host1x_syncpt *syncpt;
int i;
syncpt = devm_kzalloc(host->dev, sizeof(*syncpt) * host->info->nb_pts,
if (!syncpt)
return -ENOMEM;
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;
}
syncpt[i].id = i;
syncpt[i].host = host;
}
+ for (i = 0; i < host->info->nb_bases; i++)
+ bases[i].id = i;
+
host1x_syncpt_restore(host);
host1x_syncpt_restore(host);
+ host1x_syncpt_base_free(sp->base);
sp->dev = NULL;
sp->name = NULL;
sp->client_managed = false;
sp->dev = NULL;
sp->name = NULL;
sp->client_managed = false;
return NULL;
return host->syncpt + 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;
+}
/* Reserved for replacing an expired wait with a NOP */
#define HOST1X_SYNCPT_RESERVED 0
/* 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;
struct host1x_syncpt {
int id;
atomic_t min_val;
bool client_managed;
struct host1x *host;
struct device *dev;
bool client_managed;
struct host1x *host;
struct device *dev;
+ struct host1x_syncpt_base *base;
/* interrupt data */
struct host1x_syncpt_intr intr;
/* interrupt data */
struct host1x_syncpt_intr intr;
*/
#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;
struct host1x_syncpt;
struct host1x;
unsigned long flags);
void host1x_syncpt_free(struct host1x_syncpt *sp);
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);
+