2 * drivers/video/tegra/host/vi/vi.c
4 * Tegra Graphics Host VI
6 * Copyright (c) 2012-2016, 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 <linux/tegra-soc.h>
31 #include <linux/tegra_pm_domains.h>
32 #include <linux/debugfs.h>
34 #include <media/tegra_v4l2_camera.h>
37 #include "bus_client.h"
38 #include "nvhost_acm.h"
39 #include "t124/t124.h"
40 #include "t210/t210.h"
42 #include "vi/vi_irq.h"
43 #include "camera/vi2_fops.h"
45 #ifdef CONFIG_ARCH_TEGRA_18x_SOC
46 #include "t186/t186.h"
49 #define MAX_DEVID_LENGTH 16
50 #define TEGRA_VI_NAME "tegra_vi"
54 struct vi *tegra_vi_get(void)
58 EXPORT_SYMBOL(tegra_vi_get);
60 struct tegra_vi_data t124_vi_data = {
61 .info = (struct nvhost_device_data *)&t124_vi_info,
63 .channel_fops = &vi2_channel_fops,
66 struct tegra_vi_data t210_vi_data = {
67 .info = (struct nvhost_device_data *)&t21_vi_info,
69 .channel_fops = &vi2_channel_fops,
72 #ifdef CONFIG_ARCH_TEGRA_18x_SOC
73 struct tegra_vi_data t186_vi_data = {
74 .info = (struct nvhost_device_data *)&t18_vi_info,
78 static struct of_device_id tegra_vi_of_match[] = {
80 .compatible = "nvidia,tegra124-vi",
84 .compatible = "nvidia,tegra210-vi",
87 #ifdef CONFIG_ARCH_TEGRA_18x_SOC
89 .compatible = "nvidia,tegra186-vi",
96 static struct i2c_camera_ctrl *i2c_ctrl;
98 static void (*mfi_callback)(void *);
99 static void *mfi_callback_arg;
100 static DEFINE_MUTEX(vi_isr_lock);
102 #ifdef CONFIG_VIDEO_TEGRA_VI
103 int tegra_vi_register_mfi_cb(callback cb, void *cb_arg)
105 if (mfi_callback || mfi_callback_arg) {
106 pr_err("cb already registered\n");
110 mutex_lock(&vi_isr_lock);
112 mfi_callback_arg = cb_arg;
113 mutex_unlock(&vi_isr_lock);
117 EXPORT_SYMBOL(tegra_vi_register_mfi_cb);
119 int tegra_vi_unregister_mfi_cb(void)
121 mutex_lock(&vi_isr_lock);
123 mfi_callback_arg = NULL;
124 mutex_unlock(&vi_isr_lock);
128 EXPORT_SYMBOL(tegra_vi_unregister_mfi_cb);
131 static void vi_mfi_worker(struct work_struct *vi_work)
133 struct vi *pdev = container_of(vi_work, struct vi, mfi_cb_work);
135 if (mfi_callback == NULL) {
136 dev_dbg(&pdev->ndev->dev, "NULL callback\n");
139 mutex_lock(&vi_isr_lock);
140 mfi_callback(mfi_callback_arg);
141 mutex_unlock(&vi_isr_lock);
145 #if defined(CONFIG_TEGRA_ISOMGR)
146 static int vi_isomgr_unregister(struct vi *tegra_vi)
148 tegra_isomgr_unregister(tegra_vi->isomgr_handle);
149 tegra_vi->isomgr_handle = NULL;
155 static int vi_out_show(struct seq_file *s, void *unused)
157 struct vi *vi = s->private;
159 seq_printf(s, "vi overflow: %u\n",
160 atomic_read(&(vi->vi_out.overflow)));
165 static int vi_out_open(struct inode *inode, struct file *file)
167 return single_open(file, vi_out_show, inode->i_private);
170 static const struct file_operations vi_out_fops = {
174 .release = single_release,
177 static void vi_remove_debugfs(struct vi *vi)
179 debugfs_remove_recursive(vi->debugdir);
183 static void vi_create_debugfs(struct vi *vi)
186 char tegra_vi_name[20];
187 char debugfs_file_name[20];
190 snprintf(tegra_vi_name, sizeof(tegra_vi_name), "%s", TEGRA_VI_NAME);
192 vi->debugdir = debugfs_create_dir(tegra_vi_name, NULL);
194 dev_err(&vi->ndev->dev,
195 "%s: failed to create %s directory",
196 __func__, tegra_vi_name);
197 goto create_debugfs_fail;
200 snprintf(debugfs_file_name, sizeof(debugfs_file_name), "%s", "vi_out");
202 ret = debugfs_create_file(debugfs_file_name, S_IRUGO,
203 vi->debugdir, vi, &vi_out_fops);
205 dev_err(&vi->ndev->dev,
206 "%s: failed to create %s", __func__, debugfs_file_name);
207 goto create_debugfs_fail;
213 dev_err(&vi->ndev->dev, "%s: could not create debugfs", __func__);
214 vi_remove_debugfs(vi);
217 static int nvhost_vi_slcg_handler(struct notifier_block *nb,
218 unsigned long action, void *data)
223 struct nvhost_device_data *pdata =
224 container_of(nb, struct nvhost_device_data,
225 toggle_slcg_notifier);
226 struct vi *tegra_vi = (struct vi *)pdata->private_data;
228 if (tegra_vi->mc_vi.pg_mode)
231 clk = clk_get(&pdata->pdev->dev, "pll_d");
235 /* Make CSI sourced from PLL_D */
236 ret = tegra_clk_cfg_ex(clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
238 dev_err(&pdata->pdev->dev,
239 "%s: failed to select CSI source pll_d: %d\n",
245 ret = clk_prepare_enable(clk);
247 dev_err(&pdata->pdev->dev, "Can't enable pll_d: %d\n", ret);
254 clk_disable_unprepare(clk);
256 /* Restore CSI source */
257 ret = tegra_clk_cfg_ex(clk, TEGRA_CLK_MIPI_CSI_OUT_ENB, 1);
259 dev_err(&pdata->pdev->dev,
260 "%s: failed to restore csi source: %d\n",
270 static int vi_probe(struct platform_device *dev)
273 struct tegra_vi_data *data = NULL;
274 struct nvhost_device_data *pdata = NULL;
276 if (dev->dev.of_node) {
277 const struct of_device_id *match;
279 match = of_match_device(tegra_vi_of_match, &dev->dev);
281 data = (struct tegra_vi_data *) match->data;
283 /* DT initializes it to -1, use below WAR to set correct value.
284 * TODO: Once proper fix for dev-id goes in, remove it.
286 dev->id = dev->dev.id;
289 BUG_ON(!data || !data->info);
290 dev->dev.platform_data = data->info;
293 err = nvhost_check_bondout(pdata->bond_out_id);
295 dev_warn(&dev->dev, "No VI unit present. err:%d", err);
300 mutex_init(&pdata->lock);
301 platform_set_drvdata(dev, pdata);
303 dev_info(&dev->dev, "%s: ++\n", __func__);
305 tegra_vi = devm_kzalloc(&dev->dev, sizeof(struct vi), GFP_KERNEL);
307 dev_err(&dev->dev, "can't allocate memory for vi\n");
310 tegra_vi->ndev = dev;
311 tegra_vi->data = data;
312 tegra_vi->dev = &dev->dev;
314 /* If missing SoC fops, whole VI/CSI has be in bypass mode */
315 if (!data->vi_fops || !data->channel_fops)
316 tegra_vi->bypass = true;
318 err = nvhost_client_device_get_resources(dev);
322 if (!pdata->aperture[0]) {
323 dev_err(&dev->dev, "%s: failed to map register base\n",
328 /* create workqueue for mfi callback */
329 tegra_vi->vi_workqueue = alloc_workqueue("vi_workqueue",
330 WQ_HIGHPRI | WQ_UNBOUND, 1);
331 if (!tegra_vi->vi_workqueue) {
332 dev_err(&dev->dev, "Failed to allocated vi_workqueue");
335 /* Init mfi callback work */
336 INIT_WORK(&tegra_vi->mfi_cb_work, vi_mfi_worker);
338 /* call vi_intr_init and stats_work */
339 INIT_WORK(&tegra_vi->stats_work, vi_stats_worker);
341 err = vi_intr_init(tegra_vi);
345 vi_create_debugfs(tegra_vi);
347 i2c_ctrl = pdata->private_data;
348 pdata->private_data = tegra_vi;
349 mutex_init(&tegra_vi->update_la_lock);
351 /* Create I2C Devices according to settings from board file */
352 if (i2c_ctrl && i2c_ctrl->new_devices)
353 i2c_ctrl->new_devices(dev);
355 tegra_vi->reg = regulator_get(&tegra_vi->ndev->dev, "avdd_dsi_csi");
356 if (IS_ERR(tegra_vi->reg)) {
357 err = PTR_ERR(tegra_vi->reg);
359 dev_info(&tegra_vi->ndev->dev,
360 "%s: no regulator device\n", __func__);
362 dev_err(&tegra_vi->ndev->dev,
363 "%s: couldn't get regulator\n", __func__);
364 tegra_vi->reg = NULL;
365 if (tegra_platform_is_silicon())
366 goto camera_i2c_unregister;
369 #ifdef CONFIG_TEGRA_CAMERA
370 tegra_vi->camera = tegra_camera_register(dev);
371 if (!tegra_vi->camera) {
372 dev_err(&dev->dev, "%s: can't register tegra_camera\n",
374 goto vi_regulator_put;
378 if (pdata->slcg_notifier_enable &&
379 (pdata->powergate_id != -1)) {
380 pdata->toggle_slcg_notifier.notifier_call =
381 &nvhost_vi_slcg_handler;
383 slcg_register_notifier(pdata->powergate_id,
384 &pdata->toggle_slcg_notifier);
387 nvhost_module_init(dev);
389 #ifdef CONFIG_PM_GENERIC_DOMAINS
390 #ifndef CONFIG_PM_GENERIC_DOMAINS_OF
391 pdata->pd.name = "ve";
394 /* add module power domain and also add its domain
395 * as sub-domain of MC domain */
396 err = nvhost_module_add_domain(&pdata->pd, dev);
398 err = nvhost_client_device_init(dev);
400 goto camera_unregister;
402 tegra_vi->csi.vi = tegra_vi;
403 err = tegra_csi_init(&tegra_vi->csi, dev);
405 goto vi_mc_init_error;
407 tegra_vi->mc_vi.vi = tegra_vi;
408 tegra_vi->mc_vi.csi = &tegra_vi->csi;
409 tegra_vi->mc_vi.reg = tegra_vi->reg;
410 tegra_vi->mc_vi.fops = tegra_vi->data->vi_fops;
411 err = tegra_vi_media_controller_init(&tegra_vi->mc_vi, dev);
413 goto vi_mc_init_error;
418 nvhost_client_device_release(dev);
420 #ifdef CONFIG_TEGRA_CAMERA
421 tegra_camera_unregister(tegra_vi->camera);
424 regulator_put(tegra_vi->reg);
425 tegra_vi->reg = NULL;
427 camera_i2c_unregister:
428 if (i2c_ctrl && i2c_ctrl->remove_devices)
429 i2c_ctrl->remove_devices(dev);
430 pdata->private_data = i2c_ctrl;
432 dev_err(&dev->dev, "%s: failed\n", __func__);
436 static int __exit vi_remove(struct platform_device *dev)
438 #ifdef CONFIG_TEGRA_CAMERA
441 struct nvhost_device_data *pdata = platform_get_drvdata(dev);
442 struct vi *tegra_vi = (struct vi *)pdata->private_data;
444 #ifdef CONFIG_PM_RUNTIME
445 if (atomic_read(&dev->dev.power.usage_count) > 0)
449 dev_info(&dev->dev, "%s: ++\n", __func__);
451 #if defined(CONFIG_TEGRA_ISOMGR)
452 if (tegra_vi->isomgr_handle)
453 vi_isomgr_unregister(tegra_vi);
456 vi_remove_debugfs(tegra_vi);
458 tegra_vi_media_controller_cleanup(&tegra_vi->mc_vi);
460 nvhost_client_device_release(dev);
462 if (pdata->slcg_notifier_enable &&
463 (pdata->powergate_id != -1))
464 slcg_unregister_notifier(pdata->powergate_id,
465 &pdata->toggle_slcg_notifier);
467 vi_intr_free(tegra_vi);
469 pdata->aperture[0] = NULL;
470 flush_workqueue(tegra_vi->vi_workqueue);
471 destroy_workqueue(tegra_vi->vi_workqueue);
472 #ifdef CONFIG_TEGRA_CAMERA
473 err = tegra_camera_unregister(tegra_vi->camera);
478 #ifdef CONFIG_PM_GENERIC_DOMAINS
479 tegra_pd_remove_device(&dev->dev);
482 regulator_put(tegra_vi->reg);
483 tegra_vi->reg = NULL;
485 /* Remove I2C Devices according to settings from board file */
486 if (i2c_ctrl && i2c_ctrl->remove_devices)
487 i2c_ctrl->remove_devices(dev);
489 pdata->private_data = i2c_ctrl;
494 static struct platform_driver vi_driver = {
496 .remove = __exit_p(vi_remove),
498 .owner = THIS_MODULE,
501 .pm = &nvhost_module_pm_ops,
504 .of_match_table = tegra_vi_of_match,
509 static struct of_device_id tegra_vi_domain_match[] = {
510 {.compatible = "nvidia,tegra210-ve-pd",
511 .data = (struct nvhost_device_data *)&t21_vi_info},
512 {.compatible = "nvidia,tegra132-ve-pd",
513 .data = (struct nvhost_device_data *)&t124_vi_info},
514 {.compatible = "nvidia,tegra124-ve-pd",
515 .data = (struct nvhost_device_data *)&t124_vi_info},
519 static int __init vi_init(void)
523 ret = nvhost_domain_init(tegra_vi_domain_match);
527 return platform_driver_register(&vi_driver);
530 static void __exit vi_exit(void)
532 platform_driver_unregister(&vi_driver);
535 late_initcall(vi_init);
536 module_exit(vi_exit);
537 MODULE_LICENSE("GPL v2");