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