gpu: host1x: Add host1x driver
[deliverable/linux.git] / drivers / gpu / host1x / syncpt.c
CommitLineData
75471687
TB
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}
This page took 0.031327 seconds and 5 git commands to generate.