.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2013 NVIDIA Corporation |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License version 2 as |
---|
6 | | - * published by the Free Software Foundation. |
---|
7 | 4 | */ |
---|
8 | 5 | |
---|
9 | 6 | #include <linux/clk.h> |
---|
10 | 7 | #include <linux/debugfs.h> |
---|
| 8 | +#include <linux/delay.h> |
---|
11 | 9 | #include <linux/host1x.h> |
---|
12 | 10 | #include <linux/module.h> |
---|
13 | 11 | #include <linux/of.h> |
---|
14 | 12 | #include <linux/of_platform.h> |
---|
15 | 13 | #include <linux/platform_device.h> |
---|
16 | 14 | #include <linux/pm_runtime.h> |
---|
| 15 | +#include <linux/regulator/consumer.h> |
---|
17 | 16 | #include <linux/reset.h> |
---|
18 | 17 | |
---|
19 | | -#include <linux/regulator/consumer.h> |
---|
| 18 | +#include <video/mipi_display.h> |
---|
20 | 19 | |
---|
21 | 20 | #include <drm/drm_atomic_helper.h> |
---|
| 21 | +#include <drm/drm_debugfs.h> |
---|
| 22 | +#include <drm/drm_file.h> |
---|
22 | 23 | #include <drm/drm_mipi_dsi.h> |
---|
23 | 24 | #include <drm/drm_panel.h> |
---|
24 | | - |
---|
25 | | -#include <video/mipi_display.h> |
---|
| 25 | +#include <drm/drm_simple_kms_helper.h> |
---|
26 | 26 | |
---|
27 | 27 | #include "dc.h" |
---|
28 | 28 | #include "drm.h" |
---|
.. | .. |
---|
235 | 235 | struct drm_minor *minor = connector->dev->primary; |
---|
236 | 236 | struct dentry *root = connector->debugfs_entry; |
---|
237 | 237 | struct tegra_dsi *dsi = to_dsi(output); |
---|
238 | | - int err; |
---|
239 | 238 | |
---|
240 | 239 | dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), |
---|
241 | 240 | GFP_KERNEL); |
---|
.. | .. |
---|
245 | 244 | for (i = 0; i < count; i++) |
---|
246 | 245 | dsi->debugfs_files[i].data = dsi; |
---|
247 | 246 | |
---|
248 | | - err = drm_debugfs_create_files(dsi->debugfs_files, count, root, minor); |
---|
249 | | - if (err < 0) |
---|
250 | | - goto free; |
---|
| 247 | + drm_debugfs_create_files(dsi->debugfs_files, count, root, minor); |
---|
251 | 248 | |
---|
252 | 249 | return 0; |
---|
253 | | - |
---|
254 | | -free: |
---|
255 | | - kfree(dsi->debugfs_files); |
---|
256 | | - dsi->debugfs_files = NULL; |
---|
257 | | - |
---|
258 | | - return err; |
---|
259 | 250 | } |
---|
260 | 251 | |
---|
261 | 252 | static void tegra_dsi_early_unregister(struct drm_connector *connector) |
---|
.. | .. |
---|
679 | 670 | static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi) |
---|
680 | 671 | { |
---|
681 | 672 | u32 value; |
---|
| 673 | + int err; |
---|
682 | 674 | |
---|
683 | 675 | /* |
---|
684 | 676 | * XXX Is this still needed? The module reset is deasserted right |
---|
.. | .. |
---|
702 | 694 | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3); |
---|
703 | 695 | tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3); |
---|
704 | 696 | |
---|
705 | | - return tegra_mipi_calibrate(dsi->mipi); |
---|
| 697 | + err = tegra_mipi_start_calibration(dsi->mipi); |
---|
| 698 | + if (err < 0) |
---|
| 699 | + return err; |
---|
| 700 | + |
---|
| 701 | + return tegra_mipi_finish_calibration(dsi->mipi); |
---|
706 | 702 | } |
---|
707 | 703 | |
---|
708 | 704 | static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk, |
---|
.. | .. |
---|
825 | 821 | .mode_valid = tegra_dsi_connector_mode_valid, |
---|
826 | 822 | }; |
---|
827 | 823 | |
---|
828 | | -static const struct drm_encoder_funcs tegra_dsi_encoder_funcs = { |
---|
829 | | - .destroy = tegra_output_encoder_destroy, |
---|
830 | | -}; |
---|
831 | | - |
---|
832 | 824 | static void tegra_dsi_unprepare(struct tegra_dsi *dsi) |
---|
833 | 825 | { |
---|
834 | 826 | int err; |
---|
.. | .. |
---|
841 | 833 | dev_err(dsi->dev, "failed to disable MIPI calibration: %d\n", |
---|
842 | 834 | err); |
---|
843 | 835 | |
---|
844 | | - pm_runtime_put(dsi->dev); |
---|
| 836 | + err = host1x_client_suspend(&dsi->client); |
---|
| 837 | + if (err < 0) |
---|
| 838 | + dev_err(dsi->dev, "failed to suspend: %d\n", err); |
---|
845 | 839 | } |
---|
846 | 840 | |
---|
847 | 841 | static void tegra_dsi_encoder_disable(struct drm_encoder *encoder) |
---|
.. | .. |
---|
883 | 877 | tegra_dsi_unprepare(dsi); |
---|
884 | 878 | } |
---|
885 | 879 | |
---|
886 | | -static void tegra_dsi_prepare(struct tegra_dsi *dsi) |
---|
| 880 | +static int tegra_dsi_prepare(struct tegra_dsi *dsi) |
---|
887 | 881 | { |
---|
888 | 882 | int err; |
---|
889 | 883 | |
---|
890 | | - pm_runtime_get_sync(dsi->dev); |
---|
| 884 | + err = host1x_client_resume(&dsi->client); |
---|
| 885 | + if (err < 0) { |
---|
| 886 | + dev_err(dsi->dev, "failed to resume: %d\n", err); |
---|
| 887 | + return err; |
---|
| 888 | + } |
---|
891 | 889 | |
---|
892 | 890 | err = tegra_mipi_enable(dsi->mipi); |
---|
893 | 891 | if (err < 0) |
---|
.. | .. |
---|
900 | 898 | |
---|
901 | 899 | if (dsi->slave) |
---|
902 | 900 | tegra_dsi_prepare(dsi->slave); |
---|
| 901 | + |
---|
| 902 | + return 0; |
---|
903 | 903 | } |
---|
904 | 904 | |
---|
905 | 905 | static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) |
---|
.. | .. |
---|
910 | 910 | struct tegra_dsi *dsi = to_dsi(output); |
---|
911 | 911 | struct tegra_dsi_state *state; |
---|
912 | 912 | u32 value; |
---|
| 913 | + int err; |
---|
913 | 914 | |
---|
914 | | - tegra_dsi_prepare(dsi); |
---|
| 915 | + err = tegra_dsi_prepare(dsi); |
---|
| 916 | + if (err < 0) { |
---|
| 917 | + dev_err(dsi->dev, "failed to prepare: %d\n", err); |
---|
| 918 | + return; |
---|
| 919 | + } |
---|
915 | 920 | |
---|
916 | 921 | state = tegra_dsi_get_state(dsi); |
---|
917 | 922 | |
---|
.. | .. |
---|
1031 | 1036 | |
---|
1032 | 1037 | static int tegra_dsi_init(struct host1x_client *client) |
---|
1033 | 1038 | { |
---|
1034 | | - struct drm_device *drm = dev_get_drvdata(client->parent); |
---|
| 1039 | + struct drm_device *drm = dev_get_drvdata(client->host); |
---|
1035 | 1040 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); |
---|
1036 | 1041 | int err; |
---|
1037 | 1042 | |
---|
.. | .. |
---|
1046 | 1051 | &tegra_dsi_connector_helper_funcs); |
---|
1047 | 1052 | dsi->output.connector.dpms = DRM_MODE_DPMS_OFF; |
---|
1048 | 1053 | |
---|
1049 | | - drm_encoder_init(drm, &dsi->output.encoder, |
---|
1050 | | - &tegra_dsi_encoder_funcs, |
---|
1051 | | - DRM_MODE_ENCODER_DSI, NULL); |
---|
| 1054 | + drm_simple_encoder_init(drm, &dsi->output.encoder, |
---|
| 1055 | + DRM_MODE_ENCODER_DSI); |
---|
1052 | 1056 | drm_encoder_helper_add(&dsi->output.encoder, |
---|
1053 | 1057 | &tegra_dsi_encoder_helper_funcs); |
---|
1054 | 1058 | |
---|
.. | .. |
---|
1076 | 1080 | return 0; |
---|
1077 | 1081 | } |
---|
1078 | 1082 | |
---|
| 1083 | +static int tegra_dsi_runtime_suspend(struct host1x_client *client) |
---|
| 1084 | +{ |
---|
| 1085 | + struct tegra_dsi *dsi = host1x_client_to_dsi(client); |
---|
| 1086 | + struct device *dev = client->dev; |
---|
| 1087 | + int err; |
---|
| 1088 | + |
---|
| 1089 | + if (dsi->rst) { |
---|
| 1090 | + err = reset_control_assert(dsi->rst); |
---|
| 1091 | + if (err < 0) { |
---|
| 1092 | + dev_err(dev, "failed to assert reset: %d\n", err); |
---|
| 1093 | + return err; |
---|
| 1094 | + } |
---|
| 1095 | + } |
---|
| 1096 | + |
---|
| 1097 | + usleep_range(1000, 2000); |
---|
| 1098 | + |
---|
| 1099 | + clk_disable_unprepare(dsi->clk_lp); |
---|
| 1100 | + clk_disable_unprepare(dsi->clk); |
---|
| 1101 | + |
---|
| 1102 | + regulator_disable(dsi->vdd); |
---|
| 1103 | + pm_runtime_put_sync(dev); |
---|
| 1104 | + |
---|
| 1105 | + return 0; |
---|
| 1106 | +} |
---|
| 1107 | + |
---|
| 1108 | +static int tegra_dsi_runtime_resume(struct host1x_client *client) |
---|
| 1109 | +{ |
---|
| 1110 | + struct tegra_dsi *dsi = host1x_client_to_dsi(client); |
---|
| 1111 | + struct device *dev = client->dev; |
---|
| 1112 | + int err; |
---|
| 1113 | + |
---|
| 1114 | + err = pm_runtime_resume_and_get(dev); |
---|
| 1115 | + if (err < 0) { |
---|
| 1116 | + dev_err(dev, "failed to get runtime PM: %d\n", err); |
---|
| 1117 | + return err; |
---|
| 1118 | + } |
---|
| 1119 | + |
---|
| 1120 | + err = regulator_enable(dsi->vdd); |
---|
| 1121 | + if (err < 0) { |
---|
| 1122 | + dev_err(dev, "failed to enable VDD supply: %d\n", err); |
---|
| 1123 | + goto put_rpm; |
---|
| 1124 | + } |
---|
| 1125 | + |
---|
| 1126 | + err = clk_prepare_enable(dsi->clk); |
---|
| 1127 | + if (err < 0) { |
---|
| 1128 | + dev_err(dev, "cannot enable DSI clock: %d\n", err); |
---|
| 1129 | + goto disable_vdd; |
---|
| 1130 | + } |
---|
| 1131 | + |
---|
| 1132 | + err = clk_prepare_enable(dsi->clk_lp); |
---|
| 1133 | + if (err < 0) { |
---|
| 1134 | + dev_err(dev, "cannot enable low-power clock: %d\n", err); |
---|
| 1135 | + goto disable_clk; |
---|
| 1136 | + } |
---|
| 1137 | + |
---|
| 1138 | + usleep_range(1000, 2000); |
---|
| 1139 | + |
---|
| 1140 | + if (dsi->rst) { |
---|
| 1141 | + err = reset_control_deassert(dsi->rst); |
---|
| 1142 | + if (err < 0) { |
---|
| 1143 | + dev_err(dev, "cannot assert reset: %d\n", err); |
---|
| 1144 | + goto disable_clk_lp; |
---|
| 1145 | + } |
---|
| 1146 | + } |
---|
| 1147 | + |
---|
| 1148 | + return 0; |
---|
| 1149 | + |
---|
| 1150 | +disable_clk_lp: |
---|
| 1151 | + clk_disable_unprepare(dsi->clk_lp); |
---|
| 1152 | +disable_clk: |
---|
| 1153 | + clk_disable_unprepare(dsi->clk); |
---|
| 1154 | +disable_vdd: |
---|
| 1155 | + regulator_disable(dsi->vdd); |
---|
| 1156 | +put_rpm: |
---|
| 1157 | + pm_runtime_put_sync(dev); |
---|
| 1158 | + return err; |
---|
| 1159 | +} |
---|
| 1160 | + |
---|
1079 | 1161 | static const struct host1x_client_ops dsi_client_ops = { |
---|
1080 | 1162 | .init = tegra_dsi_init, |
---|
1081 | 1163 | .exit = tegra_dsi_exit, |
---|
| 1164 | + .suspend = tegra_dsi_runtime_suspend, |
---|
| 1165 | + .resume = tegra_dsi_runtime_resume, |
---|
1082 | 1166 | }; |
---|
1083 | 1167 | |
---|
1084 | 1168 | static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) |
---|
.. | .. |
---|
1414 | 1498 | if (IS_ERR(output->panel)) |
---|
1415 | 1499 | output->panel = NULL; |
---|
1416 | 1500 | |
---|
1417 | | - if (output->panel && output->connector.dev) { |
---|
1418 | | - drm_panel_attach(output->panel, &output->connector); |
---|
| 1501 | + if (output->panel && output->connector.dev) |
---|
1419 | 1502 | drm_helper_hpd_irq_event(output->connector.dev); |
---|
1420 | | - } |
---|
1421 | 1503 | } |
---|
1422 | 1504 | |
---|
1423 | 1505 | return 0; |
---|
.. | .. |
---|
1456 | 1538 | dsi->slave = platform_get_drvdata(gangster); |
---|
1457 | 1539 | of_node_put(np); |
---|
1458 | 1540 | |
---|
1459 | | - if (!dsi->slave) |
---|
| 1541 | + if (!dsi->slave) { |
---|
| 1542 | + put_device(&gangster->dev); |
---|
1460 | 1543 | return -EPROBE_DEFER; |
---|
| 1544 | + } |
---|
1461 | 1545 | |
---|
1462 | 1546 | dsi->slave->master = dsi; |
---|
1463 | 1547 | } |
---|
.. | .. |
---|
1539 | 1623 | if (IS_ERR(dsi->regs)) |
---|
1540 | 1624 | return PTR_ERR(dsi->regs); |
---|
1541 | 1625 | |
---|
1542 | | - dsi->mipi = tegra_mipi_request(&pdev->dev); |
---|
| 1626 | + dsi->mipi = tegra_mipi_request(&pdev->dev, pdev->dev.of_node); |
---|
1543 | 1627 | if (IS_ERR(dsi->mipi)) |
---|
1544 | 1628 | return PTR_ERR(dsi->mipi); |
---|
1545 | 1629 | |
---|
.. | .. |
---|
1597 | 1681 | return 0; |
---|
1598 | 1682 | } |
---|
1599 | 1683 | |
---|
1600 | | -#ifdef CONFIG_PM |
---|
1601 | | -static int tegra_dsi_suspend(struct device *dev) |
---|
1602 | | -{ |
---|
1603 | | - struct tegra_dsi *dsi = dev_get_drvdata(dev); |
---|
1604 | | - int err; |
---|
1605 | | - |
---|
1606 | | - if (dsi->rst) { |
---|
1607 | | - err = reset_control_assert(dsi->rst); |
---|
1608 | | - if (err < 0) { |
---|
1609 | | - dev_err(dev, "failed to assert reset: %d\n", err); |
---|
1610 | | - return err; |
---|
1611 | | - } |
---|
1612 | | - } |
---|
1613 | | - |
---|
1614 | | - usleep_range(1000, 2000); |
---|
1615 | | - |
---|
1616 | | - clk_disable_unprepare(dsi->clk_lp); |
---|
1617 | | - clk_disable_unprepare(dsi->clk); |
---|
1618 | | - |
---|
1619 | | - regulator_disable(dsi->vdd); |
---|
1620 | | - |
---|
1621 | | - return 0; |
---|
1622 | | -} |
---|
1623 | | - |
---|
1624 | | -static int tegra_dsi_resume(struct device *dev) |
---|
1625 | | -{ |
---|
1626 | | - struct tegra_dsi *dsi = dev_get_drvdata(dev); |
---|
1627 | | - int err; |
---|
1628 | | - |
---|
1629 | | - err = regulator_enable(dsi->vdd); |
---|
1630 | | - if (err < 0) { |
---|
1631 | | - dev_err(dsi->dev, "failed to enable VDD supply: %d\n", err); |
---|
1632 | | - return err; |
---|
1633 | | - } |
---|
1634 | | - |
---|
1635 | | - err = clk_prepare_enable(dsi->clk); |
---|
1636 | | - if (err < 0) { |
---|
1637 | | - dev_err(dev, "cannot enable DSI clock: %d\n", err); |
---|
1638 | | - goto disable_vdd; |
---|
1639 | | - } |
---|
1640 | | - |
---|
1641 | | - err = clk_prepare_enable(dsi->clk_lp); |
---|
1642 | | - if (err < 0) { |
---|
1643 | | - dev_err(dev, "cannot enable low-power clock: %d\n", err); |
---|
1644 | | - goto disable_clk; |
---|
1645 | | - } |
---|
1646 | | - |
---|
1647 | | - usleep_range(1000, 2000); |
---|
1648 | | - |
---|
1649 | | - if (dsi->rst) { |
---|
1650 | | - err = reset_control_deassert(dsi->rst); |
---|
1651 | | - if (err < 0) { |
---|
1652 | | - dev_err(dev, "cannot assert reset: %d\n", err); |
---|
1653 | | - goto disable_clk_lp; |
---|
1654 | | - } |
---|
1655 | | - } |
---|
1656 | | - |
---|
1657 | | - return 0; |
---|
1658 | | - |
---|
1659 | | -disable_clk_lp: |
---|
1660 | | - clk_disable_unprepare(dsi->clk_lp); |
---|
1661 | | -disable_clk: |
---|
1662 | | - clk_disable_unprepare(dsi->clk); |
---|
1663 | | -disable_vdd: |
---|
1664 | | - regulator_disable(dsi->vdd); |
---|
1665 | | - return err; |
---|
1666 | | -} |
---|
1667 | | -#endif |
---|
1668 | | - |
---|
1669 | | -static const struct dev_pm_ops tegra_dsi_pm_ops = { |
---|
1670 | | - SET_RUNTIME_PM_OPS(tegra_dsi_suspend, tegra_dsi_resume, NULL) |
---|
1671 | | -}; |
---|
1672 | | - |
---|
1673 | 1684 | static const struct of_device_id tegra_dsi_of_match[] = { |
---|
1674 | 1685 | { .compatible = "nvidia,tegra210-dsi", }, |
---|
1675 | 1686 | { .compatible = "nvidia,tegra132-dsi", }, |
---|
.. | .. |
---|
1683 | 1694 | .driver = { |
---|
1684 | 1695 | .name = "tegra-dsi", |
---|
1685 | 1696 | .of_match_table = tegra_dsi_of_match, |
---|
1686 | | - .pm = &tegra_dsi_pm_ops, |
---|
1687 | 1697 | }, |
---|
1688 | 1698 | .probe = tegra_dsi_probe, |
---|
1689 | 1699 | .remove = tegra_dsi_remove, |
---|