Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.1-rc6 155 lines 3.9 kB view raw
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 u32 min = host1x_syncpt_read_min(sp); 30 struct host1x *host = sp->host; 31 32 host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id)); 33} 34 35/* 36 * Write the current waitbase value back to hw. 37 */ 38static void syncpt_restore_wait_base(struct host1x_syncpt *sp) 39{ 40#if HOST1X_HW < 7 41 struct host1x *host = sp->host; 42 43 host1x_sync_writel(host, sp->base_val, 44 HOST1X_SYNC_SYNCPT_BASE(sp->id)); 45#endif 46} 47 48/* 49 * Read waitbase value from hw. 50 */ 51static void syncpt_read_wait_base(struct host1x_syncpt *sp) 52{ 53#if HOST1X_HW < 7 54 struct host1x *host = sp->host; 55 56 sp->base_val = 57 host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id)); 58#endif 59} 60 61/* 62 * Updates the last value read from hardware. 63 */ 64static u32 syncpt_load(struct host1x_syncpt *sp) 65{ 66 struct host1x *host = sp->host; 67 u32 old, live; 68 69 /* Loop in case there's a race writing to min_val */ 70 do { 71 old = host1x_syncpt_read_min(sp); 72 live = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT(sp->id)); 73 } while ((u32)atomic_cmpxchg(&sp->min_val, old, live) != old); 74 75 if (!host1x_syncpt_check_max(sp, live)) 76 dev_err(host->dev, "%s failed: id=%u, min=%d, max=%d\n", 77 __func__, sp->id, host1x_syncpt_read_min(sp), 78 host1x_syncpt_read_max(sp)); 79 80 return live; 81} 82 83/* 84 * Write a cpu syncpoint increment to the hardware, without touching 85 * the cache. 86 */ 87static int syncpt_cpu_incr(struct host1x_syncpt *sp) 88{ 89 struct host1x *host = sp->host; 90 u32 reg_offset = sp->id / 32; 91 92 if (!host1x_syncpt_client_managed(sp) && 93 host1x_syncpt_idle(sp)) 94 return -EINVAL; 95 96 host1x_sync_writel(host, BIT(sp->id % 32), 97 HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); 98 wmb(); 99 100 return 0; 101} 102 103/** 104 * syncpt_assign_to_channel() - Assign syncpoint to channel 105 * @sp: syncpoint 106 * @ch: channel 107 * 108 * On chips with the syncpoint protection feature (Tegra186+), assign @sp to 109 * @ch, preventing other channels from incrementing the syncpoints. If @ch is 110 * NULL, unassigns the syncpoint. 111 * 112 * On older chips, do nothing. 113 */ 114static void syncpt_assign_to_channel(struct host1x_syncpt *sp, 115 struct host1x_channel *ch) 116{ 117#if HOST1X_HW >= 6 118 struct host1x *host = sp->host; 119 120 if (!host->hv_regs) 121 return; 122 123 host1x_sync_writel(host, 124 HOST1X_SYNC_SYNCPT_CH_APP_CH(ch ? ch->id : 0xff), 125 HOST1X_SYNC_SYNCPT_CH_APP(sp->id)); 126#endif 127} 128 129/** 130 * syncpt_enable_protection() - Enable syncpoint protection 131 * @host: host1x instance 132 * 133 * On chips with the syncpoint protection feature (Tegra186+), enable this 134 * feature. On older chips, do nothing. 135 */ 136static void syncpt_enable_protection(struct host1x *host) 137{ 138#if HOST1X_HW >= 6 139 if (!host->hv_regs) 140 return; 141 142 host1x_hypervisor_writel(host, HOST1X_HV_SYNCPT_PROT_EN_CH_EN, 143 HOST1X_HV_SYNCPT_PROT_EN); 144#endif 145} 146 147static const struct host1x_syncpt_ops host1x_syncpt_ops = { 148 .restore = syncpt_restore, 149 .restore_wait_base = syncpt_restore_wait_base, 150 .load_wait_base = syncpt_read_wait_base, 151 .load = syncpt_load, 152 .cpu_incr = syncpt_cpu_incr, 153 .assign_to_channel = syncpt_assign_to_channel, 154 .enable_protection = syncpt_enable_protection, 155};