Commit 754716874389ccbea5ee03174df8ad9e72e41880

Authored by Terje Bergstrom
Committed by Thierry Reding
1 parent e1adc78caf

gpu: host1x: Add host1x driver

Add host1x, the driver for host1x and its client unit 2D. The Tegra
host1x module is the DMA engine for register access to Tegra's
graphics- and multimedia-related modules. The modules served by
host1x are referred to as clients. host1x includes some other
functionality, such as synchronization.

Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Erik Faye-Lund <kusmabite@gmail.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>

Showing 15 changed files with 957 additions and 0 deletions Side-by-side Diff

drivers/gpu/Makefile
1 1 obj-y += drm/ vga/
  2 +obj-$(CONFIG_TEGRA_HOST1X) += host1x/
drivers/gpu/host1x/Kconfig
  1 +config TEGRA_HOST1X
  2 + tristate "NVIDIA Tegra host1x driver"
  3 + depends on ARCH_TEGRA || ARCH_MULTIPLATFORM
  4 + help
  5 + Driver for the NVIDIA Tegra host1x hardware.
  6 +
  7 + The Tegra host1x module is the DMA engine for register access to
  8 + Tegra's graphics- and multimedia-related modules. The modules served
  9 + by host1x are referred to as clients. host1x includes some other
  10 + functionality, such as synchronization.
drivers/gpu/host1x/Makefile
  1 +ccflags-y = -Idrivers/gpu/host1x
  2 +
  3 +host1x-y = \
  4 + syncpt.o \
  5 + dev.o \
  6 + hw/host1x01.o
  7 +
  8 +obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
drivers/gpu/host1x/dev.c
  1 +/*
  2 + * Tegra host1x driver
  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/module.h>
  20 +#include <linux/list.h>
  21 +#include <linux/slab.h>
  22 +#include <linux/of.h>
  23 +#include <linux/of_device.h>
  24 +#include <linux/clk.h>
  25 +#include <linux/io.h>
  26 +
  27 +#define CREATE_TRACE_POINTS
  28 +#include <trace/events/host1x.h>
  29 +
  30 +#include "dev.h"
  31 +#include "hw/host1x01.h"
  32 +
  33 +void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
  34 +{
  35 + void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
  36 +
  37 + writel(v, sync_regs + r);
  38 +}
  39 +
  40 +u32 host1x_sync_readl(struct host1x *host1x, u32 r)
  41 +{
  42 + void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
  43 +
  44 + return readl(sync_regs + r);
  45 +}
  46 +
  47 +static const struct host1x_info host1x01_info = {
  48 + .nb_channels = 8,
  49 + .nb_pts = 32,
  50 + .nb_mlocks = 16,
  51 + .nb_bases = 8,
  52 + .init = host1x01_init,
  53 + .sync_offset = 0x3000,
  54 +};
  55 +
  56 +static struct of_device_id host1x_of_match[] = {
  57 + { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, },
  58 + { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, },
  59 + { },
  60 +};
  61 +MODULE_DEVICE_TABLE(of, host1x_of_match);
  62 +
  63 +static int host1x_probe(struct platform_device *pdev)
  64 +{
  65 + const struct of_device_id *id;
  66 + struct host1x *host;
  67 + struct resource *regs;
  68 + int syncpt_irq;
  69 + int err;
  70 +
  71 + id = of_match_device(host1x_of_match, &pdev->dev);
  72 + if (!id)
  73 + return -EINVAL;
  74 +
  75 + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  76 + if (!regs) {
  77 + dev_err(&pdev->dev, "failed to get registers\n");
  78 + return -ENXIO;
  79 + }
  80 +
  81 + syncpt_irq = platform_get_irq(pdev, 0);
  82 + if (syncpt_irq < 0) {
  83 + dev_err(&pdev->dev, "failed to get IRQ\n");
  84 + return -ENXIO;
  85 + }
  86 +
  87 + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
  88 + if (!host)
  89 + return -ENOMEM;
  90 +
  91 + host->dev = &pdev->dev;
  92 + host->info = id->data;
  93 +
  94 + /* set common host1x device data */
  95 + platform_set_drvdata(pdev, host);
  96 +
  97 + host->regs = devm_ioremap_resource(&pdev->dev, regs);
  98 + if (IS_ERR(host->regs))
  99 + return PTR_ERR(host->regs);
  100 +
  101 + if (host->info->init) {
  102 + err = host->info->init(host);
  103 + if (err)
  104 + return err;
  105 + }
  106 +
  107 + host->clk = devm_clk_get(&pdev->dev, NULL);
  108 + if (IS_ERR(host->clk)) {
  109 + dev_err(&pdev->dev, "failed to get clock\n");
  110 + err = PTR_ERR(host->clk);
  111 + return err;
  112 + }
  113 +
  114 + err = clk_prepare_enable(host->clk);
  115 + if (err < 0) {
  116 + dev_err(&pdev->dev, "failed to enable clock\n");
  117 + return err;
  118 + }
  119 +
  120 + err = host1x_syncpt_init(host);
  121 + if (err) {
  122 + dev_err(&pdev->dev, "failed to initialize syncpts\n");
  123 + return err;
  124 + }
  125 +
  126 + return 0;
  127 +}
  128 +
  129 +static int __exit host1x_remove(struct platform_device *pdev)
  130 +{
  131 + struct host1x *host = platform_get_drvdata(pdev);
  132 +
  133 + host1x_syncpt_deinit(host);
  134 + clk_disable_unprepare(host->clk);
  135 +
  136 + return 0;
  137 +}
  138 +
  139 +static struct platform_driver platform_driver = {
  140 + .probe = host1x_probe,
  141 + .remove = __exit_p(host1x_remove),
  142 + .driver = {
  143 + .owner = THIS_MODULE,
  144 + .name = "tegra-host1x",
  145 + .of_match_table = host1x_of_match,
  146 + },
  147 +};
  148 +
  149 +module_platform_driver(platform_driver);
  150 +
  151 +MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>");
  152 +MODULE_DESCRIPTION("Host1x driver for Tegra products");
  153 +MODULE_LICENSE("GPL");
