Skip to content

Commit

Permalink
gpu: host1x: Add syncpoint wait and interrupts
Browse files Browse the repository at this point in the history
Add support for sync point interrupts, and sync point wait. Sync
point wait used interrupts for unblocking wait.

Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Erik Faye-Lund <kusmabite@gmail.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
  • Loading branch information
Terje Bergstrom authored and Thierry Reding committed Apr 22, 2013
1 parent 7547168 commit 7ede0b0
Show file tree
Hide file tree
Showing 10 changed files with 846 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/host1x/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ccflags-y = -Idrivers/gpu/host1x
host1x-y = \
syncpt.o \
dev.o \
intr.o \
hw/host1x01.o

obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
12 changes: 12 additions & 0 deletions drivers/gpu/host1x/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <trace/events/host1x.h>

#include "dev.h"
#include "intr.h"
#include "hw/host1x01.h"

void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
Expand Down Expand Up @@ -123,13 +124,24 @@ static int host1x_probe(struct platform_device *pdev)
return err;
}

err = host1x_intr_init(host, syncpt_irq);
if (err) {
dev_err(&pdev->dev, "failed to initialize interrupts\n");
goto fail_deinit_syncpt;
}

return 0;

fail_deinit_syncpt:
host1x_syncpt_deinit(host);
return err;
}

static int __exit host1x_remove(struct platform_device *pdev)
{
struct host1x *host = platform_get_drvdata(pdev);

host1x_intr_deinit(host);
host1x_syncpt_deinit(host);
clk_disable_unprepare(host->clk);

Expand Down
51 changes: 51 additions & 0 deletions drivers/gpu/host1x/dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/device.h>

#include "syncpt.h"
#include "intr.h"

struct host1x_syncpt;

Expand All @@ -33,6 +34,17 @@ struct host1x_syncpt_ops {
int (*patch_wait)(struct host1x_syncpt *syncpt, void *patch_addr);
};

struct host1x_intr_ops {
int (*init_host_sync)(struct host1x *host, u32 cpm,
void (*syncpt_thresh_work)(struct work_struct *work));
void (*set_syncpt_threshold)(
struct host1x *host, u32 id, u32 thresh);
void (*enable_syncpt_intr)(struct host1x *host, u32 id);
void (*disable_syncpt_intr)(struct host1x *host, u32 id);
void (*disable_all_syncpt_intrs)(struct host1x *host);
int (*free_syncpt_irq)(struct host1x *host);
};

struct host1x_info {
int nb_channels; /* host1x: num channels supported */
int nb_pts; /* host1x: num syncpoints supported */
Expand All @@ -50,7 +62,13 @@ struct host1x {
struct device *dev;
struct clk *clk;

struct mutex intr_mutex;
struct workqueue_struct *intr_wq;
int intr_syncpt_irq;

const struct host1x_syncpt_ops *syncpt_op;
const struct host1x_intr_ops *intr_op;

};

void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v);
Expand Down Expand Up @@ -93,4 +111,37 @@ static inline int host1x_hw_syncpt_patch_wait(struct host1x *host,
return host->syncpt_op->patch_wait(sp, patch_addr);
}

static inline int host1x_hw_intr_init_host_sync(struct host1x *host, u32 cpm,
void (*syncpt_thresh_work)(struct work_struct *))
{
return host->intr_op->init_host_sync(host, cpm, syncpt_thresh_work);
}

static inline void host1x_hw_intr_set_syncpt_threshold(struct host1x *host,
u32 id, u32 thresh)
{
host->intr_op->set_syncpt_threshold(host, id, thresh);
}

static inline void host1x_hw_intr_enable_syncpt_intr(struct host1x *host,
u32 id)
{
host->intr_op->enable_syncpt_intr(host, id);
}

static inline void host1x_hw_intr_disable_syncpt_intr(struct host1x *host,
u32 id)
{
host->intr_op->disable_syncpt_intr(host, id);
}

static inline void host1x_hw_intr_disable_all_syncpt_intrs(struct host1x *host)
{
host->intr_op->disable_all_syncpt_intrs(host);
}

static inline int host1x_hw_intr_free_syncpt_irq(struct host1x *host)
{
return host->intr_op->free_syncpt_irq(host);
}
#endif
2 changes: 2 additions & 0 deletions drivers/gpu/host1x/hw/host1x01.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
#include "hw/host1x01_hardware.h"

/* include code */
#include "hw/intr_hw.c"
#include "hw/syncpt_hw.c"

#include "dev.h"

int host1x01_init(struct host1x *host)
{
host->syncpt_op = &host1x_syncpt_ops;
host->intr_op = &host1x_intr_ops;

return 0;
}
42 changes: 42 additions & 0 deletions drivers/gpu/host1x/hw/hw_host1x01_sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,48 @@ static inline u32 host1x_sync_syncpt_r(unsigned int id)
}
#define HOST1X_SYNC_SYNCPT(id) \
host1x_sync_syncpt_r(id)
static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(unsigned int id)
{
return 0x40 + id * REGISTER_STRIDE;
}
#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id) \
host1x_sync_syncpt_thresh_cpu0_int_status_r(id)
static inline u32 host1x_sync_syncpt_thresh_int_disable_r(unsigned int id)
{
return 0x60 + id * REGISTER_STRIDE;
}
#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id) \
host1x_sync_syncpt_thresh_int_disable_r(id)
static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id)
{
return 0x68 + id * REGISTER_STRIDE;
}
#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \
host1x_sync_syncpt_thresh_int_enable_cpu0_r(id)
static inline u32 host1x_sync_usec_clk_r(void)
{
return 0x1a4;
}
#define HOST1X_SYNC_USEC_CLK \
host1x_sync_usec_clk_r()
static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void)
{
return 0x1a8;
}
#define HOST1X_SYNC_CTXSW_TIMEOUT_CFG \
host1x_sync_ctxsw_timeout_cfg_r()
static inline u32 host1x_sync_ip_busy_timeout_r(void)
{
return 0x1bc;
}
#define HOST1X_SYNC_IP_BUSY_TIMEOUT \
host1x_sync_ip_busy_timeout_r()
static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id)
{
return 0x500 + id * REGISTER_STRIDE;
}
#define HOST1X_SYNC_SYNCPT_INT_THRESH(id) \
host1x_sync_syncpt_int_thresh_r(id)
static inline u32 host1x_sync_syncpt_base_r(unsigned int id)
{
return 0x600 + id * REGISTER_STRIDE;
Expand Down
143 changes: 143 additions & 0 deletions drivers/gpu/host1x/hw/intr_hw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* Tegra host1x Interrupt Management
*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2010-2013, NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <asm/mach/irq.h>

#include "intr.h"
#include "dev.h"

/*
* Sync point threshold interrupt service function
* Handles sync point threshold triggers, in interrupt context
*/
static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt)
{
unsigned int id = syncpt->id;
struct host1x *host = syncpt->host;

host1x_sync_writel(host, BIT_MASK(id),
HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id)));
host1x_sync_writel(host, BIT_MASK(id),
HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id)));

