18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Tegra host1x Syncpoints 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010-2013, NVIDIA Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "../dev.h" 118c2ecf20Sopenharmony_ci#include "../syncpt.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* 148c2ecf20Sopenharmony_ci * Write the current syncpoint value back to hw. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_cistatic void syncpt_restore(struct host1x_syncpt *sp) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci u32 min = host1x_syncpt_read_min(sp); 198c2ecf20Sopenharmony_ci struct host1x *host = sp->host; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id)); 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * Write the current waitbase value back to hw. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_cistatic void syncpt_restore_wait_base(struct host1x_syncpt *sp) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci#if HOST1X_HW < 7 308c2ecf20Sopenharmony_ci struct host1x *host = sp->host; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci host1x_sync_writel(host, sp->base_val, 338c2ecf20Sopenharmony_ci HOST1X_SYNC_SYNCPT_BASE(sp->id)); 348c2ecf20Sopenharmony_ci#endif 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 388c2ecf20Sopenharmony_ci * Read waitbase value from hw. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_cistatic void syncpt_read_wait_base(struct host1x_syncpt *sp) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci#if HOST1X_HW < 7 438c2ecf20Sopenharmony_ci struct host1x *host = sp->host; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci sp->base_val = 468c2ecf20Sopenharmony_ci host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id)); 478c2ecf20Sopenharmony_ci#endif 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * Updates the last value read from hardware. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_cistatic u32 syncpt_load(struct host1x_syncpt *sp) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct host1x *host = sp->host; 568c2ecf20Sopenharmony_ci u32 old, live; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* Loop in case there's a race writing to min_val */ 598c2ecf20Sopenharmony_ci do { 608c2ecf20Sopenharmony_ci old = host1x_syncpt_read_min(sp); 618c2ecf20Sopenharmony_ci live = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT(sp->id)); 628c2ecf20Sopenharmony_ci } while ((u32)atomic_cmpxchg(&sp->min_val, old, live) != old); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (!host1x_syncpt_check_max(sp, live)) 658c2ecf20Sopenharmony_ci dev_err(host->dev, "%s failed: id=%u, min=%d, max=%d\n", 668c2ecf20Sopenharmony_ci __func__, sp->id, host1x_syncpt_read_min(sp), 678c2ecf20Sopenharmony_ci host1x_syncpt_read_max(sp)); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return live; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * Write a cpu syncpoint increment to the hardware, without touching 748c2ecf20Sopenharmony_ci * the cache. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic int syncpt_cpu_incr(struct host1x_syncpt *sp) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct host1x *host = sp->host; 798c2ecf20Sopenharmony_ci u32 reg_offset = sp->id / 32; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (!host1x_syncpt_client_managed(sp) && 828c2ecf20Sopenharmony_ci host1x_syncpt_idle(sp)) 838c2ecf20Sopenharmony_ci return -EINVAL; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci host1x_sync_writel(host, BIT(sp->id % 32), 868c2ecf20Sopenharmony_ci HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); 878c2ecf20Sopenharmony_ci wmb(); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return 0; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/** 938c2ecf20Sopenharmony_ci * syncpt_assign_to_channel() - Assign syncpoint to channel 948c2ecf20Sopenharmony_ci * @sp: syncpoint 958c2ecf20Sopenharmony_ci * @ch: channel 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * On chips with the syncpoint protection feature (Tegra186+), assign @sp to 988c2ecf20Sopenharmony_ci * @ch, preventing other channels from incrementing the syncpoints. If @ch is 998c2ecf20Sopenharmony_ci * NULL, unassigns the syncpoint. 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * On older chips, do nothing. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_cistatic void syncpt_assign_to_channel(struct host1x_syncpt *sp, 1048c2ecf20Sopenharmony_ci struct host1x_channel *ch) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci#if HOST1X_HW >= 6 1078c2ecf20Sopenharmony_ci struct host1x *host = sp->host; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci host1x_sync_writel(host, 1108c2ecf20Sopenharmony_ci HOST1X_SYNC_SYNCPT_CH_APP_CH(ch ? ch->id : 0xff), 1118c2ecf20Sopenharmony_ci HOST1X_SYNC_SYNCPT_CH_APP(sp->id)); 1128c2ecf20Sopenharmony_ci#endif 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/** 1168c2ecf20Sopenharmony_ci * syncpt_enable_protection() - Enable syncpoint protection 1178c2ecf20Sopenharmony_ci * @host: host1x instance 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * On chips with the syncpoint protection feature (Tegra186+), enable this 1208c2ecf20Sopenharmony_ci * feature. On older chips, do nothing. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_cistatic void syncpt_enable_protection(struct host1x *host) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci#if HOST1X_HW >= 6 1258c2ecf20Sopenharmony_ci if (!host->hv_regs) 1268c2ecf20Sopenharmony_ci return; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci host1x_hypervisor_writel(host, HOST1X_HV_SYNCPT_PROT_EN_CH_EN, 1298c2ecf20Sopenharmony_ci HOST1X_HV_SYNCPT_PROT_EN); 1308c2ecf20Sopenharmony_ci#endif 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic const struct host1x_syncpt_ops host1x_syncpt_ops = { 1348c2ecf20Sopenharmony_ci .restore = syncpt_restore, 1358c2ecf20Sopenharmony_ci .restore_wait_base = syncpt_restore_wait_base, 1368c2ecf20Sopenharmony_ci .load_wait_base = syncpt_read_wait_base, 1378c2ecf20Sopenharmony_ci .load = syncpt_load, 1388c2ecf20Sopenharmony_ci .cpu_incr = syncpt_cpu_incr, 1398c2ecf20Sopenharmony_ci .assign_to_channel = syncpt_assign_to_channel, 1408c2ecf20Sopenharmony_ci .enable_protection = syncpt_enable_protection, 1418c2ecf20Sopenharmony_ci}; 142