drivers/gpu/host1x/dev.h
  1 +/*
  2 + * Copyright (c) 2012-2013, NVIDIA Corporation.
  3 + *
  4 + * This program is free software; you can redistribute it and/or modify it
  5 + * under the terms and conditions of the GNU General Public License,
  6 + * version 2, as published by the Free Software Foundation.
  7 + *
  8 + * This program is distributed in the hope it will be useful, but WITHOUT
  9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11 + * more details.
  12 + *
  13 + * You should have received a copy of the GNU General Public License
  14 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15 + */
  16 +
  17 +#ifndef HOST1X_DEV_H
  18 +#define HOST1X_DEV_H
  19 +
  20 +#include <linux/platform_device.h>
  21 +#include <linux/device.h>
  22 +
  23 +#include "syncpt.h"
  24 +
  25 +struct host1x_syncpt;
  26 +
  27 +struct host1x_syncpt_ops {
  28 + void (*restore)(struct host1x_syncpt *syncpt);
  29 + void (*restore_wait_base)(struct host1x_syncpt *syncpt);
  30 + void (*load_wait_base)(struct host1x_syncpt *syncpt);
  31 + u32 (*load)(struct host1x_syncpt *syncpt);
  32 + void (*cpu_incr)(struct host1x_syncpt *syncpt);
  33 + int (*patch_wait)(struct host1x_syncpt *syncpt, void *patch_addr);
  34 +};
  35 +
  36 +struct host1x_info {
  37 + int nb_channels; /* host1x: num channels supported */
  38 + int nb_pts; /* host1x: num syncpoints supported */
  39 + int nb_bases; /* host1x: num syncpoints supported */
  40 + int nb_mlocks; /* host1x: number of mlocks */
  41 + int (*init)(struct host1x *); /* initialize per SoC ops */
  42 + int sync_offset;
  43 +};
  44 +
  45 +struct host1x {
  46 + const struct host1x_info *info;
  47 +
  48 + void __iomem *regs;
  49 + struct host1x_syncpt *syncpt;
  50 + struct device *dev;
  51 + struct clk *clk;
  52 +
  53 + const struct host1x_syncpt_ops *syncpt_op;
  54 +};
  55 +
  56 +void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v);
  57 +u32 host1x_sync_readl(struct host1x *host1x, u32 r);
  58 +
  59 +static inline void host1x_hw_syncpt_restore(struct host1x *host,
  60 + struct host1x_syncpt *sp)
  61 +{
  62 + host->syncpt_op->restore(sp);
  63 +}
  64 +
  65 +static inline void host1x_hw_syncpt_restore_wait_base(struct host1x *host,
  66 + struct host1x_syncpt *sp)
  67 +{
  68 + host->syncpt_op->restore_wait_base(sp);
  69 +}
  70 +
  71 +static inline void host1x_hw_syncpt_load_wait_base(struct host1x *host,
  72 + struct host1x_syncpt *sp)
  73 +{
  74 + host->syncpt_op->load_wait_base(sp);
  75 +}
  76 +
  77 +static inline u32 host1x_hw_syncpt_load(struct host1x *host,
  78 + struct host1x_syncpt *sp)
  79 +{
  80 + return host->syncpt_op->load(sp);
  81 +}
  82 +
  83 +static inline void host1x_hw_syncpt_cpu_incr(struct host1x *host,
  84 + struct host1x_syncpt *sp)
  85 +{
  86 + host->syncpt_op->cpu_incr(sp);
  87 +}
  88 +
  89 +static inline int host1x_hw_syncpt_patch_wait(struct host1x *host,
  90 + struct host1x_syncpt *sp,
  91 + void *patch_addr)
  92 +{
  93 + return host->syncpt_op->patch_wait(sp, patch_addr);
  94 +}
  95 +
  96 +#endif
