2 * drivers/video/tegra/host/vi/vi.c
4 * Tegra Graphics Host VI
6 * Copyright (c) 2012-2017, NVIDIA CORPORATION. All rights reserved.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <linux/init.h>
22 #include <linux/export.h>
23 #include <linux/module.h>
24 #include <linux/resource.h>
25 #include <linux/pm_runtime.h>
27 #include <linux/of_device.h>
28 #include <linux/of_platform.h>
29 #include <linux/clk/tegra.h>
30 #include <soc/tegra/chip-id.h>
31 #include <linux/tegra_pm_domains.h>
32 #include <linux/debugfs.h>
33 #include <linux/slab.h>
35 #include <media/tegra_v4l2_camera.h>
38 #include "bus_client.h"
39 #include "nvhost_acm.h"
40 #include "t210/t210.h"
42 #include "vi/vi_irq.h"
43 #include "camera/vi/vi2_fops.h"
44 #include "camera/csi/csi2_fops.h"
46 #include "tegra_camera_dev_mfi.h"
48 #define MAX_DEVID_LENGTH 16
49 #define TEGRA_VI_NAME "tegra_vi"
53 struct vi *tegra_vi_get(void)
57 EXPORT_SYMBOL(tegra_vi_get);
59 static struct tegra_t210_vi_data t21_vi_data = {
60 .info = (struct nvhost_device_data *)&t21_vi_info,
62 .csi_fops = &csi2_fops,
65 static struct of_device_id tegra_vi_of_match[] = {
66 { .compatible = "nvidia,tegra210-vi",
67 .data = (struct tegra_t210_vi_data *)&t21_vi_data },
71 static struct i2c_camera_ctrl *i2c_ctrl;
73 static void (*mfi_callback)(void *);
74 static struct mfi_cb_arg *mfi_callback_arg;
75 static DEFINE_MUTEX(vi_isr_lock);
77 int tegra_vi_register_mfi_cb(callback cb, void *cb_arg)
79 mutex_lock(&vi_isr_lock);
80 if (mfi_callback || mfi_callback_arg) {
81 pr_err("cb already registered\n");
82 mutex_unlock(&vi_isr_lock);
87 mfi_callback_arg = (struct mfi_cb_arg *)cb_arg;
88 mutex_unlock(&vi_isr_lock);
92 EXPORT_SYMBOL(tegra_vi_register_mfi_cb);
94 int tegra_vi_unregister_mfi_cb(void)
96 mutex_lock(&vi_isr_lock);
98 mfi_callback_arg = NULL;
99 mutex_unlock(&vi_isr_lock);
103 EXPORT_SYMBOL(tegra_vi_unregister_mfi_cb);
105 struct tegra_mfi_chan {
106 struct work_struct mfi_cb_work;
111 struct tegra_vi_mfi_ctx {
113 struct workqueue_struct *mfi_workqueue;
114 struct tegra_mfi_chan __rcu *mfi_chans;
117 static void vi_mfi_worker(struct work_struct *vi_work)
119 struct tegra_mfi_chan *mfi_chan =
120 container_of(vi_work, struct tegra_mfi_chan, mfi_cb_work);
122 mutex_lock(&vi_isr_lock);
123 if (mfi_callback == NULL) {
124 pr_debug("NULL callback\n");
125 mutex_unlock(&vi_isr_lock);
128 if (mfi_callback_arg)
129 mfi_callback_arg->vi_chan = mfi_chan->channel;
130 mfi_callback(mfi_callback_arg);
131 mutex_unlock(&vi_isr_lock);
134 int tegra_vi_mfi_event_notify(struct tegra_vi_mfi_ctx *mfi_ctx, u8 channel)
136 struct tegra_mfi_chan *chan;
139 pr_err("Invalid mfi_ctx\n");
143 if (channel > mfi_ctx->num_channels-1) {
144 pr_err("Invalid mfi channel\n");
149 chan = rcu_dereference(mfi_ctx->mfi_chans);
150 queue_work(mfi_ctx->mfi_workqueue, &chan[channel].mfi_cb_work);
155 EXPORT_SYMBOL(tegra_vi_mfi_event_notify);
157 bool tegra_vi_has_mfi_callback(void)
161 mutex_lock(&vi_isr_lock);
162 ret = mfi_callback ? true : false;
163 mutex_unlock(&vi_isr_lock);
167 EXPORT_SYMBOL(tegra_vi_has_mfi_callback);
169 int tegra_vi_init_mfi(struct tegra_vi_mfi_ctx **pmfi_ctx, u8 num_channels)
172 struct tegra_mfi_chan *chan;
173 struct tegra_vi_mfi_ctx *mfi_ctx;
176 pr_err("mfi_ctx is invalid\n");
180 mfi_ctx = kzalloc(sizeof(*mfi_ctx), GFP_KERNEL);
181 if (unlikely(mfi_ctx == NULL))
184 /* create workqueue for mfi callback */
185 mfi_ctx->mfi_workqueue = alloc_workqueue("mfi_workqueue",
186 WQ_HIGHPRI | WQ_UNBOUND, 1);
187 if (!mfi_ctx->mfi_workqueue) {
188 pr_err("Failed to allocated mfi_workqueue");
189 tegra_vi_deinit_mfi(&mfi_ctx);
193 chan = kcalloc(num_channels, sizeof(*chan), GFP_KERNEL);
194 if (unlikely(chan == NULL)) {
195 tegra_vi_deinit_mfi(&mfi_ctx);
199 mfi_ctx->num_channels = num_channels;
201 /* Init mfi callback work */
202 for (i = 0; i < num_channels; i++) {
203 INIT_WORK(&chan[i].mfi_cb_work, vi_mfi_worker);
207 rcu_assign_pointer(mfi_ctx->mfi_chans, chan);
213 EXPORT_SYMBOL(tegra_vi_init_mfi);
215 void tegra_vi_deinit_mfi(struct tegra_vi_mfi_ctx **pmfi_ctx)
217 struct tegra_vi_mfi_ctx *mfi_ctx;
219 if (!pmfi_ctx || !*pmfi_ctx)
224 flush_workqueue(mfi_ctx->mfi_workqueue);
225 destroy_workqueue(mfi_ctx->mfi_workqueue);
227 kfree_rcu(mfi_ctx->mfi_chans, rcu);
232 EXPORT_SYMBOL(tegra_vi_deinit_mfi);
234 #if defined(CONFIG_TEGRA_ISOMGR)
235 static int vi_isomgr_unregister(struct vi *tegra_vi)
237 tegra_isomgr_unregister(tegra_vi->isomgr_handle);
238 tegra_vi->isomgr_handle = NULL;
244 static int vi_out_show(struct seq_file *s, void *unused)
246 struct vi *vi = s->private;
248 seq_printf(s, "vi overflow: %u\n",
249 atomic_read(&(vi->vi_out.overflow)));
254 static int vi_out_open(struct inode *inode, struct file *file)
256 return single_open(file, vi_out_show, inode->i_private);
259 static const struct file_operations vi_out_fops = {
263 .release = single_release,
266 static void vi_remove_debugfs(struct vi *vi)
268 debugfs_remove_recursive(vi->debugdir);
272 static void vi_create_debugfs(struct vi *vi)
275 char tegra_vi_name[20];
276 char debugfs_file_name[20];
279 snprintf(tegra_vi_name, sizeof(tegra_vi_name), "%s", TEGRA_VI_NAME);
281 vi->debugdir = debugfs_create_dir(tegra_vi_name, NULL);
283 dev_err(&vi->ndev->dev,
284 "%s: failed to create %s directory",
285 __func__, tegra_vi_name);
286 goto create_debugfs_fail;
289 snprintf(debugfs_file_name, sizeof(debugfs_file_name), "%s", "vi_out");
291 ret = debugfs_create_file(debugfs_file_name, S_IRUGO,
292 vi->debugdir, vi, &vi_out_fops);
294 dev_err(&vi->ndev->dev,
295 "%s: failed to create %s", __func__, debugfs_file_name);
296 goto create_debugfs_fail;
302 dev_err(&vi->ndev->dev, "%s: could not create debugfs", __func__);
303 vi_remove_debugfs(vi);
306 static int nvhost_vi_slcg_handler(struct notifier_block *nb,
307 unsigned long action, void *data)
312 struct nvhost_device_data *pdata =
313 container_of(nb, struct nvhost_device_data,
314 toggle_slcg_notifier);
315 struct vi *tegra_vi = (struct vi *)pdata->private_data;
317 if (tegra_vi->mc_vi.pg_mode)
320 clk = clk_get(NULL, "pll_d");
324 /* Make CSI sourced from PLL_D */
325 ret = tegra_clk_cfg_ex(clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
327 dev_err(&pdata->pdev->dev,
328 "%s: failed to select CSI source pll_d: %d\n",
334 ret = clk_prepare_enable(clk);
336 dev_err(&pdata->pdev->dev, "Can't enable pll_d: %d\n", ret);
343 clk_disable_unprepare(clk);
345 /* Restore CSI source */
346 ret = tegra_clk_cfg_ex(clk, TEGRA_CLK_MIPI_CSI_OUT_ENB, 1);
348 dev_err(&pdata->pdev->dev,
349 "%s: failed to restore csi source: %d\n",
359 static int vi_probe(struct platform_device *dev)
362 struct nvhost_device_data *pdata = NULL;
363 struct tegra_t210_vi_data *data = NULL;
366 if (dev->dev.of_node) {
367 const struct of_device_id *match;
369 match = of_match_device(tegra_vi_of_match, &dev->dev);
371 data = (struct tegra_t210_vi_data *)match->data;
373 dev->dev.platform_data = pdata;
375 /* DT initializes it to -1, use below WAR to set correct value.
376 * TODO: Once proper fix for dev-id goes in, remove it.
378 dev->id = dev->dev.id;
380 pdata = (struct nvhost_device_data *)dev->dev.platform_data;
384 dev_info(&dev->dev, "no platform data\n");
388 err = nvhost_check_bondout(pdata->bond_out_id);
390 dev_warn(&dev->dev, "No VI unit present. err:%d", err);
395 mutex_init(&pdata->lock);
396 platform_set_drvdata(dev, pdata);
398 dev_info(&dev->dev, "%s: ++\n", __func__);
400 tegra_vi = devm_kzalloc(&dev->dev, sizeof(struct vi), GFP_KERNEL);
404 tegra_vi->ndev = dev;
405 tegra_vi->dev = &dev->dev;
406 err = nvhost_client_device_get_resources(dev);
412 err = tegra_vi_init_mfi(&tegra_vi->mfi_ctx, num_channels);
416 if (!pdata->aperture[0]) {
417 dev_err(&dev->dev, "%s: failed to map register base\n",
422 /* call vi_intr_init and stats_work */
423 INIT_WORK(&tegra_vi->stats_work, vi_stats_worker);
425 err = vi_intr_init(tegra_vi);
427 goto vi_mfi_init_fail;
429 vi_create_debugfs(tegra_vi);
431 i2c_ctrl = pdata->private_data;
432 pdata->private_data = tegra_vi;
433 mutex_init(&tegra_vi->update_la_lock);
435 /* Create I2C Devices according to settings from board file */
436 if (i2c_ctrl && i2c_ctrl->new_devices)
437 i2c_ctrl->new_devices(dev);
439 tegra_vi->reg = regulator_get(&tegra_vi->ndev->dev, "avdd_dsi_csi");
440 if (IS_ERR(tegra_vi->reg)) {
441 err = PTR_ERR(tegra_vi->reg);
443 dev_info(&tegra_vi->ndev->dev,
444 "%s: no regulator device\n", __func__);
446 dev_err(&tegra_vi->ndev->dev,
447 "%s: couldn't get regulator\n", __func__);
448 tegra_vi->reg = NULL;
449 if (tegra_platform_is_silicon())
450 goto camera_i2c_unregister;
453 #ifdef CONFIG_TEGRA_CAMERA
454 tegra_vi->camera = tegra_camera_register(dev);
455 if (!tegra_vi->camera) {
456 dev_err(&dev->dev, "%s: can't register tegra_camera\n",
458 goto vi_regulator_put;
462 if (pdata->slcg_notifier_enable &&
463 (pdata->powergate_id != -1)) {
464 pdata->toggle_slcg_notifier.notifier_call =
465 &nvhost_vi_slcg_handler;
467 slcg_register_notifier(pdata->powergate_id,
468 &pdata->toggle_slcg_notifier);
471 nvhost_module_init(dev);
473 err = nvhost_client_device_init(dev);
475 goto camera_unregister;
477 tegra_vi->mc_vi.vi = tegra_vi;
478 tegra_vi->mc_vi.csi = &tegra_vi->csi;
479 tegra_vi->mc_vi.reg = tegra_vi->reg;
480 tegra_vi->mc_vi.fops = data->vi_fops;
481 tegra_vi->csi.fops = data->csi_fops;
482 err = tegra_csi_media_controller_init(&tegra_vi->csi, dev);
484 goto vi_mc_init_error;
486 err = tegra_vi_media_controller_init(&tegra_vi->mc_vi, dev);
488 goto vi_mc_init_error;
493 nvhost_client_device_release(dev);
495 #ifdef CONFIG_TEGRA_CAMERA
496 tegra_camera_unregister(tegra_vi->camera);
500 regulator_put(tegra_vi->reg);
501 tegra_vi->reg = NULL;
503 camera_i2c_unregister:
504 if (i2c_ctrl && i2c_ctrl->remove_devices)
505 i2c_ctrl->remove_devices(dev);
506 pdata->private_data = i2c_ctrl;
508 tegra_vi_deinit_mfi(&tegra_vi->mfi_ctx);
510 dev_err(&dev->dev, "%s: failed\n", __func__);
514 static int __exit vi_remove(struct platform_device *dev)
516 #ifdef CONFIG_TEGRA_CAMERA
519 struct nvhost_device_data *pdata = platform_get_drvdata(dev);
520 struct vi *tegra_vi = (struct vi *)pdata->private_data;
523 if (atomic_read(&dev->dev.power.usage_count) > 0)
527 dev_info(&dev->dev, "%s: ++\n", __func__);
529 #if defined(CONFIG_TEGRA_ISOMGR)
530 if (tegra_vi->isomgr_handle)
531 vi_isomgr_unregister(tegra_vi);
534 tegra_vi_deinit_mfi(&tegra_vi->mfi_ctx);
536 vi_remove_debugfs(tegra_vi);
538 tegra_vi_media_controller_cleanup(&tegra_vi->mc_vi);
540 nvhost_client_device_release(dev);
542 if (pdata->slcg_notifier_enable &&
543 (pdata->powergate_id != -1))
544 slcg_unregister_notifier(pdata->powergate_id,
545 &pdata->toggle_slcg_notifier);
547 vi_intr_free(tegra_vi);
549 pdata->aperture[0] = NULL;
550 #ifdef CONFIG_TEGRA_CAMERA
551 err = tegra_camera_unregister(tegra_vi->camera);
556 #ifdef CONFIG_PM_GENERIC_DOMAINS
557 tegra_pd_remove_device(&dev->dev);
560 regulator_put(tegra_vi->reg);
561 tegra_vi->reg = NULL;
563 /* Remove I2C Devices according to settings from board file */
564 if (i2c_ctrl && i2c_ctrl->remove_devices)
565 i2c_ctrl->remove_devices(dev);
567 pdata->private_data = i2c_ctrl;
572 static struct platform_driver vi_driver = {
574 .remove = __exit_p(vi_remove),
576 .owner = THIS_MODULE,
579 .pm = &nvhost_module_pm_ops,
582 .of_match_table = tegra_vi_of_match,
587 static struct of_device_id tegra_vi_domain_match[] = {
588 {.compatible = "nvidia,tegra210-ve-pd",
589 .data = (struct nvhost_device_data *)&t21_vi_info},
593 static int __init vi_init(void)
597 ret = nvhost_domain_init(tegra_vi_domain_match);
601 return platform_driver_register(&vi_driver);
604 static void __exit vi_exit(void)
606 platform_driver_unregister(&vi_driver);
609 late_initcall(vi_init);
610 module_exit(vi_exit);
611 MODULE_LICENSE("GPL v2");