queue_work(host->intr_wq, &syncpt->intr.work);
}

static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
{
struct host1x *host = dev_id;
unsigned long reg;
int i, id;

for (i = 0; i <= BIT_WORD(host->info->nb_pts); i++) {
reg = host1x_sync_readl(host,
HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
for_each_set_bit(id, &reg, BITS_PER_LONG) {
struct host1x_syncpt *syncpt =
host->syncpt + (i * BITS_PER_LONG + id);
host1x_intr_syncpt_handle(syncpt);
}
}

return IRQ_HANDLED;
}

static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host)
{
u32 i;

for (i = 0; i <= BIT_WORD(host->info->nb_pts); ++i) {
host1x_sync_writel(host, 0xffffffffu,
HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i));
host1x_sync_writel(host, 0xffffffffu,
HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
}
}

static int _host1x_intr_init_host_sync(struct host1x *host, u32 cpm,
void (*syncpt_thresh_work)(struct work_struct *))
{
int i, err;

host1x_hw_intr_disable_all_syncpt_intrs(host);

for (i = 0; i < host->info->nb_pts; i++)
INIT_WORK(&host->syncpt[i].intr.work, syncpt_thresh_work);

err = devm_request_irq(host->dev, host->intr_syncpt_irq,
syncpt_thresh_isr, IRQF_SHARED,
"host1x_syncpt", host);
if (IS_ERR_VALUE(err)) {
WARN_ON(1);
return err;
}

/* disable the ip_busy_timeout. this prevents write drops */
host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT);

/*
* increase the auto-ack timout to the maximum value. 2d will hang
* otherwise on Tegra2.
*/
host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG);

/* update host clocks per usec */
host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK);

return 0;
}

static void _host1x_intr_set_syncpt_threshold(struct host1x *host,
u32 id, u32 thresh)
{
host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id));
}

static void _host1x_intr_enable_syncpt_intr(struct host1x *host, u32 id)
{
host1x_sync_writel(host, BIT_MASK(id),
HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(BIT_WORD(id)));
}

static void _host1x_intr_disable_syncpt_intr(struct host1x *host, u32 id)
{
host1x_sync_writel(host, BIT_MASK(id),
HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id)));
host1x_sync_writel(host, BIT_MASK(id),
HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id)));
}

static int _host1x_free_syncpt_irq(struct host1x *host)
{
devm_free_irq(host->dev, host->intr_syncpt_irq, host);
flush_workqueue(host->intr_wq);
return 0;
}

static const struct host1x_intr_ops host1x_intr_ops = {
.init_host_sync = _host1x_intr_init_host_sync,
.set_syncpt_threshold = _host1x_intr_set_syncpt_threshold,
.enable_syncpt_intr = _host1x_intr_enable_syncpt_intr,
.disable_syncpt_intr = _host1x_intr_disable_syncpt_intr,
.disable_all_syncpt_intrs = _host1x_intr_disable_all_syncpt_intrs,
.free_syncpt_irq = _host1x_free_syncpt_irq,
};
Loading

0 comments on commit 7ede0b0

Please sign in to comment.