drivers/gpu/host1x/hw/Makefile
  1 +ccflags-y = -Idrivers/gpu/host1x
  2 +
  3 +host1x-hw-objs = \
  4 + host1x01.o
  5 +
  6 +obj-$(CONFIG_TEGRA_HOST1X) += host1x-hw.o
drivers/gpu/host1x/hw/host1x01.c
  1 +/*
  2 + * Host1x init for T20 and T30 Architecture Chips
  3 + *
  4 + * Copyright (c) 2011-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 hw specification */
  20 +#include "hw/host1x01.h"
  21 +#include "hw/host1x01_hardware.h"
  22 +
  23 +/* include code */
  24 +#include "hw/syncpt_hw.c"
  25 +
  26 +#include "dev.h"
  27 +
  28 +int host1x01_init(struct host1x *host)
  29 +{
  30 + host->syncpt_op = &host1x_syncpt_ops;
  31 +
  32 + return 0;
  33 +}
drivers/gpu/host1x/hw/host1x01.h
  1 +/*
  2 + * Host1x init for T20 and T30 Architecture Chips
  3 + *
  4 + * Copyright (c) 2011-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 +#ifndef HOST1X_HOST1X01_H
  19 +#define HOST1X_HOST1X01_H
  20 +
  21 +struct host1x;
  22 +
  23 +int host1x01_init(struct host1x *host);
  24 +
  25 +#endif /* HOST1X_HOST1X01_H_ */
