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 struct host1x *host = sp->host; 30 int min = host1x_syncpt_read_min(sp); 31 host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id)); 32 } 33 34 /* 35 * Write the current waitbase value back to hw. 36 */ 37 static void syncpt_restore_wait_base(struct host1x_syncpt *sp) 38 { 39 struct host1x *host = sp->host; 40 host1x_sync_writel(host, sp->base_val, 41 HOST1X_SYNC_SYNCPT_BASE(sp->id)); 42 } 43 44 /* 45 * Read waitbase value from hw. 46 */ 47 static void syncpt_read_wait_base(struct host1x_syncpt *sp) 48 { 49 struct host1x *host = sp->host; 50 sp->base_val = 51 host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id)); 52 } 53 54 /* 55 * Updates the last value read from hardware. 56 */ 57 static u32 syncpt_load(struct host1x_syncpt *sp) 58 { 59 struct host1x *host = sp->host; 60 u32 old, live; 61 62 /* Loop in case there's a race writing to min_val */ 63 do { 64 old = host1x_syncpt_read_min(sp); 65 live = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT(sp->id)); 66 } while ((u32)atomic_cmpxchg(&sp->min_val, old, live) != old); 67 68 if (!host1x_syncpt_check_max(sp, live)) 69 dev_err(host->dev, "%s failed: id=%u, min=%d, max=%d\n", 70 __func__, sp->id, host1x_syncpt_read_min(sp), 71 host1x_syncpt_read_max(sp)); 72 73 return live; 74 } 75 76 /* 77 * Write a cpu syncpoint increment to the hardware, without touching 78 * the cache. 79 */ 80 static int syncpt_cpu_incr(struct host1x_syncpt *sp) 81 { 82 struct host1x *host = sp->host; 83 u32 reg_offset = sp->id / 32; 84 85 if (!host1x_syncpt_client_managed(sp) && 86 host1x_syncpt_idle(sp)) 87 return -EINVAL; 88 host1x_sync_writel(host, BIT_MASK(sp->id), 89 HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); 90 wmb(); 91 92 return 0; 93 } 94 95 /* remove a wait pointed to by patch_addr */ 96 static int syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) 97 { 98 u32 override = host1x_class_host_wait_syncpt( 99 HOST1X_SYNCPT_RESERVED, 0); 100 101 *((u32 *)patch_addr) = override; 102 return 0; 103 } 104 105 static const struct host1x_syncpt_ops host1x_syncpt_ops = { 106 .restore = syncpt_restore, 107 .restore_wait_base = syncpt_restore_wait_base, 108 .load_wait_base = syncpt_read_wait_base, 109 .load = syncpt_load, 110 .cpu_incr = syncpt_cpu_incr, 111 .patch_wait = syncpt_patch_wait, 112 }; 113