175471687STerje Bergstrom /* 275471687STerje Bergstrom * Tegra host1x Syncpoints 375471687STerje Bergstrom * 475471687STerje Bergstrom * Copyright (c) 2010-2013, NVIDIA Corporation. 575471687STerje Bergstrom * 675471687STerje Bergstrom * This program is free software; you can redistribute it and/or modify it 775471687STerje Bergstrom * under the terms and conditions of the GNU General Public License, 875471687STerje Bergstrom * version 2, as published by the Free Software Foundation. 975471687STerje Bergstrom * 1075471687STerje Bergstrom * This program is distributed in the hope it will be useful, but WITHOUT 1175471687STerje Bergstrom * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1275471687STerje Bergstrom * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1375471687STerje Bergstrom * more details. 1475471687STerje Bergstrom * 1575471687STerje Bergstrom * You should have received a copy of the GNU General Public License 1675471687STerje Bergstrom * along with this program. If not, see <http://www.gnu.org/licenses/>. 1775471687STerje Bergstrom */ 1875471687STerje Bergstrom 1975471687STerje Bergstrom #ifndef __HOST1X_SYNCPT_H 2075471687STerje Bergstrom #define __HOST1X_SYNCPT_H 2175471687STerje Bergstrom 2275471687STerje Bergstrom #include <linux/atomic.h> 2375471687STerje Bergstrom #include <linux/kernel.h> 2475471687STerje Bergstrom #include <linux/sched.h> 2575471687STerje Bergstrom 267ede0b0bSTerje Bergstrom #include "intr.h" 277ede0b0bSTerje Bergstrom 2875471687STerje Bergstrom struct host1x; 2975471687STerje Bergstrom 306579324aSTerje Bergstrom /* Reserved for replacing an expired wait with a NOP */ 316579324aSTerje Bergstrom #define HOST1X_SYNCPT_RESERVED 0 326579324aSTerje Bergstrom 3375471687STerje Bergstrom struct host1x_syncpt { 3475471687STerje Bergstrom int id; 3575471687STerje Bergstrom atomic_t min_val; 3675471687STerje Bergstrom atomic_t max_val; 3775471687STerje Bergstrom u32 base_val; 3875471687STerje Bergstrom const char *name; 3975471687STerje Bergstrom int client_managed; 4075471687STerje Bergstrom struct host1x *host; 4175471687STerje Bergstrom struct device *dev; 427ede0b0bSTerje Bergstrom 437ede0b0bSTerje Bergstrom /* interrupt data */ 447ede0b0bSTerje Bergstrom struct host1x_syncpt_intr intr; 4575471687STerje Bergstrom }; 4675471687STerje Bergstrom 4775471687STerje Bergstrom /* Initialize sync point array */ 4875471687STerje Bergstrom int host1x_syncpt_init(struct host1x *host); 4975471687STerje Bergstrom 5075471687STerje Bergstrom /* Free sync point array */ 5175471687STerje Bergstrom void host1x_syncpt_deinit(struct host1x *host); 5275471687STerje Bergstrom 5375471687STerje Bergstrom /* 5475471687STerje Bergstrom * Read max. It indicates how many operations there are in queue, either in 5575471687STerje Bergstrom * channel or in a software thread. 5675471687STerje Bergstrom * */ 5775471687STerje Bergstrom static inline u32 host1x_syncpt_read_max(struct host1x_syncpt *sp) 5875471687STerje Bergstrom { 5975471687STerje Bergstrom smp_rmb(); 6075471687STerje Bergstrom return (u32)atomic_read(&sp->max_val); 6175471687STerje Bergstrom } 6275471687STerje Bergstrom 6375471687STerje Bergstrom /* 6475471687STerje Bergstrom * Read min, which is a shadow of the current sync point value in hardware. 6575471687STerje Bergstrom */ 6675471687STerje Bergstrom static inline u32 host1x_syncpt_read_min(struct host1x_syncpt *sp) 6775471687STerje Bergstrom { 6875471687STerje Bergstrom smp_rmb(); 6975471687STerje Bergstrom return (u32)atomic_read(&sp->min_val); 7075471687STerje Bergstrom } 7175471687STerje Bergstrom 7275471687STerje Bergstrom /* Return number of sync point supported. */ 7375471687STerje Bergstrom int host1x_syncpt_nb_pts(struct host1x *host); 7475471687STerje Bergstrom 7575471687STerje Bergstrom /* Return number of wait bases supported. */ 7675471687STerje Bergstrom int host1x_syncpt_nb_bases(struct host1x *host); 7775471687STerje Bergstrom 7875471687STerje Bergstrom /* Return number of mlocks supported. */ 7975471687STerje Bergstrom int host1x_syncpt_nb_mlocks(struct host1x *host); 8075471687STerje Bergstrom 8175471687STerje Bergstrom /* 8275471687STerje Bergstrom * Check sync point sanity. If max is larger than min, there have too many 8375471687STerje Bergstrom * sync point increments. 8475471687STerje Bergstrom * 8575471687STerje Bergstrom * Client managed sync point are not tracked. 8675471687STerje Bergstrom * */ 8775471687STerje Bergstrom static inline bool host1x_syncpt_check_max(struct host1x_syncpt *sp, u32 real) 8875471687STerje Bergstrom { 8975471687STerje Bergstrom u32 max; 9075471687STerje Bergstrom if (sp->client_managed) 9175471687STerje Bergstrom return true; 9275471687STerje Bergstrom max = host1x_syncpt_read_max(sp); 9375471687STerje Bergstrom return (s32)(max - real) >= 0; 9475471687STerje Bergstrom } 9575471687STerje Bergstrom 9675471687STerje Bergstrom /* Return true if sync point is client managed. */ 9775471687STerje Bergstrom static inline int host1x_syncpt_client_managed(struct host1x_syncpt *sp) 9875471687STerje Bergstrom { 9975471687STerje Bergstrom return sp->client_managed; 10075471687STerje Bergstrom } 10175471687STerje Bergstrom 10275471687STerje Bergstrom /* 10375471687STerje Bergstrom * Returns true if syncpoint min == max, which means that there are no 10475471687STerje Bergstrom * outstanding operations. 10575471687STerje Bergstrom */ 10675471687STerje Bergstrom static inline bool host1x_syncpt_idle(struct host1x_syncpt *sp) 10775471687STerje Bergstrom { 10875471687STerje Bergstrom int min, max; 10975471687STerje Bergstrom smp_rmb(); 11075471687STerje Bergstrom min = atomic_read(&sp->min_val); 11175471687STerje Bergstrom max = atomic_read(&sp->max_val); 11275471687STerje Bergstrom return (min == max); 11375471687STerje Bergstrom } 11475471687STerje Bergstrom 11575471687STerje Bergstrom /* Return pointer to struct denoting sync point id. */ 11675471687STerje Bergstrom struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id); 11775471687STerje Bergstrom 11875471687STerje Bergstrom /* Request incrementing a sync point. */ 11975471687STerje Bergstrom void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp); 12075471687STerje Bergstrom 12175471687STerje Bergstrom /* Load current value from hardware to the shadow register. */ 12275471687STerje Bergstrom u32 host1x_syncpt_load(struct host1x_syncpt *sp); 12375471687STerje Bergstrom 1247ede0b0bSTerje Bergstrom /* Check if the given syncpoint value has already passed */ 1257ede0b0bSTerje Bergstrom bool host1x_syncpt_is_expired(struct host1x_syncpt *sp, u32 thresh); 1267ede0b0bSTerje Bergstrom 12775471687STerje Bergstrom /* Save host1x sync point state into shadow registers. */ 12875471687STerje Bergstrom void host1x_syncpt_save(struct host1x *host); 12975471687STerje Bergstrom 13075471687STerje Bergstrom /* Reset host1x sync point state from shadow registers. */ 13175471687STerje Bergstrom void host1x_syncpt_restore(struct host1x *host); 13275471687STerje Bergstrom 13375471687STerje Bergstrom /* Read current wait base value into shadow register and return it. */ 13475471687STerje Bergstrom u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp); 13575471687STerje Bergstrom 13675471687STerje Bergstrom /* Increment sync point and its max. */ 13775471687STerje Bergstrom void host1x_syncpt_incr(struct host1x_syncpt *sp); 13875471687STerje Bergstrom 13975471687STerje Bergstrom /* Indicate future operations by incrementing the sync point max. */ 14075471687STerje Bergstrom u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs); 14175471687STerje Bergstrom 1427ede0b0bSTerje Bergstrom /* Wait until sync point reaches a threshold value, or a timeout. */ 1437ede0b0bSTerje Bergstrom int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, 1447ede0b0bSTerje Bergstrom long timeout, u32 *value); 1457ede0b0bSTerje Bergstrom 14675471687STerje Bergstrom /* Check if sync point id is valid. */ 14775471687STerje Bergstrom static inline int host1x_syncpt_is_valid(struct host1x_syncpt *sp) 14875471687STerje Bergstrom { 14975471687STerje Bergstrom return sp->id < host1x_syncpt_nb_pts(sp->host); 15075471687STerje Bergstrom } 15175471687STerje Bergstrom 1526579324aSTerje Bergstrom /* Patch a wait by replacing it with a wait for syncpt 0 value 0 */ 1536579324aSTerje Bergstrom int host1x_syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr); 1546579324aSTerje Bergstrom 15575471687STerje Bergstrom /* Return id of the sync point */ 15675471687STerje Bergstrom u32 host1x_syncpt_id(struct host1x_syncpt *sp); 15775471687STerje Bergstrom 15875471687STerje Bergstrom /* Allocate a sync point for a device. */ 15975471687STerje Bergstrom struct host1x_syncpt *host1x_syncpt_request(struct device *dev, 16075471687STerje Bergstrom int client_managed); 16175471687STerje Bergstrom 16275471687STerje Bergstrom /* Free a sync point. */ 16375471687STerje Bergstrom void host1x_syncpt_free(struct host1x_syncpt *sp); 16475471687STerje Bergstrom 16575471687STerje Bergstrom #endif 166