drivers/gpu/host1x/hw/host1x01_hardware.h
  1 +/*
  2 + * Tegra host1x Register Offsets for Tegra20 and Tegra30
  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 +#ifndef __HOST1X_HOST1X01_HARDWARE_H
  20 +#define __HOST1X_HOST1X01_HARDWARE_H
  21 +
  22 +#include <linux/types.h>
  23 +#include <linux/bitops.h>
  24 +
  25 +#include "hw_host1x01_sync.h"
  26 +
  27 +#endif
drivers/gpu/host1x/hw/hw_host1x01_sync.h
  1 +/*
  2 + * Copyright (c) 2012-2013, NVIDIA Corporation.
  3 + *
  4 + * This program is free software; you can redistribute it and/or modify it
  5 + * under the terms and conditions of the GNU General Public License,
  6 + * version 2, as published by the Free Software Foundation.
  7 + *
  8 + * This program is distributed in the hope it will be useful, but WITHOUT
  9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11 + * more details.
  12 + *
  13 + * You should have received a copy of the GNU General Public License
  14 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15 + *
  16 + */
  17 +
  18 + /*
  19 + * Function naming determines intended use:
  20 + *
  21 + * <x>_r(void) : Returns the offset for register <x>.
  22 + *
  23 + * <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
  24 + *
  25 + * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
  26 + *
  27 + * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
  28 + * and masked to place it at field <y> of register <x>. This value
  29 + * can be |'d with others to produce a full register value for
  30 + * register <x>.
  31 + *
  32 + * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This
  33 + * value can be ~'d and then &'d to clear the value of field <y> for
  34 + * register <x>.
  35 + *
  36 + * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
  37 + * to place it at field <y> of register <x>. This value can be |'d
  38 + * with others to produce a full register value for <x>.
  39 + *
  40 + * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
  41 + * <x> value 'r' after being shifted to place its LSB at bit 0.
  42 + * This value is suitable for direct comparison with other unshifted
  43 + * values appropriate for use in field <y> of register <x>.
  44 + *
  45 + * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
  46 + * field <y> of register <x>. This value is suitable for direct
  47 + * comparison with unshifted values appropriate for use in field <y>
  48 + * of register <x>.
  49 + */
  50 +
  51 +#ifndef __hw_host1x01_sync_h__
  52 +#define __hw_host1x01_sync_h__
  53 +
  54 +#define REGISTER_STRIDE 4
  55 +
  56 +static inline u32 host1x_sync_syncpt_r(unsigned int id)
  57 +{
  58 + return 0x400 + id * REGISTER_STRIDE;
  59 +}
  60 +#define HOST1X_SYNC_SYNCPT(id) \
  61 + host1x_sync_syncpt_r(id)
  62 +static inline u32 host1x_sync_syncpt_base_r(unsigned int id)
  63 +{
  64 + return 0x600 + id * REGISTER_STRIDE;
  65 +}
  66 +#define HOST1X_SYNC_SYNCPT_BASE(id) \
  67 + host1x_sync_syncpt_base_r(id)
  68 +static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id)
  69 +{
  70 + return 0x700 + id * REGISTER_STRIDE;
  71 +}
  72 +#define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \
  73 + host1x_sync_syncpt_cpu_incr_r(id)
  74 +#endif /* __hw_host1x01_sync_h__ */
drivers/gpu/host1x/hw/syncpt_hw.c
  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 void 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 + dev_err(host->dev, "Trying to increment syncpoint id %d beyond max\n",
  88 + sp->id);
  89 + return;
  90 + }
  91 + host1x_sync_writel(host, BIT_MASK(sp->id),
  92 + HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset));
  93 + wmb();
  94 +}
  95 +
  96 +static const struct host1x_syncpt_ops host1x_syncpt_ops = {
  97 + .restore = syncpt_restore,
  98 + .restore_wait_base = syncpt_restore_wait_base,
  99 + .load_wait_base = syncpt_read_wait_base,
  100 + .load = syncpt_load,
  101 + .cpu_incr = syncpt_cpu_incr,
  102 +};
