19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
275471687STerje Bergstrom /*
375471687STerje Bergstrom * Tegra host1x Syncpoints
475471687STerje Bergstrom *
5d4b57818SArto Merilainen * Copyright (c) 2010-2015, NVIDIA Corporation.
675471687STerje Bergstrom */
775471687STerje Bergstrom
875471687STerje Bergstrom #include <linux/module.h>
975471687STerje Bergstrom #include <linux/device.h>
10f0fb260aSMikko Perttunen #include <linux/dma-fence.h>
1175471687STerje Bergstrom #include <linux/slab.h>
1275471687STerje Bergstrom
1375471687STerje Bergstrom #include <trace/events/host1x.h>
1475471687STerje Bergstrom
1575471687STerje Bergstrom #include "syncpt.h"
1675471687STerje Bergstrom #include "dev.h"
177ede0b0bSTerje Bergstrom #include "intr.h"
186236451dSTerje Bergstrom #include "debug.h"
197ede0b0bSTerje Bergstrom
207ede0b0bSTerje Bergstrom #define SYNCPT_CHECK_PERIOD (2 * HZ)
217ede0b0bSTerje Bergstrom #define MAX_STUCK_CHECK_COUNT 15
2275471687STerje Bergstrom
23f5a954feSArto Merilainen static struct host1x_syncpt_base *
host1x_syncpt_base_request(struct host1x * host)24f5a954feSArto Merilainen host1x_syncpt_base_request(struct host1x *host)
25f5a954feSArto Merilainen {
26f5a954feSArto Merilainen struct host1x_syncpt_base *bases = host->bases;
27f5a954feSArto Merilainen unsigned int i;
28f5a954feSArto Merilainen
29f5a954feSArto Merilainen for (i = 0; i < host->info->nb_bases; i++)
30f5a954feSArto Merilainen if (!bases[i].requested)
31f5a954feSArto Merilainen break;
32f5a954feSArto Merilainen
33f5a954feSArto Merilainen if (i >= host->info->nb_bases)
34f5a954feSArto Merilainen return NULL;
35f5a954feSArto Merilainen
36f5a954feSArto Merilainen bases[i].requested = true;
37f5a954feSArto Merilainen return &bases[i];
38f5a954feSArto Merilainen }
39f5a954feSArto Merilainen
host1x_syncpt_base_free(struct host1x_syncpt_base * base)40f5a954feSArto Merilainen static void host1x_syncpt_base_free(struct host1x_syncpt_base *base)
41f5a954feSArto Merilainen {
42f5a954feSArto Merilainen if (base)
43f5a954feSArto Merilainen base->requested = false;
44f5a954feSArto Merilainen }
45f5a954feSArto Merilainen
4686cec7ecSMikko Perttunen /**
4786cec7ecSMikko Perttunen * host1x_syncpt_alloc() - allocate a syncpoint
4886cec7ecSMikko Perttunen * @host: host1x device data
4986cec7ecSMikko Perttunen * @flags: bitfield of HOST1X_SYNCPT_* flags
5086cec7ecSMikko Perttunen * @name: name for the syncpoint for use in debug prints
5186cec7ecSMikko Perttunen *
5286cec7ecSMikko Perttunen * Allocates a hardware syncpoint for the caller's use. The caller then has
5386cec7ecSMikko Perttunen * the sole authority to mutate the syncpoint's value until it is freed again.
5486cec7ecSMikko Perttunen *
5586cec7ecSMikko Perttunen * If no free syncpoints are available, or a NULL name was specified, returns
5686cec7ecSMikko Perttunen * NULL.
5786cec7ecSMikko Perttunen */
host1x_syncpt_alloc(struct host1x * host,unsigned long flags,const char * name)5886cec7ecSMikko Perttunen struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
5986cec7ecSMikko Perttunen unsigned long flags,
6086cec7ecSMikko Perttunen const char *name)
6175471687STerje Bergstrom {
6275471687STerje Bergstrom struct host1x_syncpt *sp = host->syncpt;
6386cec7ecSMikko Perttunen char *full_name;
64d4ad3ad9SThierry Reding unsigned int i;
6586cec7ecSMikko Perttunen
6686cec7ecSMikko Perttunen if (!name)
6786cec7ecSMikko Perttunen return NULL;
6875471687STerje Bergstrom
69d4b57818SArto Merilainen mutex_lock(&host->syncpt_mutex);
70d4b57818SArto Merilainen
71f5ba33fbSMikko Perttunen for (i = 0; i < host->info->nb_pts && kref_read(&sp->ref); i++, sp++)
7275471687STerje Bergstrom ;
73edeabfcbSArto Merilainen
74edeabfcbSArto Merilainen if (i >= host->info->nb_pts)
75d4b57818SArto Merilainen goto unlock;
7675471687STerje Bergstrom
77f5a954feSArto Merilainen if (flags & HOST1X_SYNCPT_HAS_BASE) {
78f5a954feSArto Merilainen sp->base = host1x_syncpt_base_request(host);
79f5a954feSArto Merilainen if (!sp->base)
80d4b57818SArto Merilainen goto unlock;
81f5a954feSArto Merilainen }
82f5a954feSArto Merilainen
8386cec7ecSMikko Perttunen full_name = kasprintf(GFP_KERNEL, "%u-%s", sp->id, name);
8486cec7ecSMikko Perttunen if (!full_name)
85d4b57818SArto Merilainen goto free_base;
8675471687STerje Bergstrom
8786cec7ecSMikko Perttunen sp->name = full_name;
888736fe81SArto Merilainen
898736fe81SArto Merilainen if (flags & HOST1X_SYNCPT_CLIENT_MANAGED)
908736fe81SArto Merilainen sp->client_managed = true;
918736fe81SArto Merilainen else
928736fe81SArto Merilainen sp->client_managed = false;
9375471687STerje Bergstrom
942aed4f5aSMikko Perttunen kref_init(&sp->ref);
952aed4f5aSMikko Perttunen
96d4b57818SArto Merilainen mutex_unlock(&host->syncpt_mutex);
9775471687STerje Bergstrom return sp;
98d4b57818SArto Merilainen
99d4b57818SArto Merilainen free_base:
100d4b57818SArto Merilainen host1x_syncpt_base_free(sp->base);
101d4b57818SArto Merilainen sp->base = NULL;
102d4b57818SArto Merilainen unlock:
103d4b57818SArto Merilainen mutex_unlock(&host->syncpt_mutex);
104d4b57818SArto Merilainen return NULL;
10575471687STerje Bergstrom }
10686cec7ecSMikko Perttunen EXPORT_SYMBOL(host1x_syncpt_alloc);
10775471687STerje Bergstrom
108466749f1SThierry Reding /**
109466749f1SThierry Reding * host1x_syncpt_id() - retrieve syncpoint ID
110466749f1SThierry Reding * @sp: host1x syncpoint
111466749f1SThierry Reding *
112466749f1SThierry Reding * Given a pointer to a struct host1x_syncpt, retrieves its ID. This ID is
113466749f1SThierry Reding * often used as a value to program into registers that control how hardware
114466749f1SThierry Reding * blocks interact with syncpoints.
115466749f1SThierry Reding */
host1x_syncpt_id(struct host1x_syncpt * sp)11675471687STerje Bergstrom u32 host1x_syncpt_id(struct host1x_syncpt *sp)
11775471687STerje Bergstrom {
11875471687STerje Bergstrom return sp->id;
11975471687STerje Bergstrom }
120fae798a1SThierry Reding EXPORT_SYMBOL(host1x_syncpt_id);
12175471687STerje Bergstrom
122466749f1SThierry Reding /**
123466749f1SThierry Reding * host1x_syncpt_incr_max() - update the value sent to hardware
124466749f1SThierry Reding * @sp: host1x syncpoint
125466749f1SThierry Reding * @incrs: number of increments
12675471687STerje Bergstrom */
host1x_syncpt_incr_max(struct host1x_syncpt * sp,u32 incrs)12775471687STerje Bergstrom u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs)
12875471687STerje Bergstrom {
12975471687STerje Bergstrom return (u32)atomic_add_return(incrs, &sp->max_val);
13075471687STerje Bergstrom }
13164400c37SBryan Wu EXPORT_SYMBOL(host1x_syncpt_incr_max);
13275471687STerje Bergstrom
13375471687STerje Bergstrom /*
13475471687STerje Bergstrom * Write cached syncpoint and waitbase values to hardware.
13575471687STerje Bergstrom */
host1x_syncpt_restore(struct host1x * host)13675471687STerje Bergstrom void host1x_syncpt_restore(struct host1x *host)
13775471687STerje Bergstrom {
13875471687STerje Bergstrom struct host1x_syncpt *sp_base = host->syncpt;
13914c95fc8SThierry Reding unsigned int i;
14075471687STerje Bergstrom
14122d7ee32SDmitry Osipenko for (i = 0; i < host1x_syncpt_nb_pts(host); i++) {
14222d7ee32SDmitry Osipenko /*
14322d7ee32SDmitry Osipenko * Unassign syncpt from channels for purposes of Tegra186
14422d7ee32SDmitry Osipenko * syncpoint protection. This prevents any channel from
14522d7ee32SDmitry Osipenko * accessing it until it is reassigned.
14622d7ee32SDmitry Osipenko */
14722d7ee32SDmitry Osipenko host1x_hw_syncpt_assign_to_channel(host, sp_base + i, NULL);
14875471687STerje Bergstrom host1x_hw_syncpt_restore(host, sp_base + i);
14922d7ee32SDmitry Osipenko }
1500b8070d1SThierry Reding
15175471687STerje Bergstrom for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
15275471687STerje Bergstrom host1x_hw_syncpt_restore_wait_base(host, sp_base + i);
1530b8070d1SThierry Reding
1546b6776e2SDmitry Osipenko host1x_hw_syncpt_enable_protection(host);
1556b6776e2SDmitry Osipenko
15675471687STerje Bergstrom wmb();
15775471687STerje Bergstrom }
15875471687STerje Bergstrom
15975471687STerje Bergstrom /*
16075471687STerje Bergstrom * Update the cached syncpoint and waitbase values by reading them
16175471687STerje Bergstrom * from the registers.
16275471687STerje Bergstrom */
host1x_syncpt_save(struct host1x * host)16375471687STerje Bergstrom void host1x_syncpt_save(struct host1x *host)
16475471687STerje Bergstrom {
16575471687STerje Bergstrom struct host1x_syncpt *sp_base = host->syncpt;
16614c95fc8SThierry Reding unsigned int i;
16775471687STerje Bergstrom
16875471687STerje Bergstrom for (i = 0; i < host1x_syncpt_nb_pts(host); i++) {
16975471687STerje Bergstrom if (host1x_syncpt_client_managed(sp_base + i))
17075471687STerje Bergstrom host1x_hw_syncpt_load(host, sp_base + i);
17175471687STerje Bergstrom else
17275471687STerje Bergstrom WARN_ON(!host1x_syncpt_idle(sp_base + i));
17375471687STerje Bergstrom }
17475471687STerje Bergstrom
17575471687STerje Bergstrom for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
17675471687STerje Bergstrom host1x_hw_syncpt_load_wait_base(host, sp_base + i);
17775471687STerje Bergstrom }
17875471687STerje Bergstrom
17975471687STerje Bergstrom /*
18075471687STerje Bergstrom * Updates the cached syncpoint value by reading a new value from the hardware
18175471687STerje Bergstrom * register
18275471687STerje Bergstrom */
host1x_syncpt_load(struct host1x_syncpt * sp)18375471687STerje Bergstrom u32 host1x_syncpt_load(struct host1x_syncpt *sp)
18475471687STerje Bergstrom {
18575471687STerje Bergstrom u32 val;
1866df633d0SThierry Reding
18775471687STerje Bergstrom val = host1x_hw_syncpt_load(sp->host, sp);
18875471687STerje Bergstrom trace_host1x_syncpt_load_min(sp->id, val);
18975471687STerje Bergstrom
19075471687STerje Bergstrom return val;
19175471687STerje Bergstrom }
19275471687STerje Bergstrom
19375471687STerje Bergstrom /*
19475471687STerje Bergstrom * Get the current syncpoint base
19575471687STerje Bergstrom */
host1x_syncpt_load_wait_base(struct host1x_syncpt * sp)19675471687STerje Bergstrom u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp)
19775471687STerje Bergstrom {
19875471687STerje Bergstrom host1x_hw_syncpt_load_wait_base(sp->host, sp);
1994b92e294SThierry Reding
2004b92e294SThierry Reding return sp->base_val;
20175471687STerje Bergstrom }
20275471687STerje Bergstrom
203466749f1SThierry Reding /**
204466749f1SThierry Reding * host1x_syncpt_incr() - increment syncpoint value from CPU, updating cache
205466749f1SThierry Reding * @sp: host1x syncpoint
20675471687STerje Bergstrom */
host1x_syncpt_incr(struct host1x_syncpt * sp)207ebae30b1SArto Merilainen int host1x_syncpt_incr(struct host1x_syncpt *sp)
20875471687STerje Bergstrom {
209ebae30b1SArto Merilainen return host1x_hw_syncpt_cpu_incr(sp->host, sp);
21075471687STerje Bergstrom }
211fae798a1SThierry Reding EXPORT_SYMBOL(host1x_syncpt_incr);
21275471687STerje Bergstrom
213466749f1SThierry Reding /**
214466749f1SThierry Reding * host1x_syncpt_wait() - wait for a syncpoint to reach a given value
215466749f1SThierry Reding * @sp: host1x syncpoint
216466749f1SThierry Reding * @thresh: threshold
217466749f1SThierry Reding * @timeout: maximum time to wait for the syncpoint to reach the given value
218466749f1SThierry Reding * @value: return location for the syncpoint value
2197ede0b0bSTerje Bergstrom */
host1x_syncpt_wait(struct host1x_syncpt * sp,u32 thresh,long timeout,u32 * value)2207ede0b0bSTerje Bergstrom int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
2217ede0b0bSTerje Bergstrom u32 *value)
2227ede0b0bSTerje Bergstrom {
223f0fb260aSMikko Perttunen struct dma_fence *fence;
224f0fb260aSMikko Perttunen long wait_err;
225f0fb260aSMikko Perttunen
226f0fb260aSMikko Perttunen host1x_hw_syncpt_load(sp->host, sp);
2277ede0b0bSTerje Bergstrom
2287ede0b0bSTerje Bergstrom if (value)
2297ede0b0bSTerje Bergstrom *value = host1x_syncpt_load(sp);
2300b8070d1SThierry Reding
231184b58faSMikko Perttunen if (host1x_syncpt_is_expired(sp, thresh))
2327ede0b0bSTerje Bergstrom return 0;
2337ede0b0bSTerje Bergstrom
2347ede0b0bSTerje Bergstrom if (timeout < 0)
2357ede0b0bSTerje Bergstrom timeout = LONG_MAX;
236f0fb260aSMikko Perttunen else if (timeout == 0)
237f0fb260aSMikko Perttunen return -EAGAIN;
2387ede0b0bSTerje Bergstrom
239d5179020SMikko Perttunen fence = host1x_fence_create(sp, thresh, false);
240f0fb260aSMikko Perttunen if (IS_ERR(fence))
241f0fb260aSMikko Perttunen return PTR_ERR(fence);
2420b8070d1SThierry Reding
243f0fb260aSMikko Perttunen wait_err = dma_fence_wait_timeout(fence, true, timeout);
244d5179020SMikko Perttunen if (wait_err == 0)
245d5179020SMikko Perttunen host1x_fence_cancel(fence);
246f0fb260aSMikko Perttunen dma_fence_put(fence);
247f0fb260aSMikko Perttunen
2487ede0b0bSTerje Bergstrom if (value)
2497ede0b0bSTerje Bergstrom *value = host1x_syncpt_load(sp);
2500b8070d1SThierry Reding
251*c1aaee94SMikko Perttunen /*
252*c1aaee94SMikko Perttunen * Don't rely on dma_fence_wait_timeout return value,
253*c1aaee94SMikko Perttunen * since it returns zero both on timeout and if the
254*c1aaee94SMikko Perttunen * wait completed with 0 jiffies left.
255*c1aaee94SMikko Perttunen */
256*c1aaee94SMikko Perttunen host1x_hw_syncpt_load(sp->host, sp);
257*c1aaee94SMikko Perttunen if (wait_err == 0 && !host1x_syncpt_is_expired(sp, thresh))
258f0fb260aSMikko Perttunen return -EAGAIN;
259f0fb260aSMikko Perttunen else if (wait_err < 0)
260f0fb260aSMikko Perttunen return wait_err;
261f0fb260aSMikko Perttunen else
262f0fb260aSMikko Perttunen return 0;
2637ede0b0bSTerje Bergstrom }
2647ede0b0bSTerje Bergstrom EXPORT_SYMBOL(host1x_syncpt_wait);
2657ede0b0bSTerje Bergstrom
2667ede0b0bSTerje Bergstrom /*
2677ede0b0bSTerje Bergstrom * Returns true if syncpoint is expired, false if we may need to wait
2687ede0b0bSTerje Bergstrom */
host1x_syncpt_is_expired(struct host1x_syncpt * sp,u32 thresh)2697ede0b0bSTerje Bergstrom bool host1x_syncpt_is_expired(struct host1x_syncpt *sp, u32 thresh)
2707ede0b0bSTerje Bergstrom {
2717ede0b0bSTerje Bergstrom u32 current_val;
2726df633d0SThierry Reding
2737ede0b0bSTerje Bergstrom smp_rmb();
2740b8070d1SThierry Reding
2757ede0b0bSTerje Bergstrom current_val = (u32)atomic_read(&sp->min_val);
2767ede0b0bSTerje Bergstrom
277f63b42cbSMikko Perttunen return ((current_val - thresh) & 0x80000000U) == 0U;
2787ede0b0bSTerje Bergstrom }
2797ede0b0bSTerje Bergstrom
host1x_syncpt_init(struct host1x * host)28075471687STerje Bergstrom int host1x_syncpt_init(struct host1x *host)
28175471687STerje Bergstrom {
282f5a954feSArto Merilainen struct host1x_syncpt_base *bases;
28375471687STerje Bergstrom struct host1x_syncpt *syncpt;
28414c95fc8SThierry Reding unsigned int i;
28575471687STerje Bergstrom
286b47a0491SThierry Reding syncpt = devm_kcalloc(host->dev, host->info->nb_pts, sizeof(*syncpt),
28775471687STerje Bergstrom GFP_KERNEL);
28875471687STerje Bergstrom if (!syncpt)
28975471687STerje Bergstrom return -ENOMEM;
29075471687STerje Bergstrom
291b47a0491SThierry Reding bases = devm_kcalloc(host->dev, host->info->nb_bases, sizeof(*bases),
292f5a954feSArto Merilainen GFP_KERNEL);
293f5a954feSArto Merilainen if (!bases)
294f5a954feSArto Merilainen return -ENOMEM;
295f5a954feSArto Merilainen
296f5a954feSArto Merilainen for (i = 0; i < host->info->nb_pts; i++) {
29775471687STerje Bergstrom syncpt[i].id = i;
29875471687STerje Bergstrom syncpt[i].host = host;
29975471687STerje Bergstrom }
30075471687STerje Bergstrom
301f5a954feSArto Merilainen for (i = 0; i < host->info->nb_bases; i++)
302f5a954feSArto Merilainen bases[i].id = i;
303f5a954feSArto Merilainen
304d4b57818SArto Merilainen mutex_init(&host->syncpt_mutex);
30575471687STerje Bergstrom host->syncpt = syncpt;
306f5a954feSArto Merilainen host->bases = bases;
30775471687STerje Bergstrom
3086579324aSTerje Bergstrom /* Allocate sync point to use for clearing waits for expired fences */
30986cec7ecSMikko Perttunen host->nop_sp = host1x_syncpt_alloc(host, 0, "reserved-nop");
3106579324aSTerje Bergstrom if (!host->nop_sp)
3116579324aSTerje Bergstrom return -ENOMEM;
3126579324aSTerje Bergstrom
313f5ba33fbSMikko Perttunen if (host->info->reserve_vblank_syncpts) {
314f5ba33fbSMikko Perttunen kref_init(&host->syncpt[26].ref);
315f5ba33fbSMikko Perttunen kref_init(&host->syncpt[27].ref);
316f5ba33fbSMikko Perttunen }
317f5ba33fbSMikko Perttunen
31875471687STerje Bergstrom return 0;
31975471687STerje Bergstrom }
32075471687STerje Bergstrom
321466749f1SThierry Reding /**
322466749f1SThierry Reding * host1x_syncpt_request() - request a syncpoint
323617dd7ccSThierry Reding * @client: client requesting the syncpoint
324466749f1SThierry Reding * @flags: flags
325466749f1SThierry Reding *
326466749f1SThierry Reding * host1x client drivers can use this function to allocate a syncpoint for
327466749f1SThierry Reding * subsequent use. A syncpoint returned by this function will be reserved for
328466749f1SThierry Reding * use by the client exclusively. When no longer using a syncpoint, a host1x
3292aed4f5aSMikko Perttunen * client driver needs to release it using host1x_syncpt_put().
330466749f1SThierry Reding */
host1x_syncpt_request(struct host1x_client * client,unsigned long flags)331617dd7ccSThierry Reding struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client,
3328736fe81SArto Merilainen unsigned long flags)
33375471687STerje Bergstrom {
334608f43adSThierry Reding struct host1x *host = dev_get_drvdata(client->host->parent);
3350b8070d1SThierry Reding
33686cec7ecSMikko Perttunen return host1x_syncpt_alloc(host, flags, dev_name(client->dev));
33775471687STerje Bergstrom }
338fae798a1SThierry Reding EXPORT_SYMBOL(host1x_syncpt_request);
33975471687STerje Bergstrom
syncpt_release(struct kref * ref)3402aed4f5aSMikko Perttunen static void syncpt_release(struct kref *ref)
34175471687STerje Bergstrom {
3422aed4f5aSMikko Perttunen struct host1x_syncpt *sp = container_of(ref, struct host1x_syncpt, ref);
34375471687STerje Bergstrom
344aded42adSMikko Perttunen atomic_set(&sp->max_val, host1x_syncpt_read(sp));
345aded42adSMikko Perttunen
346c78f837aSMikko Perttunen sp->locked = false;
347c78f837aSMikko Perttunen
348d4b57818SArto Merilainen mutex_lock(&sp->host->syncpt_mutex);
349d4b57818SArto Merilainen
350f5a954feSArto Merilainen host1x_syncpt_base_free(sp->base);
35175471687STerje Bergstrom kfree(sp->name);
352f5a954feSArto Merilainen sp->base = NULL;
35375471687STerje Bergstrom sp->name = NULL;
354ece66891SArto Merilainen sp->client_managed = false;
355d4b57818SArto Merilainen
356d4b57818SArto Merilainen mutex_unlock(&sp->host->syncpt_mutex);
35775471687STerje Bergstrom }
3582aed4f5aSMikko Perttunen
3592aed4f5aSMikko Perttunen /**
3602aed4f5aSMikko Perttunen * host1x_syncpt_put() - free a requested syncpoint
3612aed4f5aSMikko Perttunen * @sp: host1x syncpoint
3622aed4f5aSMikko Perttunen *
3632aed4f5aSMikko Perttunen * Release a syncpoint previously allocated using host1x_syncpt_request(). A
3642aed4f5aSMikko Perttunen * host1x client driver should call this when the syncpoint is no longer in
3652aed4f5aSMikko Perttunen * use.
3662aed4f5aSMikko Perttunen */
host1x_syncpt_put(struct host1x_syncpt * sp)3672aed4f5aSMikko Perttunen void host1x_syncpt_put(struct host1x_syncpt *sp)
3682aed4f5aSMikko Perttunen {
3692aed4f5aSMikko Perttunen if (!sp)
3702aed4f5aSMikko Perttunen return;
3712aed4f5aSMikko Perttunen
3722aed4f5aSMikko Perttunen kref_put(&sp->ref, syncpt_release);
3732aed4f5aSMikko Perttunen }
3742aed4f5aSMikko Perttunen EXPORT_SYMBOL(host1x_syncpt_put);
37575471687STerje Bergstrom
host1x_syncpt_deinit(struct host1x * host)37675471687STerje Bergstrom void host1x_syncpt_deinit(struct host1x *host)
37775471687STerje Bergstrom {
37875471687STerje Bergstrom struct host1x_syncpt *sp = host->syncpt;
37914c95fc8SThierry Reding unsigned int i;
38014c95fc8SThierry Reding
38175471687STerje Bergstrom for (i = 0; i < host->info->nb_pts; i++, sp++)
38275471687STerje Bergstrom kfree(sp->name);
38375471687STerje Bergstrom }
38475471687STerje Bergstrom
385466749f1SThierry Reding /**
386466749f1SThierry Reding * host1x_syncpt_read_max() - read maximum syncpoint value
387466749f1SThierry Reding * @sp: host1x syncpoint
388466749f1SThierry Reding *
389466749f1SThierry Reding * The maximum syncpoint value indicates how many operations there are in
390466749f1SThierry Reding * queue, either in channel or in a software thread.
3916df633d0SThierry Reding */
host1x_syncpt_read_max(struct host1x_syncpt * sp)39235d747a8SThierry Reding u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
39335d747a8SThierry Reding {
39435d747a8SThierry Reding smp_rmb();
3950b8070d1SThierry Reding
39635d747a8SThierry Reding return (u32)atomic_read(&sp->max_val);
39735d747a8SThierry Reding }
398fae798a1SThierry Reding EXPORT_SYMBOL(host1x_syncpt_read_max);
39935d747a8SThierry Reding
400466749f1SThierry Reding /**
401466749f1SThierry Reding * host1x_syncpt_read_min() - read minimum syncpoint value
402466749f1SThierry Reding * @sp: host1x syncpoint
403466749f1SThierry Reding *
404466749f1SThierry Reding * The minimum syncpoint value is a shadow of the current sync point value in
405466749f1SThierry Reding * hardware.
40635d747a8SThierry Reding */
host1x_syncpt_read_min(struct host1x_syncpt * sp)40735d747a8SThierry Reding u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
40835d747a8SThierry Reding {
40935d747a8SThierry Reding smp_rmb();
4100b8070d1SThierry Reding
41135d747a8SThierry Reding return (u32)atomic_read(&sp->min_val);
41235d747a8SThierry Reding }
413fae798a1SThierry Reding EXPORT_SYMBOL(host1x_syncpt_read_min);
41435d747a8SThierry Reding
415466749f1SThierry Reding /**
416466749f1SThierry Reding * host1x_syncpt_read() - read the current syncpoint value
417466749f1SThierry Reding * @sp: host1x syncpoint
418466749f1SThierry Reding */
host1x_syncpt_read(struct host1x_syncpt * sp)419b4a20144SThierry Reding u32 host1x_syncpt_read(struct host1x_syncpt *sp)
420b4a20144SThierry Reding {
421b4a20144SThierry Reding return host1x_syncpt_load(sp);
422b4a20144SThierry Reding }
423b4a20144SThierry Reding EXPORT_SYMBOL(host1x_syncpt_read);
424b4a20144SThierry Reding
host1x_syncpt_nb_pts(struct host1x * host)42514c95fc8SThierry Reding unsigned int host1x_syncpt_nb_pts(struct host1x *host)
42675471687STerje Bergstrom {
42775471687STerje Bergstrom return host->info->nb_pts;
42875471687STerje Bergstrom }
42975471687STerje Bergstrom
host1x_syncpt_nb_bases(struct host1x * host)43014c95fc8SThierry Reding unsigned int host1x_syncpt_nb_bases(struct host1x *host)
43175471687STerje Bergstrom {
43275471687STerje Bergstrom return host->info->nb_bases;
43375471687STerje Bergstrom }
43475471687STerje Bergstrom
host1x_syncpt_nb_mlocks(struct host1x * host)43514c95fc8SThierry Reding unsigned int host1x_syncpt_nb_mlocks(struct host1x *host)
43675471687STerje Bergstrom {
43775471687STerje Bergstrom return host->info->nb_mlocks;
43875471687STerje Bergstrom }
43975471687STerje Bergstrom
440466749f1SThierry Reding /**
4412aed4f5aSMikko Perttunen * host1x_syncpt_get_by_id() - obtain a syncpoint by ID
442466749f1SThierry Reding * @host: host1x controller
443466749f1SThierry Reding * @id: syncpoint ID
444466749f1SThierry Reding */
host1x_syncpt_get_by_id(struct host1x * host,unsigned int id)4452aed4f5aSMikko Perttunen struct host1x_syncpt *host1x_syncpt_get_by_id(struct host1x *host,
4462aed4f5aSMikko Perttunen unsigned int id)
44775471687STerje Bergstrom {
4488cadb01dSThierry Reding if (id >= host->info->nb_pts)
44975471687STerje Bergstrom return NULL;
4500b8070d1SThierry Reding
4512aed4f5aSMikko Perttunen if (kref_get_unless_zero(&host->syncpt[id].ref))
4522aed4f5aSMikko Perttunen return &host->syncpt[id];
4532aed4f5aSMikko Perttunen else
4542aed4f5aSMikko Perttunen return NULL;
4552aed4f5aSMikko Perttunen }
4562aed4f5aSMikko Perttunen EXPORT_SYMBOL(host1x_syncpt_get_by_id);
4572aed4f5aSMikko Perttunen
4582aed4f5aSMikko Perttunen /**
4592aed4f5aSMikko Perttunen * host1x_syncpt_get_by_id_noref() - obtain a syncpoint by ID but don't
4602aed4f5aSMikko Perttunen * increase the refcount.
4612aed4f5aSMikko Perttunen * @host: host1x controller
4622aed4f5aSMikko Perttunen * @id: syncpoint ID
4632aed4f5aSMikko Perttunen */
host1x_syncpt_get_by_id_noref(struct host1x * host,unsigned int id)4642aed4f5aSMikko Perttunen struct host1x_syncpt *host1x_syncpt_get_by_id_noref(struct host1x *host,
4652aed4f5aSMikko Perttunen unsigned int id)
4662aed4f5aSMikko Perttunen {
4672aed4f5aSMikko Perttunen if (id >= host->info->nb_pts)
4682aed4f5aSMikko Perttunen return NULL;
4692aed4f5aSMikko Perttunen
4702aed4f5aSMikko Perttunen return &host->syncpt[id];
4712aed4f5aSMikko Perttunen }
4722aed4f5aSMikko Perttunen EXPORT_SYMBOL(host1x_syncpt_get_by_id_noref);
4732aed4f5aSMikko Perttunen
4742aed4f5aSMikko Perttunen /**
4752aed4f5aSMikko Perttunen * host1x_syncpt_get() - increment syncpoint refcount
4762aed4f5aSMikko Perttunen * @sp: syncpoint
4772aed4f5aSMikko Perttunen */
host1x_syncpt_get(struct host1x_syncpt * sp)4782aed4f5aSMikko Perttunen struct host1x_syncpt *host1x_syncpt_get(struct host1x_syncpt *sp)
4792aed4f5aSMikko Perttunen {
4802aed4f5aSMikko Perttunen kref_get(&sp->ref);
4812aed4f5aSMikko Perttunen
4822aed4f5aSMikko Perttunen return sp;
48375471687STerje Bergstrom }
484fae798a1SThierry Reding EXPORT_SYMBOL(host1x_syncpt_get);
485f5a954feSArto Merilainen
486466749f1SThierry Reding /**
487466749f1SThierry Reding * host1x_syncpt_get_base() - obtain the wait base associated with a syncpoint
488466749f1SThierry Reding * @sp: host1x syncpoint
489466749f1SThierry Reding */
host1x_syncpt_get_base(struct host1x_syncpt * sp)490f5a954feSArto Merilainen struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp)
491f5a954feSArto Merilainen {
492f5a954feSArto Merilainen return sp ? sp->base : NULL;
493f5a954feSArto Merilainen }
494fae798a1SThierry Reding EXPORT_SYMBOL(host1x_syncpt_get_base);
495f5a954feSArto Merilainen
496466749f1SThierry Reding /**
497466749f1SThierry Reding * host1x_syncpt_base_id() - retrieve the ID of a syncpoint wait base
498466749f1SThierry Reding * @base: host1x syncpoint wait base
499466749f1SThierry Reding */
host1x_syncpt_base_id(struct host1x_syncpt_base * base)500f5a954feSArto Merilainen u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base)
501f5a954feSArto Merilainen {
502f5a954feSArto Merilainen return base->id;
503f5a954feSArto Merilainen }
504fae798a1SThierry Reding EXPORT_SYMBOL(host1x_syncpt_base_id);
505f5ba33fbSMikko Perttunen
do_nothing(struct kref * ref)506f5ba33fbSMikko Perttunen static void do_nothing(struct kref *ref)
507f5ba33fbSMikko Perttunen {
508f5ba33fbSMikko Perttunen }
509f5ba33fbSMikko Perttunen
510f5ba33fbSMikko Perttunen /**
511f5ba33fbSMikko Perttunen * host1x_syncpt_release_vblank_reservation() - Make VBLANK syncpoint
512f5ba33fbSMikko Perttunen * available for allocation
513f5ba33fbSMikko Perttunen *
514f5ba33fbSMikko Perttunen * @client: host1x bus client
515f5ba33fbSMikko Perttunen * @syncpt_id: syncpoint ID to make available
516f5ba33fbSMikko Perttunen *
517f5ba33fbSMikko Perttunen * Makes VBLANK<i> syncpoint available for allocatation if it was
518f5ba33fbSMikko Perttunen * reserved at initialization time. This should be called by the display
519f5ba33fbSMikko Perttunen * driver after it has ensured that any VBLANK increment programming configured
520f5ba33fbSMikko Perttunen * by the boot chain has been disabled.
521f5ba33fbSMikko Perttunen */
host1x_syncpt_release_vblank_reservation(struct host1x_client * client,u32 syncpt_id)522f5ba33fbSMikko Perttunen void host1x_syncpt_release_vblank_reservation(struct host1x_client *client,
523f5ba33fbSMikko Perttunen u32 syncpt_id)
524f5ba33fbSMikko Perttunen {
525f5ba33fbSMikko Perttunen struct host1x *host = dev_get_drvdata(client->host->parent);
526f5ba33fbSMikko Perttunen
527f5ba33fbSMikko Perttunen if (!host->info->reserve_vblank_syncpts)
528f5ba33fbSMikko Perttunen return;
529f5ba33fbSMikko Perttunen
530f5ba33fbSMikko Perttunen kref_put(&host->syncpt[syncpt_id].ref, do_nothing);
531f5ba33fbSMikko Perttunen }
532f5ba33fbSMikko Perttunen EXPORT_SYMBOL(host1x_syncpt_release_vblank_reservation);
533