linux/drivers/gpu/host1x/hw/syncpt_hw.c
<<
>>
Prefs
   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        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 */
  49static 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 */
  60static 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 */
  83static 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/**
 100 * syncpt_assign_to_channel() - Assign syncpoint to channel
 101 * @sp: syncpoint
 102 * @ch: channel
 103 *
 104 * On chips with the syncpoint protection feature (Tegra186+), assign @sp to
 105 * @ch, preventing other channels from incrementing the syncpoints. If @ch is
 106 * NULL, unassigns the syncpoint.
 107 *
 108 * On older chips, do nothing.
 109 */
 110static void syncpt_assign_to_channel(struct host1x_syncpt *sp,
 111                                  struct host1x_channel *ch)
 112{
 113#if HOST1X_HW >= 6
 114        struct host1x *host = sp->host;
 115
 116        if (!host->hv_regs)
 117                return;
 118
 119        host1x_sync_writel(host,
 120                           HOST1X_SYNC_SYNCPT_CH_APP_CH(ch ? ch->id : 0xff),
 121                           HOST1X_SYNC_SYNCPT_CH_APP(sp->id));
 122#endif
 123}
 124
 125/**
 126 * syncpt_enable_protection() - Enable syncpoint protection
 127 * @host: host1x instance
 128 *
 129 * On chips with the syncpoint protection feature (Tegra186+), enable this
 130 * feature. On older chips, do nothing.
 131 */
 132static void syncpt_enable_protection(struct host1x *host)
 133{
 134#if HOST1X_HW >= 6
 135        if (!host->hv_regs)
 136                return;
 137
 138        host1x_hypervisor_writel(host, HOST1X_HV_SYNCPT_PROT_EN_CH_EN,
 139                                 HOST1X_HV_SYNCPT_PROT_EN);
 140#endif
 141}
 142
 143static const struct host1x_syncpt_ops host1x_syncpt_ops = {
 144        .restore = syncpt_restore,
 145        .restore_wait_base = syncpt_restore_wait_base,
 146        .load_wait_base = syncpt_read_wait_base,
 147        .load = syncpt_load,
 148        .cpu_incr = syncpt_cpu_incr,
 149        .assign_to_channel = syncpt_assign_to_channel,
 150        .enable_protection = syncpt_enable_protection,
 151};
 152