drivers/gpu/host1x/syncpt.c
  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/module.h>
  20 +#include <linux/device.h>
  21 +#include <linux/slab.h>
  22 +
  23 +#include <trace/events/host1x.h>
  24 +
  25 +#include "syncpt.h"
  26 +#include "dev.h"
  27 +
  28 +static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host,
  29 + struct device *dev,
  30 + int client_managed)
  31 +{
  32 + int i;
  33 + struct host1x_syncpt *sp = host->syncpt;
  34 + char *name;
  35 +
  36 + for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++)
  37 + ;
  38 + if (sp->dev)
  39 + return NULL;
  40 +
  41 + name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id,
  42 + dev ? dev_name(dev) : NULL);
  43 + if (!name)
  44 + return NULL;
  45 +
  46 + sp->dev = dev;
  47 + sp->name = name;
  48 + sp->client_managed = client_managed;
  49 +
  50 + return sp;
  51 +}
  52 +
  53 +u32 host1x_syncpt_id(struct host1x_syncpt *sp)
  54 +{
  55 + return sp->id;
  56 +}
  57 +
  58 +/*
  59 + * Updates the value sent to hardware.
  60 + */
  61 +u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs)
  62 +{
  63 + return (u32)atomic_add_return(incrs, &sp->max_val);
  64 +}
  65 +
  66 + /*
  67 + * Write cached syncpoint and waitbase values to hardware.
  68 + */
  69 +void host1x_syncpt_restore(struct host1x *host)
  70 +{
  71 + struct host1x_syncpt *sp_base = host->syncpt;
  72 + u32 i;
  73 +
  74 + for (i = 0; i < host1x_syncpt_nb_pts(host); i++)
  75 + host1x_hw_syncpt_restore(host, sp_base + i);
  76 + for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
  77 + host1x_hw_syncpt_restore_wait_base(host, sp_base + i);
  78 + wmb();
  79 +}
  80 +
  81 +/*
  82 + * Update the cached syncpoint and waitbase values by reading them
  83 + * from the registers.
  84 + */
  85 +void host1x_syncpt_save(struct host1x *host)
  86 +{
  87 + struct host1x_syncpt *sp_base = host->syncpt;
  88 + u32 i;
  89 +
  90 + for (i = 0; i < host1x_syncpt_nb_pts(host); i++) {
  91 + if (host1x_syncpt_client_managed(sp_base + i))
  92 + host1x_hw_syncpt_load(host, sp_base + i);
  93 + else
  94 + WARN_ON(!host1x_syncpt_idle(sp_base + i));
  95 + }
  96 +
  97 + for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
  98 + host1x_hw_syncpt_load_wait_base(host, sp_base + i);
  99 +}
  100 +
  101 +/*
  102 + * Updates the cached syncpoint value by reading a new value from the hardware
  103 + * register
  104 + */
  105 +u32 host1x_syncpt_load(struct host1x_syncpt *sp)
  106 +{
  107 + u32 val;
  108 + val = host1x_hw_syncpt_load(sp->host, sp);
  109 + trace_host1x_syncpt_load_min(sp->id, val);
  110 +
  111 + return val;
  112 +}
  113 +
  114 +/*
  115 + * Get the current syncpoint base
  116 + */
  117 +u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp)
  118 +{
  119 + u32 val;
  120 + host1x_hw_syncpt_load_wait_base(sp->host, sp);
  121 + val = sp->base_val;
  122 + return val;
  123 +}
  124 +
  125 +/*
  126 + * Write a cpu syncpoint increment to the hardware, without touching
  127 + * the cache. Caller is responsible for host being powered.
  128 + */
  129 +void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp)
  130 +{
  131 + host1x_hw_syncpt_cpu_incr(sp->host, sp);
  132 +}
  133 +
  134 +/*
  135 + * Increment syncpoint value from cpu, updating cache
  136 + */
  137 +void host1x_syncpt_incr(struct host1x_syncpt *sp)
  138 +{
  139 + if (host1x_syncpt_client_managed(sp))
  140 + host1x_syncpt_incr_max(sp, 1);
  141 + host1x_syncpt_cpu_incr(sp);
  142 +}
  143 +
  144 +int host1x_syncpt_init(struct host1x *host)
  145 +{
  146 + struct host1x_syncpt *syncpt;
  147 + int i;
  148 +
  149 + syncpt = devm_kzalloc(host->dev, sizeof(*syncpt) * host->info->nb_pts,
  150 + GFP_KERNEL);
  151 + if (!syncpt)
  152 + return -ENOMEM;
  153 +
  154 + for (i = 0; i < host->info->nb_pts; ++i) {
  155 + syncpt[i].id = i;
  156 + syncpt[i].host = host;
  157 + }
  158 +
  159 + host->syncpt = syncpt;
  160 +
  161 + host1x_syncpt_restore(host);
  162 +
  163 + return 0;
  164 +}
  165 +
  166 +struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
  167 + int client_managed)
  168 +{
  169 + struct host1x *host = dev_get_drvdata(dev->parent);
  170 + return _host1x_syncpt_alloc(host, dev, client_managed);
  171 +}
  172 +
  173 +void host1x_syncpt_free(struct host1x_syncpt *sp)
  174 +{
  175 + if (!sp)
  176 + return;
  177 +
  178 + kfree(sp->name);
  179 + sp->dev = NULL;
  180 + sp->name = NULL;
  181 + sp->client_managed = 0;
  182 +}
  183 +
  184 +void host1x_syncpt_deinit(struct host1x *host)
  185 +{
  186 + int i;
  187 + struct host1x_syncpt *sp = host->syncpt;
  188 + for (i = 0; i < host->info->nb_pts; i++, sp++)
  189 + kfree(sp->name);
  190 +}
  191 +
  192 +int host1x_syncpt_nb_pts(struct host1x *host)
  193 +{
  194 + return host->info->nb_pts;
  195 +}
  196 +
  197 +int host1x_syncpt_nb_bases(struct host1x *host)
  198 +{
  199 + return host->info->nb_bases;
  200 +}
  201 +
  202 +int host1x_syncpt_nb_mlocks(struct host1x *host)
  203 +{
  204 + return host->info->nb_mlocks;
  205 +}
  206 +
  207 +struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id)
  208 +{
  209 + if (host->info->nb_pts < id)
  210 + return NULL;
  211 + return host->syncpt + id;
  212 +}
