blob: 4e522c532bc8a319e53b69fafb318eb2de80987a [file] [log] [blame]
Terje Bergstrom75471682013-03-22 16:34:01 +02001/*
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"
Terje Bergstrom7ede0b02013-03-22 16:34:02 +020031#include "intr.h"
Terje Bergstrom65793242013-03-22 16:34:03 +020032#include "channel.h"
Terje Bergstrom75471682013-03-22 16:34:01 +020033#include "hw/host1x01.h"
34
35void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
36{
37 void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
38
39 writel(v, sync_regs + r);
40}
41
42u32 host1x_sync_readl(struct host1x *host1x, u32 r)
43{
44 void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset;
45
46 return readl(sync_regs + r);
47}
48
Terje Bergstrom65793242013-03-22 16:34:03 +020049void host1x_ch_writel(struct host1x_channel *ch, u32 v, u32 r)
50{
51 writel(v, ch->regs + r);
52}
53
54u32 host1x_ch_readl(struct host1x_channel *ch, u32 r)
55{
56 return readl(ch->regs + r);
57}
58
Terje Bergstrom75471682013-03-22 16:34:01 +020059static const struct host1x_info host1x01_info = {
60 .nb_channels = 8,
61 .nb_pts = 32,
62 .nb_mlocks = 16,
63 .nb_bases = 8,
64 .init = host1x01_init,
65 .sync_offset = 0x3000,
66};
67
68static struct of_device_id host1x_of_match[] = {
69 { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, },
70 { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, },
71 { },
72};
73MODULE_DEVICE_TABLE(of, host1x_of_match);
74
75static int host1x_probe(struct platform_device *pdev)
76{
77 const struct of_device_id *id;
78 struct host1x *host;
79 struct resource *regs;
80 int syncpt_irq;
81 int err;
82
83 id = of_match_device(host1x_of_match, &pdev->dev);
84 if (!id)
85 return -EINVAL;
86
87 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
88 if (!regs) {
89 dev_err(&pdev->dev, "failed to get registers\n");
90 return -ENXIO;
91 }
92
93 syncpt_irq = platform_get_irq(pdev, 0);
94 if (syncpt_irq < 0) {
95 dev_err(&pdev->dev, "failed to get IRQ\n");
96 return -ENXIO;
97 }
98
99 host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
100 if (!host)
101 return -ENOMEM;
102
103 host->dev = &pdev->dev;
104 host->info = id->data;
105
106 /* set common host1x device data */
107 platform_set_drvdata(pdev, host);
108
109 host->regs = devm_ioremap_resource(&pdev->dev, regs);
110 if (IS_ERR(host->regs))
111 return PTR_ERR(host->regs);
112
113 if (host->info->init) {
114 err = host->info->init(host);
115 if (err)
116 return err;
117 }
118
119 host->clk = devm_clk_get(&pdev->dev, NULL);
120 if (IS_ERR(host->clk)) {
121 dev_err(&pdev->dev, "failed to get clock\n");
122 err = PTR_ERR(host->clk);
123 return err;
124 }
125
Terje Bergstrom65793242013-03-22 16:34:03 +0200126 err = host1x_channel_list_init(host);
127 if (err) {
128 dev_err(&pdev->dev, "failed to initialize channel list\n");
129 return err;
130 }
131
Terje Bergstrom75471682013-03-22 16:34:01 +0200132 err = clk_prepare_enable(host->clk);
133 if (err < 0) {
134 dev_err(&pdev->dev, "failed to enable clock\n");
135 return err;
136 }
137
138 err = host1x_syncpt_init(host);
139 if (err) {
140 dev_err(&pdev->dev, "failed to initialize syncpts\n");
141 return err;
142 }
143
Terje Bergstrom7ede0b02013-03-22 16:34:02 +0200144 err = host1x_intr_init(host, syncpt_irq);
145 if (err) {
146 dev_err(&pdev->dev, "failed to initialize interrupts\n");
147 goto fail_deinit_syncpt;
148 }
149
Terje Bergstrom75471682013-03-22 16:34:01 +0200150 return 0;
Terje Bergstrom7ede0b02013-03-22 16:34:02 +0200151
152fail_deinit_syncpt:
153 host1x_syncpt_deinit(host);
154 return err;
Terje Bergstrom75471682013-03-22 16:34:01 +0200155}
156
157static int __exit host1x_remove(struct platform_device *pdev)
158{
159 struct host1x *host = platform_get_drvdata(pdev);
160
Terje Bergstrom7ede0b02013-03-22 16:34:02 +0200161 host1x_intr_deinit(host);
Terje Bergstrom75471682013-03-22 16:34:01 +0200162 host1x_syncpt_deinit(host);
163 clk_disable_unprepare(host->clk);
164
165 return 0;
166}
167
168static struct platform_driver platform_driver = {
169 .probe = host1x_probe,
170 .remove = __exit_p(host1x_remove),
171 .driver = {
172 .owner = THIS_MODULE,
173 .name = "tegra-host1x",
174 .of_match_table = host1x_of_match,
175 },
176};
177
178module_platform_driver(platform_driver);
179
180MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>");
181MODULE_DESCRIPTION("Host1x driver for Tegra products");
182MODULE_LICENSE("GPL");