aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTerje Bergstrom <tbergstrom@nvidia.com>2013-03-22 10:34:01 -0400
committerThierry Reding <thierry.reding@avionic-design.de>2013-04-22 06:32:40 -0400
commit754716874389ccbea5ee03174df8ad9e72e41880 (patch)
tree637ff38c883295fce72721a9c721b0f431b7fa49
parente1adc78caf440d3f6be81a947c2b913e73514a68 (diff)
gpu: host1x: Add host1x driver
Add host1x, the driver for host1x and its client unit 2D. The Tegra host1x module is the DMA engine for register access to Tegra's graphics- and multimedia-related modules. The modules served by host1x are referred to as clients. host1x includes some other functionality, such as synchronization. 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>
-rw-r--r--drivers/gpu/Makefile1
-rw-r--r--drivers/gpu/host1x/Kconfig10
-rw-r--r--drivers/gpu/host1x/Makefile8
-rw-r--r--drivers/gpu/host1x/dev.c153
-rw-r--r--drivers/gpu/host1x/dev.h96
-rw-r--r--drivers/gpu/host1x/hw/Makefile6
-rw-r--r--drivers/gpu/host1x/hw/host1x01.c33
-rw-r--r--drivers/gpu/host1x/hw/host1x01.h25
-rw-r--r--drivers/gpu/host1x/hw/host1x01_hardware.h27
-rw-r--r--drivers/gpu/host1x/hw/hw_host1x01_sync.h74
-rw-r--r--drivers/gpu/host1x/hw/syncpt_hw.c102
-rw-r--r--drivers/gpu/host1x/syncpt.c212
-rw-r--r--drivers/gpu/host1x/syncpt.h147
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--include/trace/events/host1x.h61
15 files changed, 957 insertions, 0 deletions
diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
index 30879df3daea..d8a22c2a579d 100644
--- a/drivers/gpu/Makefile
+++ b/drivers/gpu/Makefile
@@ -1 +1,2 @@
1obj-y += drm/ vga/ 1obj-y += drm/ vga/
2obj-$(CONFIG_TEGRA_HOST1X) += host1x/
diff --git a/drivers/gpu/host1x/Kconfig b/drivers/gpu/host1x/Kconfig
new file mode 100644
index 000000000000..567ae8b7c7c9
--- /dev/null
+++ b/drivers/gpu/host1x/Kconfig
@@ -0,0 +1,10 @@
1config TEGRA_HOST1X
2 tristate "NVIDIA Tegra host1x driver"
3 depends on ARCH_TEGRA || ARCH_MULTIPLATFORM
4 help
5 Driver for the NVIDIA Tegra host1x hardware.
6
7 The Tegra host1x module is the DMA engine for register access to
8 Tegra's graphics- and multimedia-related modules. The modules served
9 by host1x are referred to as clients. host1x includes some other
10 functionality, such as synchronization.
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile
new file mode 100644
index 000000000000..363e6ab31517
--- /dev/null
+++ b/drivers/gpu/host1x/Makefile
@@ -0,0 +1,8 @@
1ccflags-y = -Idrivers/gpu/host1x
2
3host1x-y = \
4 syncpt.o \
5 dev.o \
6 hw/host1x01.o
7
8obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
new file mode 100644
index 000000000000..0d6002cb67c1
--- /dev/null
+++ b/drivers/gpu/host1x/dev.c
@@ -0,0 +1,153 @@
1/*
2 * Tegra host1x driver
3 *
4 * Copyright (c) 2010-2013, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/module.h>
20#include <linux/list.h>
21#include <linux/slab.h>
22#include <linux/of.h>
23#include <linux/of_device.h>
24#include <linux/clk.h>
25#include <linux/io.h>
26
27#define CREATE_TRACE_POINTS
28#include <trace/events/host1x.h>
29
30#include "dev.h"
31#include "hw/host1x01.h"
32
33void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
34{
35 void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
36
37 writel(v, sync_regs + r);
38}
39
40u32 host1x_sync_readl(struct host1x *host1x, u32 r)
41{
42 void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
43
44 return readl(sync_regs + r);
45}
46
47static const struct host1x_info host1x01_info = {
48 .nb_channels = 8,
49 .nb_pts = 32,
50 .nb_mlocks = 16,
51 .nb_bases = 8,
52 .init = host1x01_init,
53 .sync_offset = 0x3000,
54};
55
56static struct of_device_id host1x_of_match[] = {
57 { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, },
58 { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, },
59 { },
60};
61MODULE_DEVICE_TABLE(of, host1x_of_match);
62
63static int host1x_probe(struct platform_device *pdev)
64{
65 const struct of_device_id *id;
66 struct host1x *host;
67 struct resource *regs;
68 int syncpt_irq;
69 int err;
70
71 id = of_match_device(host1x_of_match, &pdev->dev);
72 if (!id)
73 return -EINVAL;
74
75 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
76 if (!regs) {
77 dev_err(&pdev->dev, "failed to get registers\n");
78 return -ENXIO;
79 }
80
81 syncpt_irq = platform_get_irq(pdev, 0);
82 if (syncpt_irq < 0) {
83 dev_err(&pdev->dev, "failed to get IRQ\n");
84 return -ENXIO;
85 }
86
87 host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
88 if (!host)
89 return -ENOMEM;
90
91 host->dev = &pdev->dev;
92 host->info = id->data;
93
94 /* set common host1x device data */
95 platform_set_drvdata(pdev, host);
96
97 host->regs = devm_ioremap_resource(&pdev->dev, regs);
98 if (IS_ERR(host->regs))
99 return PTR_ERR(host->regs);
100
101 if (host->info->init) {
102 err = host->info->init(host);
103 if (err)
104 return err;
105 }
106
107 host->clk = devm_clk_get(&pdev->dev, NULL);
108 if (IS_ERR(host->clk)) {
109 dev_err(&pdev->dev, "failed to get clock\n");
110 err = PTR_ERR(host->clk);
111 return err;
112 }
113
114 err = clk_prepare_enable(host->clk);
115 if (err < 0) {
116 dev_err(&pdev->dev, "failed to enable clock\n");
117 return err;
118 }
119
120 err = host1x_syncpt_init(host);
121 if (err) {
122 dev_err(&pdev->dev, "failed to initialize syncpts\n");
123 return err;
124 }
125
126 return 0;
127}
128
129static int __exit host1x_remove(struct platform_device *pdev)
130{
131 struct host1x *host = platform_get_drvdata(pdev);
132
133 host1x_syncpt_deinit(host);
134 clk_disable_unprepare(host->clk);
135
136 return 0;
137}
138
139static struct platform_driver platform_driver = {
140 .probe = host1x_probe,
141 .remove = __exit_p(host1x_remove),
142 .driver = {
143 .owner = THIS_MODULE,
144 .name = "tegra-host1x",
145 .of_match_table = host1x_of_match,
146 },
147};
148
149module_platform_driver(platform_driver);
150
151MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>");
152MODULE_DESCRIPTION("Host1x driver for Tegra products");
153MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
new file mode 100644
index 000000000000..eaf602657f76
--- /dev/null
+++ b/drivers/gpu/host1x/dev.h
@@ -0,0 +1,96 @@
1/*
2 * Copyright (c) 2012-2013, NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef HOST1X_DEV_H
18#define HOST1X_DEV_H
19
20#include <linux/platform_device.h>
21#include <linux/device.h>
22
23#include "syncpt.h"
24
25struct host1x_syncpt;
26
27struct host1x_syncpt_ops {
28 void (*restore)(struct host1x_syncpt *syncpt);
29 void (*restore_wait_base)(struct host1x_syncpt *syncpt);
30 void (*load_wait_base)(struct host1x_syncpt *syncpt);
31 u32 (*load)(struct host1x_syncpt *syncpt);
32 void (*cpu_incr)(struct host1x_syncpt *syncpt);
33 int (*patch_wait)(struct host1x_syncpt *syncpt, void *patch_addr);
34};
35
36struct host1x_info {
37 int nb_channels; /* host1x: num channels supported */
38 int nb_pts; /* host1x: num syncpoints supported */
39 int nb_bases; /* host1x: num syncpoints supported */
40 int nb_mlocks; /* host1x: number of mlocks */
41 int (*init)(struct host1x *); /* initialize per SoC ops */
42 int sync_offset;
43};
44
45struct host1x {
46 const struct host1x_info *info;
47
48 void __iomem *regs;
49 struct host1x_syncpt *syncpt;
50 struct device *dev;
51 struct clk *clk;
52
53 const struct host1x_syncpt_ops *syncpt_op;
54};
55
56void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v);
57u32 host1x_sync_readl(struct host1x *host1x, u32 r);
58
59static inline void host1x_hw_syncpt_restore(struct host1x *host,
60 struct host1x_syncpt *sp)
61{
62 host->syncpt_op->restore(sp);
63}
64
65static inline void host1x_hw_syncpt_restore_wait_base(struct host1x *host,
66 struct host1x_syncpt *sp)
67{
68 host->syncpt_op->restore_wait_base(sp);
69}
70
71static inline void host1x_hw_syncpt_load_wait_base(struct host1x *host,
72 struct host1x_syncpt *sp)
73{
74 host->syncpt_op->load_wait_base(sp);
75}
76
77static inline u32 host1x_hw_syncpt_load(struct host1x *host,
78 struct host1x_syncpt *sp)
79{
80 return host->syncpt_op->load(sp);
81}
82
83static inline void host1x_hw_syncpt_cpu_incr(struct host1x *host,
84 struct host1x_syncpt *sp)
85{
86 host->syncpt_op->cpu_incr(sp);
87}
88
89static inline int host1x_hw_syncpt_patch_wait(struct host1x *host,
90 struct host1x_syncpt *sp,
91 void *patch_addr)
92{
93 return host->syncpt_op->patch_wait(sp, patch_addr);
94}
95
96#endif
diff --git a/drivers/gpu/host1x/hw/Makefile b/drivers/gpu/host1x/hw/Makefile
new file mode 100644
index 000000000000..9b50863a2236
--- /dev/null
+++ b/drivers/gpu/host1x/hw/Makefile
@@ -0,0 +1,6 @@
1ccflags-y = -Idrivers/gpu/host1x
2
3host1x-hw-objs = \
4 host1x01.o
5
6obj-$(CONFIG_TEGRA_HOST1X) += host1x-hw.o
diff --git a/drivers/gpu/host1x/hw/host1x01.c b/drivers/gpu/host1x/hw/host1x01.c
new file mode 100644
index 000000000000..612b4574c4b6
--- /dev/null
+++ b/drivers/gpu/host1x/hw/host1x01.c
@@ -0,0 +1,33 @@
1/*
2 * Host1x init for T20 and T30 Architecture Chips
3 *
4 * Copyright (c) 2011-2013, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/* include hw specification */
20#include "hw/host1x01.h"
21#include "hw/host1x01_hardware.h"
22
23/* include code */
24#include "hw/syncpt_hw.c"
25
26#include "dev.h"
27
28int host1x01_init(struct host1x *host)
29{
30 host->syncpt_op = &host1x_syncpt_ops;
31
32 return 0;
33}
diff --git a/drivers/gpu/host1x/hw/host1x01.h b/drivers/gpu/host1x/hw/host1x01.h
new file mode 100644
index 000000000000..2706b6743250
--- /dev/null
+++ b/drivers/gpu/host1x/hw/host1x01.h
@@ -0,0 +1,25 @@
1/*
2 * Host1x init for T20 and T30 Architecture Chips
3 *
4 * Copyright (c) 2011-2013, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18#ifndef HOST1X_HOST1X01_H
19#define HOST1X_HOST1X01_H
20
21struct host1x;
22
23int host1x01_init(struct host1x *host);
24
25#endif /* HOST1X_HOST1X01_H_ */
diff --git a/drivers/gpu/host1x/hw/host1x01_hardware.h b/drivers/gpu/host1x/hw/host1x01_hardware.h
new file mode 100644
index 000000000000..8cecbee7a270
--- /dev/null
+++ b/drivers/gpu/host1x/hw/host1x01_hardware.h
@@ -0,0 +1,27 @@
1/*
2 * Tegra host1x Register Offsets for Tegra20 and Tegra30
3 *
4 * Copyright (c) 2010-2013 NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __HOST1X_HOST1X01_HARDWARE_H
20#define __HOST1X_HOST1X01_HARDWARE_H
21
22#include <linux/types.h>
23#include <linux/bitops.h>
24
25#include "hw_host1x01_sync.h"
26
27#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x01_sync.h b/drivers/gpu/host1x/hw/hw_host1x01_sync.h
new file mode 100644
index 000000000000..3af258b46e62
--- /dev/null
+++ b/drivers/gpu/host1x/hw/hw_host1x01_sync.h
@@ -0,0 +1,74 @@
1/*
2 * Copyright (c) 2012-2013, NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 /*
19 * Function naming determines intended use:
20 *
21 * <x>_r(void) : Returns the offset for register <x>.
22 *
23 * <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
24 *
25 * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
26 *
27 * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
28 * and masked to place it at field <y> of register <x>. This value
29 * can be |'d with others to produce a full register value for
30 * register <x>.
31 *
32 * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
33 * value can be ~'d and then &'d to clear the value of field <y> for
34 * register <x>.
35 *
36 * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
37 * to place it at field <y> of register <x>. This value can be |'d
38 * with others to produce a full register value for <x>.
39 *
40 * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
41 * <x> value 'r' after being shifted to place its LSB at bit 0.
42 * This value is suitable for direct comparison with other unshifted
43 * values appropriate for use in field <y> of register <x>.
44 *
45 * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
46 * field <y> of register <x>. This value is suitable for direct
47 * comparison with unshifted values appropriate for use in field <y>
48 * of register <x>.
49 */
50
51#ifndef __hw_host1x01_sync_h__
52#define __hw_host1x01_sync_h__
53
54#define REGISTER_STRIDE 4
55
56static inline u32 host1x_sync_syncpt_r(unsigned int id)
57{
58 return 0x400 + id * REGISTER_STRIDE;
59}
60#define HOST1X_SYNC_SYNCPT(id) \
61 host1x_sync_syncpt_r(id)
62static inline u32 host1x_sync_syncpt_base_r(unsigned int id)
63{
64 return 0x600 + id * REGISTER_STRIDE;
65}
66#define HOST1X_SYNC_SYNCPT_BASE(id) \
67 host1x_sync_syncpt_base_r(id)
68static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id)
69{
70 return 0x700 + id * REGISTER_STRIDE;
71}
72#define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \
73 host1x_sync_syncpt_cpu_incr_r(id)
74#endif /* __hw_host1x01_sync_h__ */
diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c
new file mode 100644
index 000000000000..885b2578dc86
--- /dev/null
+++ b/drivers/gpu/host1x/hw/syncpt_hw.c
@@ -0,0 +1,102 @@
1/*
2 * Tegra host1x Syncpoints
3 *
4 * Copyright (c) 2010-2013, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/io.h>
20
21#include "dev.h"
22#include "syncpt.h"
23
24/*
25 * Write the current syncpoint value back to hw.
26 */
27static void syncpt_restore(struct host1x_syncpt *sp)
28{
29 struct host1x *host = sp->host;
30 int min = host1x_syncpt_read_min(sp);
31 host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id));
32}
33
34/*
35 * Write the current waitbase value back to hw.
36 */
37static void syncpt_restore_wait_base(struct host1x_syncpt *sp)
38{
39 struct host1x *host = sp->host;
40 host1x_sync_writel(host, sp->base_val,
41 HOST1X_SYNC_SYNCPT_BASE(sp->id));
42}
43
44/*
45 * Read waitbase value from hw.
46 */
47static void syncpt_read_wait_base(struct host1x_syncpt *sp)
48{
49 struct host1x *host = sp->host;
50 sp->base_val =
51 host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id));
52}
53
54/*
55 * Updates the last value read from hardware.
56 */
57static u32 syncpt_load(struct host1x_syncpt *sp)
58{
59 struct host1x *host = sp->host;
60 u32 old, live;
61
62 /* Loop in case there's a race writing to min_val */
63 do {
64 old = host1x_syncpt_read_min(sp);
65 live = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT(sp->id));
66 } while ((u32)atomic_cmpxchg(&sp->min_val, old, live) != old);
67
68 if (!host1x_syncpt_check_max(sp, live))
69 dev_err(host->dev, "%s failed: id=%u, min=%d, max=%d\n",
70 __func__, sp->id, host1x_syncpt_read_min(sp),
71 host1x_syncpt_read_max(sp));
72
73 return live;
74}
75
76/*
77 * Write a cpu syncpoint increment to the hardware, without touching
78 * the cache.
79 */
80static void syncpt_cpu_incr(struct host1x_syncpt *sp)
81{
82 struct host1x *host = sp->host;
83 u32 reg_offset = sp->id / 32;
84
85 if (!host1x_syncpt_client_managed(sp) &&
86 host1x_syncpt_idle(sp)) {
87 dev_err(host->dev, "Trying to increment syncpoint id %d beyond max\n",
88 sp->id);
89 return;
90 }
91 host1x_sync_writel(host, BIT_MASK(sp->id),
92 HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset));
93 wmb();
94}
95
96static const struct host1x_syncpt_ops host1x_syncpt_ops = {
97 .restore = syncpt_restore,
98 .restore_wait_base = syncpt_restore_wait_base,
99 .load_wait_base = syncpt_read_wait_base,
100 .load = syncpt_load,
101 .cpu_incr = syncpt_cpu_incr,
102};
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
new file mode 100644
index 000000000000..30385f62daee
--- /dev/null
+++ b/drivers/gpu/host1x/syncpt.c
@@ -0,0 +1,212 @@
1/*
2 * Tegra host1x Syncpoints
3 *
4 * Copyright (c) 2010-2013, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/module.h>
20#include <linux/device.h>
21#include <linux/slab.h>
22
23#include <trace/events/host1x.h>
24
25#include "syncpt.h"
26#include "dev.h"
27
28static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host,
29 struct device *dev,
30 int client_managed)
31{
32 int i;
33 struct host1x_syncpt *sp = host->syncpt;
34 char *name;
35
36 for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++)
37 ;
38 if (sp->dev)
39 return NULL;
40
41 name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id,
42 dev ? dev_name(dev) : NULL);
43 if (!name)
44 return NULL;
45
46 sp->dev = dev;
47 sp->name = name;
48 sp->client_managed = client_managed;
49
50 return sp;
51}
52
53u32 host1x_syncpt_id(struct host1x_syncpt *sp)
54{
55 return sp->id;
56}
57
58/*
59 * Updates the value sent to hardware.
60 */
61u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs)
62{
63 return (u32)atomic_add_return(incrs, &sp->max_val);
64}
65
66 /*
67 * Write cached syncpoint and waitbase values to hardware.
68 */
69void host1x_syncpt_restore(struct host1x *host)
70{
71 struct host1x_syncpt *sp_base = host->syncpt;
72 u32 i;
73
74 for (i = 0; i < host1x_syncpt_nb_pts(host); i++)
75 host1x_hw_syncpt_restore(host, sp_base + i);
76 for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
77 host1x_hw_syncpt_restore_wait_base(host, sp_base + i);
78 wmb();
79}
80
81/*
82 * Update the cached syncpoint and waitbase values by reading them
83 * from the registers.
84 */
85void host1x_syncpt_save(struct host1x *host)
86{
87 struct host1x_syncpt *sp_base = host->syncpt;
88 u32 i;
89
90 for (i = 0; i < host1x_syncpt_nb_pts(host); i++) {
91 if (host1x_syncpt_client_managed(sp_base + i))
92 host1x_hw_syncpt_load(host, sp_base + i);
93 else
94 WARN_ON(!host1x_syncpt_idle(sp_base + i));
95 }
96
97 for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
98 host1x_hw_syncpt_load_wait_base(host, sp_base + i);
99}
100
101/*
102 * Updates the cached syncpoint value by reading a new value from the hardware
103 * register
104 */
105u32 host1x_syncpt_load(struct host1x_syncpt *sp)
106{
107 u32 val;
108 val = host1x_hw_syncpt_load(sp->host, sp);
109 trace_host1x_syncpt_load_min(sp->id, val);
110
111 return val;
112}
113
114/*
115 * Get the current syncpoint base
116 */
117u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp)
118{
119 u32 val;
120 host1x_hw_syncpt_load_wait_base(sp->host, sp);
121 val = sp->base_val;
122 return val;
123}
124
125/*
126 * Write a cpu syncpoint increment to the hardware, without touching
127 * the cache. Caller is responsible for host being powered.
128 */
129void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp)
130{
131 host1x_hw_syncpt_cpu_incr(sp->host, sp);
132}
133
134/*
135 * Increment syncpoint value from cpu, updating cache
136 */
137void host1x_syncpt_incr(struct host1x_syncpt *sp)
138{
139 if (host1x_syncpt_client_managed(sp))
140 host1x_syncpt_incr_max(sp, 1);
141 host1x_syncpt_cpu_incr(sp);
142}
143
144int host1x_syncpt_init(struct host1x *host)
145{
146 struct host1x_syncpt *syncpt;
147 int i;
148
149 syncpt = devm_kzalloc(host->dev, sizeof(*syncpt) * host->info->nb_pts,
150 GFP_KERNEL);
151 if (!syncpt)
152 return -ENOMEM;
153
154 for (i = 0; i < host->info->nb_pts; ++i) {
155 syncpt[i].id = i;
156 syncpt[i].host = host;
157 }
158
159 host->syncpt = syncpt;
160
161 host1x_syncpt_restore(host);
162
163 return 0;
164}
165
166struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
167 int client_managed)
168{
169 struct host1x *host = dev_get_drvdata(dev->parent);
170 return _host1x_syncpt_alloc(host, dev, client_managed);
171}
172
173void host1x_syncpt_free(struct host1x_syncpt *sp)
174{
175 if (!sp)
176 return;
177
178 kfree(sp->name);
179 sp->dev = NULL;
180 sp->name = NULL;
181 sp->client_managed = 0;
182}
183
184void host1x_syncpt_deinit(struct host1x *host)
185{
186 int i;
187 struct host1x_syncpt *sp = host->syncpt;
188 for (i = 0; i < host->info->nb_pts; i++, sp++)
189 kfree(sp->name);
190}
191
192int host1x_syncpt_nb_pts(struct host1x *host)
193{
194 return host->info->nb_pts;
195}
196
197int host1x_syncpt_nb_bases(struct host1x *host)
198{
199 return host->info->nb_bases;
200}
201
202int host1x_syncpt_nb_mlocks(struct host1x *host)
203{
204 return host->info->nb_mlocks;
205}
206
207struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id)
208{
209 if (host->info->nb_pts < id)
210 return NULL;
211 return host->syncpt + id;
212}
diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h
new file mode 100644
index 000000000000..efa2b6e659d6
--- /dev/null
+++ b/drivers/gpu/host1x/syncpt.h
@@ -0,0 +1,147 @@
1/*
2 * Tegra host1x Syncpoints
3 *
4 * Copyright (c) 2010-2013, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __HOST1X_SYNCPT_H
20#define __HOST1X_SYNCPT_H
21
22#include <linux/atomic.h>
23#include <linux/kernel.h>
24#include <linux/sched.h>
25
26struct host1x;
27
28struct host1x_syncpt {
29 int id;
30 atomic_t min_val;
31 atomic_t max_val;
32 u32 base_val;
33 const char *name;
34 int client_managed;
35 struct host1x *host;
36 struct device *dev;
37};
38
39/* Initialize sync point array */
40int host1x_syncpt_init(struct host1x *host);
41
42/* Free sync point array */
43void host1x_syncpt_deinit(struct host1x *host);
44
45/*
46 * Read max. It indicates how many operations there are in queue, either in
47 * channel or in a software thread.
48 * */
49static inline u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
50{
51 smp_rmb();
52 return (u32)atomic_read(&sp->max_val);
53}
54
55/*
56 * Read min, which is a shadow of the current sync point value in hardware.
57 */
58static inline u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
59{
60 smp_rmb();
61 return (u32)atomic_read(&sp->min_val);
62}
63
64/* Return number of sync point supported. */
65int host1x_syncpt_nb_pts(struct host1x *host);
66
67/* Return number of wait bases supported. */
68int host1x_syncpt_nb_bases(struct host1x *host);
69
70/* Return number of mlocks supported. */
71int host1x_syncpt_nb_mlocks(struct host1x *host);
72
73/*
74 * Check sync point sanity. If max is larger than min, there have too many
75 * sync point increments.
76 *
77 * Client managed sync point are not tracked.
78 * */
79static inline bool host1x_syncpt_check_max(struct host1x_syncpt *sp, u32 real)
80{
81 u32 max;
82 if (sp->client_managed)
83 return true;
84 max = host1x_syncpt_read_max(sp);
85 return (s32)(max - real) >= 0;
86}
87
88/* Return true if sync point is client managed. */
89static inline int host1x_syncpt_client_managed(struct host1x_syncpt *sp)
90{
91 return sp->client_managed;
92}
93
94/*
95 * Returns true if syncpoint min == max, which means that there are no
96 * outstanding operations.
97 */
98static inline bool host1x_syncpt_idle(struct host1x_syncpt *sp)
99{
100 int min, max;
101 smp_rmb();
102 min = atomic_read(&sp->min_val);
103 max = atomic_read(&sp->max_val);
104 return (min == max);
105}
106
107/* Return pointer to struct denoting sync point id. */
108struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id);
109
110/* Request incrementing a sync point. */
111void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp);
112
113/* Load current value from hardware to the shadow register. */
114u32 host1x_syncpt_load(struct host1x_syncpt *sp);
115
116/* Save host1x sync point state into shadow registers. */
117void host1x_syncpt_save(struct host1x *host);
118
119/* Reset host1x sync point state from shadow registers. */
120void host1x_syncpt_restore(struct host1x *host);
121
122/* Read current wait base value into shadow register and return it. */
123u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp);
124
125/* Increment sync point and its max. */
126void host1x_syncpt_incr(struct host1x_syncpt *sp);
127
128/* Indicate future operations by incrementing the sync point max. */
129u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
130
131/* Check if sync point id is valid. */
132static inline int host1x_syncpt_is_valid(struct host1x_syncpt *sp)
133{
134 return sp->id < host1x_syncpt_nb_pts(sp->host);
135}
136
137/* Return id of the sync point */
138u32 host1x_syncpt_id(struct host1x_syncpt *sp);
139
140/* Allocate a sync point for a device. */
141struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
142 int client_managed);
143
144/* Free a sync point. */
145void host1x_syncpt_free(struct host1x_syncpt *sp);
146
147#endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4c1546f71d56..3e0e3f088686 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -21,6 +21,8 @@ source "drivers/gpu/vga/Kconfig"
21 21
22source "drivers/gpu/drm/Kconfig" 22source "drivers/gpu/drm/Kconfig"
23 23
24source "drivers/gpu/host1x/Kconfig"
25
24config VGASTATE 26config VGASTATE
25 tristate 27 tristate
26 default n 28 default n
diff --git a/include/trace/events/host1x.h b/include/trace/events/host1x.h
new file mode 100644
index 000000000000..4bd2b0253d27
--- /dev/null
+++ b/include/trace/events/host1x.h
@@ -0,0 +1,61 @@
1/*
2 * include/trace/events/host1x.h
3 *
4 * host1x event logging to ftrace.
5 *
6 * Copyright (c) 2010-2013, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#undef TRACE_SYSTEM
24#define TRACE_SYSTEM host1x
25
26#if !defined(_TRACE_HOST1X_H) || defined(TRACE_HEADER_MULTI_READ)
27#define _TRACE_HOST1X_H
28
29#include <linux/ktime.h>
30#include <linux/tracepoint.h>
31
32DECLARE_EVENT_CLASS(host1x,
33 TP_PROTO(const char *name),
34 TP_ARGS(name),
35 TP_STRUCT__entry(__field(const char *, name)),
36 TP_fast_assign(__entry->name = name;),
37 TP_printk("name=%s", __entry->name)
38);
39
40TRACE_EVENT(host1x_syncpt_load_min,
41 TP_PROTO(u32 id, u32 val),
42
43 TP_ARGS(id, val),
44
45 TP_STRUCT__entry(
46 __field(u32, id)
47 __field(u32, val)
48 ),
49
50 TP_fast_assign(
51 __entry->id = id;
52 __entry->val = val;
53 ),
54
55 TP_printk("id=%d, val=%d", __entry->id, __entry->val)
56);
57
58#endif /* _TRACE_HOST1X_H */
59
60/* This part must be outside protection */
61#include <trace/define_trace.h>