drivers/gpu/host1x/syncpt.h
  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 +#ifndef __HOST1X_SYNCPT_H
  20 +#define __HOST1X_SYNCPT_H
  21 +
  22 +#include <linux/atomic.h>
  23 +#include <linux/kernel.h>
  24 +#include <linux/sched.h>
  25 +
  26 +struct host1x;
  27 +
  28 +struct host1x_syncpt {
  29 + int id;
  30 + atomic_t min_val;
  31 + atomic_t max_val;
  32 + u32 base_val;
  33 + const char *name;
  34 + int client_managed;
  35 + struct host1x *host;
  36 + struct device *dev;
  37 +};
  38 +
  39 +/* Initialize sync point array */
  40 +int host1x_syncpt_init(struct host1x *host);
  41 +
  42 +/* Free sync point array */
  43 +void host1x_syncpt_deinit(struct host1x *host);
  44 +
  45 +/*
  46 + * Read max. It indicates how many operations there are in queue, either in
  47 + * channel or in a software thread.
  48 + * */
  49 +static inline u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
  50 +{
  51 + smp_rmb();
  52 + return (u32)atomic_read(&sp->max_val);
  53 +}
  54 +
  55 +/*
  56 + * Read min, which is a shadow of the current sync point value in hardware.
  57 + */
  58 +static inline u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
  59 +{
  60 + smp_rmb();
  61 + return (u32)atomic_read(&sp->min_val);
  62 +}
  63 +
  64 +/* Return number of sync point supported. */
  65 +int host1x_syncpt_nb_pts(struct host1x *host);
  66 +
  67 +/* Return number of wait bases supported. */
  68 +int host1x_syncpt_nb_bases(struct host1x *host);
  69 +
  70 +/* Return number of mlocks supported. */
  71 +int host1x_syncpt_nb_mlocks(struct host1x *host);
  72 +
  73 +/*
  74 + * Check sync point sanity. If max is larger than min, there have too many
  75 + * sync point increments.
  76 + *
  77 + * Client managed sync point are not tracked.
  78 + * */
  79 +static inline bool host1x_syncpt_check_max(struct host1x_syncpt *sp, u32 real)
  80 +{
  81 + u32 max;
  82 + if (sp->client_managed)
  83 + return true;
  84 + max = host1x_syncpt_read_max(sp);
  85 + return (s32)(max - real) >= 0;
  86 +}
  87 +
  88 +/* Return true if sync point is client managed. */
  89 +static inline int host1x_syncpt_client_managed(struct host1x_syncpt *sp)
  90 +{
  91 + return sp->client_managed;
  92 +}
  93 +
  94 +/*
  95 + * Returns true if syncpoint min == max, which means that there are no
  96 + * outstanding operations.
  97 + */
  98 +static inline bool host1x_syncpt_idle(struct host1x_syncpt *sp)
  99 +{
  100 + int min, max;
  101 + smp_rmb();
  102 + min = atomic_read(&sp->min_val);
  103 + max = atomic_read(&sp->max_val);
  104 + return (min == max);
  105 +}
  106 +
  107 +/* Return pointer to struct denoting sync point id. */
  108 +struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id);
  109 +
  110 +/* Request incrementing a sync point. */
  111 +void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp);
  112 +
  113 +/* Load current value from hardware to the shadow register. */
  114 +u32 host1x_syncpt_load(struct host1x_syncpt *sp);
  115 +
  116 +/* Save host1x sync point state into shadow registers. */
  117 +void host1x_syncpt_save(struct host1x *host);
  118 +
  119 +/* Reset host1x sync point state from shadow registers. */
  120 +void host1x_syncpt_restore(struct host1x *host);
  121 +
  122 +/* Read current wait base value into shadow register and return it. */
  123 +u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp);
  124 +
  125 +/* Increment sync point and its max. */
  126 +void host1x_syncpt_incr(struct host1x_syncpt *sp);
  127 +
  128 +/* Indicate future operations by incrementing the sync point max. */
  129 +u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
  130 +
  131 +/* Check if sync point id is valid. */
  132 +static inline int host1x_syncpt_is_valid(struct host1x_syncpt *sp)
  133 +{
  134 + return sp->id < host1x_syncpt_nb_pts(sp->host);
  135 +}
  136 +
  137 +/* Return id of the sync point */
  138 +u32 host1x_syncpt_id(struct host1x_syncpt *sp);
  139 +
  140 +/* Allocate a sync point for a device. */
  141 +struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
  142 + int client_managed);
  143 +
  144 +/* Free a sync point. */
  145 +void host1x_syncpt_free(struct host1x_syncpt *sp);
  146 +
  147 +#endif
