Commit 754716874389ccbea5ee03174df8ad9e72e41880
Committed by
Thierry Reding
1 parent
e1adc78caf
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 15 changed files with 957 additions and 0 deletions Side-by-side Diff
- drivers/gpu/Makefile
- drivers/gpu/host1x/Kconfig
- drivers/gpu/host1x/Makefile
- drivers/gpu/host1x/dev.c
- drivers/gpu/host1x/dev.h
- drivers/gpu/host1x/hw/Makefile
- drivers/gpu/host1x/hw/host1x01.c
- drivers/gpu/host1x/hw/host1x01.h
- drivers/gpu/host1x/hw/host1x01_hardware.h
- drivers/gpu/host1x/hw/hw_host1x01_sync.h
- drivers/gpu/host1x/hw/syncpt_hw.c
- drivers/gpu/host1x/syncpt.c
- drivers/gpu/host1x/syncpt.h
- drivers/video/Kconfig
- include/trace/events/host1x.h
drivers/gpu/Makefile
drivers/gpu/host1x/Kconfig
1 | +config 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. |
drivers/gpu/host1x/Makefile
drivers/gpu/host1x/dev.c
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 | + | |
33 | +void 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 | + | |
40 | +u32 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 | + | |
47 | +static 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 | + | |
56 | +static 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 | +}; | |
61 | +MODULE_DEVICE_TABLE(of, host1x_of_match); | |
62 | + | |
63 | +static 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 | + | |
129 | +static 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 | + | |
139 | +static 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 | + | |
149 | +module_platform_driver(platform_driver); | |
150 | + | |
151 | +MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>"); | |
152 | +MODULE_DESCRIPTION("Host1x driver for Tegra products"); | |
153 | +MODULE_LICENSE("GPL"); |
drivers/gpu/host1x/dev.h
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 | + | |
25 | +struct host1x_syncpt; | |
26 | + | |
27 | +struct 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 | + | |
36 | +struct 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 | + | |
45 | +struct 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 | + | |
56 | +void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); | |
57 | +u32 host1x_sync_readl(struct host1x *host1x, u32 r); | |
58 | + | |
59 | +static inline void host1x_hw_syncpt_restore(struct host1x *host, | |
60 | + struct host1x_syncpt *sp) | |
61 | +{ | |
62 | + host->syncpt_op->restore(sp); | |
63 | +} | |
64 | + | |
65 | +static 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 | + | |
71 | +static 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 | + | |
77 | +static inline u32 host1x_hw_syncpt_load(struct host1x *host, | |
78 | + struct host1x_syncpt *sp) | |
79 | +{ | |
80 | + return host->syncpt_op->load(sp); | |
81 | +} | |
82 | + | |
83 | +static 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 | + | |
89 | +static 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 |
drivers/gpu/host1x/hw/Makefile
drivers/gpu/host1x/hw/host1x01.c
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 | + | |
28 | +int host1x01_init(struct host1x *host) | |
29 | +{ | |
30 | + host->syncpt_op = &host1x_syncpt_ops; | |
31 | + | |
32 | + return 0; | |
33 | +} |
drivers/gpu/host1x/hw/host1x01.h
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 | + | |
21 | +struct host1x; | |
22 | + | |
23 | +int host1x01_init(struct host1x *host); | |
24 | + | |
25 | +#endif /* HOST1X_HOST1X01_H_ */ |
drivers/gpu/host1x/hw/host1x01_hardware.h
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 |
drivers/gpu/host1x/hw/hw_host1x01_sync.h
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 | + | |
56 | +static 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) | |
62 | +static 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) | |
68 | +static 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__ */ |
drivers/gpu/host1x/hw/syncpt_hw.c
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 | + */ | |
27 | +static 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 | + */ | |
37 | +static 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 | + */ | |
47 | +static 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 | + */ | |
57 | +static 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 | + */ | |
80 | +static 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 | + | |
96 | +static 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 | +}; |
drivers/gpu/host1x/syncpt.c
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 | + | |
28 | +static 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 | + | |
53 | +u32 host1x_syncpt_id(struct host1x_syncpt *sp) | |
54 | +{ | |
55 | + return sp->id; | |
56 | +} | |
57 | + | |
58 | +/* | |
59 | + * Updates the value sent to hardware. | |
60 | + */ | |
61 | +u32 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 | + */ | |
69 | +void 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 | + */ | |
85 | +void 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 | + */ | |
105 | +u32 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 | + */ | |
117 | +u32 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 | + */ | |
129 | +void 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 | + */ | |
137 | +void 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 | + | |
144 | +int 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 | + | |
166 | +struct 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 | + | |
173 | +void 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 | + | |
184 | +void 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 | + | |
192 | +int host1x_syncpt_nb_pts(struct host1x *host) | |
193 | +{ | |
194 | + return host->info->nb_pts; | |
195 | +} | |
196 | + | |
197 | +int host1x_syncpt_nb_bases(struct host1x *host) | |
198 | +{ | |
199 | + return host->info->nb_bases; | |
200 | +} | |
201 | + | |
202 | +int host1x_syncpt_nb_mlocks(struct host1x *host) | |
203 | +{ | |
204 | + return host->info->nb_mlocks; | |
205 | +} | |
206 | + | |
207 | +struct 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 | +} |
drivers/gpu/host1x/syncpt.h
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 | + | |
26 | +struct host1x; | |
27 | + | |
28 | +struct 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 */ | |
40 | +int host1x_syncpt_init(struct host1x *host); | |
41 | + | |
42 | +/* Free sync point array */ | |
43 | +void 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 | + * */ | |
49 | +static 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 | + */ | |
58 | +static 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. */ | |
65 | +int host1x_syncpt_nb_pts(struct host1x *host); | |
66 | + | |
67 | +/* Return number of wait bases supported. */ | |
68 | +int host1x_syncpt_nb_bases(struct host1x *host); | |
69 | + | |
70 | +/* Return number of mlocks supported. */ | |
71 | +int 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 | + * */ | |
79 | +static 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. */ | |
89 | +static 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 | + */ | |
98 | +static 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. */ | |
108 | +struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id); | |
109 | + | |
110 | +/* Request incrementing a sync point. */ | |
111 | +void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp); | |
112 | + | |
113 | +/* Load current value from hardware to the shadow register. */ | |
114 | +u32 host1x_syncpt_load(struct host1x_syncpt *sp); | |
115 | + | |
116 | +/* Save host1x sync point state into shadow registers. */ | |
117 | +void host1x_syncpt_save(struct host1x *host); | |
118 | + | |
119 | +/* Reset host1x sync point state from shadow registers. */ | |
120 | +void host1x_syncpt_restore(struct host1x *host); | |
121 | + | |
122 | +/* Read current wait base value into shadow register and return it. */ | |
123 | +u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp); | |
124 | + | |
125 | +/* Increment sync point and its max. */ | |
126 | +void host1x_syncpt_incr(struct host1x_syncpt *sp); | |
127 | + | |
128 | +/* Indicate future operations by incrementing the sync point max. */ | |
129 | +u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs); | |
130 | + | |
131 | +/* Check if sync point id is valid. */ | |
132 | +static 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 */ | |
138 | +u32 host1x_syncpt_id(struct host1x_syncpt *sp); | |
139 | + | |
140 | +/* Allocate a sync point for a device. */ | |
141 | +struct host1x_syncpt *host1x_syncpt_request(struct device *dev, | |
142 | + int client_managed); | |
143 | + | |
144 | +/* Free a sync point. */ | |
145 | +void host1x_syncpt_free(struct host1x_syncpt *sp); | |
146 | + | |
147 | +#endif |
drivers/video/Kconfig
include/trace/events/host1x.h
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 | + | |
32 | +DECLARE_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 | + | |
40 | +TRACE_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> |