1*9952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
275471687STerje Bergstrom /*
375471687STerje Bergstrom * Tegra host1x Syncpoints
475471687STerje Bergstrom *
575471687STerje Bergstrom * Copyright (c) 2010-2013, NVIDIA Corporation.
675471687STerje Bergstrom */
775471687STerje Bergstrom
875471687STerje Bergstrom #include <linux/io.h>
975471687STerje Bergstrom
10fc3be3e8SThierry Reding #include "../dev.h"
11fc3be3e8SThierry Reding #include "../syncpt.h"
1275471687STerje Bergstrom
1375471687STerje Bergstrom /*
1475471687STerje Bergstrom * Write the current syncpoint value back to hw.
1575471687STerje Bergstrom */
syncpt_restore(struct host1x_syncpt * sp)1675471687STerje Bergstrom static void syncpt_restore(struct host1x_syncpt *sp)
1775471687STerje Bergstrom {
1814c95fc8SThierry Reding u32 min = host1x_syncpt_read_min(sp);
1975471687STerje Bergstrom struct host1x *host = sp->host;
2014c95fc8SThierry Reding
2175471687STerje Bergstrom host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id));
2275471687STerje Bergstrom }
2375471687STerje Bergstrom
2475471687STerje Bergstrom /*
2575471687STerje Bergstrom * Write the current waitbase value back to hw.
2675471687STerje Bergstrom */
syncpt_restore_wait_base(struct host1x_syncpt * sp)2775471687STerje Bergstrom static void syncpt_restore_wait_base(struct host1x_syncpt *sp)
2875471687STerje Bergstrom {
29ac1bdbf2SThierry Reding #if HOST1X_HW < 7
3075471687STerje Bergstrom struct host1x *host = sp->host;
316df633d0SThierry Reding
3275471687STerje Bergstrom host1x_sync_writel(host, sp->base_val,
3375471687STerje Bergstrom HOST1X_SYNC_SYNCPT_BASE(sp->id));
34ac1bdbf2SThierry Reding #endif
3575471687STerje Bergstrom }
3675471687STerje Bergstrom
3775471687STerje Bergstrom /*
3875471687STerje Bergstrom * Read waitbase value from hw.
3975471687STerje Bergstrom */
syncpt_read_wait_base(struct host1x_syncpt * sp)4075471687STerje Bergstrom static void syncpt_read_wait_base(struct host1x_syncpt *sp)
4175471687STerje Bergstrom {
42ac1bdbf2SThierry Reding #if HOST1X_HW < 7
4375471687STerje Bergstrom struct host1x *host = sp->host;
446df633d0SThierry Reding
4575471687STerje Bergstrom sp->base_val =
4675471687STerje Bergstrom host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id));
47ac1bdbf2SThierry Reding #endif
4875471687STerje Bergstrom }
4975471687STerje Bergstrom
5075471687STerje Bergstrom /*
5175471687STerje Bergstrom * Updates the last value read from hardware.
5275471687STerje Bergstrom */
syncpt_load(struct host1x_syncpt * sp)5375471687STerje Bergstrom static u32 syncpt_load(struct host1x_syncpt *sp)
5475471687STerje Bergstrom {
5575471687STerje Bergstrom struct host1x *host = sp->host;
5675471687STerje Bergstrom u32 old, live;
5775471687STerje Bergstrom
5875471687STerje Bergstrom /* Loop in case there's a race writing to min_val */
5975471687STerje Bergstrom do {
6075471687STerje Bergstrom old = host1x_syncpt_read_min(sp);
6175471687STerje Bergstrom live = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT(sp->id));
6275471687STerje Bergstrom } while ((u32)atomic_cmpxchg(&sp->min_val, old, live) != old);
6375471687STerje Bergstrom
6475471687STerje Bergstrom if (!host1x_syncpt_check_max(sp, live))
6575471687STerje Bergstrom dev_err(host->dev, "%s failed: id=%u, min=%d, max=%d\n",
6675471687STerje Bergstrom __func__, sp->id, host1x_syncpt_read_min(sp),
6775471687STerje Bergstrom host1x_syncpt_read_max(sp));
6875471687STerje Bergstrom
6975471687STerje Bergstrom return live;
7075471687STerje Bergstrom }
7175471687STerje Bergstrom
7275471687STerje Bergstrom /*
7375471687STerje Bergstrom * Write a cpu syncpoint increment to the hardware, without touching
7475471687STerje Bergstrom * the cache.
7575471687STerje Bergstrom */
syncpt_cpu_incr(struct host1x_syncpt * sp)76ebae30b1SArto Merilainen static int syncpt_cpu_incr(struct host1x_syncpt *sp)
7775471687STerje Bergstrom {
7875471687STerje Bergstrom struct host1x *host = sp->host;
7975471687STerje Bergstrom u32 reg_offset = sp->id / 32;
8075471687STerje Bergstrom
8175471687STerje Bergstrom if (!host1x_syncpt_client_managed(sp) &&
82ebae30b1SArto Merilainen host1x_syncpt_idle(sp))
83ebae30b1SArto Merilainen return -EINVAL;
840b8070d1SThierry Reding
854ac45eb8SMikko Perttunen host1x_sync_writel(host, BIT(sp->id % 32),
8675471687STerje Bergstrom HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset));
8775471687STerje Bergstrom wmb();
88ebae30b1SArto Merilainen
89ebae30b1SArto Merilainen return 0;
9075471687STerje Bergstrom }
9175471687STerje Bergstrom
92c3f52220SMikko Perttunen /**
93c3f52220SMikko Perttunen * syncpt_assign_to_channel() - Assign syncpoint to channel
94c3f52220SMikko Perttunen * @sp: syncpoint
95c3f52220SMikko Perttunen * @ch: channel
96c3f52220SMikko Perttunen *
97c3f52220SMikko Perttunen * On chips with the syncpoint protection feature (Tegra186+), assign @sp to
98c3f52220SMikko Perttunen * @ch, preventing other channels from incrementing the syncpoints. If @ch is
99c3f52220SMikko Perttunen * NULL, unassigns the syncpoint.
100c3f52220SMikko Perttunen *
101c3f52220SMikko Perttunen * On older chips, do nothing.
102c3f52220SMikko Perttunen */
syncpt_assign_to_channel(struct host1x_syncpt * sp,struct host1x_channel * ch)103c3f52220SMikko Perttunen static void syncpt_assign_to_channel(struct host1x_syncpt *sp,
104c3f52220SMikko Perttunen struct host1x_channel *ch)
105c3f52220SMikko Perttunen {
106c3f52220SMikko Perttunen #if HOST1X_HW >= 6
107c3f52220SMikko Perttunen struct host1x *host = sp->host;
108c3f52220SMikko Perttunen
109c3f52220SMikko Perttunen host1x_sync_writel(host,
110c3f52220SMikko Perttunen HOST1X_SYNC_SYNCPT_CH_APP_CH(ch ? ch->id : 0xff),
111c3f52220SMikko Perttunen HOST1X_SYNC_SYNCPT_CH_APP(sp->id));
112c3f52220SMikko Perttunen #endif
113c3f52220SMikko Perttunen }
114c3f52220SMikko Perttunen
115c3f52220SMikko Perttunen /**
116c3f52220SMikko Perttunen * syncpt_enable_protection() - Enable syncpoint protection
117c3f52220SMikko Perttunen * @host: host1x instance
118c3f52220SMikko Perttunen *
119c3f52220SMikko Perttunen * On chips with the syncpoint protection feature (Tegra186+), enable this
120c3f52220SMikko Perttunen * feature. On older chips, do nothing.
121c3f52220SMikko Perttunen */
syncpt_enable_protection(struct host1x * host)122c3f52220SMikko Perttunen static void syncpt_enable_protection(struct host1x *host)
123c3f52220SMikko Perttunen {
124c3f52220SMikko Perttunen #if HOST1X_HW >= 6
125c3f52220SMikko Perttunen if (!host->hv_regs)
126c3f52220SMikko Perttunen return;
127c3f52220SMikko Perttunen
128c3f52220SMikko Perttunen host1x_hypervisor_writel(host, HOST1X_HV_SYNCPT_PROT_EN_CH_EN,
129c3f52220SMikko Perttunen HOST1X_HV_SYNCPT_PROT_EN);
130c3f52220SMikko Perttunen #endif
131c3f52220SMikko Perttunen }
132c3f52220SMikko Perttunen
13375471687STerje Bergstrom static const struct host1x_syncpt_ops host1x_syncpt_ops = {
13475471687STerje Bergstrom .restore = syncpt_restore,
13575471687STerje Bergstrom .restore_wait_base = syncpt_restore_wait_base,
13675471687STerje Bergstrom .load_wait_base = syncpt_read_wait_base,
13775471687STerje Bergstrom .load = syncpt_load,
13875471687STerje Bergstrom .cpu_incr = syncpt_cpu_incr,
139c3f52220SMikko Perttunen .assign_to_channel = syncpt_assign_to_channel,
140c3f52220SMikko Perttunen .enable_protection = syncpt_enable_protection,
14175471687STerje Bergstrom };
142