drivers/video/Kconfig
... ... @@ -21,6 +21,8 @@
21 21  
22 22 source "drivers/gpu/drm/Kconfig"
23 23  
  24 +source "drivers/gpu/host1x/Kconfig"
  25 +
24 26 config VGASTATE
25 27 tristate
26 28 default n
include/trace/events/host1x.h
  1 +/*
  2 + * include/trace/events/host1x.h
  3 + *
  4 + * host1x event logging to ftrace.
  5 + *
  6 + * Copyright (c) 2010-2013, NVIDIA Corporation.
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License as published by
  10 + * the Free Software Foundation; either version 2 of the License, or
  11 + * (at your option) any later version.
  12 + *
  13 + * This program is distributed in the hope that it will be useful, but WITHOUT
  14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16 + * more details.
  17 + *
  18 + * You should have received a copy of the GNU General Public License along
  19 + * with this program; if not, write to the Free Software Foundation, Inc.,
  20 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21 + */
  22 +
  23 +#undef TRACE_SYSTEM
  24 +#define TRACE_SYSTEM host1x
  25 +
  26 +#if !defined(_TRACE_HOST1X_H) || defined(TRACE_HEADER_MULTI_READ)
  27 +#define _TRACE_HOST1X_H
  28 +
  29 +#include <linux/ktime.h>
  30 +#include <linux/tracepoint.h>
  31 +
  32 +DECLARE_EVENT_CLASS(host1x,
  33 + TP_PROTO(const char *name),
  34 + TP_ARGS(name),
  35 + TP_STRUCT__entry(__field(const char *, name)),
  36 + TP_fast_assign(__entry->name = name;),
  37 + TP_printk("name=%s", __entry->name)
  38 +);
  39 +
  40 +TRACE_EVENT(host1x_syncpt_load_min,
  41 + TP_PROTO(u32 id, u32 val),
  42 +
  43 + TP_ARGS(id, val),
  44 +
  45 + TP_STRUCT__entry(
  46 + __field(u32, id)
  47 + __field(u32, val)
  48 + ),
  49 +
  50 + TP_fast_assign(
  51 + __entry->id = id;
  52 + __entry->val = val;
  53 + ),
  54 +
  55 + TP_printk("id=%d, val=%d", __entry->id, __entry->val)
  56 +);
  57 +
  58 +#endif /* _TRACE_HOST1X_H */
  59 +
  60 +/* This part must be outside protection */
  61 +#include <trace/define_trace.h>