diff options
28 files changed, 1636 insertions, 702 deletions
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt index a3bd8c050c4e..0fad7ed2ea19 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt | |||
@@ -208,6 +208,7 @@ of the following host1x client modules: | |||
208 | See ../clocks/clock-bindings.txt for details. | 208 | See ../clocks/clock-bindings.txt for details. |
209 | - clock-names: Must include the following entries: | 209 | - clock-names: Must include the following entries: |
210 | - sor: clock input for the SOR hardware | 210 | - sor: clock input for the SOR hardware |
211 | - source: source clock for the SOR clock | ||
211 | - parent: input for the pixel clock | 212 | - parent: input for the pixel clock |
212 | - dp: reference clock for the SOR clock | 213 | - dp: reference clock for the SOR clock |
213 | - safe: safe reference for the SOR clock during power up | 214 | - safe: safe reference for the SOR clock during power up |
@@ -226,9 +227,9 @@ of the following host1x client modules: | |||
226 | - nvidia,dpaux: phandle to a DispayPort AUX interface | 227 | - nvidia,dpaux: phandle to a DispayPort AUX interface |
227 | 228 | ||
228 | - dpaux: DisplayPort AUX interface | 229 | - dpaux: DisplayPort AUX interface |
229 | - compatible: For Tegra124, must contain "nvidia,tegra124-dpaux". Otherwise, | 230 | - compatible : Should contain one of the following: |
230 | must contain '"nvidia,<chip>-dpaux", "nvidia,tegra124-dpaux"', where | 231 | - "nvidia,tegra124-dpaux": for Tegra124 and Tegra132 |
231 | <chip> is tegra132. | 232 | - "nvidia,tegra210-dpaux": for Tegra210 |
232 | - reg: Physical base address and length of the controller's registers. | 233 | - reg: Physical base address and length of the controller's registers. |
233 | - interrupts: The interrupt outputs from the controller. | 234 | - interrupts: The interrupt outputs from the controller. |
234 | - clocks: Must contain an entry for each entry in clock-names. | 235 | - clocks: Must contain an entry for each entry in clock-names. |
@@ -241,6 +242,12 @@ of the following host1x client modules: | |||
241 | - reset-names: Must include the following entries: | 242 | - reset-names: Must include the following entries: |
242 | - dpaux | 243 | - dpaux |
243 | - vdd-supply: phandle of a supply that powers the DisplayPort link | 244 | - vdd-supply: phandle of a supply that powers the DisplayPort link |
245 | - i2c-bus: Subnode where I2C slave devices are listed. This subnode | ||
246 | must be always present. If there are no I2C slave devices, an empty | ||
247 | node should be added. See ../../i2c/i2c.txt for more information. | ||
248 | |||
249 | See ../pinctrl/nvidia,tegra124-dpaux-padctl.txt for information | ||
250 | regarding the DPAUX pad controller bindings. | ||
244 | 251 | ||
245 | Example: | 252 | Example: |
246 | 253 | ||
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt new file mode 100644 index 000000000000..f2abdaee9022 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt | |||
@@ -0,0 +1,60 @@ | |||
1 | Device tree binding for NVIDIA Tegra DPAUX pad controller | ||
2 | ======================================================== | ||
3 | |||
4 | The Tegra Display Port Auxiliary (DPAUX) pad controller manages two pins | ||
5 | which can be assigned to either the DPAUX channel or to an I2C | ||
6 | controller. | ||
7 | |||
8 | This document defines the device-specific binding for the DPAUX pad | ||
9 | controller. Refer to pinctrl-bindings.txt in this directory for generic | ||
10 | information about pin controller device tree bindings. Please refer to | ||
11 | the binding document ../display/tegra/nvidia,tegra20-host1x.txt for more | ||
12 | details on the DPAUX binding. | ||
13 | |||
14 | Pin muxing: | ||
15 | ----------- | ||
16 | |||
17 | Child nodes contain the pinmux configurations following the conventions | ||
18 | from the pinctrl-bindings.txt document. | ||
19 | |||
20 | Since only three configurations are possible, only three child nodes are | ||
21 | needed to describe the pin mux'ing options for the DPAUX pads. | ||
22 | Furthermore, given that the pad functions are only applicable to a | ||
23 | single set of pads, the child nodes only need to describe the pad group | ||
24 | the functions are being applied to rather than the individual pads. | ||
25 | |||
26 | Required properties: | ||
27 | - groups: Must be "dpaux-io" | ||
28 | - function: Must be either "aux", "i2c" or "off". | ||
29 | |||
30 | Example: | ||
31 | -------- | ||
32 | |||
33 | dpaux@545c0000 { | ||
34 | ... | ||
35 | |||
36 | state_dpaux_aux: pinmux-aux { | ||
37 | groups = "dpaux-io"; | ||
38 | function = "aux"; | ||
39 | }; | ||
40 | |||
41 | state_dpaux_i2c: pinmux-i2c { | ||
42 | groups = "dpaux-io"; | ||
43 | function = "i2c"; | ||
44 | }; | ||
45 | |||
46 | state_dpaux_off: pinmux-off { | ||
47 | groups = "dpaux-io"; | ||
48 | function = "off"; | ||
49 | }; | ||
50 | }; | ||
51 | |||
52 | ... | ||
53 | |||
54 | i2c@7000d100 { | ||
55 | ... | ||
56 | pinctrl-0 = <&state_dpaux_i2c>; | ||
57 | pinctrl-1 = <&state_dpaux_off>; | ||
58 | pinctrl-names = "default", "idle"; | ||
59 | status = "disabled"; | ||
60 | }; | ||
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 39940f5b7c91..8495bd01b544 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
11 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
12 | #include <linux/iommu.h> | 12 | #include <linux/iommu.h> |
13 | #include <linux/pm_runtime.h> | ||
13 | #include <linux/reset.h> | 14 | #include <linux/reset.h> |
14 | 15 | ||
15 | #include <soc/tegra/pmc.h> | 16 | #include <soc/tegra/pmc.h> |
@@ -1216,6 +1217,8 @@ static void tegra_crtc_disable(struct drm_crtc *crtc) | |||
1216 | 1217 | ||
1217 | tegra_dc_stats_reset(&dc->stats); | 1218 | tegra_dc_stats_reset(&dc->stats); |
1218 | drm_crtc_vblank_off(crtc); | 1219 | drm_crtc_vblank_off(crtc); |
1220 | |||
1221 | pm_runtime_put_sync(dc->dev); | ||
1219 | } | 1222 | } |
1220 | 1223 | ||
1221 | static void tegra_crtc_enable(struct drm_crtc *crtc) | 1224 | static void tegra_crtc_enable(struct drm_crtc *crtc) |
@@ -1225,6 +1228,48 @@ static void tegra_crtc_enable(struct drm_crtc *crtc) | |||
1225 | struct tegra_dc *dc = to_tegra_dc(crtc); | 1228 | struct tegra_dc *dc = to_tegra_dc(crtc); |
1226 | u32 value; | 1229 | u32 value; |
1227 | 1230 | ||
1231 | pm_runtime_get_sync(dc->dev); | ||
1232 | |||
1233 | /* initialize display controller */ | ||
1234 | if (dc->syncpt) { | ||
1235 | u32 syncpt = host1x_syncpt_id(dc->syncpt); | ||
1236 | |||
1237 | value = SYNCPT_CNTRL_NO_STALL; | ||
1238 | tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); | ||
1239 | |||
1240 | value = SYNCPT_VSYNC_ENABLE | syncpt; | ||
1241 | tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC); | ||
1242 | } | ||
1243 | |||
1244 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1245 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1246 | tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); | ||
1247 | |||
1248 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1249 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1250 | tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); | ||
1251 | |||
1252 | /* initialize timer */ | ||
1253 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | | ||
1254 | WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); | ||
1255 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY); | ||
1256 | |||
1257 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) | | ||
1258 | WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1); | ||
1259 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
1260 | |||
1261 | value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1262 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1263 | tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); | ||
1264 | |||
1265 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1266 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1267 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
1268 | |||
1269 | if (dc->soc->supports_border_color) | ||
1270 | tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR); | ||
1271 | |||
1272 | /* apply PLL and pixel clock changes */ | ||
1228 | tegra_dc_commit_state(dc, state); | 1273 | tegra_dc_commit_state(dc, state); |
1229 | 1274 | ||
1230 | /* program display mode */ | 1275 | /* program display mode */ |
@@ -1685,7 +1730,6 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1685 | struct tegra_drm *tegra = drm->dev_private; | 1730 | struct tegra_drm *tegra = drm->dev_private; |
1686 | struct drm_plane *primary = NULL; | 1731 | struct drm_plane *primary = NULL; |
1687 | struct drm_plane *cursor = NULL; | 1732 | struct drm_plane *cursor = NULL; |
1688 | u32 value; | ||
1689 | int err; | 1733 | int err; |
1690 | 1734 | ||
1691 | dc->syncpt = host1x_syncpt_request(dc->dev, flags); | 1735 | dc->syncpt = host1x_syncpt_request(dc->dev, flags); |
@@ -1755,47 +1799,6 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1755 | goto cleanup; | 1799 | goto cleanup; |
1756 | } | 1800 | } |
1757 | 1801 | ||
1758 | /* initialize display controller */ | ||
1759 | if (dc->syncpt) { | ||
1760 | u32 syncpt = host1x_syncpt_id(dc->syncpt); | ||
1761 | |||
1762 | value = SYNCPT_CNTRL_NO_STALL; | ||
1763 | tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); | ||
1764 | |||
1765 | value = SYNCPT_VSYNC_ENABLE | syncpt; | ||
1766 | tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC); | ||
1767 | } | ||
1768 | |||
1769 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1770 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1771 | tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); | ||
1772 | |||
1773 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1774 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1775 | tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); | ||
1776 | |||
1777 | /* initialize timer */ | ||
1778 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | | ||
1779 | WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); | ||
1780 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY); | ||
1781 | |||
1782 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) | | ||
1783 | WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1); | ||
1784 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
1785 | |||
1786 | value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1787 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1788 | tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); | ||
1789 | |||
1790 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1791 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1792 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
1793 | |||
1794 | if (dc->soc->supports_border_color) | ||
1795 | tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR); | ||
1796 | |||
1797 | tegra_dc_stats_reset(&dc->stats); | ||
1798 | |||
1799 | return 0; | 1802 | return 0; |
1800 | 1803 | ||
1801 | cleanup: | 1804 | cleanup: |
@@ -1987,33 +1990,15 @@ static int tegra_dc_probe(struct platform_device *pdev) | |||
1987 | return PTR_ERR(dc->rst); | 1990 | return PTR_ERR(dc->rst); |
1988 | } | 1991 | } |
1989 | 1992 | ||
1993 | reset_control_assert(dc->rst); | ||
1994 | |||
1990 | if (dc->soc->has_powergate) { | 1995 | if (dc->soc->has_powergate) { |
1991 | if (dc->pipe == 0) | 1996 | if (dc->pipe == 0) |
1992 | dc->powergate = TEGRA_POWERGATE_DIS; | 1997 | dc->powergate = TEGRA_POWERGATE_DIS; |
1993 | else | 1998 | else |
1994 | dc->powergate = TEGRA_POWERGATE_DISB; | 1999 | dc->powergate = TEGRA_POWERGATE_DISB; |
1995 | 2000 | ||
1996 | err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, | 2001 | tegra_powergate_power_off(dc->powergate); |
1997 | dc->rst); | ||
1998 | if (err < 0) { | ||
1999 | dev_err(&pdev->dev, "failed to power partition: %d\n", | ||
2000 | err); | ||
2001 | return err; | ||
2002 | } | ||
2003 | } else { | ||
2004 | err = clk_prepare_enable(dc->clk); | ||
2005 | if (err < 0) { | ||
2006 | dev_err(&pdev->dev, "failed to enable clock: %d\n", | ||
2007 | err); | ||
2008 | return err; | ||
2009 | } | ||
2010 | |||
2011 | err = reset_control_deassert(dc->rst); | ||
2012 | if (err < 0) { | ||
2013 | dev_err(&pdev->dev, "failed to deassert reset: %d\n", | ||
2014 | err); | ||
2015 | return err; | ||
2016 | } | ||
2017 | } | 2002 | } |
2018 | 2003 | ||
2019 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2004 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -2027,16 +2012,19 @@ static int tegra_dc_probe(struct platform_device *pdev) | |||
2027 | return -ENXIO; | 2012 | return -ENXIO; |
2028 | } | 2013 | } |
2029 | 2014 | ||
2030 | INIT_LIST_HEAD(&dc->client.list); | ||
2031 | dc->client.ops = &dc_client_ops; | ||
2032 | dc->client.dev = &pdev->dev; | ||
2033 | |||
2034 | err = tegra_dc_rgb_probe(dc); | 2015 | err = tegra_dc_rgb_probe(dc); |
2035 | if (err < 0 && err != -ENODEV) { | 2016 | if (err < 0 && err != -ENODEV) { |
2036 | dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err); | 2017 | dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err); |
2037 | return err; | 2018 | return err; |
2038 | } | 2019 | } |
2039 | 2020 | ||
2021 | platform_set_drvdata(pdev, dc); | ||
2022 | pm_runtime_enable(&pdev->dev); | ||
2023 | |||
2024 | INIT_LIST_HEAD(&dc->client.list); | ||
2025 | dc->client.ops = &dc_client_ops; | ||
2026 | dc->client.dev = &pdev->dev; | ||
2027 | |||
2040 | err = host1x_client_register(&dc->client); | 2028 | err = host1x_client_register(&dc->client); |
2041 | if (err < 0) { | 2029 | if (err < 0) { |
2042 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", | 2030 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", |
@@ -2044,8 +2032,6 @@ static int tegra_dc_probe(struct platform_device *pdev) | |||
2044 | return err; | 2032 | return err; |
2045 | } | 2033 | } |
2046 | 2034 | ||
2047 | platform_set_drvdata(pdev, dc); | ||
2048 | |||
2049 | return 0; | 2035 | return 0; |
2050 | } | 2036 | } |
2051 | 2037 | ||
@@ -2067,7 +2053,22 @@ static int tegra_dc_remove(struct platform_device *pdev) | |||
2067 | return err; | 2053 | return err; |
2068 | } | 2054 | } |
2069 | 2055 | ||
2070 | reset_control_assert(dc->rst); | 2056 | pm_runtime_disable(&pdev->dev); |
2057 | |||
2058 | return 0; | ||
2059 | } | ||
2060 | |||
2061 | #ifdef CONFIG_PM | ||
2062 | static int tegra_dc_suspend(struct device *dev) | ||
2063 | { | ||
2064 | struct tegra_dc *dc = dev_get_drvdata(dev); | ||
2065 | int err; | ||
2066 | |||
2067 | err = reset_control_assert(dc->rst); | ||
2068 | if (err < 0) { | ||
2069 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
2070 | return err; | ||
2071 | } | ||
2071 | 2072 | ||
2072 | if (dc->soc->has_powergate) | 2073 | if (dc->soc->has_powergate) |
2073 | tegra_powergate_power_off(dc->powergate); | 2074 | tegra_powergate_power_off(dc->powergate); |
@@ -2077,10 +2078,45 @@ static int tegra_dc_remove(struct platform_device *pdev) | |||
2077 | return 0; | 2078 | return 0; |
2078 | } | 2079 | } |
2079 | 2080 | ||
2081 | static int tegra_dc_resume(struct device *dev) | ||
2082 | { | ||
2083 | struct tegra_dc *dc = dev_get_drvdata(dev); | ||
2084 | int err; | ||
2085 | |||
2086 | if (dc->soc->has_powergate) { | ||
2087 | err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, | ||
2088 | dc->rst); | ||
2089 | if (err < 0) { | ||
2090 | dev_err(dev, "failed to power partition: %d\n", err); | ||
2091 | return err; | ||
2092 | } | ||
2093 | } else { | ||
2094 | err = clk_prepare_enable(dc->clk); | ||
2095 | if (err < 0) { | ||
2096 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
2097 | return err; | ||
2098 | } | ||
2099 | |||
2100 | err = reset_control_deassert(dc->rst); | ||
2101 | if (err < 0) { | ||
2102 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
2103 | return err; | ||
2104 | } | ||
2105 | } | ||
2106 | |||
2107 | return 0; | ||
2108 | } | ||
2109 | #endif | ||
2110 | |||
2111 | static const struct dev_pm_ops tegra_dc_pm_ops = { | ||
2112 | SET_RUNTIME_PM_OPS(tegra_dc_suspend, tegra_dc_resume, NULL) | ||
2113 | }; | ||
2114 | |||
2080 | struct platform_driver tegra_dc_driver = { | 2115 | struct platform_driver tegra_dc_driver = { |
2081 | .driver = { | 2116 | .driver = { |
2082 | .name = "tegra-dc", | 2117 | .name = "tegra-dc", |
2083 | .of_match_table = tegra_dc_of_match, | 2118 | .of_match_table = tegra_dc_of_match, |
2119 | .pm = &tegra_dc_pm_ops, | ||
2084 | }, | 2120 | }, |
2085 | .probe = tegra_dc_probe, | 2121 | .probe = tegra_dc_probe, |
2086 | .remove = tegra_dc_remove, | 2122 | .remove = tegra_dc_remove, |
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index b24a0f14821a..059f409556d5 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c | |||
@@ -12,6 +12,9 @@ | |||
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/io.h> | 13 | #include <linux/io.h> |
14 | #include <linux/of_gpio.h> | 14 | #include <linux/of_gpio.h> |
15 | #include <linux/pinctrl/pinconf-generic.h> | ||
16 | #include <linux/pinctrl/pinctrl.h> | ||
17 | #include <linux/pinctrl/pinmux.h> | ||
15 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
16 | #include <linux/reset.h> | 19 | #include <linux/reset.h> |
17 | #include <linux/regulator/consumer.h> | 20 | #include <linux/regulator/consumer.h> |
@@ -44,6 +47,11 @@ struct tegra_dpaux { | |||
44 | struct completion complete; | 47 | struct completion complete; |
45 | struct work_struct work; | 48 | struct work_struct work; |
46 | struct list_head list; | 49 | struct list_head list; |
50 | |||
51 | #ifdef CONFIG_GENERIC_PINCONF | ||
52 | struct pinctrl_dev *pinctrl; | ||
53 | struct pinctrl_desc desc; | ||
54 | #endif | ||
47 | }; | 55 | }; |
48 | 56 | ||
49 | static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux) | 57 | static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux) |
@@ -267,6 +275,148 @@ static irqreturn_t tegra_dpaux_irq(int irq, void *data) | |||
267 | return ret; | 275 | return ret; |
268 | } | 276 | } |
269 | 277 | ||
278 | enum tegra_dpaux_functions { | ||
279 | DPAUX_PADCTL_FUNC_AUX, | ||
280 | DPAUX_PADCTL_FUNC_I2C, | ||
281 | DPAUX_PADCTL_FUNC_OFF, | ||
282 | }; | ||
283 | |||
284 | static void tegra_dpaux_pad_power_down(struct tegra_dpaux *dpaux) | ||
285 | { | ||
286 | u32 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); | ||
287 | |||
288 | value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; | ||
289 | |||
290 | tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); | ||
291 | } | ||
292 | |||
293 | static void tegra_dpaux_pad_power_up(struct tegra_dpaux *dpaux) | ||
294 | { | ||
295 | u32 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); | ||
296 | |||
297 | value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; | ||
298 | |||
299 | tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); | ||
300 | } | ||
301 | |||
302 | static int tegra_dpaux_pad_config(struct tegra_dpaux *dpaux, unsigned function) | ||
303 | { | ||
304 | u32 value; | ||
305 | |||
306 | switch (function) { | ||
307 | case DPAUX_PADCTL_FUNC_AUX: | ||
308 | value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) | | ||
309 | DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) | | ||
310 | DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) | | ||
311 | DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV | | ||
312 | DPAUX_HYBRID_PADCTL_MODE_AUX; | ||
313 | break; | ||
314 | |||
315 | case DPAUX_PADCTL_FUNC_I2C: | ||
316 | value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV | | ||
317 | DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV | | ||
318 | DPAUX_HYBRID_PADCTL_MODE_I2C; | ||
319 | break; | ||
320 | |||
321 | case DPAUX_PADCTL_FUNC_OFF: | ||
322 | tegra_dpaux_pad_power_down(dpaux); | ||
323 | return 0; | ||
324 | |||
325 | default: | ||
326 | return -ENOTSUPP; | ||
327 | } | ||
328 | |||
329 | tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL); | ||
330 | tegra_dpaux_pad_power_up(dpaux); | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | #ifdef CONFIG_GENERIC_PINCONF | ||
336 | static const struct pinctrl_pin_desc tegra_dpaux_pins[] = { | ||
337 | PINCTRL_PIN(0, "DP_AUX_CHx_P"), | ||
338 | PINCTRL_PIN(1, "DP_AUX_CHx_N"), | ||
339 | }; | ||
340 | |||
341 | static const unsigned tegra_dpaux_pin_numbers[] = { 0, 1 }; | ||
342 | |||
343 | static const char * const tegra_dpaux_groups[] = { | ||
344 | "dpaux-io", | ||
345 | }; | ||
346 | |||
347 | static const char * const tegra_dpaux_functions[] = { | ||
348 | "aux", | ||
349 | "i2c", | ||
350 | "off", | ||
351 | }; | ||
352 | |||
353 | static int tegra_dpaux_get_groups_count(struct pinctrl_dev *pinctrl) | ||
354 | { | ||
355 | return ARRAY_SIZE(tegra_dpaux_groups); | ||
356 | } | ||
357 | |||
358 | static const char *tegra_dpaux_get_group_name(struct pinctrl_dev *pinctrl, | ||
359 | unsigned int group) | ||
360 | { | ||
361 | return tegra_dpaux_groups[group]; | ||
362 | } | ||
363 | |||
364 | static int tegra_dpaux_get_group_pins(struct pinctrl_dev *pinctrl, | ||
365 | unsigned group, const unsigned **pins, | ||
366 | unsigned *num_pins) | ||
367 | { | ||
368 | *pins = tegra_dpaux_pin_numbers; | ||
369 | *num_pins = ARRAY_SIZE(tegra_dpaux_pin_numbers); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static const struct pinctrl_ops tegra_dpaux_pinctrl_ops = { | ||
375 | .get_groups_count = tegra_dpaux_get_groups_count, | ||
376 | .get_group_name = tegra_dpaux_get_group_name, | ||
377 | .get_group_pins = tegra_dpaux_get_group_pins, | ||
378 | .dt_node_to_map = pinconf_generic_dt_node_to_map_group, | ||
379 | .dt_free_map = pinconf_generic_dt_free_map, | ||
380 | }; | ||
381 | |||
382 | static int tegra_dpaux_get_functions_count(struct pinctrl_dev *pinctrl) | ||
383 | { | ||
384 | return ARRAY_SIZE(tegra_dpaux_functions); | ||
385 | } | ||
386 | |||
387 | static const char *tegra_dpaux_get_function_name(struct pinctrl_dev *pinctrl, | ||
388 | unsigned int function) | ||
389 | { | ||
390 | return tegra_dpaux_functions[function]; | ||
391 | } | ||
392 | |||
393 | static int tegra_dpaux_get_function_groups(struct pinctrl_dev *pinctrl, | ||
394 | unsigned int function, | ||
395 | const char * const **groups, | ||
396 | unsigned * const num_groups) | ||
397 | { | ||
398 | *num_groups = ARRAY_SIZE(tegra_dpaux_groups); | ||
399 | *groups = tegra_dpaux_groups; | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int tegra_dpaux_set_mux(struct pinctrl_dev *pinctrl, | ||
405 | unsigned int function, unsigned int group) | ||
406 | { | ||
407 | struct tegra_dpaux *dpaux = pinctrl_dev_get_drvdata(pinctrl); | ||
408 | |||
409 | return tegra_dpaux_pad_config(dpaux, function); | ||
410 | } | ||
411 | |||
412 | static const struct pinmux_ops tegra_dpaux_pinmux_ops = { | ||
413 | .get_functions_count = tegra_dpaux_get_functions_count, | ||
414 | .get_function_name = tegra_dpaux_get_function_name, | ||
415 | .get_function_groups = tegra_dpaux_get_function_groups, | ||
416 | .set_mux = tegra_dpaux_set_mux, | ||
417 | }; | ||
418 | #endif | ||
419 | |||
270 | static int tegra_dpaux_probe(struct platform_device *pdev) | 420 | static int tegra_dpaux_probe(struct platform_device *pdev) |
271 | { | 421 | { |
272 | struct tegra_dpaux *dpaux; | 422 | struct tegra_dpaux *dpaux; |
@@ -294,11 +444,14 @@ static int tegra_dpaux_probe(struct platform_device *pdev) | |||
294 | return -ENXIO; | 444 | return -ENXIO; |
295 | } | 445 | } |
296 | 446 | ||
297 | dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux"); | 447 | if (!pdev->dev.pm_domain) { |
298 | if (IS_ERR(dpaux->rst)) { | 448 | dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux"); |
299 | dev_err(&pdev->dev, "failed to get reset control: %ld\n", | 449 | if (IS_ERR(dpaux->rst)) { |
300 | PTR_ERR(dpaux->rst)); | 450 | dev_err(&pdev->dev, |
301 | return PTR_ERR(dpaux->rst); | 451 | "failed to get reset control: %ld\n", |
452 | PTR_ERR(dpaux->rst)); | ||
453 | return PTR_ERR(dpaux->rst); | ||
454 | } | ||
302 | } | 455 | } |
303 | 456 | ||
304 | dpaux->clk = devm_clk_get(&pdev->dev, NULL); | 457 | dpaux->clk = devm_clk_get(&pdev->dev, NULL); |
@@ -315,34 +468,37 @@ static int tegra_dpaux_probe(struct platform_device *pdev) | |||
315 | return err; | 468 | return err; |
316 | } | 469 | } |
317 | 470 | ||
318 | reset_control_deassert(dpaux->rst); | 471 | if (dpaux->rst) |
472 | reset_control_deassert(dpaux->rst); | ||
319 | 473 | ||
320 | dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent"); | 474 | dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent"); |
321 | if (IS_ERR(dpaux->clk_parent)) { | 475 | if (IS_ERR(dpaux->clk_parent)) { |
322 | dev_err(&pdev->dev, "failed to get parent clock: %ld\n", | 476 | dev_err(&pdev->dev, "failed to get parent clock: %ld\n", |
323 | PTR_ERR(dpaux->clk_parent)); | 477 | PTR_ERR(dpaux->clk_parent)); |
324 | return PTR_ERR(dpaux->clk_parent); | 478 | err = PTR_ERR(dpaux->clk_parent); |
479 | goto assert_reset; | ||
325 | } | 480 | } |
326 | 481 | ||
327 | err = clk_prepare_enable(dpaux->clk_parent); | 482 | err = clk_prepare_enable(dpaux->clk_parent); |
328 | if (err < 0) { | 483 | if (err < 0) { |
329 | dev_err(&pdev->dev, "failed to enable parent clock: %d\n", | 484 | dev_err(&pdev->dev, "failed to enable parent clock: %d\n", |
330 | err); | 485 | err); |
331 | return err; | 486 | goto assert_reset; |
332 | } | 487 | } |
333 | 488 | ||
334 | err = clk_set_rate(dpaux->clk_parent, 270000000); | 489 | err = clk_set_rate(dpaux->clk_parent, 270000000); |
335 | if (err < 0) { | 490 | if (err < 0) { |
336 | dev_err(&pdev->dev, "failed to set clock to 270 MHz: %d\n", | 491 | dev_err(&pdev->dev, "failed to set clock to 270 MHz: %d\n", |
337 | err); | 492 | err); |
338 | return err; | 493 | goto disable_parent_clk; |
339 | } | 494 | } |
340 | 495 | ||
341 | dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd"); | 496 | dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd"); |
342 | if (IS_ERR(dpaux->vdd)) { | 497 | if (IS_ERR(dpaux->vdd)) { |
343 | dev_err(&pdev->dev, "failed to get VDD supply: %ld\n", | 498 | dev_err(&pdev->dev, "failed to get VDD supply: %ld\n", |
344 | PTR_ERR(dpaux->vdd)); | 499 | PTR_ERR(dpaux->vdd)); |
345 | return PTR_ERR(dpaux->vdd); | 500 | err = PTR_ERR(dpaux->vdd); |
501 | goto disable_parent_clk; | ||
346 | } | 502 | } |
347 | 503 | ||
348 | err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0, | 504 | err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0, |
@@ -350,7 +506,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) | |||
350 | if (err < 0) { | 506 | if (err < 0) { |
351 | dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n", | 507 | dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n", |
352 | dpaux->irq, err); | 508 | dpaux->irq, err); |
353 | return err; | 509 | goto disable_parent_clk; |
354 | } | 510 | } |
355 | 511 | ||
356 | disable_irq(dpaux->irq); | 512 | disable_irq(dpaux->irq); |
@@ -360,7 +516,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) | |||
360 | 516 | ||
361 | err = drm_dp_aux_register(&dpaux->aux); | 517 | err = drm_dp_aux_register(&dpaux->aux); |
362 | if (err < 0) | 518 | if (err < 0) |
363 | return err; | 519 | goto disable_parent_clk; |
364 | 520 | ||
365 | /* | 521 | /* |
366 | * Assume that by default the DPAUX/I2C pads will be used for HDMI, | 522 | * Assume that by default the DPAUX/I2C pads will be used for HDMI, |
@@ -370,16 +526,24 @@ static int tegra_dpaux_probe(struct platform_device *pdev) | |||
370 | * is no possibility to perform the I2C mode configuration in the | 526 | * is no possibility to perform the I2C mode configuration in the |
371 | * HDMI path. | 527 | * HDMI path. |
372 | */ | 528 | */ |
373 | value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); | 529 | err = tegra_dpaux_pad_config(dpaux, DPAUX_HYBRID_PADCTL_MODE_I2C); |
374 | value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; | 530 | if (err < 0) |
375 | tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); | 531 | return err; |
376 | |||
377 | value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_PADCTL); | ||
378 | value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV | | ||
379 | DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV | | ||
380 | DPAUX_HYBRID_PADCTL_MODE_I2C; | ||
381 | tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL); | ||
382 | 532 | ||
533 | #ifdef CONFIG_GENERIC_PINCONF | ||
534 | dpaux->desc.name = dev_name(&pdev->dev); | ||
535 | dpaux->desc.pins = tegra_dpaux_pins; | ||
536 | dpaux->desc.npins = ARRAY_SIZE(tegra_dpaux_pins); | ||
537 | dpaux->desc.pctlops = &tegra_dpaux_pinctrl_ops; | ||
538 | dpaux->desc.pmxops = &tegra_dpaux_pinmux_ops; | ||
539 | dpaux->desc.owner = THIS_MODULE; | ||
540 | |||
541 | dpaux->pinctrl = devm_pinctrl_register(&pdev->dev, &dpaux->desc, dpaux); | ||
542 | if (!dpaux->pinctrl) { | ||
543 | dev_err(&pdev->dev, "failed to register pincontrol\n"); | ||
544 | return -ENODEV; | ||
545 | } | ||
546 | #endif | ||
383 | /* enable and clear all interrupts */ | 547 | /* enable and clear all interrupts */ |
384 | value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT | | 548 | value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT | |
385 | DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT; | 549 | DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT; |
@@ -393,17 +557,24 @@ static int tegra_dpaux_probe(struct platform_device *pdev) | |||
393 | platform_set_drvdata(pdev, dpaux); | 557 | platform_set_drvdata(pdev, dpaux); |
394 | 558 | ||
395 | return 0; | 559 | return 0; |
560 | |||
561 | disable_parent_clk: | ||
562 | clk_disable_unprepare(dpaux->clk_parent); | ||
563 | assert_reset: | ||
564 | if (dpaux->rst) | ||
565 | reset_control_assert(dpaux->rst); | ||
566 | |||
567 | clk_disable_unprepare(dpaux->clk); | ||
568 | |||
569 | return err; | ||
396 | } | 570 | } |
397 | 571 | ||
398 | static int tegra_dpaux_remove(struct platform_device *pdev) | 572 | static int tegra_dpaux_remove(struct platform_device *pdev) |
399 | { | 573 | { |
400 | struct tegra_dpaux *dpaux = platform_get_drvdata(pdev); | 574 | struct tegra_dpaux *dpaux = platform_get_drvdata(pdev); |
401 | u32 value; | ||
402 | 575 | ||
403 | /* make sure pads are powered down when not in use */ | 576 | /* make sure pads are powered down when not in use */ |
404 | value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); | 577 | tegra_dpaux_pad_power_down(dpaux); |
405 | value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; | ||
406 | tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); | ||
407 | 578 | ||
408 | drm_dp_aux_unregister(&dpaux->aux); | 579 | drm_dp_aux_unregister(&dpaux->aux); |
409 | 580 | ||
@@ -414,7 +585,10 @@ static int tegra_dpaux_remove(struct platform_device *pdev) | |||
414 | cancel_work_sync(&dpaux->work); | 585 | cancel_work_sync(&dpaux->work); |
415 | 586 | ||
416 | clk_disable_unprepare(dpaux->clk_parent); | 587 | clk_disable_unprepare(dpaux->clk_parent); |
417 | reset_control_assert(dpaux->rst); | 588 | |
589 | if (dpaux->rst) | ||
590 | reset_control_assert(dpaux->rst); | ||
591 | |||
418 | clk_disable_unprepare(dpaux->clk); | 592 | clk_disable_unprepare(dpaux->clk); |
419 | 593 | ||
420 | return 0; | 594 | return 0; |
@@ -528,30 +702,15 @@ enum drm_connector_status drm_dp_aux_detect(struct drm_dp_aux *aux) | |||
528 | int drm_dp_aux_enable(struct drm_dp_aux *aux) | 702 | int drm_dp_aux_enable(struct drm_dp_aux *aux) |
529 | { | 703 | { |
530 | struct tegra_dpaux *dpaux = to_dpaux(aux); | 704 | struct tegra_dpaux *dpaux = to_dpaux(aux); |
531 | u32 value; | ||
532 | |||
533 | value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) | | ||
534 | DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) | | ||
535 | DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) | | ||
536 | DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV | | ||
537 | DPAUX_HYBRID_PADCTL_MODE_AUX; | ||
538 | tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL); | ||
539 | |||
540 | value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); | ||
541 | value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; | ||
542 | tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); | ||
543 | 705 | ||
544 | return 0; | 706 | return tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_AUX); |
545 | } | 707 | } |
546 | 708 | ||
547 | int drm_dp_aux_disable(struct drm_dp_aux *aux) | 709 | int drm_dp_aux_disable(struct drm_dp_aux *aux) |
548 | { | 710 | { |
549 | struct tegra_dpaux *dpaux = to_dpaux(aux); | 711 | struct tegra_dpaux *dpaux = to_dpaux(aux); |
550 | u32 value; | ||
551 | 712 | ||
552 | value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); | 713 | tegra_dpaux_pad_power_down(dpaux); |
553 | value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; | ||
554 | tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); | ||
555 | 714 | ||
556 | return 0; | 715 | return 0; |
557 | } | 716 | } |
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index a177a42a9849..755264d9db22 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
@@ -56,8 +56,8 @@ static void tegra_atomic_complete(struct tegra_drm *tegra, | |||
56 | */ | 56 | */ |
57 | 57 | ||
58 | drm_atomic_helper_commit_modeset_disables(drm, state); | 58 | drm_atomic_helper_commit_modeset_disables(drm, state); |
59 | drm_atomic_helper_commit_planes(drm, state, false); | ||
60 | drm_atomic_helper_commit_modeset_enables(drm, state); | 59 | drm_atomic_helper_commit_modeset_enables(drm, state); |
60 | drm_atomic_helper_commit_planes(drm, state, true); | ||
61 | 61 | ||
62 | drm_atomic_helper_wait_for_vblanks(drm, state); | 62 | drm_atomic_helper_wait_for_vblanks(drm, state); |
63 | 63 | ||
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 099cccb2fbcb..3d228ad90e0f 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/of.h> | 13 | #include <linux/of.h> |
14 | #include <linux/of_platform.h> | 14 | #include <linux/of_platform.h> |
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/pm_runtime.h> | ||
16 | #include <linux/reset.h> | 17 | #include <linux/reset.h> |
17 | 18 | ||
18 | #include <linux/regulator/consumer.h> | 19 | #include <linux/regulator/consumer.h> |
@@ -677,6 +678,45 @@ static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi) | |||
677 | tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL); | 678 | tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL); |
678 | } | 679 | } |
679 | 680 | ||
681 | static int tegra_dsi_pad_enable(struct tegra_dsi *dsi) | ||
682 | { | ||
683 | u32 value; | ||
684 | |||
685 | value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0); | ||
686 | tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0); | ||
687 | |||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi) | ||
692 | { | ||
693 | u32 value; | ||
694 | |||
695 | /* | ||
696 | * XXX Is this still needed? The module reset is deasserted right | ||
697 | * before this function is called. | ||
698 | */ | ||
699 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0); | ||
700 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1); | ||
701 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2); | ||
702 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3); | ||
703 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4); | ||
704 | |||
705 | /* start calibration */ | ||
706 | tegra_dsi_pad_enable(dsi); | ||
707 | |||
708 | value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) | | ||
709 | DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) | | ||
710 | DSI_PAD_OUT_CLK(0x0); | ||
711 | tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2); | ||
712 | |||
713 | value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | | ||
714 | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3); | ||
715 | tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3); | ||
716 | |||
717 | return tegra_mipi_calibrate(dsi->mipi); | ||
718 | } | ||
719 | |||
680 | static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk, | 720 | static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk, |
681 | unsigned int vrefresh) | 721 | unsigned int vrefresh) |
682 | { | 722 | { |
@@ -836,7 +876,7 @@ static void tegra_dsi_encoder_disable(struct drm_encoder *encoder) | |||
836 | 876 | ||
837 | tegra_dsi_disable(dsi); | 877 | tegra_dsi_disable(dsi); |
838 | 878 | ||
839 | return; | 879 | pm_runtime_put(dsi->dev); |
840 | } | 880 | } |
841 | 881 | ||
842 | static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) | 882 | static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) |
@@ -847,6 +887,13 @@ static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) | |||
847 | struct tegra_dsi *dsi = to_dsi(output); | 887 | struct tegra_dsi *dsi = to_dsi(output); |
848 | struct tegra_dsi_state *state; | 888 | struct tegra_dsi_state *state; |
849 | u32 value; | 889 | u32 value; |
890 | int err; | ||
891 | |||
892 | pm_runtime_get_sync(dsi->dev); | ||
893 | |||
894 | err = tegra_dsi_pad_calibrate(dsi); | ||
895 | if (err < 0) | ||
896 | dev_err(dsi->dev, "MIPI calibration failed: %d\n", err); | ||
850 | 897 | ||
851 | state = tegra_dsi_get_state(dsi); | 898 | state = tegra_dsi_get_state(dsi); |
852 | 899 | ||
@@ -875,8 +922,6 @@ static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) | |||
875 | 922 | ||
876 | if (output->panel) | 923 | if (output->panel) |
877 | drm_panel_enable(output->panel); | 924 | drm_panel_enable(output->panel); |
878 | |||
879 | return; | ||
880 | } | 925 | } |
881 | 926 | ||
882 | static int | 927 | static int |
@@ -966,55 +1011,12 @@ static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = { | |||
966 | .atomic_check = tegra_dsi_encoder_atomic_check, | 1011 | .atomic_check = tegra_dsi_encoder_atomic_check, |
967 | }; | 1012 | }; |
968 | 1013 | ||
969 | static int tegra_dsi_pad_enable(struct tegra_dsi *dsi) | ||
970 | { | ||
971 | u32 value; | ||
972 | |||
973 | value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0); | ||
974 | tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0); | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi) | ||
980 | { | ||
981 | u32 value; | ||
982 | |||
983 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0); | ||
984 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1); | ||
985 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2); | ||
986 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3); | ||
987 | tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4); | ||
988 | |||
989 | /* start calibration */ | ||
990 | tegra_dsi_pad_enable(dsi); | ||
991 | |||
992 | value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) | | ||
993 | DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) | | ||
994 | DSI_PAD_OUT_CLK(0x0); | ||
995 | tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2); | ||
996 | |||
997 | value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) | | ||
998 | DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3); | ||
999 | tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3); | ||
1000 | |||
1001 | return tegra_mipi_calibrate(dsi->mipi); | ||
1002 | } | ||
1003 | |||
1004 | static int tegra_dsi_init(struct host1x_client *client) | 1014 | static int tegra_dsi_init(struct host1x_client *client) |
1005 | { | 1015 | { |
1006 | struct drm_device *drm = dev_get_drvdata(client->parent); | 1016 | struct drm_device *drm = dev_get_drvdata(client->parent); |
1007 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); | 1017 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); |
1008 | int err; | 1018 | int err; |
1009 | 1019 | ||
1010 | reset_control_deassert(dsi->rst); | ||
1011 | |||
1012 | err = tegra_dsi_pad_calibrate(dsi); | ||
1013 | if (err < 0) { | ||
1014 | dev_err(dsi->dev, "MIPI calibration failed: %d\n", err); | ||
1015 | goto reset; | ||
1016 | } | ||
1017 | |||
1018 | /* Gangsters must not register their own outputs. */ | 1020 | /* Gangsters must not register their own outputs. */ |
1019 | if (!dsi->master) { | 1021 | if (!dsi->master) { |
1020 | dsi->output.dev = client->dev; | 1022 | dsi->output.dev = client->dev; |
@@ -1037,12 +1039,9 @@ static int tegra_dsi_init(struct host1x_client *client) | |||
1037 | drm_connector_register(&dsi->output.connector); | 1039 | drm_connector_register(&dsi->output.connector); |
1038 | 1040 | ||
1039 | err = tegra_output_init(drm, &dsi->output); | 1041 | err = tegra_output_init(drm, &dsi->output); |
1040 | if (err < 0) { | 1042 | if (err < 0) |
1041 | dev_err(client->dev, | 1043 | dev_err(dsi->dev, "failed to initialize output: %d\n", |
1042 | "failed to initialize output: %d\n", | ||
1043 | err); | 1044 | err); |
1044 | goto reset; | ||
1045 | } | ||
1046 | 1045 | ||
1047 | dsi->output.encoder.possible_crtcs = 0x3; | 1046 | dsi->output.encoder.possible_crtcs = 0x3; |
1048 | } | 1047 | } |
@@ -1054,10 +1053,6 @@ static int tegra_dsi_init(struct host1x_client *client) | |||
1054 | } | 1053 | } |
1055 | 1054 | ||
1056 | return 0; | 1055 | return 0; |
1057 | |||
1058 | reset: | ||
1059 | reset_control_assert(dsi->rst); | ||
1060 | return err; | ||
1061 | } | 1056 | } |
1062 | 1057 | ||
1063 | static int tegra_dsi_exit(struct host1x_client *client) | 1058 | static int tegra_dsi_exit(struct host1x_client *client) |
@@ -1069,7 +1064,7 @@ static int tegra_dsi_exit(struct host1x_client *client) | |||
1069 | if (IS_ENABLED(CONFIG_DEBUG_FS)) | 1064 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
1070 | tegra_dsi_debugfs_exit(dsi); | 1065 | tegra_dsi_debugfs_exit(dsi); |
1071 | 1066 | ||
1072 | reset_control_assert(dsi->rst); | 1067 | regulator_disable(dsi->vdd); |
1073 | 1068 | ||
1074 | return 0; | 1069 | return 0; |
1075 | } | 1070 | } |
@@ -1493,74 +1488,50 @@ static int tegra_dsi_probe(struct platform_device *pdev) | |||
1493 | dsi->format = MIPI_DSI_FMT_RGB888; | 1488 | dsi->format = MIPI_DSI_FMT_RGB888; |
1494 | dsi->lanes = 4; | 1489 | dsi->lanes = 4; |
1495 | 1490 | ||
1496 | dsi->rst = devm_reset_control_get(&pdev->dev, "dsi"); | 1491 | if (!pdev->dev.pm_domain) { |
1497 | if (IS_ERR(dsi->rst)) | 1492 | dsi->rst = devm_reset_control_get(&pdev->dev, "dsi"); |
1498 | return PTR_ERR(dsi->rst); | 1493 | if (IS_ERR(dsi->rst)) |
1494 | return PTR_ERR(dsi->rst); | ||
1495 | } | ||
1499 | 1496 | ||
1500 | dsi->clk = devm_clk_get(&pdev->dev, NULL); | 1497 | dsi->clk = devm_clk_get(&pdev->dev, NULL); |
1501 | if (IS_ERR(dsi->clk)) { | 1498 | if (IS_ERR(dsi->clk)) { |
1502 | dev_err(&pdev->dev, "cannot get DSI clock\n"); | 1499 | dev_err(&pdev->dev, "cannot get DSI clock\n"); |
1503 | err = PTR_ERR(dsi->clk); | 1500 | return PTR_ERR(dsi->clk); |
1504 | goto reset; | ||
1505 | } | ||
1506 | |||
1507 | err = clk_prepare_enable(dsi->clk); | ||
1508 | if (err < 0) { | ||
1509 | dev_err(&pdev->dev, "cannot enable DSI clock\n"); | ||
1510 | goto reset; | ||
1511 | } | 1501 | } |
1512 | 1502 | ||
1513 | dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); | 1503 | dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); |
1514 | if (IS_ERR(dsi->clk_lp)) { | 1504 | if (IS_ERR(dsi->clk_lp)) { |
1515 | dev_err(&pdev->dev, "cannot get low-power clock\n"); | 1505 | dev_err(&pdev->dev, "cannot get low-power clock\n"); |
1516 | err = PTR_ERR(dsi->clk_lp); | 1506 | return PTR_ERR(dsi->clk_lp); |
1517 | goto disable_clk; | ||
1518 | } | ||
1519 | |||
1520 | err = clk_prepare_enable(dsi->clk_lp); | ||
1521 | if (err < 0) { | ||
1522 | dev_err(&pdev->dev, "cannot enable low-power clock\n"); | ||
1523 | goto disable_clk; | ||
1524 | } | 1507 | } |
1525 | 1508 | ||
1526 | dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); | 1509 | dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); |
1527 | if (IS_ERR(dsi->clk_parent)) { | 1510 | if (IS_ERR(dsi->clk_parent)) { |
1528 | dev_err(&pdev->dev, "cannot get parent clock\n"); | 1511 | dev_err(&pdev->dev, "cannot get parent clock\n"); |
1529 | err = PTR_ERR(dsi->clk_parent); | 1512 | return PTR_ERR(dsi->clk_parent); |
1530 | goto disable_clk_lp; | ||
1531 | } | 1513 | } |
1532 | 1514 | ||
1533 | dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); | 1515 | dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); |
1534 | if (IS_ERR(dsi->vdd)) { | 1516 | if (IS_ERR(dsi->vdd)) { |
1535 | dev_err(&pdev->dev, "cannot get VDD supply\n"); | 1517 | dev_err(&pdev->dev, "cannot get VDD supply\n"); |
1536 | err = PTR_ERR(dsi->vdd); | 1518 | return PTR_ERR(dsi->vdd); |
1537 | goto disable_clk_lp; | ||
1538 | } | ||
1539 | |||
1540 | err = regulator_enable(dsi->vdd); | ||
1541 | if (err < 0) { | ||
1542 | dev_err(&pdev->dev, "cannot enable VDD supply\n"); | ||
1543 | goto disable_clk_lp; | ||
1544 | } | 1519 | } |
1545 | 1520 | ||
1546 | err = tegra_dsi_setup_clocks(dsi); | 1521 | err = tegra_dsi_setup_clocks(dsi); |
1547 | if (err < 0) { | 1522 | if (err < 0) { |
1548 | dev_err(&pdev->dev, "cannot setup clocks\n"); | 1523 | dev_err(&pdev->dev, "cannot setup clocks\n"); |
1549 | goto disable_vdd; | 1524 | return err; |
1550 | } | 1525 | } |
1551 | 1526 | ||
1552 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1527 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1553 | dsi->regs = devm_ioremap_resource(&pdev->dev, regs); | 1528 | dsi->regs = devm_ioremap_resource(&pdev->dev, regs); |
1554 | if (IS_ERR(dsi->regs)) { | 1529 | if (IS_ERR(dsi->regs)) |
1555 | err = PTR_ERR(dsi->regs); | 1530 | return PTR_ERR(dsi->regs); |
1556 | goto disable_vdd; | ||
1557 | } | ||
1558 | 1531 | ||
1559 | dsi->mipi = tegra_mipi_request(&pdev->dev); | 1532 | dsi->mipi = tegra_mipi_request(&pdev->dev); |
1560 | if (IS_ERR(dsi->mipi)) { | 1533 | if (IS_ERR(dsi->mipi)) |
1561 | err = PTR_ERR(dsi->mipi); | 1534 | return PTR_ERR(dsi->mipi); |
1562 | goto disable_vdd; | ||
1563 | } | ||
1564 | 1535 | ||
1565 | dsi->host.ops = &tegra_dsi_host_ops; | 1536 | dsi->host.ops = &tegra_dsi_host_ops; |
1566 | dsi->host.dev = &pdev->dev; | 1537 | dsi->host.dev = &pdev->dev; |
@@ -1571,6 +1542,9 @@ static int tegra_dsi_probe(struct platform_device *pdev) | |||
1571 | goto mipi_free; | 1542 | goto mipi_free; |
1572 | } | 1543 | } |
1573 | 1544 | ||
1545 | platform_set_drvdata(pdev, dsi); | ||
1546 | pm_runtime_enable(&pdev->dev); | ||
1547 | |||
1574 | INIT_LIST_HEAD(&dsi->client.list); | 1548 | INIT_LIST_HEAD(&dsi->client.list); |
1575 | dsi->client.ops = &dsi_client_ops; | 1549 | dsi->client.ops = &dsi_client_ops; |
1576 | dsi->client.dev = &pdev->dev; | 1550 | dsi->client.dev = &pdev->dev; |
@@ -1582,22 +1556,12 @@ static int tegra_dsi_probe(struct platform_device *pdev) | |||
1582 | goto unregister; | 1556 | goto unregister; |
1583 | } | 1557 | } |
1584 | 1558 | ||
1585 | platform_set_drvdata(pdev, dsi); | ||
1586 | |||
1587 | return 0; | 1559 | return 0; |
1588 | 1560 | ||
1589 | unregister: | 1561 | unregister: |
1590 | mipi_dsi_host_unregister(&dsi->host); | 1562 | mipi_dsi_host_unregister(&dsi->host); |
1591 | mipi_free: | 1563 | mipi_free: |
1592 | tegra_mipi_free(dsi->mipi); | 1564 | tegra_mipi_free(dsi->mipi); |
1593 | disable_vdd: | ||
1594 | regulator_disable(dsi->vdd); | ||
1595 | disable_clk_lp: | ||
1596 | clk_disable_unprepare(dsi->clk_lp); | ||
1597 | disable_clk: | ||
1598 | clk_disable_unprepare(dsi->clk); | ||
1599 | reset: | ||
1600 | reset_control_assert(dsi->rst); | ||
1601 | return err; | 1565 | return err; |
1602 | } | 1566 | } |
1603 | 1567 | ||
@@ -1606,6 +1570,8 @@ static int tegra_dsi_remove(struct platform_device *pdev) | |||
1606 | struct tegra_dsi *dsi = platform_get_drvdata(pdev); | 1570 | struct tegra_dsi *dsi = platform_get_drvdata(pdev); |
1607 | int err; | 1571 | int err; |
1608 | 1572 | ||
1573 | pm_runtime_disable(&pdev->dev); | ||
1574 | |||
1609 | err = host1x_client_unregister(&dsi->client); | 1575 | err = host1x_client_unregister(&dsi->client); |
1610 | if (err < 0) { | 1576 | if (err < 0) { |
1611 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", | 1577 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", |
@@ -1618,14 +1584,82 @@ static int tegra_dsi_remove(struct platform_device *pdev) | |||
1618 | mipi_dsi_host_unregister(&dsi->host); | 1584 | mipi_dsi_host_unregister(&dsi->host); |
1619 | tegra_mipi_free(dsi->mipi); | 1585 | tegra_mipi_free(dsi->mipi); |
1620 | 1586 | ||
1621 | regulator_disable(dsi->vdd); | 1587 | return 0; |
1588 | } | ||
1589 | |||
1590 | #ifdef CONFIG_PM | ||
1591 | static int tegra_dsi_suspend(struct device *dev) | ||
1592 | { | ||
1593 | struct tegra_dsi *dsi = dev_get_drvdata(dev); | ||
1594 | int err; | ||
1595 | |||
1596 | if (dsi->rst) { | ||
1597 | err = reset_control_assert(dsi->rst); | ||
1598 | if (err < 0) { | ||
1599 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
1600 | return err; | ||
1601 | } | ||
1602 | } | ||
1603 | |||
1604 | usleep_range(1000, 2000); | ||
1605 | |||
1622 | clk_disable_unprepare(dsi->clk_lp); | 1606 | clk_disable_unprepare(dsi->clk_lp); |
1623 | clk_disable_unprepare(dsi->clk); | 1607 | clk_disable_unprepare(dsi->clk); |
1624 | reset_control_assert(dsi->rst); | 1608 | |
1609 | regulator_disable(dsi->vdd); | ||
1625 | 1610 | ||
1626 | return 0; | 1611 | return 0; |
1627 | } | 1612 | } |
1628 | 1613 | ||
1614 | static int tegra_dsi_resume(struct device *dev) | ||
1615 | { | ||
1616 | struct tegra_dsi *dsi = dev_get_drvdata(dev); | ||
1617 | int err; | ||
1618 | |||
1619 | err = regulator_enable(dsi->vdd); | ||
1620 | if (err < 0) { | ||
1621 | dev_err(dsi->dev, "failed to enable VDD supply: %d\n", err); | ||
1622 | return err; | ||
1623 | } | ||
1624 | |||
1625 | err = clk_prepare_enable(dsi->clk); | ||
1626 | if (err < 0) { | ||
1627 | dev_err(dev, "cannot enable DSI clock: %d\n", err); | ||
1628 | goto disable_vdd; | ||
1629 | } | ||
1630 | |||
1631 | err = clk_prepare_enable(dsi->clk_lp); | ||
1632 | if (err < 0) { | ||
1633 | dev_err(dev, "cannot enable low-power clock: %d\n", err); | ||
1634 | goto disable_clk; | ||
1635 | } | ||
1636 | |||
1637 | usleep_range(1000, 2000); | ||
1638 | |||
1639 | if (dsi->rst) { | ||
1640 | err = reset_control_deassert(dsi->rst); | ||
1641 | if (err < 0) { | ||
1642 | dev_err(dev, "cannot assert reset: %d\n", err); | ||
1643 | goto disable_clk_lp; | ||
1644 | } | ||
1645 | } | ||
1646 | |||
1647 | return 0; | ||
1648 | |||
1649 | disable_clk_lp: | ||
1650 | clk_disable_unprepare(dsi->clk_lp); | ||
1651 | disable_clk: | ||
1652 | clk_disable_unprepare(dsi->clk); | ||
1653 | disable_vdd: | ||
1654 | regulator_disable(dsi->vdd); | ||
1655 | return err; | ||
1656 | } | ||
1657 | #endif | ||
1658 | |||
1659 | static const struct dev_pm_ops tegra_dsi_pm_ops = { | ||
1660 | SET_RUNTIME_PM_OPS(tegra_dsi_suspend, tegra_dsi_resume, NULL) | ||
1661 | }; | ||
1662 | |||
1629 | static const struct of_device_id tegra_dsi_of_match[] = { | 1663 | static const struct of_device_id tegra_dsi_of_match[] = { |
1630 | { .compatible = "nvidia,tegra210-dsi", }, | 1664 | { .compatible = "nvidia,tegra210-dsi", }, |
1631 | { .compatible = "nvidia,tegra132-dsi", }, | 1665 | { .compatible = "nvidia,tegra132-dsi", }, |
@@ -1639,6 +1673,7 @@ struct platform_driver tegra_dsi_driver = { | |||
1639 | .driver = { | 1673 | .driver = { |
1640 | .name = "tegra-dsi", | 1674 | .name = "tegra-dsi", |
1641 | .of_match_table = tegra_dsi_of_match, | 1675 | .of_match_table = tegra_dsi_of_match, |
1676 | .pm = &tegra_dsi_pm_ops, | ||
1642 | }, | 1677 | }, |
1643 | .probe = tegra_dsi_probe, | 1678 | .probe = tegra_dsi_probe, |
1644 | .remove = tegra_dsi_remove, | 1679 | .remove = tegra_dsi_remove, |
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 2fdb8796443e..cda0491ed6bf 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
12 | #include <linux/gpio.h> | 12 | #include <linux/gpio.h> |
13 | #include <linux/hdmi.h> | 13 | #include <linux/hdmi.h> |
14 | #include <linux/pm_runtime.h> | ||
14 | #include <linux/regulator/consumer.h> | 15 | #include <linux/regulator/consumer.h> |
15 | #include <linux/reset.h> | 16 | #include <linux/reset.h> |
16 | 17 | ||
@@ -18,10 +19,14 @@ | |||
18 | #include <drm/drm_crtc.h> | 19 | #include <drm/drm_crtc.h> |
19 | #include <drm/drm_crtc_helper.h> | 20 | #include <drm/drm_crtc_helper.h> |
20 | 21 | ||
22 | #include <sound/hda_verbs.h> | ||
23 | |||
21 | #include "hdmi.h" | 24 | #include "hdmi.h" |
22 | #include "drm.h" | 25 | #include "drm.h" |
23 | #include "dc.h" | 26 | #include "dc.h" |
24 | 27 | ||
28 | #define HDMI_ELD_BUFFER_SIZE 96 | ||
29 | |||
25 | struct tmds_config { | 30 | struct tmds_config { |
26 | unsigned int pclk; | 31 | unsigned int pclk; |
27 | u32 pll0; | 32 | u32 pll0; |
@@ -39,6 +44,8 @@ struct tegra_hdmi_config { | |||
39 | u32 fuse_override_value; | 44 | u32 fuse_override_value; |
40 | 45 | ||
41 | bool has_sor_io_peak_current; | 46 | bool has_sor_io_peak_current; |
47 | bool has_hda; | ||
48 | bool has_hbr; | ||
42 | }; | 49 | }; |
43 | 50 | ||
44 | struct tegra_hdmi { | 51 | struct tegra_hdmi { |
@@ -60,7 +67,10 @@ struct tegra_hdmi { | |||
60 | const struct tegra_hdmi_config *config; | 67 | const struct tegra_hdmi_config *config; |
61 | 68 | ||
62 | unsigned int audio_source; | 69 | unsigned int audio_source; |
63 | unsigned int audio_freq; | 70 | unsigned int audio_sample_rate; |
71 | unsigned int audio_channels; | ||
72 | |||
73 | unsigned int pixel_clock; | ||
64 | bool stereo; | 74 | bool stereo; |
65 | bool dvi; | 75 | bool dvi; |
66 | 76 | ||
@@ -402,11 +412,11 @@ static const struct tmds_config tegra124_tmds_config[] = { | |||
402 | }; | 412 | }; |
403 | 413 | ||
404 | static const struct tegra_hdmi_audio_config * | 414 | static const struct tegra_hdmi_audio_config * |
405 | tegra_hdmi_get_audio_config(unsigned int audio_freq, unsigned int pclk) | 415 | tegra_hdmi_get_audio_config(unsigned int sample_rate, unsigned int pclk) |
406 | { | 416 | { |
407 | const struct tegra_hdmi_audio_config *table; | 417 | const struct tegra_hdmi_audio_config *table; |
408 | 418 | ||
409 | switch (audio_freq) { | 419 | switch (sample_rate) { |
410 | case 32000: | 420 | case 32000: |
411 | table = tegra_hdmi_audio_32k; | 421 | table = tegra_hdmi_audio_32k; |
412 | break; | 422 | break; |
@@ -476,44 +486,114 @@ static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi) | |||
476 | } | 486 | } |
477 | } | 487 | } |
478 | 488 | ||
479 | static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk) | 489 | static void tegra_hdmi_write_aval(struct tegra_hdmi *hdmi, u32 value) |
490 | { | ||
491 | static const struct { | ||
492 | unsigned int sample_rate; | ||
493 | unsigned int offset; | ||
494 | } regs[] = { | ||
495 | { 32000, HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320 }, | ||
496 | { 44100, HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441 }, | ||
497 | { 48000, HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480 }, | ||
498 | { 88200, HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882 }, | ||
499 | { 96000, HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960 }, | ||
500 | { 176400, HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764 }, | ||
501 | { 192000, HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920 }, | ||
502 | }; | ||
503 | unsigned int i; | ||
504 | |||
505 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
506 | if (regs[i].sample_rate == hdmi->audio_sample_rate) { | ||
507 | tegra_hdmi_writel(hdmi, value, regs[i].offset); | ||
508 | break; | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | |||
513 | static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi) | ||
480 | { | 514 | { |
481 | struct device_node *node = hdmi->dev->of_node; | ||
482 | const struct tegra_hdmi_audio_config *config; | 515 | const struct tegra_hdmi_audio_config *config; |
483 | unsigned int offset = 0; | 516 | u32 source, value; |
484 | u32 value; | ||
485 | 517 | ||
486 | switch (hdmi->audio_source) { | 518 | switch (hdmi->audio_source) { |
487 | case HDA: | 519 | case HDA: |
488 | value = AUDIO_CNTRL0_SOURCE_SELECT_HDAL; | 520 | if (hdmi->config->has_hda) |
521 | source = SOR_AUDIO_CNTRL0_SOURCE_SELECT_HDAL; | ||
522 | else | ||
523 | return -EINVAL; | ||
524 | |||
489 | break; | 525 | break; |
490 | 526 | ||
491 | case SPDIF: | 527 | case SPDIF: |
492 | value = AUDIO_CNTRL0_SOURCE_SELECT_SPDIF; | 528 | if (hdmi->config->has_hda) |
529 | source = SOR_AUDIO_CNTRL0_SOURCE_SELECT_SPDIF; | ||
530 | else | ||
531 | source = AUDIO_CNTRL0_SOURCE_SELECT_SPDIF; | ||
493 | break; | 532 | break; |
494 | 533 | ||
495 | default: | 534 | default: |
496 | value = AUDIO_CNTRL0_SOURCE_SELECT_AUTO; | 535 | if (hdmi->config->has_hda) |
536 | source = SOR_AUDIO_CNTRL0_SOURCE_SELECT_AUTO; | ||
537 | else | ||
538 | source = AUDIO_CNTRL0_SOURCE_SELECT_AUTO; | ||
497 | break; | 539 | break; |
498 | } | 540 | } |
499 | 541 | ||
500 | if (of_device_is_compatible(node, "nvidia,tegra30-hdmi")) { | 542 | /* |
501 | value |= AUDIO_CNTRL0_ERROR_TOLERANCE(6) | | 543 | * Tegra30 and later use a slightly modified version of the register |
502 | AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0); | 544 | * layout to accomodate for changes related to supporting HDA as the |
503 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_CNTRL0); | 545 | * audio input source for HDMI. The source select field has moved to |
504 | } else { | 546 | * the SOR_AUDIO_CNTRL0 register, but the error tolerance and frames |
505 | value |= AUDIO_CNTRL0_INJECT_NULLSMPL; | 547 | * per block fields remain in the AUDIO_CNTRL0 register. |
548 | */ | ||
549 | if (hdmi->config->has_hda) { | ||
550 | /* | ||
551 | * Inject null samples into the audio FIFO for every frame in | ||
552 | * which the codec did not receive any samples. This applies | ||
553 | * to stereo LPCM only. | ||
554 | * | ||
555 | * XXX: This seems to be a remnant of MCP days when this was | ||
556 | * used to work around issues with monitors not being able to | ||
557 | * play back system startup sounds early. It is possibly not | ||
558 | * needed on Linux at all. | ||
559 | */ | ||
560 | if (hdmi->audio_channels == 2) | ||
561 | value = SOR_AUDIO_CNTRL0_INJECT_NULLSMPL; | ||
562 | else | ||
563 | value = 0; | ||
564 | |||
565 | value |= source; | ||
566 | |||
506 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_AUDIO_CNTRL0); | 567 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_AUDIO_CNTRL0); |
568 | } | ||
507 | 569 | ||
508 | value = AUDIO_CNTRL0_ERROR_TOLERANCE(6) | | 570 | /* |
509 | AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0); | 571 | * On Tegra20, HDA is not a supported audio source and the source |
510 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_CNTRL0); | 572 | * select field is part of the AUDIO_CNTRL0 register. |
573 | */ | ||
574 | value = AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0) | | ||
575 | AUDIO_CNTRL0_ERROR_TOLERANCE(6); | ||
576 | |||
577 | if (!hdmi->config->has_hda) | ||
578 | value |= source; | ||
579 | |||
580 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
581 | |||
582 | /* | ||
583 | * Advertise support for High Bit-Rate on Tegra114 and later. | ||
584 | */ | ||
585 | if (hdmi->config->has_hbr) { | ||
586 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_AUDIO_SPARE0); | ||
587 | value |= SOR_AUDIO_SPARE0_HBR_ENABLE; | ||
588 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_AUDIO_SPARE0); | ||
511 | } | 589 | } |
512 | 590 | ||
513 | config = tegra_hdmi_get_audio_config(hdmi->audio_freq, pclk); | 591 | config = tegra_hdmi_get_audio_config(hdmi->audio_sample_rate, |
592 | hdmi->pixel_clock); | ||
514 | if (!config) { | 593 | if (!config) { |
515 | dev_err(hdmi->dev, "cannot set audio to %u at %u pclk\n", | 594 | dev_err(hdmi->dev, |
516 | hdmi->audio_freq, pclk); | 595 | "cannot set audio to %u Hz at %u Hz pixel clock\n", |
596 | hdmi->audio_sample_rate, hdmi->pixel_clock); | ||
517 | return -EINVAL; | 597 | return -EINVAL; |
518 | } | 598 | } |
519 | 599 | ||
@@ -526,8 +606,8 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk) | |||
526 | tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config->n) | ACR_ENABLE, | 606 | tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config->n) | ACR_ENABLE, |
527 | HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); | 607 | HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); |
528 | 608 | ||
529 | value = ACR_SUBPACK_CTS(config->cts); | 609 | tegra_hdmi_writel(hdmi, ACR_SUBPACK_CTS(config->cts), |
530 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); | 610 | HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); |
531 | 611 | ||
532 | value = SPARE_HW_CTS | SPARE_FORCE_SW_CTS | SPARE_CTS_RESET_VAL(1); | 612 | value = SPARE_HW_CTS | SPARE_FORCE_SW_CTS | SPARE_CTS_RESET_VAL(1); |
533 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_SPARE); | 613 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_SPARE); |
@@ -536,43 +616,53 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk) | |||
536 | value &= ~AUDIO_N_RESETF; | 616 | value &= ~AUDIO_N_RESETF; |
537 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N); | 617 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N); |
538 | 618 | ||
539 | if (of_device_is_compatible(node, "nvidia,tegra30-hdmi")) { | 619 | if (hdmi->config->has_hda) |
540 | switch (hdmi->audio_freq) { | 620 | tegra_hdmi_write_aval(hdmi, config->aval); |
541 | case 32000: | ||
542 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320; | ||
543 | break; | ||
544 | 621 | ||
545 | case 44100: | 622 | tegra_hdmi_setup_audio_fs_tables(hdmi); |
546 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441; | ||
547 | break; | ||
548 | 623 | ||
549 | case 48000: | 624 | return 0; |
550 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480; | 625 | } |
551 | break; | ||
552 | 626 | ||
553 | case 88200: | 627 | static void tegra_hdmi_disable_audio(struct tegra_hdmi *hdmi) |
554 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882; | 628 | { |
555 | break; | 629 | u32 value; |
556 | 630 | ||
557 | case 96000: | 631 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); |
558 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960; | 632 | value &= ~GENERIC_CTRL_AUDIO; |
559 | break; | 633 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); |
634 | } | ||
560 | 635 | ||
561 | case 176400: | 636 | static void tegra_hdmi_enable_audio(struct tegra_hdmi *hdmi) |
562 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764; | 637 | { |
563 | break; | 638 | u32 value; |
564 | 639 | ||
565 | case 192000: | 640 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); |
566 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920; | 641 | value |= GENERIC_CTRL_AUDIO; |
567 | break; | 642 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); |
568 | } | 643 | } |
569 | 644 | ||
570 | tegra_hdmi_writel(hdmi, config->aval, offset); | 645 | static void tegra_hdmi_write_eld(struct tegra_hdmi *hdmi) |
571 | } | 646 | { |
647 | size_t length = drm_eld_size(hdmi->output.connector.eld), i; | ||
648 | u32 value; | ||
572 | 649 | ||
573 | tegra_hdmi_setup_audio_fs_tables(hdmi); | 650 | for (i = 0; i < length; i++) |
651 | tegra_hdmi_writel(hdmi, i << 8 | hdmi->output.connector.eld[i], | ||
652 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR); | ||
574 | 653 | ||
575 | return 0; | 654 | /* |
655 | * The HDA codec will always report an ELD buffer size of 96 bytes and | ||
656 | * the HDA codec driver will check that each byte read from the buffer | ||
657 | * is valid. Therefore every byte must be written, even if no 96 bytes | ||
658 | * were parsed from EDID. | ||
659 | */ | ||
660 | for (i = length; i < HDMI_ELD_BUFFER_SIZE; i++) | ||
661 | tegra_hdmi_writel(hdmi, i << 8 | 0, | ||
662 | HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR); | ||
663 | |||
664 | value = SOR_AUDIO_HDA_PRESENSE_VALID | SOR_AUDIO_HDA_PRESENSE_PRESENT; | ||
665 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE); | ||
576 | } | 666 | } |
577 | 667 | ||
578 | static inline u32 tegra_hdmi_subpack(const u8 *ptr, size_t size) | 668 | static inline u32 tegra_hdmi_subpack(const u8 *ptr, size_t size) |
@@ -644,12 +734,6 @@ static void tegra_hdmi_setup_avi_infoframe(struct tegra_hdmi *hdmi, | |||
644 | u8 buffer[17]; | 734 | u8 buffer[17]; |
645 | ssize_t err; | 735 | ssize_t err; |
646 | 736 | ||
647 | if (hdmi->dvi) { | ||
648 | tegra_hdmi_writel(hdmi, 0, | ||
649 | HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
650 | return; | ||
651 | } | ||
652 | |||
653 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); | 737 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); |
654 | if (err < 0) { | 738 | if (err < 0) { |
655 | dev_err(hdmi->dev, "failed to setup AVI infoframe: %zd\n", err); | 739 | dev_err(hdmi->dev, "failed to setup AVI infoframe: %zd\n", err); |
@@ -663,9 +747,24 @@ static void tegra_hdmi_setup_avi_infoframe(struct tegra_hdmi *hdmi, | |||
663 | } | 747 | } |
664 | 748 | ||
665 | tegra_hdmi_write_infopack(hdmi, buffer, err); | 749 | tegra_hdmi_write_infopack(hdmi, buffer, err); |
750 | } | ||
751 | |||
752 | static void tegra_hdmi_disable_avi_infoframe(struct tegra_hdmi *hdmi) | ||
753 | { | ||
754 | u32 value; | ||
666 | 755 | ||
667 | tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE, | 756 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); |
668 | HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | 757 | value &= ~INFOFRAME_CTRL_ENABLE; |
758 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
759 | } | ||
760 | |||
761 | static void tegra_hdmi_enable_avi_infoframe(struct tegra_hdmi *hdmi) | ||
762 | { | ||
763 | u32 value; | ||
764 | |||
765 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
766 | value |= INFOFRAME_CTRL_ENABLE; | ||
767 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
669 | } | 768 | } |
670 | 769 | ||
671 | static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi) | 770 | static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi) |
@@ -674,12 +773,6 @@ static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi) | |||
674 | u8 buffer[14]; | 773 | u8 buffer[14]; |
675 | ssize_t err; | 774 | ssize_t err; |
676 | 775 | ||
677 | if (hdmi->dvi) { | ||
678 | tegra_hdmi_writel(hdmi, 0, | ||
679 | HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
680 | return; | ||
681 | } | ||
682 | |||
683 | err = hdmi_audio_infoframe_init(&frame); | 776 | err = hdmi_audio_infoframe_init(&frame); |
684 | if (err < 0) { | 777 | if (err < 0) { |
685 | dev_err(hdmi->dev, "failed to setup audio infoframe: %zd\n", | 778 | dev_err(hdmi->dev, "failed to setup audio infoframe: %zd\n", |
@@ -687,7 +780,7 @@ static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi) | |||
687 | return; | 780 | return; |
688 | } | 781 | } |
689 | 782 | ||
690 | frame.channels = 2; | 783 | frame.channels = hdmi->audio_channels; |
691 | 784 | ||
692 | err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); | 785 | err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); |
693 | if (err < 0) { | 786 | if (err < 0) { |
@@ -703,9 +796,24 @@ static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi) | |||
703 | * bytes can be programmed. | 796 | * bytes can be programmed. |
704 | */ | 797 | */ |
705 | tegra_hdmi_write_infopack(hdmi, buffer, min_t(size_t, 10, err)); | 798 | tegra_hdmi_write_infopack(hdmi, buffer, min_t(size_t, 10, err)); |
799 | } | ||
706 | 800 | ||
707 | tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE, | 801 | static void tegra_hdmi_disable_audio_infoframe(struct tegra_hdmi *hdmi) |
708 | HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | 802 | { |
803 | u32 value; | ||
804 | |||
805 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
806 | value &= ~INFOFRAME_CTRL_ENABLE; | ||
807 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
808 | } | ||
809 | |||
810 | static void tegra_hdmi_enable_audio_infoframe(struct tegra_hdmi *hdmi) | ||
811 | { | ||
812 | u32 value; | ||
813 | |||
814 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
815 | value |= INFOFRAME_CTRL_ENABLE; | ||
816 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
709 | } | 817 | } |
710 | 818 | ||
711 | static void tegra_hdmi_setup_stereo_infoframe(struct tegra_hdmi *hdmi) | 819 | static void tegra_hdmi_setup_stereo_infoframe(struct tegra_hdmi *hdmi) |
@@ -713,14 +821,6 @@ static void tegra_hdmi_setup_stereo_infoframe(struct tegra_hdmi *hdmi) | |||
713 | struct hdmi_vendor_infoframe frame; | 821 | struct hdmi_vendor_infoframe frame; |
714 | u8 buffer[10]; | 822 | u8 buffer[10]; |
715 | ssize_t err; | 823 | ssize_t err; |
716 | u32 value; | ||
717 | |||
718 | if (!hdmi->stereo) { | ||
719 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
720 | value &= ~GENERIC_CTRL_ENABLE; | ||
721 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
722 | return; | ||
723 | } | ||
724 | 824 | ||
725 | hdmi_vendor_infoframe_init(&frame); | 825 | hdmi_vendor_infoframe_init(&frame); |
726 | frame.s3d_struct = HDMI_3D_STRUCTURE_FRAME_PACKING; | 826 | frame.s3d_struct = HDMI_3D_STRUCTURE_FRAME_PACKING; |
@@ -733,6 +833,20 @@ static void tegra_hdmi_setup_stereo_infoframe(struct tegra_hdmi *hdmi) | |||
733 | } | 833 | } |
734 | 834 | ||
735 | tegra_hdmi_write_infopack(hdmi, buffer, err); | 835 | tegra_hdmi_write_infopack(hdmi, buffer, err); |
836 | } | ||
837 | |||
838 | static void tegra_hdmi_disable_stereo_infoframe(struct tegra_hdmi *hdmi) | ||
839 | { | ||
840 | u32 value; | ||
841 | |||
842 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
843 | value &= ~GENERIC_CTRL_ENABLE; | ||
844 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
845 | } | ||
846 | |||
847 | static void tegra_hdmi_enable_stereo_infoframe(struct tegra_hdmi *hdmi) | ||
848 | { | ||
849 | u32 value; | ||
736 | 850 | ||
737 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | 851 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); |
738 | value |= GENERIC_CTRL_ENABLE; | 852 | value |= GENERIC_CTRL_ENABLE; |
@@ -772,10 +886,25 @@ static bool tegra_output_is_hdmi(struct tegra_output *output) | |||
772 | return drm_detect_hdmi_monitor(edid); | 886 | return drm_detect_hdmi_monitor(edid); |
773 | } | 887 | } |
774 | 888 | ||
889 | static enum drm_connector_status | ||
890 | tegra_hdmi_connector_detect(struct drm_connector *connector, bool force) | ||
891 | { | ||
892 | struct tegra_output *output = connector_to_output(connector); | ||
893 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
894 | enum drm_connector_status status; | ||
895 | |||
896 | status = tegra_output_connector_detect(connector, force); | ||
897 | if (status == connector_status_connected) | ||
898 | return status; | ||
899 | |||
900 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE); | ||
901 | return status; | ||
902 | } | ||
903 | |||
775 | static const struct drm_connector_funcs tegra_hdmi_connector_funcs = { | 904 | static const struct drm_connector_funcs tegra_hdmi_connector_funcs = { |
776 | .dpms = drm_atomic_helper_connector_dpms, | 905 | .dpms = drm_atomic_helper_connector_dpms, |
777 | .reset = drm_atomic_helper_connector_reset, | 906 | .reset = drm_atomic_helper_connector_reset, |
778 | .detect = tegra_output_connector_detect, | 907 | .detect = tegra_hdmi_connector_detect, |
779 | .fill_modes = drm_helper_probe_single_connector_modes, | 908 | .fill_modes = drm_helper_probe_single_connector_modes, |
780 | .destroy = tegra_output_connector_destroy, | 909 | .destroy = tegra_output_connector_destroy, |
781 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 910 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
@@ -814,7 +943,9 @@ static const struct drm_encoder_funcs tegra_hdmi_encoder_funcs = { | |||
814 | 943 | ||
815 | static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder) | 944 | static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder) |
816 | { | 945 | { |
946 | struct tegra_output *output = encoder_to_output(encoder); | ||
817 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); | 947 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); |
948 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
818 | u32 value; | 949 | u32 value; |
819 | 950 | ||
820 | /* | 951 | /* |
@@ -828,6 +959,20 @@ static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder) | |||
828 | 959 | ||
829 | tegra_dc_commit(dc); | 960 | tegra_dc_commit(dc); |
830 | } | 961 | } |
962 | |||
963 | if (!hdmi->dvi) { | ||
964 | if (hdmi->stereo) | ||
965 | tegra_hdmi_disable_stereo_infoframe(hdmi); | ||
966 | |||
967 | tegra_hdmi_disable_audio_infoframe(hdmi); | ||
968 | tegra_hdmi_disable_avi_infoframe(hdmi); | ||
969 | tegra_hdmi_disable_audio(hdmi); | ||
970 | } | ||
971 | |||
972 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_ENABLE); | ||
973 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_MASK); | ||
974 | |||
975 | pm_runtime_put(hdmi->dev); | ||
831 | } | 976 | } |
832 | 977 | ||
833 | static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) | 978 | static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) |
@@ -836,21 +981,28 @@ static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) | |||
836 | unsigned int h_sync_width, h_front_porch, h_back_porch, i, rekey; | 981 | unsigned int h_sync_width, h_front_porch, h_back_porch, i, rekey; |
837 | struct tegra_output *output = encoder_to_output(encoder); | 982 | struct tegra_output *output = encoder_to_output(encoder); |
838 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); | 983 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); |
839 | struct device_node *node = output->dev->of_node; | ||
840 | struct tegra_hdmi *hdmi = to_hdmi(output); | 984 | struct tegra_hdmi *hdmi = to_hdmi(output); |
841 | unsigned int pulse_start, div82, pclk; | 985 | unsigned int pulse_start, div82; |
842 | int retries = 1000; | 986 | int retries = 1000; |
843 | u32 value; | 987 | u32 value; |
844 | int err; | 988 | int err; |
845 | 989 | ||
846 | hdmi->dvi = !tegra_output_is_hdmi(output); | 990 | pm_runtime_get_sync(hdmi->dev); |
847 | 991 | ||
848 | pclk = mode->clock * 1000; | 992 | /* |
993 | * Enable and unmask the HDA codec SCRATCH0 register interrupt. This | ||
994 | * is used for interoperability between the HDA codec driver and the | ||
995 | * HDMI driver. | ||
996 | */ | ||
997 | tegra_hdmi_writel(hdmi, INT_CODEC_SCRATCH0, HDMI_NV_PDISP_INT_ENABLE); | ||
998 | tegra_hdmi_writel(hdmi, INT_CODEC_SCRATCH0, HDMI_NV_PDISP_INT_MASK); | ||
999 | |||
1000 | hdmi->pixel_clock = mode->clock * 1000; | ||
849 | h_sync_width = mode->hsync_end - mode->hsync_start; | 1001 | h_sync_width = mode->hsync_end - mode->hsync_start; |
850 | h_back_porch = mode->htotal - mode->hsync_end; | 1002 | h_back_porch = mode->htotal - mode->hsync_end; |
851 | h_front_porch = mode->hsync_start - mode->hdisplay; | 1003 | h_front_porch = mode->hsync_start - mode->hdisplay; |
852 | 1004 | ||
853 | err = clk_set_rate(hdmi->clk, pclk); | 1005 | err = clk_set_rate(hdmi->clk, hdmi->pixel_clock); |
854 | if (err < 0) { | 1006 | if (err < 0) { |
855 | dev_err(hdmi->dev, "failed to set HDMI clock frequency: %d\n", | 1007 | dev_err(hdmi->dev, "failed to set HDMI clock frequency: %d\n", |
856 | err); | 1008 | err); |
@@ -909,17 +1061,15 @@ static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) | |||
909 | value = SOR_REFCLK_DIV_INT(div82 >> 2) | SOR_REFCLK_DIV_FRAC(div82); | 1061 | value = SOR_REFCLK_DIV_INT(div82 >> 2) | SOR_REFCLK_DIV_FRAC(div82); |
910 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_REFCLK); | 1062 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_REFCLK); |
911 | 1063 | ||
1064 | hdmi->dvi = !tegra_output_is_hdmi(output); | ||
912 | if (!hdmi->dvi) { | 1065 | if (!hdmi->dvi) { |
913 | err = tegra_hdmi_setup_audio(hdmi, pclk); | 1066 | err = tegra_hdmi_setup_audio(hdmi); |
914 | if (err < 0) | 1067 | if (err < 0) |
915 | hdmi->dvi = true; | 1068 | hdmi->dvi = true; |
916 | } | 1069 | } |
917 | 1070 | ||
918 | if (of_device_is_compatible(node, "nvidia,tegra20-hdmi")) { | 1071 | if (hdmi->config->has_hda) |
919 | /* | 1072 | tegra_hdmi_write_eld(hdmi); |
920 | * TODO: add ELD support | ||
921 | */ | ||
922 | } | ||
923 | 1073 | ||
924 | rekey = HDMI_REKEY_DEFAULT; | 1074 | rekey = HDMI_REKEY_DEFAULT; |
925 | value = HDMI_CTRL_REKEY(rekey); | 1075 | value = HDMI_CTRL_REKEY(rekey); |
@@ -931,20 +1081,17 @@ static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) | |||
931 | 1081 | ||
932 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_CTRL); | 1082 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_CTRL); |
933 | 1083 | ||
934 | if (hdmi->dvi) | 1084 | if (!hdmi->dvi) { |
935 | tegra_hdmi_writel(hdmi, 0x0, | 1085 | tegra_hdmi_setup_avi_infoframe(hdmi, mode); |
936 | HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | 1086 | tegra_hdmi_setup_audio_infoframe(hdmi); |
937 | else | ||
938 | tegra_hdmi_writel(hdmi, GENERIC_CTRL_AUDIO, | ||
939 | HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
940 | 1087 | ||
941 | tegra_hdmi_setup_avi_infoframe(hdmi, mode); | 1088 | if (hdmi->stereo) |
942 | tegra_hdmi_setup_audio_infoframe(hdmi); | 1089 | tegra_hdmi_setup_stereo_infoframe(hdmi); |
943 | tegra_hdmi_setup_stereo_infoframe(hdmi); | 1090 | } |
944 | 1091 | ||
945 | /* TMDS CONFIG */ | 1092 | /* TMDS CONFIG */ |
946 | for (i = 0; i < hdmi->config->num_tmds; i++) { | 1093 | for (i = 0; i < hdmi->config->num_tmds; i++) { |
947 | if (pclk <= hdmi->config->tmds[i].pclk) { | 1094 | if (hdmi->pixel_clock <= hdmi->config->tmds[i].pclk) { |
948 | tegra_hdmi_setup_tmds(hdmi, &hdmi->config->tmds[i]); | 1095 | tegra_hdmi_setup_tmds(hdmi, &hdmi->config->tmds[i]); |
949 | break; | 1096 | break; |
950 | } | 1097 | } |
@@ -1031,6 +1178,15 @@ static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) | |||
1031 | 1178 | ||
1032 | tegra_dc_commit(dc); | 1179 | tegra_dc_commit(dc); |
1033 | 1180 | ||
1181 | if (!hdmi->dvi) { | ||
1182 | tegra_hdmi_enable_avi_infoframe(hdmi); | ||
1183 | tegra_hdmi_enable_audio_infoframe(hdmi); | ||
1184 | tegra_hdmi_enable_audio(hdmi); | ||
1185 | |||
1186 | if (hdmi->stereo) | ||
1187 | tegra_hdmi_enable_stereo_infoframe(hdmi); | ||
1188 | } | ||
1189 | |||
1034 | /* TODO: add HDCP support */ | 1190 | /* TODO: add HDCP support */ |
1035 | } | 1191 | } |
1036 | 1192 | ||
@@ -1235,8 +1391,14 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data) | |||
1235 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG); | 1391 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG); |
1236 | DUMP_REG(HDMI_NV_PDISP_KEY_SKEY_INDEX); | 1392 | DUMP_REG(HDMI_NV_PDISP_KEY_SKEY_INDEX); |
1237 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_CNTRL0); | 1393 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_CNTRL0); |
1394 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_SPARE0); | ||
1395 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH0); | ||
1396 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH1); | ||
1238 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR); | 1397 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR); |
1239 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE); | 1398 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE); |
1399 | DUMP_REG(HDMI_NV_PDISP_INT_STATUS); | ||
1400 | DUMP_REG(HDMI_NV_PDISP_INT_MASK); | ||
1401 | DUMP_REG(HDMI_NV_PDISP_INT_ENABLE); | ||
1240 | DUMP_REG(HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT); | 1402 | DUMP_REG(HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT); |
1241 | 1403 | ||
1242 | #undef DUMP_REG | 1404 | #undef DUMP_REG |
@@ -1360,14 +1522,6 @@ static int tegra_hdmi_init(struct host1x_client *client) | |||
1360 | return err; | 1522 | return err; |
1361 | } | 1523 | } |
1362 | 1524 | ||
1363 | err = clk_prepare_enable(hdmi->clk); | ||
1364 | if (err < 0) { | ||
1365 | dev_err(hdmi->dev, "failed to enable clock: %d\n", err); | ||
1366 | return err; | ||
1367 | } | ||
1368 | |||
1369 | reset_control_deassert(hdmi->rst); | ||
1370 | |||
1371 | return 0; | 1525 | return 0; |
1372 | } | 1526 | } |
1373 | 1527 | ||
@@ -1377,9 +1531,6 @@ static int tegra_hdmi_exit(struct host1x_client *client) | |||
1377 | 1531 | ||
1378 | tegra_output_exit(&hdmi->output); | 1532 | tegra_output_exit(&hdmi->output); |
1379 | 1533 | ||
1380 | reset_control_assert(hdmi->rst); | ||
1381 | clk_disable_unprepare(hdmi->clk); | ||
1382 | |||
1383 | regulator_disable(hdmi->vdd); | 1534 | regulator_disable(hdmi->vdd); |
1384 | regulator_disable(hdmi->pll); | 1535 | regulator_disable(hdmi->pll); |
1385 | regulator_disable(hdmi->hdmi); | 1536 | regulator_disable(hdmi->hdmi); |
@@ -1401,6 +1552,8 @@ static const struct tegra_hdmi_config tegra20_hdmi_config = { | |||
1401 | .fuse_override_offset = HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT, | 1552 | .fuse_override_offset = HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT, |
1402 | .fuse_override_value = 1 << 31, | 1553 | .fuse_override_value = 1 << 31, |
1403 | .has_sor_io_peak_current = false, | 1554 | .has_sor_io_peak_current = false, |
1555 | .has_hda = false, | ||
1556 | .has_hbr = false, | ||
1404 | }; | 1557 | }; |
1405 | 1558 | ||
1406 | static const struct tegra_hdmi_config tegra30_hdmi_config = { | 1559 | static const struct tegra_hdmi_config tegra30_hdmi_config = { |
@@ -1409,6 +1562,8 @@ static const struct tegra_hdmi_config tegra30_hdmi_config = { | |||
1409 | .fuse_override_offset = HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT, | 1562 | .fuse_override_offset = HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT, |
1410 | .fuse_override_value = 1 << 31, | 1563 | .fuse_override_value = 1 << 31, |
1411 | .has_sor_io_peak_current = false, | 1564 | .has_sor_io_peak_current = false, |
1565 | .has_hda = true, | ||
1566 | .has_hbr = false, | ||
1412 | }; | 1567 | }; |
1413 | 1568 | ||
1414 | static const struct tegra_hdmi_config tegra114_hdmi_config = { | 1569 | static const struct tegra_hdmi_config tegra114_hdmi_config = { |
@@ -1417,6 +1572,8 @@ static const struct tegra_hdmi_config tegra114_hdmi_config = { | |||
1417 | .fuse_override_offset = HDMI_NV_PDISP_SOR_PAD_CTLS0, | 1572 | .fuse_override_offset = HDMI_NV_PDISP_SOR_PAD_CTLS0, |
1418 | .fuse_override_value = 1 << 31, | 1573 | .fuse_override_value = 1 << 31, |
1419 | .has_sor_io_peak_current = true, | 1574 | .has_sor_io_peak_current = true, |
1575 | .has_hda = true, | ||
1576 | .has_hbr = true, | ||
1420 | }; | 1577 | }; |
1421 | 1578 | ||
1422 | static const struct tegra_hdmi_config tegra124_hdmi_config = { | 1579 | static const struct tegra_hdmi_config tegra124_hdmi_config = { |
@@ -1425,6 +1582,8 @@ static const struct tegra_hdmi_config tegra124_hdmi_config = { | |||
1425 | .fuse_override_offset = HDMI_NV_PDISP_SOR_PAD_CTLS0, | 1582 | .fuse_override_offset = HDMI_NV_PDISP_SOR_PAD_CTLS0, |
1426 | .fuse_override_value = 1 << 31, | 1583 | .fuse_override_value = 1 << 31, |
1427 | .has_sor_io_peak_current = true, | 1584 | .has_sor_io_peak_current = true, |
1585 | .has_hda = true, | ||
1586 | .has_hbr = true, | ||
1428 | }; | 1587 | }; |
1429 | 1588 | ||
1430 | static const struct of_device_id tegra_hdmi_of_match[] = { | 1589 | static const struct of_device_id tegra_hdmi_of_match[] = { |
@@ -1436,6 +1595,67 @@ static const struct of_device_id tegra_hdmi_of_match[] = { | |||
1436 | }; | 1595 | }; |
1437 | MODULE_DEVICE_TABLE(of, tegra_hdmi_of_match); | 1596 | MODULE_DEVICE_TABLE(of, tegra_hdmi_of_match); |
1438 | 1597 | ||
1598 | static void hda_format_parse(unsigned int format, unsigned int *rate, | ||
1599 | unsigned int *channels) | ||
1600 | { | ||
1601 | unsigned int mul, div; | ||
1602 | |||
1603 | if (format & AC_FMT_BASE_44K) | ||
1604 | *rate = 44100; | ||
1605 | else | ||
1606 | *rate = 48000; | ||
1607 | |||
1608 | mul = (format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT; | ||
1609 | div = (format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT; | ||
1610 | |||
1611 | *rate = *rate * (mul + 1) / (div + 1); | ||
1612 | |||
1613 | *channels = (format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT; | ||
1614 | } | ||
1615 | |||
1616 | static irqreturn_t tegra_hdmi_irq(int irq, void *data) | ||
1617 | { | ||
1618 | struct tegra_hdmi *hdmi = data; | ||
1619 | u32 value; | ||
1620 | int err; | ||
1621 | |||
1622 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_INT_STATUS); | ||
1623 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_INT_STATUS); | ||
1624 | |||
1625 | if (value & INT_CODEC_SCRATCH0) { | ||
1626 | unsigned int format; | ||
1627 | u32 value; | ||
1628 | |||
1629 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH0); | ||
1630 | |||
1631 | if (value & SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID) { | ||
1632 | unsigned int sample_rate, channels; | ||
1633 | |||
1634 | format = value & SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK; | ||
1635 | |||
1636 | hda_format_parse(format, &sample_rate, &channels); | ||
1637 | |||
1638 | hdmi->audio_sample_rate = sample_rate; | ||
1639 | hdmi->audio_channels = channels; | ||
1640 | |||
1641 | err = tegra_hdmi_setup_audio(hdmi); | ||
1642 | if (err < 0) { | ||
1643 | tegra_hdmi_disable_audio_infoframe(hdmi); | ||
1644 | tegra_hdmi_disable_audio(hdmi); | ||
1645 | } else { | ||
1646 | tegra_hdmi_setup_audio_infoframe(hdmi); | ||
1647 | tegra_hdmi_enable_audio_infoframe(hdmi); | ||
1648 | tegra_hdmi_enable_audio(hdmi); | ||
1649 | } | ||
1650 | } else { | ||
1651 | tegra_hdmi_disable_audio_infoframe(hdmi); | ||
1652 | tegra_hdmi_disable_audio(hdmi); | ||
1653 | } | ||
1654 | } | ||
1655 | |||
1656 | return IRQ_HANDLED; | ||
1657 | } | ||
1658 | |||
1439 | static int tegra_hdmi_probe(struct platform_device *pdev) | 1659 | static int tegra_hdmi_probe(struct platform_device *pdev) |
1440 | { | 1660 | { |
1441 | const struct of_device_id *match; | 1661 | const struct of_device_id *match; |
@@ -1453,8 +1673,10 @@ static int tegra_hdmi_probe(struct platform_device *pdev) | |||
1453 | 1673 | ||
1454 | hdmi->config = match->data; | 1674 | hdmi->config = match->data; |
1455 | hdmi->dev = &pdev->dev; | 1675 | hdmi->dev = &pdev->dev; |
1676 | |||
1456 | hdmi->audio_source = AUTO; | 1677 | hdmi->audio_source = AUTO; |
1457 | hdmi->audio_freq = 44100; | 1678 | hdmi->audio_sample_rate = 48000; |
1679 | hdmi->audio_channels = 2; | ||
1458 | hdmi->stereo = false; | 1680 | hdmi->stereo = false; |
1459 | hdmi->dvi = false; | 1681 | hdmi->dvi = false; |
1460 | 1682 | ||
@@ -1515,6 +1737,17 @@ static int tegra_hdmi_probe(struct platform_device *pdev) | |||
1515 | 1737 | ||
1516 | hdmi->irq = err; | 1738 | hdmi->irq = err; |
1517 | 1739 | ||
1740 | err = devm_request_irq(hdmi->dev, hdmi->irq, tegra_hdmi_irq, 0, | ||
1741 | dev_name(hdmi->dev), hdmi); | ||
1742 | if (err < 0) { | ||
1743 | dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", | ||
1744 | hdmi->irq, err); | ||
1745 | return err; | ||
1746 | } | ||
1747 | |||
1748 | platform_set_drvdata(pdev, hdmi); | ||
1749 | pm_runtime_enable(&pdev->dev); | ||
1750 | |||
1518 | INIT_LIST_HEAD(&hdmi->client.list); | 1751 | INIT_LIST_HEAD(&hdmi->client.list); |
1519 | hdmi->client.ops = &hdmi_client_ops; | 1752 | hdmi->client.ops = &hdmi_client_ops; |
1520 | hdmi->client.dev = &pdev->dev; | 1753 | hdmi->client.dev = &pdev->dev; |
@@ -1526,8 +1759,6 @@ static int tegra_hdmi_probe(struct platform_device *pdev) | |||
1526 | return err; | 1759 | return err; |
1527 | } | 1760 | } |
1528 | 1761 | ||
1529 | platform_set_drvdata(pdev, hdmi); | ||
1530 | |||
1531 | return 0; | 1762 | return 0; |
1532 | } | 1763 | } |
1533 | 1764 | ||
@@ -1536,6 +1767,8 @@ static int tegra_hdmi_remove(struct platform_device *pdev) | |||
1536 | struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); | 1767 | struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); |
1537 | int err; | 1768 | int err; |
1538 | 1769 | ||
1770 | pm_runtime_disable(&pdev->dev); | ||
1771 | |||
1539 | err = host1x_client_unregister(&hdmi->client); | 1772 | err = host1x_client_unregister(&hdmi->client); |
1540 | if (err < 0) { | 1773 | if (err < 0) { |
1541 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", | 1774 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", |
@@ -1545,17 +1778,61 @@ static int tegra_hdmi_remove(struct platform_device *pdev) | |||
1545 | 1778 | ||
1546 | tegra_output_remove(&hdmi->output); | 1779 | tegra_output_remove(&hdmi->output); |
1547 | 1780 | ||
1548 | clk_disable_unprepare(hdmi->clk_parent); | 1781 | return 0; |
1782 | } | ||
1783 | |||
1784 | #ifdef CONFIG_PM | ||
1785 | static int tegra_hdmi_suspend(struct device *dev) | ||
1786 | { | ||
1787 | struct tegra_hdmi *hdmi = dev_get_drvdata(dev); | ||
1788 | int err; | ||
1789 | |||
1790 | err = reset_control_assert(hdmi->rst); | ||
1791 | if (err < 0) { | ||
1792 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
1793 | return err; | ||
1794 | } | ||
1795 | |||
1796 | usleep_range(1000, 2000); | ||
1797 | |||
1549 | clk_disable_unprepare(hdmi->clk); | 1798 | clk_disable_unprepare(hdmi->clk); |
1550 | 1799 | ||
1551 | return 0; | 1800 | return 0; |
1552 | } | 1801 | } |
1553 | 1802 | ||
1803 | static int tegra_hdmi_resume(struct device *dev) | ||
1804 | { | ||
1805 | struct tegra_hdmi *hdmi = dev_get_drvdata(dev); | ||
1806 | int err; | ||
1807 | |||
1808 | err = clk_prepare_enable(hdmi->clk); | ||
1809 | if (err < 0) { | ||
1810 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
1811 | return err; | ||
1812 | } | ||
1813 | |||
1814 | usleep_range(1000, 2000); | ||
1815 | |||
1816 | err = reset_control_deassert(hdmi->rst); | ||
1817 | if (err < 0) { | ||
1818 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
1819 | clk_disable_unprepare(hdmi->clk); | ||
1820 | return err; | ||
1821 | } | ||
1822 | |||
1823 | return 0; | ||
1824 | } | ||
1825 | #endif | ||
1826 | |||
1827 | static const struct dev_pm_ops tegra_hdmi_pm_ops = { | ||
1828 | SET_RUNTIME_PM_OPS(tegra_hdmi_suspend, tegra_hdmi_resume, NULL) | ||
1829 | }; | ||
1830 | |||
1554 | struct platform_driver tegra_hdmi_driver = { | 1831 | struct platform_driver tegra_hdmi_driver = { |
1555 | .driver = { | 1832 | .driver = { |
1556 | .name = "tegra-hdmi", | 1833 | .name = "tegra-hdmi", |
1557 | .owner = THIS_MODULE, | ||
1558 | .of_match_table = tegra_hdmi_of_match, | 1834 | .of_match_table = tegra_hdmi_of_match, |
1835 | .pm = &tegra_hdmi_pm_ops, | ||
1559 | }, | 1836 | }, |
1560 | .probe = tegra_hdmi_probe, | 1837 | .probe = tegra_hdmi_probe, |
1561 | .remove = tegra_hdmi_remove, | 1838 | .remove = tegra_hdmi_remove, |
diff --git a/drivers/gpu/drm/tegra/hdmi.h b/drivers/gpu/drm/tegra/hdmi.h index a882514389cd..2339f134a09a 100644 --- a/drivers/gpu/drm/tegra/hdmi.h +++ b/drivers/gpu/drm/tegra/hdmi.h | |||
@@ -468,9 +468,20 @@ | |||
468 | #define HDMI_NV_PDISP_KEY_SKEY_INDEX 0xa3 | 468 | #define HDMI_NV_PDISP_KEY_SKEY_INDEX 0xa3 |
469 | 469 | ||
470 | #define HDMI_NV_PDISP_SOR_AUDIO_CNTRL0 0xac | 470 | #define HDMI_NV_PDISP_SOR_AUDIO_CNTRL0 0xac |
471 | #define AUDIO_CNTRL0_INJECT_NULLSMPL (1 << 29) | 471 | #define SOR_AUDIO_CNTRL0_SOURCE_SELECT_AUTO (0 << 20) |
472 | #define SOR_AUDIO_CNTRL0_SOURCE_SELECT_SPDIF (1 << 20) | ||
473 | #define SOR_AUDIO_CNTRL0_SOURCE_SELECT_HDAL (2 << 20) | ||
474 | #define SOR_AUDIO_CNTRL0_INJECT_NULLSMPL (1 << 29) | ||
475 | #define HDMI_NV_PDISP_SOR_AUDIO_SPARE0 0xae | ||
476 | #define SOR_AUDIO_SPARE0_HBR_ENABLE (1 << 27) | ||
477 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH0 0xba | ||
478 | #define SOR_AUDIO_HDA_CODEC_SCRATCH0_VALID (1 << 30) | ||
479 | #define SOR_AUDIO_HDA_CODEC_SCRATCH0_FMT_MASK 0xffff | ||
480 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH1 0xbb | ||
472 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR 0xbc | 481 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR 0xbc |
473 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE 0xbd | 482 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE 0xbd |
483 | #define SOR_AUDIO_HDA_PRESENSE_VALID (1 << 1) | ||
484 | #define SOR_AUDIO_HDA_PRESENSE_PRESENT (1 << 0) | ||
474 | 485 | ||
475 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320 0xbf | 486 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320 0xbf |
476 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441 0xc0 | 487 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441 0xc0 |
@@ -481,6 +492,14 @@ | |||
481 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920 0xc5 | 492 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920 0xc5 |
482 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_DEFAULT 0xc5 | 493 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_DEFAULT 0xc5 |
483 | 494 | ||
495 | #define HDMI_NV_PDISP_INT_STATUS 0xcc | ||
496 | #define INT_SCRATCH (1 << 3) | ||
497 | #define INT_CP_REQUEST (1 << 2) | ||
498 | #define INT_CODEC_SCRATCH1 (1 << 1) | ||
499 | #define INT_CODEC_SCRATCH0 (1 << 0) | ||
500 | #define HDMI_NV_PDISP_INT_MASK 0xcd | ||
501 | #define HDMI_NV_PDISP_INT_ENABLE 0xce | ||
502 | |||
484 | #define HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT 0xd1 | 503 | #define HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT 0xd1 |
485 | #define PEAK_CURRENT_LANE0(x) (((x) & 0x7f) << 0) | 504 | #define PEAK_CURRENT_LANE0(x) (((x) & 0x7f) << 0) |
486 | #define PEAK_CURRENT_LANE1(x) (((x) & 0x7f) << 8) | 505 | #define PEAK_CURRENT_LANE1(x) (((x) & 0x7f) << 8) |
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 1480f6aaffe4..595d1ec3e02e 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c | |||
@@ -36,6 +36,7 @@ int tegra_output_connector_get_modes(struct drm_connector *connector) | |||
36 | 36 | ||
37 | if (edid) { | 37 | if (edid) { |
38 | err = drm_add_edid_modes(connector, edid); | 38 | err = drm_add_edid_modes(connector, edid); |
39 | drm_edid_to_eld(connector, edid); | ||
39 | kfree(edid); | 40 | kfree(edid); |
40 | } | 41 | } |
41 | 42 | ||
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 34958d71284b..74d0540b8d4c 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c | |||
@@ -7,11 +7,13 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
10 | #include <linux/clk-provider.h> | ||
10 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
11 | #include <linux/gpio.h> | 12 | #include <linux/gpio.h> |
12 | #include <linux/io.h> | 13 | #include <linux/io.h> |
13 | #include <linux/of_device.h> | 14 | #include <linux/of_device.h> |
14 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/pm_runtime.h> | ||
15 | #include <linux/regulator/consumer.h> | 17 | #include <linux/regulator/consumer.h> |
16 | #include <linux/reset.h> | 18 | #include <linux/reset.h> |
17 | 19 | ||
@@ -149,6 +151,8 @@ struct tegra_sor_soc { | |||
149 | 151 | ||
150 | const struct tegra_sor_hdmi_settings *settings; | 152 | const struct tegra_sor_hdmi_settings *settings; |
151 | unsigned int num_settings; | 153 | unsigned int num_settings; |
154 | |||
155 | const u8 *xbar_cfg; | ||
152 | }; | 156 | }; |
153 | 157 | ||
154 | struct tegra_sor; | 158 | struct tegra_sor; |
@@ -169,7 +173,9 @@ struct tegra_sor { | |||
169 | 173 | ||
170 | struct reset_control *rst; | 174 | struct reset_control *rst; |
171 | struct clk *clk_parent; | 175 | struct clk *clk_parent; |
176 | struct clk *clk_brick; | ||
172 | struct clk *clk_safe; | 177 | struct clk *clk_safe; |
178 | struct clk *clk_src; | ||
173 | struct clk *clk_dp; | 179 | struct clk *clk_dp; |
174 | struct clk *clk; | 180 | struct clk *clk; |
175 | 181 | ||
@@ -190,6 +196,18 @@ struct tegra_sor { | |||
190 | struct regulator *hdmi_supply; | 196 | struct regulator *hdmi_supply; |
191 | }; | 197 | }; |
192 | 198 | ||
199 | struct tegra_sor_state { | ||
200 | struct drm_connector_state base; | ||
201 | |||
202 | unsigned int bpc; | ||
203 | }; | ||
204 | |||
205 | static inline struct tegra_sor_state * | ||
206 | to_sor_state(struct drm_connector_state *state) | ||
207 | { | ||
208 | return container_of(state, struct tegra_sor_state, base); | ||
209 | } | ||
210 | |||
193 | struct tegra_sor_config { | 211 | struct tegra_sor_config { |
194 | u32 bits_per_pixel; | 212 | u32 bits_per_pixel; |
195 | 213 | ||
@@ -225,6 +243,118 @@ static inline void tegra_sor_writel(struct tegra_sor *sor, u32 value, | |||
225 | writel(value, sor->regs + (offset << 2)); | 243 | writel(value, sor->regs + (offset << 2)); |
226 | } | 244 | } |
227 | 245 | ||
246 | static int tegra_sor_set_parent_clock(struct tegra_sor *sor, struct clk *parent) | ||
247 | { | ||
248 | int err; | ||
249 | |||
250 | clk_disable_unprepare(sor->clk); | ||
251 | |||
252 | err = clk_set_parent(sor->clk, parent); | ||
253 | if (err < 0) | ||
254 | return err; | ||
255 | |||
256 | err = clk_prepare_enable(sor->clk); | ||
257 | if (err < 0) | ||
258 | return err; | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | struct tegra_clk_sor_brick { | ||
264 | struct clk_hw hw; | ||
265 | struct tegra_sor *sor; | ||
266 | }; | ||
267 | |||
268 | static inline struct tegra_clk_sor_brick *to_brick(struct clk_hw *hw) | ||
269 | { | ||
270 | return container_of(hw, struct tegra_clk_sor_brick, hw); | ||
271 | } | ||
272 | |||
273 | static const char * const tegra_clk_sor_brick_parents[] = { | ||
274 | "pll_d2_out0", "pll_dp" | ||
275 | }; | ||
276 | |||
277 | static int tegra_clk_sor_brick_set_parent(struct clk_hw *hw, u8 index) | ||
278 | { | ||
279 | struct tegra_clk_sor_brick *brick = to_brick(hw); | ||
280 | struct tegra_sor *sor = brick->sor; | ||
281 | u32 value; | ||
282 | |||
283 | value = tegra_sor_readl(sor, SOR_CLK_CNTRL); | ||
284 | value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; | ||
285 | |||
286 | switch (index) { | ||
287 | case 0: | ||
288 | value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK; | ||
289 | break; | ||
290 | |||
291 | case 1: | ||
292 | value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; | ||
293 | break; | ||
294 | } | ||
295 | |||
296 | tegra_sor_writel(sor, value, SOR_CLK_CNTRL); | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static u8 tegra_clk_sor_brick_get_parent(struct clk_hw *hw) | ||
302 | { | ||
303 | struct tegra_clk_sor_brick *brick = to_brick(hw); | ||
304 | struct tegra_sor *sor = brick->sor; | ||
305 | u8 parent = U8_MAX; | ||
306 | u32 value; | ||
307 | |||
308 | value = tegra_sor_readl(sor, SOR_CLK_CNTRL); | ||
309 | |||
310 | switch (value & SOR_CLK_CNTRL_DP_CLK_SEL_MASK) { | ||
311 | case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK: | ||
312 | case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK: | ||
313 | parent = 0; | ||
314 | break; | ||
315 | |||
316 | case SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK: | ||
317 | case SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK: | ||
318 | parent = 1; | ||
319 | break; | ||
320 | } | ||
321 | |||
322 | return parent; | ||
323 | } | ||
324 | |||
325 | static const struct clk_ops tegra_clk_sor_brick_ops = { | ||
326 | .set_parent = tegra_clk_sor_brick_set_parent, | ||
327 | .get_parent = tegra_clk_sor_brick_get_parent, | ||
328 | }; | ||
329 | |||
330 | static struct clk *tegra_clk_sor_brick_register(struct tegra_sor *sor, | ||
331 | const char *name) | ||
332 | { | ||
333 | struct tegra_clk_sor_brick *brick; | ||
334 | struct clk_init_data init; | ||
335 | struct clk *clk; | ||
336 | |||
337 | brick = devm_kzalloc(sor->dev, sizeof(*brick), GFP_KERNEL); | ||
338 | if (!brick) | ||
339 | return ERR_PTR(-ENOMEM); | ||
340 | |||
341 | brick->sor = sor; | ||
342 | |||
343 | init.name = name; | ||
344 | init.flags = 0; | ||
345 | init.parent_names = tegra_clk_sor_brick_parents; | ||
346 | init.num_parents = ARRAY_SIZE(tegra_clk_sor_brick_parents); | ||
347 | init.ops = &tegra_clk_sor_brick_ops; | ||
348 | |||
349 | brick->hw.init = &init; | ||
350 | |||
351 | clk = devm_clk_register(sor->dev, &brick->hw); | ||
352 | if (IS_ERR(clk)) | ||
353 | kfree(brick); | ||
354 | |||
355 | return clk; | ||
356 | } | ||
357 | |||
228 | static int tegra_sor_dp_train_fast(struct tegra_sor *sor, | 358 | static int tegra_sor_dp_train_fast(struct tegra_sor *sor, |
229 | struct drm_dp_link *link) | 359 | struct drm_dp_link *link) |
230 | { | 360 | { |
@@ -569,10 +699,10 @@ static int tegra_sor_compute_params(struct tegra_sor *sor, | |||
569 | return false; | 699 | return false; |
570 | } | 700 | } |
571 | 701 | ||
572 | static int tegra_sor_calc_config(struct tegra_sor *sor, | 702 | static int tegra_sor_compute_config(struct tegra_sor *sor, |
573 | const struct drm_display_mode *mode, | 703 | const struct drm_display_mode *mode, |
574 | struct tegra_sor_config *config, | 704 | struct tegra_sor_config *config, |
575 | struct drm_dp_link *link) | 705 | struct drm_dp_link *link) |
576 | { | 706 | { |
577 | const u64 f = 100000, link_rate = link->rate * 1000; | 707 | const u64 f = 100000, link_rate = link->rate * 1000; |
578 | const u64 pclk = mode->clock * 1000; | 708 | const u64 pclk = mode->clock * 1000; |
@@ -661,6 +791,135 @@ static int tegra_sor_calc_config(struct tegra_sor *sor, | |||
661 | return 0; | 791 | return 0; |
662 | } | 792 | } |
663 | 793 | ||
794 | static void tegra_sor_apply_config(struct tegra_sor *sor, | ||
795 | const struct tegra_sor_config *config) | ||
796 | { | ||
797 | u32 value; | ||
798 | |||
799 | value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); | ||
800 | value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; | ||
801 | value |= SOR_DP_LINKCTL_TU_SIZE(config->tu_size); | ||
802 | tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); | ||
803 | |||
804 | value = tegra_sor_readl(sor, SOR_DP_CONFIG0); | ||
805 | value &= ~SOR_DP_CONFIG_WATERMARK_MASK; | ||
806 | value |= SOR_DP_CONFIG_WATERMARK(config->watermark); | ||
807 | |||
808 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; | ||
809 | value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(config->active_count); | ||
810 | |||
811 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; | ||
812 | value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(config->active_frac); | ||
813 | |||
814 | if (config->active_polarity) | ||
815 | value |= SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; | ||
816 | else | ||
817 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; | ||
818 | |||
819 | value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; | ||
820 | value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; | ||
821 | tegra_sor_writel(sor, value, SOR_DP_CONFIG0); | ||
822 | |||
823 | value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); | ||
824 | value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; | ||
825 | value |= config->hblank_symbols & 0xffff; | ||
826 | tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); | ||
827 | |||
828 | value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); | ||
829 | value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; | ||
830 | value |= config->vblank_symbols & 0xffff; | ||
831 | tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); | ||
832 | } | ||
833 | |||
834 | static void tegra_sor_mode_set(struct tegra_sor *sor, | ||
835 | const struct drm_display_mode *mode, | ||
836 | struct tegra_sor_state *state) | ||
837 | { | ||
838 | struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc); | ||
839 | unsigned int vbe, vse, hbe, hse, vbs, hbs; | ||
840 | u32 value; | ||
841 | |||
842 | value = tegra_sor_readl(sor, SOR_STATE1); | ||
843 | value &= ~SOR_STATE_ASY_PIXELDEPTH_MASK; | ||
844 | value &= ~SOR_STATE_ASY_CRC_MODE_MASK; | ||
845 | value &= ~SOR_STATE_ASY_OWNER_MASK; | ||
846 | |||
847 | value |= SOR_STATE_ASY_CRC_MODE_COMPLETE | | ||
848 | SOR_STATE_ASY_OWNER(dc->pipe + 1); | ||
849 | |||
850 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
851 | value &= ~SOR_STATE_ASY_HSYNCPOL; | ||
852 | |||
853 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
854 | value |= SOR_STATE_ASY_HSYNCPOL; | ||
855 | |||
856 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
857 | value &= ~SOR_STATE_ASY_VSYNCPOL; | ||
858 | |||
859 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
860 | value |= SOR_STATE_ASY_VSYNCPOL; | ||
861 | |||
862 | switch (state->bpc) { | ||
863 | case 16: | ||
864 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_48_444; | ||
865 | break; | ||
866 | |||
867 | case 12: | ||
868 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_36_444; | ||
869 | break; | ||
870 | |||
871 | case 10: | ||
872 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_30_444; | ||
873 | break; | ||
874 | |||
875 | case 8: | ||
876 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; | ||
877 | break; | ||
878 | |||
879 | case 6: | ||
880 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; | ||
881 | break; | ||
882 | |||
883 | default: | ||
884 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; | ||
885 | break; | ||
886 | } | ||
887 | |||
888 | tegra_sor_writel(sor, value, SOR_STATE1); | ||
889 | |||
890 | /* | ||
891 | * TODO: The video timing programming below doesn't seem to match the | ||
892 | * register definitions. | ||
893 | */ | ||
894 | |||
895 | value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); | ||
896 | tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe)); | ||
897 | |||
898 | /* sync end = sync width - 1 */ | ||
899 | vse = mode->vsync_end - mode->vsync_start - 1; | ||
900 | hse = mode->hsync_end - mode->hsync_start - 1; | ||
901 | |||
902 | value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); | ||
903 | tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe)); | ||
904 | |||
905 | /* blank end = sync end + back porch */ | ||
906 | vbe = vse + (mode->vtotal - mode->vsync_end); | ||
907 | hbe = hse + (mode->htotal - mode->hsync_end); | ||
908 | |||
909 | value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); | ||
910 | tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe)); | ||
911 | |||
912 | /* blank start = blank end + active */ | ||
913 | vbs = vbe + mode->vdisplay; | ||
914 | hbs = hbe + mode->hdisplay; | ||
915 | |||
916 | value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); | ||
917 | tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe)); | ||
918 | |||
919 | /* XXX interlacing support */ | ||
920 | tegra_sor_writel(sor, 0x001, SOR_HEAD_STATE5(dc->pipe)); | ||
921 | } | ||
922 | |||
664 | static int tegra_sor_detach(struct tegra_sor *sor) | 923 | static int tegra_sor_detach(struct tegra_sor *sor) |
665 | { | 924 | { |
666 | unsigned long value, timeout; | 925 | unsigned long value, timeout; |
@@ -733,7 +992,8 @@ static int tegra_sor_power_down(struct tegra_sor *sor) | |||
733 | if ((value & SOR_PWR_TRIGGER) != 0) | 992 | if ((value & SOR_PWR_TRIGGER) != 0) |
734 | return -ETIMEDOUT; | 993 | return -ETIMEDOUT; |
735 | 994 | ||
736 | err = clk_set_parent(sor->clk, sor->clk_safe); | 995 | /* switch to safe parent clock */ |
996 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | ||
737 | if (err < 0) | 997 | if (err < 0) |
738 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); | 998 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); |
739 | 999 | ||
@@ -1038,6 +1298,22 @@ static void tegra_sor_debugfs_exit(struct tegra_sor *sor) | |||
1038 | sor->debugfs = NULL; | 1298 | sor->debugfs = NULL; |
1039 | } | 1299 | } |
1040 | 1300 | ||
1301 | static void tegra_sor_connector_reset(struct drm_connector *connector) | ||
1302 | { | ||
1303 | struct tegra_sor_state *state; | ||
1304 | |||
1305 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
1306 | if (!state) | ||
1307 | return; | ||
1308 | |||
1309 | if (connector->state) { | ||
1310 | __drm_atomic_helper_connector_destroy_state(connector->state); | ||
1311 | kfree(connector->state); | ||
1312 | } | ||
1313 | |||
1314 | __drm_atomic_helper_connector_reset(connector, &state->base); | ||
1315 | } | ||
1316 | |||
1041 | static enum drm_connector_status | 1317 | static enum drm_connector_status |
1042 | tegra_sor_connector_detect(struct drm_connector *connector, bool force) | 1318 | tegra_sor_connector_detect(struct drm_connector *connector, bool force) |
1043 | { | 1319 | { |
@@ -1050,13 +1326,28 @@ tegra_sor_connector_detect(struct drm_connector *connector, bool force) | |||
1050 | return tegra_output_connector_detect(connector, force); | 1326 | return tegra_output_connector_detect(connector, force); |
1051 | } | 1327 | } |
1052 | 1328 | ||
1329 | static struct drm_connector_state * | ||
1330 | tegra_sor_connector_duplicate_state(struct drm_connector *connector) | ||
1331 | { | ||
1332 | struct tegra_sor_state *state = to_sor_state(connector->state); | ||
1333 | struct tegra_sor_state *copy; | ||
1334 | |||
1335 | copy = kmemdup(state, sizeof(*state), GFP_KERNEL); | ||
1336 | if (!copy) | ||
1337 | return NULL; | ||
1338 | |||
1339 | __drm_atomic_helper_connector_duplicate_state(connector, ©->base); | ||
1340 | |||
1341 | return ©->base; | ||
1342 | } | ||
1343 | |||
1053 | static const struct drm_connector_funcs tegra_sor_connector_funcs = { | 1344 | static const struct drm_connector_funcs tegra_sor_connector_funcs = { |
1054 | .dpms = drm_atomic_helper_connector_dpms, | 1345 | .dpms = drm_atomic_helper_connector_dpms, |
1055 | .reset = drm_atomic_helper_connector_reset, | 1346 | .reset = tegra_sor_connector_reset, |
1056 | .detect = tegra_sor_connector_detect, | 1347 | .detect = tegra_sor_connector_detect, |
1057 | .fill_modes = drm_helper_probe_single_connector_modes, | 1348 | .fill_modes = drm_helper_probe_single_connector_modes, |
1058 | .destroy = tegra_output_connector_destroy, | 1349 | .destroy = tegra_output_connector_destroy, |
1059 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | 1350 | .atomic_duplicate_state = tegra_sor_connector_duplicate_state, |
1060 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 1351 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
1061 | }; | 1352 | }; |
1062 | 1353 | ||
@@ -1081,6 +1372,10 @@ static enum drm_mode_status | |||
1081 | tegra_sor_connector_mode_valid(struct drm_connector *connector, | 1372 | tegra_sor_connector_mode_valid(struct drm_connector *connector, |
1082 | struct drm_display_mode *mode) | 1373 | struct drm_display_mode *mode) |
1083 | { | 1374 | { |
1375 | /* HDMI 2.0 modes are not yet supported */ | ||
1376 | if (mode->clock > 340000) | ||
1377 | return MODE_NOCLOCK; | ||
1378 | |||
1084 | return MODE_OK; | 1379 | return MODE_OK; |
1085 | } | 1380 | } |
1086 | 1381 | ||
@@ -1140,8 +1435,7 @@ static void tegra_sor_edp_disable(struct drm_encoder *encoder) | |||
1140 | if (output->panel) | 1435 | if (output->panel) |
1141 | drm_panel_unprepare(output->panel); | 1436 | drm_panel_unprepare(output->panel); |
1142 | 1437 | ||
1143 | reset_control_assert(sor->rst); | 1438 | pm_runtime_put(sor->dev); |
1144 | clk_disable_unprepare(sor->clk); | ||
1145 | } | 1439 | } |
1146 | 1440 | ||
1147 | #if 0 | 1441 | #if 0 |
@@ -1191,19 +1485,18 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1191 | struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; | 1485 | struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; |
1192 | struct tegra_output *output = encoder_to_output(encoder); | 1486 | struct tegra_output *output = encoder_to_output(encoder); |
1193 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); | 1487 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); |
1194 | unsigned int vbe, vse, hbe, hse, vbs, hbs, i; | ||
1195 | struct tegra_sor *sor = to_sor(output); | 1488 | struct tegra_sor *sor = to_sor(output); |
1196 | struct tegra_sor_config config; | 1489 | struct tegra_sor_config config; |
1490 | struct tegra_sor_state *state; | ||
1197 | struct drm_dp_link link; | 1491 | struct drm_dp_link link; |
1198 | u8 rate, lanes; | 1492 | u8 rate, lanes; |
1493 | unsigned int i; | ||
1199 | int err = 0; | 1494 | int err = 0; |
1200 | u32 value; | 1495 | u32 value; |
1201 | 1496 | ||
1202 | err = clk_prepare_enable(sor->clk); | 1497 | state = to_sor_state(output->connector.state); |
1203 | if (err < 0) | ||
1204 | dev_err(sor->dev, "failed to enable clock: %d\n", err); | ||
1205 | 1498 | ||
1206 | reset_control_deassert(sor->rst); | 1499 | pm_runtime_get_sync(sor->dev); |
1207 | 1500 | ||
1208 | if (output->panel) | 1501 | if (output->panel) |
1209 | drm_panel_prepare(output->panel); | 1502 | drm_panel_prepare(output->panel); |
@@ -1218,17 +1511,17 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1218 | return; | 1511 | return; |
1219 | } | 1512 | } |
1220 | 1513 | ||
1221 | err = clk_set_parent(sor->clk, sor->clk_safe); | 1514 | /* switch to safe parent clock */ |
1515 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | ||
1222 | if (err < 0) | 1516 | if (err < 0) |
1223 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); | 1517 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); |
1224 | 1518 | ||
1225 | memset(&config, 0, sizeof(config)); | 1519 | memset(&config, 0, sizeof(config)); |
1226 | config.bits_per_pixel = output->connector.display_info.bpc * 3; | 1520 | config.bits_per_pixel = state->bpc * 3; |
1227 | 1521 | ||
1228 | err = tegra_sor_calc_config(sor, mode, &config, &link); | 1522 | err = tegra_sor_compute_config(sor, mode, &config, &link); |
1229 | if (err < 0) | 1523 | if (err < 0) |
1230 | dev_err(sor->dev, "failed to compute link configuration: %d\n", | 1524 | dev_err(sor->dev, "failed to compute configuration: %d\n", err); |
1231 | err); | ||
1232 | 1525 | ||
1233 | value = tegra_sor_readl(sor, SOR_CLK_CNTRL); | 1526 | value = tegra_sor_readl(sor, SOR_CLK_CNTRL); |
1234 | value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; | 1527 | value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; |
@@ -1325,10 +1618,18 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1325 | value &= ~SOR_PLL2_PORT_POWERDOWN; | 1618 | value &= ~SOR_PLL2_PORT_POWERDOWN; |
1326 | tegra_sor_writel(sor, value, SOR_PLL2); | 1619 | tegra_sor_writel(sor, value, SOR_PLL2); |
1327 | 1620 | ||
1328 | /* switch to DP clock */ | 1621 | /* XXX not in TRM */ |
1329 | err = clk_set_parent(sor->clk, sor->clk_dp); | 1622 | for (value = 0, i = 0; i < 5; i++) |
1623 | value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) | | ||
1624 | SOR_XBAR_CTRL_LINK1_XSEL(i, i); | ||
1625 | |||
1626 | tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); | ||
1627 | tegra_sor_writel(sor, value, SOR_XBAR_CTRL); | ||
1628 | |||
1629 | /* switch to DP parent clock */ | ||
1630 | err = tegra_sor_set_parent_clock(sor, sor->clk_dp); | ||
1330 | if (err < 0) | 1631 | if (err < 0) |
1331 | dev_err(sor->dev, "failed to set DP parent clock: %d\n", err); | 1632 | dev_err(sor->dev, "failed to set parent clock: %d\n", err); |
1332 | 1633 | ||
1333 | /* power DP lanes */ | 1634 | /* power DP lanes */ |
1334 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); | 1635 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); |
@@ -1374,13 +1675,11 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1374 | value |= drm_dp_link_rate_to_bw_code(link.rate) << 2; | 1675 | value |= drm_dp_link_rate_to_bw_code(link.rate) << 2; |
1375 | tegra_sor_writel(sor, value, SOR_CLK_CNTRL); | 1676 | tegra_sor_writel(sor, value, SOR_CLK_CNTRL); |
1376 | 1677 | ||
1377 | /* set linkctl */ | 1678 | tegra_sor_apply_config(sor, &config); |
1679 | |||
1680 | /* enable link */ | ||
1378 | value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); | 1681 | value = tegra_sor_readl(sor, SOR_DP_LINKCTL0); |
1379 | value |= SOR_DP_LINKCTL_ENABLE; | 1682 | value |= SOR_DP_LINKCTL_ENABLE; |
1380 | |||
1381 | value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; | ||
1382 | value |= SOR_DP_LINKCTL_TU_SIZE(config.tu_size); | ||
1383 | |||
1384 | value |= SOR_DP_LINKCTL_ENHANCED_FRAME; | 1683 | value |= SOR_DP_LINKCTL_ENHANCED_FRAME; |
1385 | tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); | 1684 | tegra_sor_writel(sor, value, SOR_DP_LINKCTL0); |
1386 | 1685 | ||
@@ -1393,35 +1692,6 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1393 | 1692 | ||
1394 | tegra_sor_writel(sor, value, SOR_DP_TPG); | 1693 | tegra_sor_writel(sor, value, SOR_DP_TPG); |
1395 | 1694 | ||
1396 | value = tegra_sor_readl(sor, SOR_DP_CONFIG0); | ||
1397 | value &= ~SOR_DP_CONFIG_WATERMARK_MASK; | ||
1398 | value |= SOR_DP_CONFIG_WATERMARK(config.watermark); | ||
1399 | |||
1400 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; | ||
1401 | value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(config.active_count); | ||
1402 | |||
1403 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; | ||
1404 | value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(config.active_frac); | ||
1405 | |||
1406 | if (config.active_polarity) | ||
1407 | value |= SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; | ||
1408 | else | ||
1409 | value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; | ||
1410 | |||
1411 | value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; | ||
1412 | value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; | ||
1413 | tegra_sor_writel(sor, value, SOR_DP_CONFIG0); | ||
1414 | |||
1415 | value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); | ||
1416 | value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; | ||
1417 | value |= config.hblank_symbols & 0xffff; | ||
1418 | tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); | ||
1419 | |||
1420 | value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); | ||
1421 | value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; | ||
1422 | value |= config.vblank_symbols & 0xffff; | ||
1423 | tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); | ||
1424 | |||
1425 | /* enable pad calibration logic */ | 1695 | /* enable pad calibration logic */ |
1426 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); | 1696 | value = tegra_sor_readl(sor, SOR_DP_PADCTL0); |
1427 | value |= SOR_DP_PADCTL_PAD_CAL_PD; | 1697 | value |= SOR_DP_PADCTL_PAD_CAL_PD; |
@@ -1477,75 +1747,19 @@ static void tegra_sor_edp_enable(struct drm_encoder *encoder) | |||
1477 | if (err < 0) | 1747 | if (err < 0) |
1478 | dev_err(sor->dev, "failed to power up SOR: %d\n", err); | 1748 | dev_err(sor->dev, "failed to power up SOR: %d\n", err); |
1479 | 1749 | ||
1480 | /* | ||
1481 | * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete | ||
1482 | * raster, associate with display controller) | ||
1483 | */ | ||
1484 | value = SOR_STATE_ASY_PROTOCOL_DP_A | | ||
1485 | SOR_STATE_ASY_CRC_MODE_COMPLETE | | ||
1486 | SOR_STATE_ASY_OWNER(dc->pipe + 1); | ||
1487 | |||
1488 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
1489 | value &= ~SOR_STATE_ASY_HSYNCPOL; | ||
1490 | |||
1491 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
1492 | value |= SOR_STATE_ASY_HSYNCPOL; | ||
1493 | |||
1494 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
1495 | value &= ~SOR_STATE_ASY_VSYNCPOL; | ||
1496 | |||
1497 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
1498 | value |= SOR_STATE_ASY_VSYNCPOL; | ||
1499 | |||
1500 | switch (config.bits_per_pixel) { | ||
1501 | case 24: | ||
1502 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; | ||
1503 | break; | ||
1504 | |||
1505 | case 18: | ||
1506 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; | ||
1507 | break; | ||
1508 | |||
1509 | default: | ||
1510 | BUG(); | ||
1511 | break; | ||
1512 | } | ||
1513 | |||
1514 | tegra_sor_writel(sor, value, SOR_STATE1); | ||
1515 | |||
1516 | /* | ||
1517 | * TODO: The video timing programming below doesn't seem to match the | ||
1518 | * register definitions. | ||
1519 | */ | ||
1520 | |||
1521 | value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); | ||
1522 | tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe)); | ||
1523 | |||
1524 | vse = mode->vsync_end - mode->vsync_start - 1; | ||
1525 | hse = mode->hsync_end - mode->hsync_start - 1; | ||
1526 | |||
1527 | value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); | ||
1528 | tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe)); | ||
1529 | |||
1530 | vbe = vse + (mode->vsync_start - mode->vdisplay); | ||
1531 | hbe = hse + (mode->hsync_start - mode->hdisplay); | ||
1532 | |||
1533 | value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); | ||
1534 | tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe)); | ||
1535 | |||
1536 | vbs = vbe + mode->vdisplay; | ||
1537 | hbs = hbe + mode->hdisplay; | ||
1538 | |||
1539 | value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); | ||
1540 | tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe)); | ||
1541 | |||
1542 | tegra_sor_writel(sor, 0x1, SOR_HEAD_STATE5(dc->pipe)); | ||
1543 | |||
1544 | /* CSTM (LVDS, link A/B, upper) */ | 1750 | /* CSTM (LVDS, link A/B, upper) */ |
1545 | value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B | | 1751 | value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B | |
1546 | SOR_CSTM_UPPER; | 1752 | SOR_CSTM_UPPER; |
1547 | tegra_sor_writel(sor, value, SOR_CSTM); | 1753 | tegra_sor_writel(sor, value, SOR_CSTM); |
1548 | 1754 | ||
1755 | /* use DP-A protocol */ | ||
1756 | value = tegra_sor_readl(sor, SOR_STATE1); | ||
1757 | value &= ~SOR_STATE_ASY_PROTOCOL_MASK; | ||
1758 | value |= SOR_STATE_ASY_PROTOCOL_DP_A; | ||
1759 | tegra_sor_writel(sor, value, SOR_STATE1); | ||
1760 | |||
1761 | tegra_sor_mode_set(sor, mode, state); | ||
1762 | |||
1549 | /* PWM setup */ | 1763 | /* PWM setup */ |
1550 | err = tegra_sor_setup_pwm(sor, 250); | 1764 | err = tegra_sor_setup_pwm(sor, 250); |
1551 | if (err < 0) | 1765 | if (err < 0) |
@@ -1577,11 +1791,15 @@ tegra_sor_encoder_atomic_check(struct drm_encoder *encoder, | |||
1577 | struct drm_connector_state *conn_state) | 1791 | struct drm_connector_state *conn_state) |
1578 | { | 1792 | { |
1579 | struct tegra_output *output = encoder_to_output(encoder); | 1793 | struct tegra_output *output = encoder_to_output(encoder); |
1794 | struct tegra_sor_state *state = to_sor_state(conn_state); | ||
1580 | struct tegra_dc *dc = to_tegra_dc(conn_state->crtc); | 1795 | struct tegra_dc *dc = to_tegra_dc(conn_state->crtc); |
1581 | unsigned long pclk = crtc_state->mode.clock * 1000; | 1796 | unsigned long pclk = crtc_state->mode.clock * 1000; |
1582 | struct tegra_sor *sor = to_sor(output); | 1797 | struct tegra_sor *sor = to_sor(output); |
1798 | struct drm_display_info *info; | ||
1583 | int err; | 1799 | int err; |
1584 | 1800 | ||
1801 | info = &output->connector.display_info; | ||
1802 | |||
1585 | err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, | 1803 | err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent, |
1586 | pclk, 0); | 1804 | pclk, 0); |
1587 | if (err < 0) { | 1805 | if (err < 0) { |
@@ -1589,6 +1807,18 @@ tegra_sor_encoder_atomic_check(struct drm_encoder *encoder, | |||
1589 | return err; | 1807 | return err; |
1590 | } | 1808 | } |
1591 | 1809 | ||
1810 | switch (info->bpc) { | ||
1811 | case 8: | ||
1812 | case 6: | ||
1813 | state->bpc = info->bpc; | ||
1814 | break; | ||
1815 | |||
1816 | default: | ||
1817 | DRM_DEBUG_KMS("%u bits-per-color not supported\n", info->bpc); | ||
1818 | state->bpc = 8; | ||
1819 | break; | ||
1820 | } | ||
1821 | |||
1592 | return 0; | 1822 | return 0; |
1593 | } | 1823 | } |
1594 | 1824 | ||
@@ -1751,9 +1981,7 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) | |||
1751 | if (err < 0) | 1981 | if (err < 0) |
1752 | dev_err(sor->dev, "failed to power off HDMI rail: %d\n", err); | 1982 | dev_err(sor->dev, "failed to power off HDMI rail: %d\n", err); |
1753 | 1983 | ||
1754 | reset_control_assert(sor->rst); | 1984 | pm_runtime_put(sor->dev); |
1755 | usleep_range(1000, 2000); | ||
1756 | clk_disable_unprepare(sor->clk); | ||
1757 | } | 1985 | } |
1758 | 1986 | ||
1759 | static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | 1987 | static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) |
@@ -1761,26 +1989,21 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
1761 | struct tegra_output *output = encoder_to_output(encoder); | 1989 | struct tegra_output *output = encoder_to_output(encoder); |
1762 | unsigned int h_ref_to_sync = 1, pulse_start, max_ac; | 1990 | unsigned int h_ref_to_sync = 1, pulse_start, max_ac; |
1763 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); | 1991 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); |
1764 | unsigned int vbe, vse, hbe, hse, vbs, hbs, div; | ||
1765 | struct tegra_sor_hdmi_settings *settings; | 1992 | struct tegra_sor_hdmi_settings *settings; |
1766 | struct tegra_sor *sor = to_sor(output); | 1993 | struct tegra_sor *sor = to_sor(output); |
1994 | struct tegra_sor_state *state; | ||
1767 | struct drm_display_mode *mode; | 1995 | struct drm_display_mode *mode; |
1768 | struct drm_display_info *info; | 1996 | unsigned int div, i; |
1769 | u32 value; | 1997 | u32 value; |
1770 | int err; | 1998 | int err; |
1771 | 1999 | ||
2000 | state = to_sor_state(output->connector.state); | ||
1772 | mode = &encoder->crtc->state->adjusted_mode; | 2001 | mode = &encoder->crtc->state->adjusted_mode; |
1773 | info = &output->connector.display_info; | ||
1774 | 2002 | ||
1775 | err = clk_prepare_enable(sor->clk); | 2003 | pm_runtime_get_sync(sor->dev); |
1776 | if (err < 0) | ||
1777 | dev_err(sor->dev, "failed to enable clock: %d\n", err); | ||
1778 | 2004 | ||
1779 | usleep_range(1000, 2000); | 2005 | /* switch to safe parent clock */ |
1780 | 2006 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | |
1781 | reset_control_deassert(sor->rst); | ||
1782 | |||
1783 | err = clk_set_parent(sor->clk, sor->clk_safe); | ||
1784 | if (err < 0) | 2007 | if (err < 0) |
1785 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); | 2008 | dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); |
1786 | 2009 | ||
@@ -1876,22 +2099,20 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
1876 | value = SOR_REFCLK_DIV_INT(div) | SOR_REFCLK_DIV_FRAC(div); | 2099 | value = SOR_REFCLK_DIV_INT(div) | SOR_REFCLK_DIV_FRAC(div); |
1877 | tegra_sor_writel(sor, value, SOR_REFCLK); | 2100 | tegra_sor_writel(sor, value, SOR_REFCLK); |
1878 | 2101 | ||
1879 | /* XXX don't hardcode */ | 2102 | /* XXX not in TRM */ |
1880 | value = SOR_XBAR_CTRL_LINK1_XSEL(4, 4) | | 2103 | for (value = 0, i = 0; i < 5; i++) |
1881 | SOR_XBAR_CTRL_LINK1_XSEL(3, 3) | | 2104 | value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) | |
1882 | SOR_XBAR_CTRL_LINK1_XSEL(2, 2) | | 2105 | SOR_XBAR_CTRL_LINK1_XSEL(i, i); |
1883 | SOR_XBAR_CTRL_LINK1_XSEL(1, 1) | | ||
1884 | SOR_XBAR_CTRL_LINK1_XSEL(0, 0) | | ||
1885 | SOR_XBAR_CTRL_LINK0_XSEL(4, 4) | | ||
1886 | SOR_XBAR_CTRL_LINK0_XSEL(3, 3) | | ||
1887 | SOR_XBAR_CTRL_LINK0_XSEL(2, 0) | | ||
1888 | SOR_XBAR_CTRL_LINK0_XSEL(1, 1) | | ||
1889 | SOR_XBAR_CTRL_LINK0_XSEL(0, 2); | ||
1890 | tegra_sor_writel(sor, value, SOR_XBAR_CTRL); | ||
1891 | 2106 | ||
1892 | tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); | 2107 | tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL); |
2108 | tegra_sor_writel(sor, value, SOR_XBAR_CTRL); | ||
1893 | 2109 | ||
1894 | err = clk_set_parent(sor->clk, sor->clk_parent); | 2110 | /* switch to parent clock */ |
2111 | err = clk_set_parent(sor->clk_src, sor->clk_parent); | ||
2112 | if (err < 0) | ||
2113 | dev_err(sor->dev, "failed to set source clock: %d\n", err); | ||
2114 | |||
2115 | err = tegra_sor_set_parent_clock(sor, sor->clk_src); | ||
1895 | if (err < 0) | 2116 | if (err < 0) |
1896 | dev_err(sor->dev, "failed to set parent clock: %d\n", err); | 2117 | dev_err(sor->dev, "failed to set parent clock: %d\n", err); |
1897 | 2118 | ||
@@ -2001,7 +2222,7 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
2001 | value &= ~DITHER_CONTROL_MASK; | 2222 | value &= ~DITHER_CONTROL_MASK; |
2002 | value &= ~BASE_COLOR_SIZE_MASK; | 2223 | value &= ~BASE_COLOR_SIZE_MASK; |
2003 | 2224 | ||
2004 | switch (info->bpc) { | 2225 | switch (state->bpc) { |
2005 | case 6: | 2226 | case 6: |
2006 | value |= BASE_COLOR_SIZE_666; | 2227 | value |= BASE_COLOR_SIZE_666; |
2007 | break; | 2228 | break; |
@@ -2011,7 +2232,8 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
2011 | break; | 2232 | break; |
2012 | 2233 | ||
2013 | default: | 2234 | default: |
2014 | WARN(1, "%u bits-per-color not supported\n", info->bpc); | 2235 | WARN(1, "%u bits-per-color not supported\n", state->bpc); |
2236 | value |= BASE_COLOR_SIZE_888; | ||
2015 | break; | 2237 | break; |
2016 | } | 2238 | } |
2017 | 2239 | ||
@@ -2021,83 +2243,19 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | |||
2021 | if (err < 0) | 2243 | if (err < 0) |
2022 | dev_err(sor->dev, "failed to power up SOR: %d\n", err); | 2244 | dev_err(sor->dev, "failed to power up SOR: %d\n", err); |
2023 | 2245 | ||
2024 | /* configure mode */ | 2246 | /* configure dynamic range of output */ |
2025 | value = tegra_sor_readl(sor, SOR_STATE1); | ||
2026 | value &= ~SOR_STATE_ASY_PIXELDEPTH_MASK; | ||
2027 | value &= ~SOR_STATE_ASY_CRC_MODE_MASK; | ||
2028 | value &= ~SOR_STATE_ASY_OWNER_MASK; | ||
2029 | |||
2030 | value |= SOR_STATE_ASY_CRC_MODE_COMPLETE | | ||
2031 | SOR_STATE_ASY_OWNER(dc->pipe + 1); | ||
2032 | |||
2033 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
2034 | value &= ~SOR_STATE_ASY_HSYNCPOL; | ||
2035 | |||
2036 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
2037 | value |= SOR_STATE_ASY_HSYNCPOL; | ||
2038 | |||
2039 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
2040 | value &= ~SOR_STATE_ASY_VSYNCPOL; | ||
2041 | |||
2042 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
2043 | value |= SOR_STATE_ASY_VSYNCPOL; | ||
2044 | |||
2045 | switch (info->bpc) { | ||
2046 | case 8: | ||
2047 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; | ||
2048 | break; | ||
2049 | |||
2050 | case 6: | ||
2051 | value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; | ||
2052 | break; | ||
2053 | |||
2054 | default: | ||
2055 | BUG(); | ||
2056 | break; | ||
2057 | } | ||
2058 | |||
2059 | tegra_sor_writel(sor, value, SOR_STATE1); | ||
2060 | |||
2061 | value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); | 2247 | value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); |
2062 | value &= ~SOR_HEAD_STATE_RANGECOMPRESS_MASK; | 2248 | value &= ~SOR_HEAD_STATE_RANGECOMPRESS_MASK; |
2063 | value &= ~SOR_HEAD_STATE_DYNRANGE_MASK; | 2249 | value &= ~SOR_HEAD_STATE_DYNRANGE_MASK; |
2064 | tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); | 2250 | tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); |
2065 | 2251 | ||
2252 | /* configure colorspace */ | ||
2066 | value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); | 2253 | value = tegra_sor_readl(sor, SOR_HEAD_STATE0(dc->pipe)); |
2067 | value &= ~SOR_HEAD_STATE_COLORSPACE_MASK; | 2254 | value &= ~SOR_HEAD_STATE_COLORSPACE_MASK; |
2068 | value |= SOR_HEAD_STATE_COLORSPACE_RGB; | 2255 | value |= SOR_HEAD_STATE_COLORSPACE_RGB; |
2069 | tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); | 2256 | tegra_sor_writel(sor, value, SOR_HEAD_STATE0(dc->pipe)); |
2070 | 2257 | ||
2071 | /* | 2258 | tegra_sor_mode_set(sor, mode, state); |
2072 | * TODO: The video timing programming below doesn't seem to match the | ||
2073 | * register definitions. | ||
2074 | */ | ||
2075 | |||
2076 | value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); | ||
2077 | tegra_sor_writel(sor, value, SOR_HEAD_STATE1(dc->pipe)); | ||
2078 | |||
2079 | /* sync end = sync width - 1 */ | ||
2080 | vse = mode->vsync_end - mode->vsync_start - 1; | ||
2081 | hse = mode->hsync_end - mode->hsync_start - 1; | ||
2082 | |||
2083 | value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); | ||
2084 | tegra_sor_writel(sor, value, SOR_HEAD_STATE2(dc->pipe)); | ||
2085 | |||
2086 | /* blank end = sync end + back porch */ | ||
2087 | vbe = vse + (mode->vtotal - mode->vsync_end); | ||
2088 | hbe = hse + (mode->htotal - mode->hsync_end); | ||
2089 | |||
2090 | value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); | ||
2091 | tegra_sor_writel(sor, value, SOR_HEAD_STATE3(dc->pipe)); | ||
2092 | |||
2093 | /* blank start = blank end + active */ | ||
2094 | vbs = vbe + mode->vdisplay; | ||
2095 | hbs = hbe + mode->hdisplay; | ||
2096 | |||
2097 | value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); | ||
2098 | tegra_sor_writel(sor, value, SOR_HEAD_STATE4(dc->pipe)); | ||
2099 | |||
2100 | tegra_sor_writel(sor, 0x1, SOR_HEAD_STATE5(dc->pipe)); | ||
2101 | 2259 | ||
2102 | tegra_sor_update(sor); | 2260 | tegra_sor_update(sor); |
2103 | 2261 | ||
@@ -2195,10 +2353,13 @@ static int tegra_sor_init(struct host1x_client *client) | |||
2195 | * XXX: Remove this reset once proper hand-over from firmware to | 2353 | * XXX: Remove this reset once proper hand-over from firmware to |
2196 | * kernel is possible. | 2354 | * kernel is possible. |
2197 | */ | 2355 | */ |
2198 | err = reset_control_assert(sor->rst); | 2356 | if (sor->rst) { |
2199 | if (err < 0) { | 2357 | err = reset_control_assert(sor->rst); |
2200 | dev_err(sor->dev, "failed to assert SOR reset: %d\n", err); | 2358 | if (err < 0) { |
2201 | return err; | 2359 | dev_err(sor->dev, "failed to assert SOR reset: %d\n", |
2360 | err); | ||
2361 | return err; | ||
2362 | } | ||
2202 | } | 2363 | } |
2203 | 2364 | ||
2204 | err = clk_prepare_enable(sor->clk); | 2365 | err = clk_prepare_enable(sor->clk); |
@@ -2209,10 +2370,13 @@ static int tegra_sor_init(struct host1x_client *client) | |||
2209 | 2370 | ||
2210 | usleep_range(1000, 3000); | 2371 | usleep_range(1000, 3000); |
2211 | 2372 | ||
2212 | err = reset_control_deassert(sor->rst); | 2373 | if (sor->rst) { |
2213 | if (err < 0) { | 2374 | err = reset_control_deassert(sor->rst); |
2214 | dev_err(sor->dev, "failed to deassert SOR reset: %d\n", err); | 2375 | if (err < 0) { |
2215 | return err; | 2376 | dev_err(sor->dev, "failed to deassert SOR reset: %d\n", |
2377 | err); | ||
2378 | return err; | ||
2379 | } | ||
2216 | } | 2380 | } |
2217 | 2381 | ||
2218 | err = clk_prepare_enable(sor->clk_safe); | 2382 | err = clk_prepare_enable(sor->clk_safe); |
@@ -2323,11 +2487,16 @@ static const struct tegra_sor_ops tegra_sor_hdmi_ops = { | |||
2323 | .remove = tegra_sor_hdmi_remove, | 2487 | .remove = tegra_sor_hdmi_remove, |
2324 | }; | 2488 | }; |
2325 | 2489 | ||
2490 | static const u8 tegra124_sor_xbar_cfg[5] = { | ||
2491 | 0, 1, 2, 3, 4 | ||
2492 | }; | ||
2493 | |||
2326 | static const struct tegra_sor_soc tegra124_sor = { | 2494 | static const struct tegra_sor_soc tegra124_sor = { |
2327 | .supports_edp = true, | 2495 | .supports_edp = true, |
2328 | .supports_lvds = true, | 2496 | .supports_lvds = true, |
2329 | .supports_hdmi = false, | 2497 | .supports_hdmi = false, |
2330 | .supports_dp = false, | 2498 | .supports_dp = false, |
2499 | .xbar_cfg = tegra124_sor_xbar_cfg, | ||
2331 | }; | 2500 | }; |
2332 | 2501 | ||
2333 | static const struct tegra_sor_soc tegra210_sor = { | 2502 | static const struct tegra_sor_soc tegra210_sor = { |
@@ -2335,6 +2504,11 @@ static const struct tegra_sor_soc tegra210_sor = { | |||
2335 | .supports_lvds = false, | 2504 | .supports_lvds = false, |
2336 | .supports_hdmi = false, | 2505 | .supports_hdmi = false, |
2337 | .supports_dp = false, | 2506 | .supports_dp = false, |
2507 | .xbar_cfg = tegra124_sor_xbar_cfg, | ||
2508 | }; | ||
2509 | |||
2510 | static const u8 tegra210_sor_xbar_cfg[5] = { | ||
2511 | 2, 1, 0, 3, 4 | ||
2338 | }; | 2512 | }; |
2339 | 2513 | ||
2340 | static const struct tegra_sor_soc tegra210_sor1 = { | 2514 | static const struct tegra_sor_soc tegra210_sor1 = { |
@@ -2345,6 +2519,8 @@ static const struct tegra_sor_soc tegra210_sor1 = { | |||
2345 | 2519 | ||
2346 | .num_settings = ARRAY_SIZE(tegra210_sor_hdmi_defaults), | 2520 | .num_settings = ARRAY_SIZE(tegra210_sor_hdmi_defaults), |
2347 | .settings = tegra210_sor_hdmi_defaults, | 2521 | .settings = tegra210_sor_hdmi_defaults, |
2522 | |||
2523 | .xbar_cfg = tegra210_sor_xbar_cfg, | ||
2348 | }; | 2524 | }; |
2349 | 2525 | ||
2350 | static const struct of_device_id tegra_sor_of_match[] = { | 2526 | static const struct of_device_id tegra_sor_of_match[] = { |
@@ -2434,11 +2610,14 @@ static int tegra_sor_probe(struct platform_device *pdev) | |||
2434 | goto remove; | 2610 | goto remove; |
2435 | } | 2611 | } |
2436 | 2612 | ||
2437 | sor->rst = devm_reset_control_get(&pdev->dev, "sor"); | 2613 | if (!pdev->dev.pm_domain) { |
2438 | if (IS_ERR(sor->rst)) { | 2614 | sor->rst = devm_reset_control_get(&pdev->dev, "sor"); |
2439 | err = PTR_ERR(sor->rst); | 2615 | if (IS_ERR(sor->rst)) { |
2440 | dev_err(&pdev->dev, "failed to get reset control: %d\n", err); | 2616 | err = PTR_ERR(sor->rst); |
2441 | goto remove; | 2617 | dev_err(&pdev->dev, "failed to get reset control: %d\n", |
2618 | err); | ||
2619 | goto remove; | ||
2620 | } | ||
2442 | } | 2621 | } |
2443 | 2622 | ||
2444 | sor->clk = devm_clk_get(&pdev->dev, NULL); | 2623 | sor->clk = devm_clk_get(&pdev->dev, NULL); |
@@ -2448,6 +2627,16 @@ static int tegra_sor_probe(struct platform_device *pdev) | |||
2448 | goto remove; | 2627 | goto remove; |
2449 | } | 2628 | } |
2450 | 2629 | ||
2630 | if (sor->soc->supports_hdmi || sor->soc->supports_dp) { | ||
2631 | sor->clk_src = devm_clk_get(&pdev->dev, "source"); | ||
2632 | if (IS_ERR(sor->clk_src)) { | ||
2633 | err = PTR_ERR(sor->clk_src); | ||
2634 | dev_err(sor->dev, "failed to get source clock: %d\n", | ||
2635 | err); | ||
2636 | goto remove; | ||
2637 | } | ||
2638 | } | ||
2639 | |||
2451 | sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); | 2640 | sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); |
2452 | if (IS_ERR(sor->clk_parent)) { | 2641 | if (IS_ERR(sor->clk_parent)) { |
2453 | err = PTR_ERR(sor->clk_parent); | 2642 | err = PTR_ERR(sor->clk_parent); |
@@ -2469,6 +2658,19 @@ static int tegra_sor_probe(struct platform_device *pdev) | |||
2469 | goto remove; | 2658 | goto remove; |
2470 | } | 2659 | } |
2471 | 2660 | ||
2661 | platform_set_drvdata(pdev, sor); | ||
2662 | pm_runtime_enable(&pdev->dev); | ||
2663 | |||
2664 | pm_runtime_get_sync(&pdev->dev); | ||
2665 | sor->clk_brick = tegra_clk_sor_brick_register(sor, "sor1_brick"); | ||
2666 | pm_runtime_put(&pdev->dev); | ||
2667 | |||
2668 | if (IS_ERR(sor->clk_brick)) { | ||
2669 | err = PTR_ERR(sor->clk_brick); | ||
2670 | dev_err(&pdev->dev, "failed to register SOR clock: %d\n", err); | ||
2671 | goto remove; | ||
2672 | } | ||
2673 | |||
2472 | INIT_LIST_HEAD(&sor->client.list); | 2674 | INIT_LIST_HEAD(&sor->client.list); |
2473 | sor->client.ops = &sor_client_ops; | 2675 | sor->client.ops = &sor_client_ops; |
2474 | sor->client.dev = &pdev->dev; | 2676 | sor->client.dev = &pdev->dev; |
@@ -2480,8 +2682,6 @@ static int tegra_sor_probe(struct platform_device *pdev) | |||
2480 | goto remove; | 2682 | goto remove; |
2481 | } | 2683 | } |
2482 | 2684 | ||
2483 | platform_set_drvdata(pdev, sor); | ||
2484 | |||
2485 | return 0; | 2685 | return 0; |
2486 | 2686 | ||
2487 | remove: | 2687 | remove: |
@@ -2497,6 +2697,8 @@ static int tegra_sor_remove(struct platform_device *pdev) | |||
2497 | struct tegra_sor *sor = platform_get_drvdata(pdev); | 2697 | struct tegra_sor *sor = platform_get_drvdata(pdev); |
2498 | int err; | 2698 | int err; |
2499 | 2699 | ||
2700 | pm_runtime_disable(&pdev->dev); | ||
2701 | |||
2500 | err = host1x_client_unregister(&sor->client); | 2702 | err = host1x_client_unregister(&sor->client); |
2501 | if (err < 0) { | 2703 | if (err < 0) { |
2502 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", | 2704 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", |
@@ -2515,10 +2717,62 @@ static int tegra_sor_remove(struct platform_device *pdev) | |||
2515 | return 0; | 2717 | return 0; |
2516 | } | 2718 | } |
2517 | 2719 | ||
2720 | #ifdef CONFIG_PM | ||
2721 | static int tegra_sor_suspend(struct device *dev) | ||
2722 | { | ||
2723 | struct tegra_sor *sor = dev_get_drvdata(dev); | ||
2724 | int err; | ||
2725 | |||
2726 | if (sor->rst) { | ||
2727 | err = reset_control_assert(sor->rst); | ||
2728 | if (err < 0) { | ||
2729 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
2730 | return err; | ||
2731 | } | ||
2732 | } | ||
2733 | |||
2734 | usleep_range(1000, 2000); | ||
2735 | |||
2736 | clk_disable_unprepare(sor->clk); | ||
2737 | |||
2738 | return 0; | ||
2739 | } | ||
2740 | |||
2741 | static int tegra_sor_resume(struct device *dev) | ||
2742 | { | ||
2743 | struct tegra_sor *sor = dev_get_drvdata(dev); | ||
2744 | int err; | ||
2745 | |||
2746 | err = clk_prepare_enable(sor->clk); | ||
2747 | if (err < 0) { | ||
2748 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
2749 | return err; | ||
2750 | } | ||
2751 | |||
2752 | usleep_range(1000, 2000); | ||
2753 | |||
2754 | if (sor->rst) { | ||
2755 | err = reset_control_deassert(sor->rst); | ||
2756 | if (err < 0) { | ||
2757 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
2758 | clk_disable_unprepare(sor->clk); | ||
2759 | return err; | ||
2760 | } | ||
2761 | } | ||
2762 | |||
2763 | return 0; | ||
2764 | } | ||
2765 | #endif | ||
2766 | |||
2767 | static const struct dev_pm_ops tegra_sor_pm_ops = { | ||
2768 | SET_RUNTIME_PM_OPS(tegra_sor_suspend, tegra_sor_resume, NULL) | ||
2769 | }; | ||
2770 | |||
2518 | struct platform_driver tegra_sor_driver = { | 2771 | struct platform_driver tegra_sor_driver = { |
2519 | .driver = { | 2772 | .driver = { |
2520 | .name = "tegra-sor", | 2773 | .name = "tegra-sor", |
2521 | .of_match_table = tegra_sor_of_match, | 2774 | .of_match_table = tegra_sor_of_match, |
2775 | .pm = &tegra_sor_pm_ops, | ||
2522 | }, | 2776 | }, |
2523 | .probe = tegra_sor_probe, | 2777 | .probe = tegra_sor_probe, |
2524 | .remove = tegra_sor_remove, | 2778 | .remove = tegra_sor_remove, |
diff --git a/drivers/gpu/drm/tegra/sor.h b/drivers/gpu/drm/tegra/sor.h index 2d31d027e3f6..865c73b48968 100644 --- a/drivers/gpu/drm/tegra/sor.h +++ b/drivers/gpu/drm/tegra/sor.h | |||
@@ -27,6 +27,9 @@ | |||
27 | #define SOR_STATE_ASY_PIXELDEPTH_MASK (0xf << 17) | 27 | #define SOR_STATE_ASY_PIXELDEPTH_MASK (0xf << 17) |
28 | #define SOR_STATE_ASY_PIXELDEPTH_BPP_18_444 (0x2 << 17) | 28 | #define SOR_STATE_ASY_PIXELDEPTH_BPP_18_444 (0x2 << 17) |
29 | #define SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 (0x5 << 17) | 29 | #define SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 (0x5 << 17) |
30 | #define SOR_STATE_ASY_PIXELDEPTH_BPP_30_444 (0x6 << 17) | ||
31 | #define SOR_STATE_ASY_PIXELDEPTH_BPP_36_444 (0x8 << 17) | ||
32 | #define SOR_STATE_ASY_PIXELDEPTH_BPP_48_444 (0x9 << 17) | ||
30 | #define SOR_STATE_ASY_VSYNCPOL (1 << 13) | 33 | #define SOR_STATE_ASY_VSYNCPOL (1 << 13) |
31 | #define SOR_STATE_ASY_HSYNCPOL (1 << 12) | 34 | #define SOR_STATE_ASY_HSYNCPOL (1 << 12) |
32 | #define SOR_STATE_ASY_PROTOCOL_MASK (0xf << 8) | 35 | #define SOR_STATE_ASY_PROTOCOL_MASK (0xf << 8) |
diff --git a/drivers/gpu/host1x/cdma.c b/drivers/gpu/host1x/cdma.c index a18db4d5347c..c5d82a8a2ec9 100644 --- a/drivers/gpu/host1x/cdma.c +++ b/drivers/gpu/host1x/cdma.c | |||
@@ -96,12 +96,12 @@ fail: | |||
96 | */ | 96 | */ |
97 | static void host1x_pushbuffer_push(struct push_buffer *pb, u32 op1, u32 op2) | 97 | static void host1x_pushbuffer_push(struct push_buffer *pb, u32 op1, u32 op2) |
98 | { | 98 | { |
99 | u32 pos = pb->pos; | 99 | u32 *p = (u32 *)((void *)pb->mapped + pb->pos); |
100 | u32 *p = (u32 *)((void *)pb->mapped + pos); | 100 | |
101 | WARN_ON(pos == pb->fence); | 101 | WARN_ON(pb->pos == pb->fence); |
102 | *(p++) = op1; | 102 | *(p++) = op1; |
103 | *(p++) = op2; | 103 | *(p++) = op2; |
104 | pb->pos = (pos + 8) & (pb->size_bytes - 1); | 104 | pb->pos = (pb->pos + 8) & (pb->size_bytes - 1); |
105 | } | 105 | } |
106 | 106 | ||
107 | /* | 107 | /* |
@@ -134,14 +134,19 @@ unsigned int host1x_cdma_wait_locked(struct host1x_cdma *cdma, | |||
134 | enum cdma_event event) | 134 | enum cdma_event event) |
135 | { | 135 | { |
136 | for (;;) { | 136 | for (;;) { |
137 | struct push_buffer *pb = &cdma->push_buffer; | ||
137 | unsigned int space; | 138 | unsigned int space; |
138 | 139 | ||
139 | if (event == CDMA_EVENT_SYNC_QUEUE_EMPTY) | 140 | switch (event) { |
141 | case CDMA_EVENT_SYNC_QUEUE_EMPTY: | ||
140 | space = list_empty(&cdma->sync_queue) ? 1 : 0; | 142 | space = list_empty(&cdma->sync_queue) ? 1 : 0; |
141 | else if (event == CDMA_EVENT_PUSH_BUFFER_SPACE) { | 143 | break; |
142 | struct push_buffer *pb = &cdma->push_buffer; | 144 | |
145 | case CDMA_EVENT_PUSH_BUFFER_SPACE: | ||
143 | space = host1x_pushbuffer_space(pb); | 146 | space = host1x_pushbuffer_space(pb); |
144 | } else { | 147 | break; |
148 | |||
149 | default: | ||
145 | WARN_ON(1); | 150 | WARN_ON(1); |
146 | return -EINVAL; | 151 | return -EINVAL; |
147 | } | 152 | } |
@@ -159,12 +164,14 @@ unsigned int host1x_cdma_wait_locked(struct host1x_cdma *cdma, | |||
159 | mutex_lock(&cdma->lock); | 164 | mutex_lock(&cdma->lock); |
160 | continue; | 165 | continue; |
161 | } | 166 | } |
167 | |||
162 | cdma->event = event; | 168 | cdma->event = event; |
163 | 169 | ||
164 | mutex_unlock(&cdma->lock); | 170 | mutex_unlock(&cdma->lock); |
165 | down(&cdma->sem); | 171 | down(&cdma->sem); |
166 | mutex_lock(&cdma->lock); | 172 | mutex_lock(&cdma->lock); |
167 | } | 173 | } |
174 | |||
168 | return 0; | 175 | return 0; |
169 | } | 176 | } |
170 | 177 | ||
@@ -234,6 +241,7 @@ static void update_cdma_locked(struct host1x_cdma *cdma) | |||
234 | /* Start timer on next pending syncpt */ | 241 | /* Start timer on next pending syncpt */ |
235 | if (job->timeout) | 242 | if (job->timeout) |
236 | cdma_start_timer_locked(cdma, job); | 243 | cdma_start_timer_locked(cdma, job); |
244 | |||
237 | break; | 245 | break; |
238 | } | 246 | } |
239 | 247 | ||
@@ -247,7 +255,9 @@ static void update_cdma_locked(struct host1x_cdma *cdma) | |||
247 | /* Pop push buffer slots */ | 255 | /* Pop push buffer slots */ |
248 | if (job->num_slots) { | 256 | if (job->num_slots) { |
249 | struct push_buffer *pb = &cdma->push_buffer; | 257 | struct push_buffer *pb = &cdma->push_buffer; |
258 | |||
250 | host1x_pushbuffer_pop(pb, job->num_slots); | 259 | host1x_pushbuffer_pop(pb, job->num_slots); |
260 | |||
251 | if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE) | 261 | if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE) |
252 | signal = true; | 262 | signal = true; |
253 | } | 263 | } |
@@ -269,11 +279,9 @@ static void update_cdma_locked(struct host1x_cdma *cdma) | |||
269 | void host1x_cdma_update_sync_queue(struct host1x_cdma *cdma, | 279 | void host1x_cdma_update_sync_queue(struct host1x_cdma *cdma, |
270 | struct device *dev) | 280 | struct device *dev) |
271 | { | 281 | { |
272 | u32 restart_addr; | ||
273 | u32 syncpt_incrs; | ||
274 | struct host1x_job *job = NULL; | ||
275 | u32 syncpt_val; | ||
276 | struct host1x *host1x = cdma_to_host1x(cdma); | 282 | struct host1x *host1x = cdma_to_host1x(cdma); |
283 | u32 restart_addr, syncpt_incrs, syncpt_val; | ||
284 | struct host1x_job *job = NULL; | ||
277 | 285 | ||
278 | syncpt_val = host1x_syncpt_load(cdma->timeout.syncpt); | 286 | syncpt_val = host1x_syncpt_load(cdma->timeout.syncpt); |
279 | 287 | ||
@@ -342,9 +350,11 @@ void host1x_cdma_update_sync_queue(struct host1x_cdma *cdma, | |||
342 | syncpt_val += syncpt_incrs; | 350 | syncpt_val += syncpt_incrs; |
343 | } | 351 | } |
344 | 352 | ||
345 | /* The following sumbits from the same client may be dependent on the | 353 | /* |
354 | * The following sumbits from the same client may be dependent on the | ||
346 | * failed submit and therefore they may fail. Force a small timeout | 355 | * failed submit and therefore they may fail. Force a small timeout |
347 | * to make the queue cleanup faster */ | 356 | * to make the queue cleanup faster. |
357 | */ | ||
348 | 358 | ||
349 | list_for_each_entry_from(job, &cdma->sync_queue, list) | 359 | list_for_each_entry_from(job, &cdma->sync_queue, list) |
350 | if (job->client == cdma->timeout.client) | 360 | if (job->client == cdma->timeout.client) |
@@ -375,6 +385,7 @@ int host1x_cdma_init(struct host1x_cdma *cdma) | |||
375 | err = host1x_pushbuffer_init(&cdma->push_buffer); | 385 | err = host1x_pushbuffer_init(&cdma->push_buffer); |
376 | if (err) | 386 | if (err) |
377 | return err; | 387 | return err; |
388 | |||
378 | return 0; | 389 | return 0; |
379 | } | 390 | } |
380 | 391 | ||
@@ -410,6 +421,7 @@ int host1x_cdma_begin(struct host1x_cdma *cdma, struct host1x_job *job) | |||
410 | /* init state on first submit with timeout value */ | 421 | /* init state on first submit with timeout value */ |
411 | if (!cdma->timeout.initialized) { | 422 | if (!cdma->timeout.initialized) { |
412 | int err; | 423 | int err; |
424 | |||
413 | err = host1x_hw_cdma_timeout_init(host1x, cdma, | 425 | err = host1x_hw_cdma_timeout_init(host1x, cdma, |
414 | job->syncpt_id); | 426 | job->syncpt_id); |
415 | if (err) { | 427 | if (err) { |
@@ -418,6 +430,7 @@ int host1x_cdma_begin(struct host1x_cdma *cdma, struct host1x_job *job) | |||
418 | } | 430 | } |
419 | } | 431 | } |
420 | } | 432 | } |
433 | |||
421 | if (!cdma->running) | 434 | if (!cdma->running) |
422 | host1x_hw_cdma_start(host1x, cdma); | 435 | host1x_hw_cdma_start(host1x, cdma); |
423 | 436 | ||
@@ -448,6 +461,7 @@ void host1x_cdma_push(struct host1x_cdma *cdma, u32 op1, u32 op2) | |||
448 | slots_free = host1x_cdma_wait_locked(cdma, | 461 | slots_free = host1x_cdma_wait_locked(cdma, |
449 | CDMA_EVENT_PUSH_BUFFER_SPACE); | 462 | CDMA_EVENT_PUSH_BUFFER_SPACE); |
450 | } | 463 | } |
464 | |||
451 | cdma->slots_free = slots_free - 1; | 465 | cdma->slots_free = slots_free - 1; |
452 | cdma->slots_used++; | 466 | cdma->slots_used++; |
453 | host1x_pushbuffer_push(pb, op1, op2); | 467 | host1x_pushbuffer_push(pb, op1, op2); |
diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c index b4ae3affb987..8f437d924c10 100644 --- a/drivers/gpu/host1x/channel.c +++ b/drivers/gpu/host1x/channel.c | |||
@@ -83,9 +83,10 @@ EXPORT_SYMBOL(host1x_channel_put); | |||
83 | struct host1x_channel *host1x_channel_request(struct device *dev) | 83 | struct host1x_channel *host1x_channel_request(struct device *dev) |
84 | { | 84 | { |
85 | struct host1x *host = dev_get_drvdata(dev->parent); | 85 | struct host1x *host = dev_get_drvdata(dev->parent); |
86 | int max_channels = host->info->nb_channels; | 86 | unsigned int max_channels = host->info->nb_channels; |
87 | struct host1x_channel *channel = NULL; | 87 | struct host1x_channel *channel = NULL; |
88 | int index, err; | 88 | unsigned long index; |
89 | int err; | ||
89 | 90 | ||
90 | mutex_lock(&host->chlist_mutex); | 91 | mutex_lock(&host->chlist_mutex); |
91 | 92 | ||
diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c index ee3d12b51c50..d9330fcc62ad 100644 --- a/drivers/gpu/host1x/debug.c +++ b/drivers/gpu/host1x/debug.c | |||
@@ -39,6 +39,7 @@ void host1x_debug_output(struct output *o, const char *fmt, ...) | |||
39 | va_start(args, fmt); | 39 | va_start(args, fmt); |
40 | len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); | 40 | len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); |
41 | va_end(args); | 41 | va_end(args); |
42 | |||
42 | o->fn(o->ctx, o->buf, len); | 43 | o->fn(o->ctx, o->buf, len); |
43 | } | 44 | } |
44 | 45 | ||
@@ -48,13 +49,17 @@ static int show_channels(struct host1x_channel *ch, void *data, bool show_fifo) | |||
48 | struct output *o = data; | 49 | struct output *o = data; |
49 | 50 | ||
50 | mutex_lock(&ch->reflock); | 51 | mutex_lock(&ch->reflock); |
52 | |||
51 | if (ch->refcount) { | 53 | if (ch->refcount) { |
52 | mutex_lock(&ch->cdma.lock); | 54 | mutex_lock(&ch->cdma.lock); |
55 | |||
53 | if (show_fifo) | 56 | if (show_fifo) |
54 | host1x_hw_show_channel_fifo(m, ch, o); | 57 | host1x_hw_show_channel_fifo(m, ch, o); |
58 | |||
55 | host1x_hw_show_channel_cdma(m, ch, o); | 59 | host1x_hw_show_channel_cdma(m, ch, o); |
56 | mutex_unlock(&ch->cdma.lock); | 60 | mutex_unlock(&ch->cdma.lock); |
57 | } | 61 | } |
62 | |||
58 | mutex_unlock(&ch->reflock); | 63 | mutex_unlock(&ch->reflock); |
59 | 64 | ||
60 | return 0; | 65 | return 0; |
@@ -62,22 +67,27 @@ static int show_channels(struct host1x_channel *ch, void *data, bool show_fifo) | |||
62 | 67 | ||
63 | static void show_syncpts(struct host1x *m, struct output *o) | 68 | static void show_syncpts(struct host1x *m, struct output *o) |
64 | { | 69 | { |
65 | int i; | 70 | unsigned int i; |
71 | |||
66 | host1x_debug_output(o, "---- syncpts ----\n"); | 72 | host1x_debug_output(o, "---- syncpts ----\n"); |
73 | |||
67 | for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { | 74 | for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { |
68 | u32 max = host1x_syncpt_read_max(m->syncpt + i); | 75 | u32 max = host1x_syncpt_read_max(m->syncpt + i); |
69 | u32 min = host1x_syncpt_load(m->syncpt + i); | 76 | u32 min = host1x_syncpt_load(m->syncpt + i); |
77 | |||
70 | if (!min && !max) | 78 | if (!min && !max) |
71 | continue; | 79 | continue; |
72 | host1x_debug_output(o, "id %d (%s) min %d max %d\n", | 80 | |
81 | host1x_debug_output(o, "id %u (%s) min %d max %d\n", | ||
73 | i, m->syncpt[i].name, min, max); | 82 | i, m->syncpt[i].name, min, max); |
74 | } | 83 | } |
75 | 84 | ||
76 | for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { | 85 | for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { |
77 | u32 base_val; | 86 | u32 base_val; |
87 | |||
78 | base_val = host1x_syncpt_load_wait_base(m->syncpt + i); | 88 | base_val = host1x_syncpt_load_wait_base(m->syncpt + i); |
79 | if (base_val) | 89 | if (base_val) |
80 | host1x_debug_output(o, "waitbase id %d val %d\n", i, | 90 | host1x_debug_output(o, "waitbase id %u val %d\n", i, |
81 | base_val); | 91 | base_val); |
82 | } | 92 | } |
83 | 93 | ||
@@ -114,7 +124,9 @@ static int host1x_debug_show_all(struct seq_file *s, void *unused) | |||
114 | .fn = write_to_seqfile, | 124 | .fn = write_to_seqfile, |
115 | .ctx = s | 125 | .ctx = s |
116 | }; | 126 | }; |
127 | |||
117 | show_all(s->private, &o); | 128 | show_all(s->private, &o); |
129 | |||
118 | return 0; | 130 | return 0; |
119 | } | 131 | } |
120 | 132 | ||
@@ -124,7 +136,9 @@ static int host1x_debug_show(struct seq_file *s, void *unused) | |||
124 | .fn = write_to_seqfile, | 136 | .fn = write_to_seqfile, |
125 | .ctx = s | 137 | .ctx = s |
126 | }; | 138 | }; |
139 | |||
127 | show_all_no_fifo(s->private, &o); | 140 | show_all_no_fifo(s->private, &o); |
141 | |||
128 | return 0; | 142 | return 0; |
129 | } | 143 | } |
130 | 144 | ||
@@ -134,10 +148,10 @@ static int host1x_debug_open_all(struct inode *inode, struct file *file) | |||
134 | } | 148 | } |
135 | 149 | ||
136 | static const struct file_operations host1x_debug_all_fops = { | 150 | static const struct file_operations host1x_debug_all_fops = { |
137 | .open = host1x_debug_open_all, | 151 | .open = host1x_debug_open_all, |
138 | .read = seq_read, | 152 | .read = seq_read, |
139 | .llseek = seq_lseek, | 153 | .llseek = seq_lseek, |
140 | .release = single_release, | 154 | .release = single_release, |
141 | }; | 155 | }; |
142 | 156 | ||
143 | static int host1x_debug_open(struct inode *inode, struct file *file) | 157 | static int host1x_debug_open(struct inode *inode, struct file *file) |
@@ -146,10 +160,10 @@ static int host1x_debug_open(struct inode *inode, struct file *file) | |||
146 | } | 160 | } |
147 | 161 | ||
148 | static const struct file_operations host1x_debug_fops = { | 162 | static const struct file_operations host1x_debug_fops = { |
149 | .open = host1x_debug_open, | 163 | .open = host1x_debug_open, |
150 | .read = seq_read, | 164 | .read = seq_read, |
151 | .llseek = seq_lseek, | 165 | .llseek = seq_lseek, |
152 | .release = single_release, | 166 | .release = single_release, |
153 | }; | 167 | }; |
154 | 168 | ||
155 | static void host1x_debugfs_init(struct host1x *host1x) | 169 | static void host1x_debugfs_init(struct host1x *host1x) |
@@ -201,6 +215,7 @@ void host1x_debug_dump(struct host1x *host1x) | |||
201 | struct output o = { | 215 | struct output o = { |
202 | .fn = write_to_printk | 216 | .fn = write_to_printk |
203 | }; | 217 | }; |
218 | |||
204 | show_all(host1x, &o); | 219 | show_all(host1x, &o); |
205 | } | 220 | } |
206 | 221 | ||
@@ -209,5 +224,6 @@ void host1x_debug_dump_syncpts(struct host1x *host1x) | |||
209 | struct output o = { | 224 | struct output o = { |
210 | .fn = write_to_printk | 225 | .fn = write_to_printk |
211 | }; | 226 | }; |
227 | |||
212 | show_syncpts(host1x, &o); | 228 | show_syncpts(host1x, &o); |
213 | } | 229 | } |
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index ff348690df94..a62317af76ad 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c | |||
@@ -63,13 +63,13 @@ u32 host1x_ch_readl(struct host1x_channel *ch, u32 r) | |||
63 | } | 63 | } |
64 | 64 | ||
65 | static const struct host1x_info host1x01_info = { | 65 | static const struct host1x_info host1x01_info = { |
66 | .nb_channels = 8, | 66 | .nb_channels = 8, |
67 | .nb_pts = 32, | 67 | .nb_pts = 32, |
68 | .nb_mlocks = 16, | 68 | .nb_mlocks = 16, |
69 | .nb_bases = 8, | 69 | .nb_bases = 8, |
70 | .init = host1x01_init, | 70 | .init = host1x01_init, |
71 | .sync_offset = 0x3000, | 71 | .sync_offset = 0x3000, |
72 | .dma_mask = DMA_BIT_MASK(32), | 72 | .dma_mask = DMA_BIT_MASK(32), |
73 | }; | 73 | }; |
74 | 74 | ||
75 | static const struct host1x_info host1x02_info = { | 75 | static const struct host1x_info host1x02_info = { |
@@ -102,7 +102,7 @@ static const struct host1x_info host1x05_info = { | |||
102 | .dma_mask = DMA_BIT_MASK(34), | 102 | .dma_mask = DMA_BIT_MASK(34), |
103 | }; | 103 | }; |
104 | 104 | ||
105 | static struct of_device_id host1x_of_match[] = { | 105 | static const struct of_device_id host1x_of_match[] = { |
106 | { .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, }, | 106 | { .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, }, |
107 | { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, }, | 107 | { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, }, |
108 | { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, }, | 108 | { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, }, |
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index dace124994bb..5220510f39da 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h | |||
@@ -45,7 +45,7 @@ struct host1x_cdma_ops { | |||
45 | void (*start)(struct host1x_cdma *cdma); | 45 | void (*start)(struct host1x_cdma *cdma); |
46 | void (*stop)(struct host1x_cdma *cdma); | 46 | void (*stop)(struct host1x_cdma *cdma); |
47 | void (*flush)(struct host1x_cdma *cdma); | 47 | void (*flush)(struct host1x_cdma *cdma); |
48 | int (*timeout_init)(struct host1x_cdma *cdma, u32 syncpt_id); | 48 | int (*timeout_init)(struct host1x_cdma *cdma, unsigned int syncpt); |
49 | void (*timeout_destroy)(struct host1x_cdma *cdma); | 49 | void (*timeout_destroy)(struct host1x_cdma *cdma); |
50 | void (*freeze)(struct host1x_cdma *cdma); | 50 | void (*freeze)(struct host1x_cdma *cdma); |
51 | void (*resume)(struct host1x_cdma *cdma, u32 getptr); | 51 | void (*resume)(struct host1x_cdma *cdma, u32 getptr); |
@@ -82,21 +82,21 @@ struct host1x_intr_ops { | |||
82 | int (*init_host_sync)(struct host1x *host, u32 cpm, | 82 | int (*init_host_sync)(struct host1x *host, u32 cpm, |
83 | void (*syncpt_thresh_work)(struct work_struct *work)); | 83 | void (*syncpt_thresh_work)(struct work_struct *work)); |
84 | void (*set_syncpt_threshold)( | 84 | void (*set_syncpt_threshold)( |
85 | struct host1x *host, u32 id, u32 thresh); | 85 | struct host1x *host, unsigned int id, u32 thresh); |
86 | void (*enable_syncpt_intr)(struct host1x *host, u32 id); | 86 | void (*enable_syncpt_intr)(struct host1x *host, unsigned int id); |
87 | void (*disable_syncpt_intr)(struct host1x *host, u32 id); | 87 | void (*disable_syncpt_intr)(struct host1x *host, unsigned int id); |
88 | void (*disable_all_syncpt_intrs)(struct host1x *host); | 88 | void (*disable_all_syncpt_intrs)(struct host1x *host); |
89 | int (*free_syncpt_irq)(struct host1x *host); | 89 | int (*free_syncpt_irq)(struct host1x *host); |
90 | }; | 90 | }; |
91 | 91 | ||
92 | struct host1x_info { | 92 | struct host1x_info { |
93 | int nb_channels; /* host1x: num channels supported */ | 93 | unsigned int nb_channels; /* host1x: number of channels supported */ |
94 | int nb_pts; /* host1x: num syncpoints supported */ | 94 | unsigned int nb_pts; /* host1x: number of syncpoints supported */ |
95 | int nb_bases; /* host1x: num syncpoints supported */ | 95 | unsigned int nb_bases; /* host1x: number of syncpoint bases supported */ |
96 | int nb_mlocks; /* host1x: number of mlocks */ | 96 | unsigned int nb_mlocks; /* host1x: number of mlocks supported */ |
97 | int (*init)(struct host1x *); /* initialize per SoC ops */ | 97 | int (*init)(struct host1x *host1x); /* initialize per SoC ops */ |
98 | int sync_offset; | 98 | unsigned int sync_offset; /* offset of syncpoint registers */ |
99 | u64 dma_mask; /* mask of addressable memory */ | 99 | u64 dma_mask; /* mask of addressable memory */ |
100 | }; | 100 | }; |
101 | 101 | ||
102 | struct host1x { | 102 | struct host1x { |
@@ -109,7 +109,6 @@ struct host1x { | |||
109 | struct clk *clk; | 109 | struct clk *clk; |
110 | 110 | ||
111 | struct mutex intr_mutex; | 111 | struct mutex intr_mutex; |
112 | struct workqueue_struct *intr_wq; | ||
113 | int intr_syncpt_irq; | 112 | int intr_syncpt_irq; |
114 | 113 | ||
115 | const struct host1x_syncpt_ops *syncpt_op; | 114 | const struct host1x_syncpt_ops *syncpt_op; |
@@ -183,19 +182,20 @@ static inline int host1x_hw_intr_init_host_sync(struct host1x *host, u32 cpm, | |||
183 | } | 182 | } |
184 | 183 | ||
185 | static inline void host1x_hw_intr_set_syncpt_threshold(struct host1x *host, | 184 | static inline void host1x_hw_intr_set_syncpt_threshold(struct host1x *host, |
186 | u32 id, u32 thresh) | 185 | unsigned int id, |
186 | u32 thresh) | ||
187 | { | 187 | { |
188 | host->intr_op->set_syncpt_threshold(host, id, thresh); | 188 | host->intr_op->set_syncpt_threshold(host, id, thresh); |
189 | } | 189 | } |
190 | 190 | ||
191 | static inline void host1x_hw_intr_enable_syncpt_intr(struct host1x *host, | 191 | static inline void host1x_hw_intr_enable_syncpt_intr(struct host1x *host, |
192 | u32 id) | 192 | unsigned int id) |
193 | { | 193 | { |
194 | host->intr_op->enable_syncpt_intr(host, id); | 194 | host->intr_op->enable_syncpt_intr(host, id); |
195 | } | 195 | } |
196 | 196 | ||
197 | static inline void host1x_hw_intr_disable_syncpt_intr(struct host1x *host, | 197 | static inline void host1x_hw_intr_disable_syncpt_intr(struct host1x *host, |
198 | u32 id) | 198 | unsigned int id) |
199 | { | 199 | { |
200 | host->intr_op->disable_syncpt_intr(host, id); | 200 | host->intr_op->disable_syncpt_intr(host, id); |
201 | } | 201 | } |
@@ -212,9 +212,9 @@ static inline int host1x_hw_intr_free_syncpt_irq(struct host1x *host) | |||
212 | 212 | ||
213 | static inline int host1x_hw_channel_init(struct host1x *host, | 213 | static inline int host1x_hw_channel_init(struct host1x *host, |
214 | struct host1x_channel *channel, | 214 | struct host1x_channel *channel, |
215 | int chid) | 215 | unsigned int id) |
216 | { | 216 | { |
217 | return host->channel_op->init(channel, host, chid); | 217 | return host->channel_op->init(channel, host, id); |
218 | } | 218 | } |
219 | 219 | ||
220 | static inline int host1x_hw_channel_submit(struct host1x *host, | 220 | static inline int host1x_hw_channel_submit(struct host1x *host, |
@@ -243,9 +243,9 @@ static inline void host1x_hw_cdma_flush(struct host1x *host, | |||
243 | 243 | ||
244 | static inline int host1x_hw_cdma_timeout_init(struct host1x *host, | 244 | static inline int host1x_hw_cdma_timeout_init(struct host1x *host, |
245 | struct host1x_cdma *cdma, | 245 | struct host1x_cdma *cdma, |
246 | u32 syncpt_id) | 246 | unsigned int syncpt) |
247 | { | 247 | { |
248 | return host->cdma_op->timeout_init(cdma, syncpt_id); | 248 | return host->cdma_op->timeout_init(cdma, syncpt); |
249 | } | 249 | } |
250 | 250 | ||
251 | static inline void host1x_hw_cdma_timeout_destroy(struct host1x *host, | 251 | static inline void host1x_hw_cdma_timeout_destroy(struct host1x *host, |
diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c index 305ea8f3382d..659c1bbfeeba 100644 --- a/drivers/gpu/host1x/hw/cdma_hw.c +++ b/drivers/gpu/host1x/hw/cdma_hw.c | |||
@@ -41,7 +41,7 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr, | |||
41 | { | 41 | { |
42 | struct host1x *host1x = cdma_to_host1x(cdma); | 42 | struct host1x *host1x = cdma_to_host1x(cdma); |
43 | struct push_buffer *pb = &cdma->push_buffer; | 43 | struct push_buffer *pb = &cdma->push_buffer; |
44 | u32 i; | 44 | unsigned int i; |
45 | 45 | ||
46 | for (i = 0; i < syncpt_incrs; i++) | 46 | for (i = 0; i < syncpt_incrs; i++) |
47 | host1x_syncpt_incr(cdma->timeout.syncpt); | 47 | host1x_syncpt_incr(cdma->timeout.syncpt); |
@@ -58,6 +58,7 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr, | |||
58 | &pb->phys, getptr); | 58 | &pb->phys, getptr); |
59 | getptr = (getptr + 8) & (pb->size_bytes - 1); | 59 | getptr = (getptr + 8) & (pb->size_bytes - 1); |
60 | } | 60 | } |
61 | |||
61 | wmb(); | 62 | wmb(); |
62 | } | 63 | } |
63 | 64 | ||
@@ -162,12 +163,14 @@ static void cdma_stop(struct host1x_cdma *cdma) | |||
162 | struct host1x_channel *ch = cdma_to_channel(cdma); | 163 | struct host1x_channel *ch = cdma_to_channel(cdma); |
163 | 164 | ||
164 | mutex_lock(&cdma->lock); | 165 | mutex_lock(&cdma->lock); |
166 | |||
165 | if (cdma->running) { | 167 | if (cdma->running) { |
166 | host1x_cdma_wait_locked(cdma, CDMA_EVENT_SYNC_QUEUE_EMPTY); | 168 | host1x_cdma_wait_locked(cdma, CDMA_EVENT_SYNC_QUEUE_EMPTY); |
167 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | 169 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, |
168 | HOST1X_CHANNEL_DMACTRL); | 170 | HOST1X_CHANNEL_DMACTRL); |
169 | cdma->running = false; | 171 | cdma->running = false; |
170 | } | 172 | } |
173 | |||
171 | mutex_unlock(&cdma->lock); | 174 | mutex_unlock(&cdma->lock); |
172 | } | 175 | } |
173 | 176 | ||
@@ -213,11 +216,11 @@ static void cdma_resume(struct host1x_cdma *cdma, u32 getptr) | |||
213 | u32 cmdproc_stop; | 216 | u32 cmdproc_stop; |
214 | 217 | ||
215 | dev_dbg(host1x->dev, | 218 | dev_dbg(host1x->dev, |
216 | "resuming channel (id %d, DMAGET restart = 0x%x)\n", | 219 | "resuming channel (id %u, DMAGET restart = 0x%x)\n", |
217 | ch->id, getptr); | 220 | ch->id, getptr); |
218 | 221 | ||
219 | cmdproc_stop = host1x_sync_readl(host1x, HOST1X_SYNC_CMDPROC_STOP); | 222 | cmdproc_stop = host1x_sync_readl(host1x, HOST1X_SYNC_CMDPROC_STOP); |
220 | cmdproc_stop &= ~(BIT(ch->id)); | 223 | cmdproc_stop &= ~BIT(ch->id); |
221 | host1x_sync_writel(host1x, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | 224 | host1x_sync_writel(host1x, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); |
222 | 225 | ||
223 | cdma->torndown = false; | 226 | cdma->torndown = false; |
@@ -231,14 +234,11 @@ static void cdma_resume(struct host1x_cdma *cdma, u32 getptr) | |||
231 | */ | 234 | */ |
232 | static void cdma_timeout_handler(struct work_struct *work) | 235 | static void cdma_timeout_handler(struct work_struct *work) |
233 | { | 236 | { |
237 | u32 prev_cmdproc, cmdproc_stop, syncpt_val; | ||
234 | struct host1x_cdma *cdma; | 238 | struct host1x_cdma *cdma; |
235 | struct host1x *host1x; | 239 | struct host1x *host1x; |
236 | struct host1x_channel *ch; | 240 | struct host1x_channel *ch; |
237 | 241 | ||
238 | u32 syncpt_val; | ||
239 | |||
240 | u32 prev_cmdproc, cmdproc_stop; | ||
241 | |||
242 | cdma = container_of(to_delayed_work(work), struct host1x_cdma, | 242 | cdma = container_of(to_delayed_work(work), struct host1x_cdma, |
243 | timeout.wq); | 243 | timeout.wq); |
244 | host1x = cdma_to_host1x(cdma); | 244 | host1x = cdma_to_host1x(cdma); |
@@ -277,9 +277,9 @@ static void cdma_timeout_handler(struct work_struct *work) | |||
277 | return; | 277 | return; |
278 | } | 278 | } |
279 | 279 | ||
280 | dev_warn(host1x->dev, "%s: timeout: %d (%s), HW thresh %d, done %d\n", | 280 | dev_warn(host1x->dev, "%s: timeout: %u (%s), HW thresh %d, done %d\n", |
281 | __func__, cdma->timeout.syncpt->id, cdma->timeout.syncpt->name, | 281 | __func__, cdma->timeout.syncpt->id, cdma->timeout.syncpt->name, |
282 | syncpt_val, cdma->timeout.syncpt_val); | 282 | syncpt_val, cdma->timeout.syncpt_val); |
283 | 283 | ||
284 | /* stop HW, resetting channel/module */ | 284 | /* stop HW, resetting channel/module */ |
285 | host1x_hw_cdma_freeze(host1x, cdma); | 285 | host1x_hw_cdma_freeze(host1x, cdma); |
@@ -291,7 +291,7 @@ static void cdma_timeout_handler(struct work_struct *work) | |||
291 | /* | 291 | /* |
292 | * Init timeout resources | 292 | * Init timeout resources |
293 | */ | 293 | */ |
294 | static int cdma_timeout_init(struct host1x_cdma *cdma, u32 syncpt_id) | 294 | static int cdma_timeout_init(struct host1x_cdma *cdma, unsigned int syncpt) |
295 | { | 295 | { |
296 | INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler); | 296 | INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler); |
297 | cdma->timeout.initialized = true; | 297 | cdma->timeout.initialized = true; |
@@ -306,6 +306,7 @@ static void cdma_timeout_destroy(struct host1x_cdma *cdma) | |||
306 | { | 306 | { |
307 | if (cdma->timeout.initialized) | 307 | if (cdma->timeout.initialized) |
308 | cancel_delayed_work(&cdma->timeout.wq); | 308 | cancel_delayed_work(&cdma->timeout.wq); |
309 | |||
309 | cdma->timeout.initialized = false; | 310 | cdma->timeout.initialized = false; |
310 | } | 311 | } |
311 | 312 | ||
diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c index 946c332c3906..5e8df78b7acd 100644 --- a/drivers/gpu/host1x/hw/channel_hw.c +++ b/drivers/gpu/host1x/hw/channel_hw.c | |||
@@ -46,6 +46,7 @@ static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, | |||
46 | */ | 46 | */ |
47 | for (i = 0; i < words; i += TRACE_MAX_LENGTH) { | 47 | for (i = 0; i < words; i += TRACE_MAX_LENGTH) { |
48 | u32 num_words = min(words - i, TRACE_MAX_LENGTH); | 48 | u32 num_words = min(words - i, TRACE_MAX_LENGTH); |
49 | |||
49 | offset += i * sizeof(u32); | 50 | offset += i * sizeof(u32); |
50 | 51 | ||
51 | trace_host1x_cdma_push_gather(dev_name(dev), bo, | 52 | trace_host1x_cdma_push_gather(dev_name(dev), bo, |
@@ -66,6 +67,7 @@ static void submit_gathers(struct host1x_job *job) | |||
66 | struct host1x_job_gather *g = &job->gathers[i]; | 67 | struct host1x_job_gather *g = &job->gathers[i]; |
67 | u32 op1 = host1x_opcode_gather(g->words); | 68 | u32 op1 = host1x_opcode_gather(g->words); |
68 | u32 op2 = g->base + g->offset; | 69 | u32 op2 = g->base + g->offset; |
70 | |||
69 | trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff); | 71 | trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff); |
70 | host1x_cdma_push(cdma, op1, op2); | 72 | host1x_cdma_push(cdma, op1, op2); |
71 | } | 73 | } |
@@ -75,7 +77,8 @@ static inline void synchronize_syncpt_base(struct host1x_job *job) | |||
75 | { | 77 | { |
76 | struct host1x *host = dev_get_drvdata(job->channel->dev->parent); | 78 | struct host1x *host = dev_get_drvdata(job->channel->dev->parent); |
77 | struct host1x_syncpt *sp = host->syncpt + job->syncpt_id; | 79 | struct host1x_syncpt *sp = host->syncpt + job->syncpt_id; |
78 | u32 id, value; | 80 | unsigned int id; |
81 | u32 value; | ||
79 | 82 | ||
80 | value = host1x_syncpt_read_max(sp); | 83 | value = host1x_syncpt_read_max(sp); |
81 | id = sp->base->id; | 84 | id = sp->base->id; |
diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c index cc3f1825c735..7a4a3286e4a7 100644 --- a/drivers/gpu/host1x/hw/debug_hw.c +++ b/drivers/gpu/host1x/hw/debug_hw.c | |||
@@ -40,8 +40,7 @@ enum { | |||
40 | 40 | ||
41 | static unsigned int show_channel_command(struct output *o, u32 val) | 41 | static unsigned int show_channel_command(struct output *o, u32 val) |
42 | { | 42 | { |
43 | unsigned mask; | 43 | unsigned int mask, subop; |
44 | unsigned subop; | ||
45 | 44 | ||
46 | switch (val >> 28) { | 45 | switch (val >> 28) { |
47 | case HOST1X_OPCODE_SETCLASS: | 46 | case HOST1X_OPCODE_SETCLASS: |
@@ -51,12 +50,11 @@ static unsigned int show_channel_command(struct output *o, u32 val) | |||
51 | val >> 6 & 0x3ff, | 50 | val >> 6 & 0x3ff, |
52 | val >> 16 & 0xfff, mask); | 51 | val >> 16 & 0xfff, mask); |
53 | return hweight8(mask); | 52 | return hweight8(mask); |
54 | } else { | ||
55 | host1x_debug_output(o, "SETCL(class=%03x)\n", | ||
56 | val >> 6 & 0x3ff); | ||
57 | return 0; | ||
58 | } | 53 | } |
59 | 54 | ||
55 | host1x_debug_output(o, "SETCL(class=%03x)\n", val >> 6 & 0x3ff); | ||
56 | return 0; | ||
57 | |||
60 | case HOST1X_OPCODE_INCR: | 58 | case HOST1X_OPCODE_INCR: |
61 | host1x_debug_output(o, "INCR(offset=%03x, [", | 59 | host1x_debug_output(o, "INCR(offset=%03x, [", |
62 | val >> 16 & 0xfff); | 60 | val >> 16 & 0xfff); |
@@ -143,7 +141,8 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) | |||
143 | struct host1x_job *job; | 141 | struct host1x_job *job; |
144 | 142 | ||
145 | list_for_each_entry(job, &cdma->sync_queue, list) { | 143 | list_for_each_entry(job, &cdma->sync_queue, list) { |
146 | int i; | 144 | unsigned int i; |
145 | |||
147 | host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n", | 146 | host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n", |
148 | job, job->syncpt_id, job->syncpt_end, | 147 | job, job->syncpt_id, job->syncpt_end, |
149 | job->first_get, job->timeout, | 148 | job->first_get, job->timeout, |
@@ -190,7 +189,7 @@ static void host1x_debug_show_channel_cdma(struct host1x *host, | |||
190 | cbread = host1x_sync_readl(host, HOST1X_SYNC_CBREAD(ch->id)); | 189 | cbread = host1x_sync_readl(host, HOST1X_SYNC_CBREAD(ch->id)); |
191 | cbstat = host1x_sync_readl(host, HOST1X_SYNC_CBSTAT(ch->id)); | 190 | cbstat = host1x_sync_readl(host, HOST1X_SYNC_CBSTAT(ch->id)); |
192 | 191 | ||
193 | host1x_debug_output(o, "%d-%s: ", ch->id, dev_name(ch->dev)); | 192 | host1x_debug_output(o, "%u-%s: ", ch->id, dev_name(ch->dev)); |
194 | 193 | ||
195 | if (HOST1X_CHANNEL_DMACTRL_DMASTOP_V(dmactrl) || | 194 | if (HOST1X_CHANNEL_DMACTRL_DMASTOP_V(dmactrl) || |
196 | !ch->cdma.push_buffer.mapped) { | 195 | !ch->cdma.push_buffer.mapped) { |
@@ -200,14 +199,13 @@ static void host1x_debug_show_channel_cdma(struct host1x *host, | |||
200 | 199 | ||
201 | if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == HOST1X_CLASS_HOST1X && | 200 | if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == HOST1X_CLASS_HOST1X && |
202 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) == | 201 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) == |
203 | HOST1X_UCLASS_WAIT_SYNCPT) | 202 | HOST1X_UCLASS_WAIT_SYNCPT) |
204 | host1x_debug_output(o, "waiting on syncpt %d val %d\n", | 203 | host1x_debug_output(o, "waiting on syncpt %d val %d\n", |
205 | cbread >> 24, cbread & 0xffffff); | 204 | cbread >> 24, cbread & 0xffffff); |
206 | else if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == | 205 | else if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == |
207 | HOST1X_CLASS_HOST1X && | 206 | HOST1X_CLASS_HOST1X && |
208 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) == | 207 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) == |
209 | HOST1X_UCLASS_WAIT_SYNCPT_BASE) { | 208 | HOST1X_UCLASS_WAIT_SYNCPT_BASE) { |
210 | |||
211 | base = (cbread >> 16) & 0xff; | 209 | base = (cbread >> 16) & 0xff; |
212 | baseval = | 210 | baseval = |
213 | host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(base)); | 211 | host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(base)); |
@@ -236,7 +234,7 @@ static void host1x_debug_show_channel_fifo(struct host1x *host, | |||
236 | u32 val, rd_ptr, wr_ptr, start, end; | 234 | u32 val, rd_ptr, wr_ptr, start, end; |
237 | unsigned int data_count = 0; | 235 | unsigned int data_count = 0; |
238 | 236 | ||
239 | host1x_debug_output(o, "%d: fifo:\n", ch->id); | 237 | host1x_debug_output(o, "%u: fifo:\n", ch->id); |
240 | 238 | ||
241 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT); | 239 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT); |
242 | host1x_debug_output(o, "FIFOSTAT %08x\n", val); | 240 | host1x_debug_output(o, "FIFOSTAT %08x\n", val); |
@@ -290,20 +288,22 @@ static void host1x_debug_show_channel_fifo(struct host1x *host, | |||
290 | 288 | ||
291 | static void host1x_debug_show_mlocks(struct host1x *host, struct output *o) | 289 | static void host1x_debug_show_mlocks(struct host1x *host, struct output *o) |
292 | { | 290 | { |
293 | int i; | 291 | unsigned int i; |
294 | 292 | ||
295 | host1x_debug_output(o, "---- mlocks ----\n"); | 293 | host1x_debug_output(o, "---- mlocks ----\n"); |
294 | |||
296 | for (i = 0; i < host1x_syncpt_nb_mlocks(host); i++) { | 295 | for (i = 0; i < host1x_syncpt_nb_mlocks(host); i++) { |
297 | u32 owner = | 296 | u32 owner = |
298 | host1x_sync_readl(host, HOST1X_SYNC_MLOCK_OWNER(i)); | 297 | host1x_sync_readl(host, HOST1X_SYNC_MLOCK_OWNER(i)); |
299 | if (HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(owner)) | 298 | if (HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(owner)) |
300 | host1x_debug_output(o, "%d: locked by channel %d\n", | 299 | host1x_debug_output(o, "%u: locked by channel %u\n", |
301 | i, HOST1X_SYNC_MLOCK_OWNER_CHID_V(owner)); | 300 | i, HOST1X_SYNC_MLOCK_OWNER_CHID_V(owner)); |
302 | else if (HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(owner)) | 301 | else if (HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(owner)) |
303 | host1x_debug_output(o, "%d: locked by cpu\n", i); | 302 | host1x_debug_output(o, "%u: locked by cpu\n", i); |
304 | else | 303 | else |
305 | host1x_debug_output(o, "%d: unlocked\n", i); | 304 | host1x_debug_output(o, "%u: unlocked\n", i); |
306 | } | 305 | } |
306 | |||
307 | host1x_debug_output(o, "\n"); | 307 | host1x_debug_output(o, "\n"); |
308 | } | 308 | } |
309 | 309 | ||
diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c index e1e31e9e67cd..dacb8009a605 100644 --- a/drivers/gpu/host1x/hw/intr_hw.c +++ b/drivers/gpu/host1x/hw/intr_hw.c | |||
@@ -38,14 +38,14 @@ static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt) | |||
38 | host1x_sync_writel(host, BIT_MASK(id), | 38 | host1x_sync_writel(host, BIT_MASK(id), |
39 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); | 39 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(BIT_WORD(id))); |
40 | 40 | ||
41 | queue_work(host->intr_wq, &syncpt->intr.work); | 41 | schedule_work(&syncpt->intr.work); |
42 | } | 42 | } |
43 | 43 | ||
44 | static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) | 44 | static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) |
45 | { | 45 | { |
46 | struct host1x *host = dev_id; | 46 | struct host1x *host = dev_id; |
47 | unsigned long reg; | 47 | unsigned long reg; |
48 | int i, id; | 48 | unsigned int i, id; |
49 | 49 | ||
50 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { | 50 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { |
51 | reg = host1x_sync_readl(host, | 51 | reg = host1x_sync_readl(host, |
@@ -62,7 +62,7 @@ static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) | |||
62 | 62 | ||
63 | static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host) | 63 | static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host) |
64 | { | 64 | { |
65 | u32 i; | 65 | unsigned int i; |
66 | 66 | ||
67 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) { | 67 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) { |
68 | host1x_sync_writel(host, 0xffffffffu, | 68 | host1x_sync_writel(host, 0xffffffffu, |
@@ -72,10 +72,12 @@ static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host) | |||
72 | } | 72 | } |
73 | } | 73 | } |
74 | 74 | ||
75 | static int _host1x_intr_init_host_sync(struct host1x *host, u32 cpm, | 75 | static int |
76 | void (*syncpt_thresh_work)(struct work_struct *)) | 76 | _host1x_intr_init_host_sync(struct host1x *host, u32 cpm, |
77 | void (*syncpt_thresh_work)(struct work_struct *)) | ||
77 | { | 78 | { |
78 | int i, err; | 79 | unsigned int i; |
80 | int err; | ||
79 | 81 | ||
80 | host1x_hw_intr_disable_all_syncpt_intrs(host); | 82 | host1x_hw_intr_disable_all_syncpt_intrs(host); |
81 | 83 | ||
@@ -106,18 +108,21 @@ static int _host1x_intr_init_host_sync(struct host1x *host, u32 cpm, | |||
106 | } | 108 | } |
107 | 109 | ||
108 | static void _host1x_intr_set_syncpt_threshold(struct host1x *host, | 110 | static void _host1x_intr_set_syncpt_threshold(struct host1x *host, |
109 | u32 id, u32 thresh) | 111 | unsigned int id, |
112 | u32 thresh) | ||
110 | { | 113 | { |
111 | host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id)); | 114 | host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id)); |
112 | } | 115 | } |
113 | 116 | ||
114 | static void _host1x_intr_enable_syncpt_intr(struct host1x *host, u32 id) | 117 | static void _host1x_intr_enable_syncpt_intr(struct host1x *host, |
118 | unsigned int id) | ||
115 | { | 119 | { |
116 | host1x_sync_writel(host, BIT_MASK(id), | 120 | host1x_sync_writel(host, BIT_MASK(id), |
117 | HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(BIT_WORD(id))); | 121 | HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(BIT_WORD(id))); |
118 | } | 122 | } |
119 | 123 | ||
120 | static void _host1x_intr_disable_syncpt_intr(struct host1x *host, u32 id) | 124 | static void _host1x_intr_disable_syncpt_intr(struct host1x *host, |
125 | unsigned int id) | ||
121 | { | 126 | { |
122 | host1x_sync_writel(host, BIT_MASK(id), | 127 | host1x_sync_writel(host, BIT_MASK(id), |
123 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); | 128 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(BIT_WORD(id))); |
@@ -127,8 +132,13 @@ static void _host1x_intr_disable_syncpt_intr(struct host1x *host, u32 id) | |||
127 | 132 | ||
128 | static int _host1x_free_syncpt_irq(struct host1x *host) | 133 | static int _host1x_free_syncpt_irq(struct host1x *host) |
129 | { | 134 | { |
135 | unsigned int i; | ||
136 | |||
130 | devm_free_irq(host->dev, host->intr_syncpt_irq, host); | 137 | devm_free_irq(host->dev, host->intr_syncpt_irq, host); |
131 | flush_workqueue(host->intr_wq); | 138 | |
139 | for (i = 0; i < host->info->nb_pts; i++) | ||
140 | cancel_work_sync(&host->syncpt[i].intr.work); | ||
141 | |||
132 | return 0; | 142 | return 0; |
133 | } | 143 | } |
134 | 144 | ||
diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c index 56e85395ac24..c93f74fcce72 100644 --- a/drivers/gpu/host1x/hw/syncpt_hw.c +++ b/drivers/gpu/host1x/hw/syncpt_hw.c | |||
@@ -26,8 +26,9 @@ | |||
26 | */ | 26 | */ |
27 | static void syncpt_restore(struct host1x_syncpt *sp) | 27 | static void syncpt_restore(struct host1x_syncpt *sp) |
28 | { | 28 | { |
29 | u32 min = host1x_syncpt_read_min(sp); | ||
29 | struct host1x *host = sp->host; | 30 | struct host1x *host = sp->host; |
30 | int min = host1x_syncpt_read_min(sp); | 31 | |
31 | host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id)); | 32 | host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id)); |
32 | } | 33 | } |
33 | 34 | ||
@@ -37,6 +38,7 @@ static void syncpt_restore(struct host1x_syncpt *sp) | |||
37 | static void syncpt_restore_wait_base(struct host1x_syncpt *sp) | 38 | static void syncpt_restore_wait_base(struct host1x_syncpt *sp) |
38 | { | 39 | { |
39 | struct host1x *host = sp->host; | 40 | struct host1x *host = sp->host; |
41 | |||
40 | host1x_sync_writel(host, sp->base_val, | 42 | host1x_sync_writel(host, sp->base_val, |
41 | HOST1X_SYNC_SYNCPT_BASE(sp->id)); | 43 | HOST1X_SYNC_SYNCPT_BASE(sp->id)); |
42 | } | 44 | } |
@@ -47,6 +49,7 @@ static void syncpt_restore_wait_base(struct host1x_syncpt *sp) | |||
47 | static void syncpt_read_wait_base(struct host1x_syncpt *sp) | 49 | static void syncpt_read_wait_base(struct host1x_syncpt *sp) |
48 | { | 50 | { |
49 | struct host1x *host = sp->host; | 51 | struct host1x *host = sp->host; |
52 | |||
50 | sp->base_val = | 53 | sp->base_val = |
51 | host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id)); | 54 | host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id)); |
52 | } | 55 | } |
@@ -85,6 +88,7 @@ static int syncpt_cpu_incr(struct host1x_syncpt *sp) | |||
85 | if (!host1x_syncpt_client_managed(sp) && | 88 | if (!host1x_syncpt_client_managed(sp) && |
86 | host1x_syncpt_idle(sp)) | 89 | host1x_syncpt_idle(sp)) |
87 | return -EINVAL; | 90 | return -EINVAL; |
91 | |||
88 | host1x_sync_writel(host, BIT_MASK(sp->id), | 92 | host1x_sync_writel(host, BIT_MASK(sp->id), |
89 | HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); | 93 | HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); |
90 | wmb(); | 94 | wmb(); |
@@ -95,10 +99,10 @@ static int syncpt_cpu_incr(struct host1x_syncpt *sp) | |||
95 | /* remove a wait pointed to by patch_addr */ | 99 | /* remove a wait pointed to by patch_addr */ |
96 | static int syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) | 100 | static int syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) |
97 | { | 101 | { |
98 | u32 override = host1x_class_host_wait_syncpt( | 102 | u32 override = host1x_class_host_wait_syncpt(HOST1X_SYNCPT_RESERVED, 0); |
99 | HOST1X_SYNCPT_RESERVED, 0); | ||
100 | 103 | ||
101 | *((u32 *)patch_addr) = override; | 104 | *((u32 *)patch_addr) = override; |
105 | |||
102 | return 0; | 106 | return 0; |
103 | } | 107 | } |
104 | 108 | ||
diff --git a/drivers/gpu/host1x/intr.c b/drivers/gpu/host1x/intr.c index 2491bf82e30c..8b4fad0ab35d 100644 --- a/drivers/gpu/host1x/intr.c +++ b/drivers/gpu/host1x/intr.c | |||
@@ -122,18 +122,20 @@ static void action_submit_complete(struct host1x_waitlist *waiter) | |||
122 | static void action_wakeup(struct host1x_waitlist *waiter) | 122 | static void action_wakeup(struct host1x_waitlist *waiter) |
123 | { | 123 | { |
124 | wait_queue_head_t *wq = waiter->data; | 124 | wait_queue_head_t *wq = waiter->data; |
125 | |||
125 | wake_up(wq); | 126 | wake_up(wq); |
126 | } | 127 | } |
127 | 128 | ||
128 | static void action_wakeup_interruptible(struct host1x_waitlist *waiter) | 129 | static void action_wakeup_interruptible(struct host1x_waitlist *waiter) |
129 | { | 130 | { |
130 | wait_queue_head_t *wq = waiter->data; | 131 | wait_queue_head_t *wq = waiter->data; |
132 | |||
131 | wake_up_interruptible(wq); | 133 | wake_up_interruptible(wq); |
132 | } | 134 | } |
133 | 135 | ||
134 | typedef void (*action_handler)(struct host1x_waitlist *waiter); | 136 | typedef void (*action_handler)(struct host1x_waitlist *waiter); |
135 | 137 | ||
136 | static action_handler action_handlers[HOST1X_INTR_ACTION_COUNT] = { | 138 | static const action_handler action_handlers[HOST1X_INTR_ACTION_COUNT] = { |
137 | action_submit_complete, | 139 | action_submit_complete, |
138 | action_wakeup, | 140 | action_wakeup, |
139 | action_wakeup_interruptible, | 141 | action_wakeup_interruptible, |
@@ -209,7 +211,7 @@ static void syncpt_thresh_work(struct work_struct *work) | |||
209 | host1x_syncpt_load(host->syncpt + id)); | 211 | host1x_syncpt_load(host->syncpt + id)); |
210 | } | 212 | } |
211 | 213 | ||
212 | int host1x_intr_add_action(struct host1x *host, u32 id, u32 thresh, | 214 | int host1x_intr_add_action(struct host1x *host, unsigned int id, u32 thresh, |
213 | enum host1x_intr_action action, void *data, | 215 | enum host1x_intr_action action, void *data, |
214 | struct host1x_waitlist *waiter, void **ref) | 216 | struct host1x_waitlist *waiter, void **ref) |
215 | { | 217 | { |
@@ -254,7 +256,7 @@ int host1x_intr_add_action(struct host1x *host, u32 id, u32 thresh, | |||
254 | return 0; | 256 | return 0; |
255 | } | 257 | } |
256 | 258 | ||
257 | void host1x_intr_put_ref(struct host1x *host, u32 id, void *ref) | 259 | void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref) |
258 | { | 260 | { |
259 | struct host1x_waitlist *waiter = ref; | 261 | struct host1x_waitlist *waiter = ref; |
260 | struct host1x_syncpt *syncpt; | 262 | struct host1x_syncpt *syncpt; |
@@ -277,9 +279,6 @@ int host1x_intr_init(struct host1x *host, unsigned int irq_sync) | |||
277 | 279 | ||
278 | mutex_init(&host->intr_mutex); | 280 | mutex_init(&host->intr_mutex); |
279 | host->intr_syncpt_irq = irq_sync; | 281 | host->intr_syncpt_irq = irq_sync; |
280 | host->intr_wq = create_workqueue("host_syncpt"); | ||
281 | if (!host->intr_wq) | ||
282 | return -ENOMEM; | ||
283 | 282 | ||
284 | for (id = 0; id < nb_pts; ++id) { | 283 | for (id = 0; id < nb_pts; ++id) { |
285 | struct host1x_syncpt *syncpt = host->syncpt + id; | 284 | struct host1x_syncpt *syncpt = host->syncpt + id; |
@@ -288,7 +287,7 @@ int host1x_intr_init(struct host1x *host, unsigned int irq_sync) | |||
288 | INIT_LIST_HEAD(&syncpt->intr.wait_head); | 287 | INIT_LIST_HEAD(&syncpt->intr.wait_head); |
289 | snprintf(syncpt->intr.thresh_irq_name, | 288 | snprintf(syncpt->intr.thresh_irq_name, |
290 | sizeof(syncpt->intr.thresh_irq_name), | 289 | sizeof(syncpt->intr.thresh_irq_name), |
291 | "host1x_sp_%02d", id); | 290 | "host1x_sp_%02u", id); |
292 | } | 291 | } |
293 | 292 | ||
294 | host1x_intr_start(host); | 293 | host1x_intr_start(host); |
@@ -299,7 +298,6 @@ int host1x_intr_init(struct host1x *host, unsigned int irq_sync) | |||
299 | void host1x_intr_deinit(struct host1x *host) | 298 | void host1x_intr_deinit(struct host1x *host) |
300 | { | 299 | { |
301 | host1x_intr_stop(host); | 300 | host1x_intr_stop(host); |
302 | destroy_workqueue(host->intr_wq); | ||
303 | } | 301 | } |
304 | 302 | ||
305 | void host1x_intr_start(struct host1x *host) | 303 | void host1x_intr_start(struct host1x *host) |
@@ -342,7 +340,7 @@ void host1x_intr_stop(struct host1x *host) | |||
342 | if (!list_empty(&syncpt[id].intr.wait_head)) { | 340 | if (!list_empty(&syncpt[id].intr.wait_head)) { |
343 | /* output diagnostics */ | 341 | /* output diagnostics */ |
344 | mutex_unlock(&host->intr_mutex); | 342 | mutex_unlock(&host->intr_mutex); |
345 | pr_warn("%s cannot stop syncpt intr id=%d\n", | 343 | pr_warn("%s cannot stop syncpt intr id=%u\n", |
346 | __func__, id); | 344 | __func__, id); |
347 | return; | 345 | return; |
348 | } | 346 | } |
diff --git a/drivers/gpu/host1x/intr.h b/drivers/gpu/host1x/intr.h index 2b8adf016a05..1370c2bb75b8 100644 --- a/drivers/gpu/host1x/intr.h +++ b/drivers/gpu/host1x/intr.h | |||
@@ -75,7 +75,7 @@ struct host1x_waitlist { | |||
75 | * | 75 | * |
76 | * This is a non-blocking api. | 76 | * This is a non-blocking api. |
77 | */ | 77 | */ |
78 | int host1x_intr_add_action(struct host1x *host, u32 id, u32 thresh, | 78 | int host1x_intr_add_action(struct host1x *host, unsigned int id, u32 thresh, |
79 | enum host1x_intr_action action, void *data, | 79 | enum host1x_intr_action action, void *data, |
80 | struct host1x_waitlist *waiter, void **ref); | 80 | struct host1x_waitlist *waiter, void **ref); |
81 | 81 | ||
@@ -84,7 +84,7 @@ int host1x_intr_add_action(struct host1x *host, u32 id, u32 thresh, | |||
84 | * You must call this if you passed non-NULL as ref. | 84 | * You must call this if you passed non-NULL as ref. |
85 | * @ref the ref returned from host1x_intr_add_action() | 85 | * @ref the ref returned from host1x_intr_add_action() |
86 | */ | 86 | */ |
87 | void host1x_intr_put_ref(struct host1x *host, u32 id, void *ref); | 87 | void host1x_intr_put_ref(struct host1x *host, unsigned int id, void *ref); |
88 | 88 | ||
89 | /* Initialize host1x sync point interrupt */ | 89 | /* Initialize host1x sync point interrupt */ |
90 | int host1x_intr_init(struct host1x *host, unsigned int irq_sync); | 90 | int host1x_intr_init(struct host1x *host, unsigned int irq_sync); |
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index b4515d544039..a91b7c4a6110 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c | |||
@@ -161,7 +161,7 @@ static int do_waitchks(struct host1x_job *job, struct host1x *host, | |||
161 | 161 | ||
162 | if (host1x_syncpt_is_expired(sp, wait->thresh)) { | 162 | if (host1x_syncpt_is_expired(sp, wait->thresh)) { |
163 | dev_dbg(host->dev, | 163 | dev_dbg(host->dev, |
164 | "drop WAIT id %d (%s) thresh 0x%x, min 0x%x\n", | 164 | "drop WAIT id %u (%s) thresh 0x%x, min 0x%x\n", |
165 | wait->syncpt_id, sp->name, wait->thresh, | 165 | wait->syncpt_id, sp->name, wait->thresh, |
166 | host1x_syncpt_read_min(sp)); | 166 | host1x_syncpt_read_min(sp)); |
167 | 167 | ||
@@ -464,6 +464,7 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev) | |||
464 | 464 | ||
465 | for (i = 0; i < job->num_gathers; i++) { | 465 | for (i = 0; i < job->num_gathers; i++) { |
466 | struct host1x_job_gather *g = &job->gathers[i]; | 466 | struct host1x_job_gather *g = &job->gathers[i]; |
467 | |||
467 | size += g->words * sizeof(u32); | 468 | size += g->words * sizeof(u32); |
468 | } | 469 | } |
469 | 470 | ||
@@ -514,6 +515,7 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev) | |||
514 | bitmap_zero(waitchk_mask, host1x_syncpt_nb_pts(host)); | 515 | bitmap_zero(waitchk_mask, host1x_syncpt_nb_pts(host)); |
515 | for (i = 0; i < job->num_waitchk; i++) { | 516 | for (i = 0; i < job->num_waitchk; i++) { |
516 | u32 syncpt_id = job->waitchk[i].syncpt_id; | 517 | u32 syncpt_id = job->waitchk[i].syncpt_id; |
518 | |||
517 | if (syncpt_id < host1x_syncpt_nb_pts(host)) | 519 | if (syncpt_id < host1x_syncpt_nb_pts(host)) |
518 | set_bit(syncpt_id, waitchk_mask); | 520 | set_bit(syncpt_id, waitchk_mask); |
519 | } | 521 | } |
@@ -571,14 +573,16 @@ void host1x_job_unpin(struct host1x_job *job) | |||
571 | 573 | ||
572 | for (i = 0; i < job->num_unpins; i++) { | 574 | for (i = 0; i < job->num_unpins; i++) { |
573 | struct host1x_job_unpin_data *unpin = &job->unpins[i]; | 575 | struct host1x_job_unpin_data *unpin = &job->unpins[i]; |
576 | |||
574 | host1x_bo_unpin(unpin->bo, unpin->sgt); | 577 | host1x_bo_unpin(unpin->bo, unpin->sgt); |
575 | host1x_bo_put(unpin->bo); | 578 | host1x_bo_put(unpin->bo); |
576 | } | 579 | } |
580 | |||
577 | job->num_unpins = 0; | 581 | job->num_unpins = 0; |
578 | 582 | ||
579 | if (job->gather_copy_size) | 583 | if (job->gather_copy_size) |
580 | dma_free_wc(job->channel->dev, job->gather_copy_size, | 584 | dma_free_wc(job->channel->dev, job->gather_copy_size, |
581 | job->gather_copy_mapped, job->gather_copy); | 585 | job->gather_copy_mapped, job->gather_copy); |
582 | } | 586 | } |
583 | EXPORT_SYMBOL(host1x_job_unpin); | 587 | EXPORT_SYMBOL(host1x_job_unpin); |
584 | 588 | ||
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index 6b7fdc1e2ed0..95589328ad52 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c | |||
@@ -73,7 +73,7 @@ static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, | |||
73 | return NULL; | 73 | return NULL; |
74 | } | 74 | } |
75 | 75 | ||
76 | name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id, | 76 | name = kasprintf(GFP_KERNEL, "%02u-%s", sp->id, |
77 | dev ? dev_name(dev) : NULL); | 77 | dev ? dev_name(dev) : NULL); |
78 | if (!name) | 78 | if (!name) |
79 | return NULL; | 79 | return NULL; |
@@ -110,12 +110,14 @@ EXPORT_SYMBOL(host1x_syncpt_incr_max); | |||
110 | void host1x_syncpt_restore(struct host1x *host) | 110 | void host1x_syncpt_restore(struct host1x *host) |
111 | { | 111 | { |
112 | struct host1x_syncpt *sp_base = host->syncpt; | 112 | struct host1x_syncpt *sp_base = host->syncpt; |
113 | u32 i; | 113 | unsigned int i; |
114 | 114 | ||
115 | for (i = 0; i < host1x_syncpt_nb_pts(host); i++) | 115 | for (i = 0; i < host1x_syncpt_nb_pts(host); i++) |
116 | host1x_hw_syncpt_restore(host, sp_base + i); | 116 | host1x_hw_syncpt_restore(host, sp_base + i); |
117 | |||
117 | for (i = 0; i < host1x_syncpt_nb_bases(host); i++) | 118 | for (i = 0; i < host1x_syncpt_nb_bases(host); i++) |
118 | host1x_hw_syncpt_restore_wait_base(host, sp_base + i); | 119 | host1x_hw_syncpt_restore_wait_base(host, sp_base + i); |
120 | |||
119 | wmb(); | 121 | wmb(); |
120 | } | 122 | } |
121 | 123 | ||
@@ -126,7 +128,7 @@ void host1x_syncpt_restore(struct host1x *host) | |||
126 | void host1x_syncpt_save(struct host1x *host) | 128 | void host1x_syncpt_save(struct host1x *host) |
127 | { | 129 | { |
128 | struct host1x_syncpt *sp_base = host->syncpt; | 130 | struct host1x_syncpt *sp_base = host->syncpt; |
129 | u32 i; | 131 | unsigned int i; |
130 | 132 | ||
131 | for (i = 0; i < host1x_syncpt_nb_pts(host); i++) { | 133 | for (i = 0; i < host1x_syncpt_nb_pts(host); i++) { |
132 | if (host1x_syncpt_client_managed(sp_base + i)) | 134 | if (host1x_syncpt_client_managed(sp_base + i)) |
@@ -146,6 +148,7 @@ void host1x_syncpt_save(struct host1x *host) | |||
146 | u32 host1x_syncpt_load(struct host1x_syncpt *sp) | 148 | u32 host1x_syncpt_load(struct host1x_syncpt *sp) |
147 | { | 149 | { |
148 | u32 val; | 150 | u32 val; |
151 | |||
149 | val = host1x_hw_syncpt_load(sp->host, sp); | 152 | val = host1x_hw_syncpt_load(sp->host, sp); |
150 | trace_host1x_syncpt_load_min(sp->id, val); | 153 | trace_host1x_syncpt_load_min(sp->id, val); |
151 | 154 | ||
@@ -157,10 +160,9 @@ u32 host1x_syncpt_load(struct host1x_syncpt *sp) | |||
157 | */ | 160 | */ |
158 | u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp) | 161 | u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp) |
159 | { | 162 | { |
160 | u32 val; | ||
161 | host1x_hw_syncpt_load_wait_base(sp->host, sp); | 163 | host1x_hw_syncpt_load_wait_base(sp->host, sp); |
162 | val = sp->base_val; | 164 | |
163 | return val; | 165 | return sp->base_val; |
164 | } | 166 | } |
165 | 167 | ||
166 | /* | 168 | /* |
@@ -179,6 +181,7 @@ EXPORT_SYMBOL(host1x_syncpt_incr); | |||
179 | static bool syncpt_load_min_is_expired(struct host1x_syncpt *sp, u32 thresh) | 181 | static bool syncpt_load_min_is_expired(struct host1x_syncpt *sp, u32 thresh) |
180 | { | 182 | { |
181 | host1x_hw_syncpt_load(sp->host, sp); | 183 | host1x_hw_syncpt_load(sp->host, sp); |
184 | |||
182 | return host1x_syncpt_is_expired(sp, thresh); | 185 | return host1x_syncpt_is_expired(sp, thresh); |
183 | } | 186 | } |
184 | 187 | ||
@@ -186,7 +189,7 @@ static bool syncpt_load_min_is_expired(struct host1x_syncpt *sp, u32 thresh) | |||
186 | * Main entrypoint for syncpoint value waits. | 189 | * Main entrypoint for syncpoint value waits. |
187 | */ | 190 | */ |
188 | int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, | 191 | int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, |
189 | u32 *value) | 192 | u32 *value) |
190 | { | 193 | { |
191 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); | 194 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); |
192 | void *ref; | 195 | void *ref; |
@@ -201,6 +204,7 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, | |||
201 | if (host1x_syncpt_is_expired(sp, thresh)) { | 204 | if (host1x_syncpt_is_expired(sp, thresh)) { |
202 | if (value) | 205 | if (value) |
203 | *value = host1x_syncpt_load(sp); | 206 | *value = host1x_syncpt_load(sp); |
207 | |||
204 | return 0; | 208 | return 0; |
205 | } | 209 | } |
206 | 210 | ||
@@ -209,6 +213,7 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, | |||
209 | if (host1x_syncpt_is_expired(sp, thresh)) { | 213 | if (host1x_syncpt_is_expired(sp, thresh)) { |
210 | if (value) | 214 | if (value) |
211 | *value = val; | 215 | *value = val; |
216 | |||
212 | goto done; | 217 | goto done; |
213 | } | 218 | } |
214 | 219 | ||
@@ -239,32 +244,42 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, | |||
239 | /* wait for the syncpoint, or timeout, or signal */ | 244 | /* wait for the syncpoint, or timeout, or signal */ |
240 | while (timeout) { | 245 | while (timeout) { |
241 | long check = min_t(long, SYNCPT_CHECK_PERIOD, timeout); | 246 | long check = min_t(long, SYNCPT_CHECK_PERIOD, timeout); |
242 | int remain = wait_event_interruptible_timeout(wq, | 247 | int remain; |
248 | |||
249 | remain = wait_event_interruptible_timeout(wq, | ||
243 | syncpt_load_min_is_expired(sp, thresh), | 250 | syncpt_load_min_is_expired(sp, thresh), |
244 | check); | 251 | check); |
245 | if (remain > 0 || host1x_syncpt_is_expired(sp, thresh)) { | 252 | if (remain > 0 || host1x_syncpt_is_expired(sp, thresh)) { |
246 | if (value) | 253 | if (value) |
247 | *value = host1x_syncpt_load(sp); | 254 | *value = host1x_syncpt_load(sp); |
255 | |||
248 | err = 0; | 256 | err = 0; |
257 | |||
249 | break; | 258 | break; |
250 | } | 259 | } |
260 | |||
251 | if (remain < 0) { | 261 | if (remain < 0) { |
252 | err = remain; | 262 | err = remain; |
253 | break; | 263 | break; |
254 | } | 264 | } |
265 | |||
255 | timeout -= check; | 266 | timeout -= check; |
267 | |||
256 | if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) { | 268 | if (timeout && check_count <= MAX_STUCK_CHECK_COUNT) { |
257 | dev_warn(sp->host->dev, | 269 | dev_warn(sp->host->dev, |
258 | "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%ld\n", | 270 | "%s: syncpoint id %u (%s) stuck waiting %d, timeout=%ld\n", |
259 | current->comm, sp->id, sp->name, | 271 | current->comm, sp->id, sp->name, |
260 | thresh, timeout); | 272 | thresh, timeout); |
261 | 273 | ||
262 | host1x_debug_dump_syncpts(sp->host); | 274 | host1x_debug_dump_syncpts(sp->host); |
275 | |||
263 | if (check_count == MAX_STUCK_CHECK_COUNT) | 276 | if (check_count == MAX_STUCK_CHECK_COUNT) |
264 | host1x_debug_dump(sp->host); | 277 | host1x_debug_dump(sp->host); |
278 | |||
265 | check_count++; | 279 | check_count++; |
266 | } | 280 | } |
267 | } | 281 | } |
282 | |||
268 | host1x_intr_put_ref(sp->host, sp->id, ref); | 283 | host1x_intr_put_ref(sp->host, sp->id, ref); |
269 | 284 | ||
270 | done: | 285 | done: |
@@ -279,7 +294,9 @@ bool host1x_syncpt_is_expired(struct host1x_syncpt *sp, u32 thresh) | |||
279 | { | 294 | { |
280 | u32 current_val; | 295 | u32 current_val; |
281 | u32 future_val; | 296 | u32 future_val; |
297 | |||
282 | smp_rmb(); | 298 | smp_rmb(); |
299 | |||
283 | current_val = (u32)atomic_read(&sp->min_val); | 300 | current_val = (u32)atomic_read(&sp->min_val); |
284 | future_val = (u32)atomic_read(&sp->max_val); | 301 | future_val = (u32)atomic_read(&sp->max_val); |
285 | 302 | ||
@@ -341,14 +358,14 @@ int host1x_syncpt_init(struct host1x *host) | |||
341 | { | 358 | { |
342 | struct host1x_syncpt_base *bases; | 359 | struct host1x_syncpt_base *bases; |
343 | struct host1x_syncpt *syncpt; | 360 | struct host1x_syncpt *syncpt; |
344 | int i; | 361 | unsigned int i; |
345 | 362 | ||
346 | syncpt = devm_kzalloc(host->dev, sizeof(*syncpt) * host->info->nb_pts, | 363 | syncpt = devm_kcalloc(host->dev, host->info->nb_pts, sizeof(*syncpt), |
347 | GFP_KERNEL); | 364 | GFP_KERNEL); |
348 | if (!syncpt) | 365 | if (!syncpt) |
349 | return -ENOMEM; | 366 | return -ENOMEM; |
350 | 367 | ||
351 | bases = devm_kzalloc(host->dev, sizeof(*bases) * host->info->nb_bases, | 368 | bases = devm_kcalloc(host->dev, host->info->nb_bases, sizeof(*bases), |
352 | GFP_KERNEL); | 369 | GFP_KERNEL); |
353 | if (!bases) | 370 | if (!bases) |
354 | return -ENOMEM; | 371 | return -ENOMEM; |
@@ -378,6 +395,7 @@ struct host1x_syncpt *host1x_syncpt_request(struct device *dev, | |||
378 | unsigned long flags) | 395 | unsigned long flags) |
379 | { | 396 | { |
380 | struct host1x *host = dev_get_drvdata(dev->parent); | 397 | struct host1x *host = dev_get_drvdata(dev->parent); |
398 | |||
381 | return host1x_syncpt_alloc(host, dev, flags); | 399 | return host1x_syncpt_alloc(host, dev, flags); |
382 | } | 400 | } |
383 | EXPORT_SYMBOL(host1x_syncpt_request); | 401 | EXPORT_SYMBOL(host1x_syncpt_request); |
@@ -398,8 +416,9 @@ EXPORT_SYMBOL(host1x_syncpt_free); | |||
398 | 416 | ||
399 | void host1x_syncpt_deinit(struct host1x *host) | 417 | void host1x_syncpt_deinit(struct host1x *host) |
400 | { | 418 | { |
401 | int i; | ||
402 | struct host1x_syncpt *sp = host->syncpt; | 419 | struct host1x_syncpt *sp = host->syncpt; |
420 | unsigned int i; | ||
421 | |||
403 | for (i = 0; i < host->info->nb_pts; i++, sp++) | 422 | for (i = 0; i < host->info->nb_pts; i++, sp++) |
404 | kfree(sp->name); | 423 | kfree(sp->name); |
405 | } | 424 | } |
@@ -407,10 +426,11 @@ void host1x_syncpt_deinit(struct host1x *host) | |||
407 | /* | 426 | /* |
408 | * Read max. It indicates how many operations there are in queue, either in | 427 | * Read max. It indicates how many operations there are in queue, either in |
409 | * channel or in a software thread. | 428 | * channel or in a software thread. |
410 | * */ | 429 | */ |
411 | u32 host1x_syncpt_read_max(struct host1x_syncpt *sp) | 430 | u32 host1x_syncpt_read_max(struct host1x_syncpt *sp) |
412 | { | 431 | { |
413 | smp_rmb(); | 432 | smp_rmb(); |
433 | |||
414 | return (u32)atomic_read(&sp->max_val); | 434 | return (u32)atomic_read(&sp->max_val); |
415 | } | 435 | } |
416 | EXPORT_SYMBOL(host1x_syncpt_read_max); | 436 | EXPORT_SYMBOL(host1x_syncpt_read_max); |
@@ -421,6 +441,7 @@ EXPORT_SYMBOL(host1x_syncpt_read_max); | |||
421 | u32 host1x_syncpt_read_min(struct host1x_syncpt *sp) | 441 | u32 host1x_syncpt_read_min(struct host1x_syncpt *sp) |
422 | { | 442 | { |
423 | smp_rmb(); | 443 | smp_rmb(); |
444 | |||
424 | return (u32)atomic_read(&sp->min_val); | 445 | return (u32)atomic_read(&sp->min_val); |
425 | } | 446 | } |
426 | EXPORT_SYMBOL(host1x_syncpt_read_min); | 447 | EXPORT_SYMBOL(host1x_syncpt_read_min); |
@@ -431,25 +452,26 @@ u32 host1x_syncpt_read(struct host1x_syncpt *sp) | |||
431 | } | 452 | } |
432 | EXPORT_SYMBOL(host1x_syncpt_read); | 453 | EXPORT_SYMBOL(host1x_syncpt_read); |
433 | 454 | ||
434 | int host1x_syncpt_nb_pts(struct host1x *host) | 455 | unsigned int host1x_syncpt_nb_pts(struct host1x *host) |
435 | { | 456 | { |
436 | return host->info->nb_pts; | 457 | return host->info->nb_pts; |
437 | } | 458 | } |
438 | 459 | ||
439 | int host1x_syncpt_nb_bases(struct host1x *host) | 460 | unsigned int host1x_syncpt_nb_bases(struct host1x *host) |
440 | { | 461 | { |
441 | return host->info->nb_bases; | 462 | return host->info->nb_bases; |
442 | } | 463 | } |
443 | 464 | ||
444 | int host1x_syncpt_nb_mlocks(struct host1x *host) | 465 | unsigned int host1x_syncpt_nb_mlocks(struct host1x *host) |
445 | { | 466 | { |
446 | return host->info->nb_mlocks; | 467 | return host->info->nb_mlocks; |
447 | } | 468 | } |
448 | 469 | ||
449 | struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id) | 470 | struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, unsigned int id) |
450 | { | 471 | { |
451 | if (host->info->nb_pts < id) | 472 | if (host->info->nb_pts < id) |
452 | return NULL; | 473 | return NULL; |
474 | |||
453 | return host->syncpt + id; | 475 | return host->syncpt + id; |
454 | } | 476 | } |
455 | EXPORT_SYMBOL(host1x_syncpt_get); | 477 | EXPORT_SYMBOL(host1x_syncpt_get); |
diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h index 9056465ecd3f..f719205105ac 100644 --- a/drivers/gpu/host1x/syncpt.h +++ b/drivers/gpu/host1x/syncpt.h | |||
@@ -37,7 +37,7 @@ struct host1x_syncpt_base { | |||
37 | }; | 37 | }; |
38 | 38 | ||
39 | struct host1x_syncpt { | 39 | struct host1x_syncpt { |
40 | int id; | 40 | unsigned int id; |
41 | atomic_t min_val; | 41 | atomic_t min_val; |
42 | atomic_t max_val; | 42 | atomic_t max_val; |
43 | u32 base_val; | 43 | u32 base_val; |
@@ -58,13 +58,13 @@ int host1x_syncpt_init(struct host1x *host); | |||
58 | void host1x_syncpt_deinit(struct host1x *host); | 58 | void host1x_syncpt_deinit(struct host1x *host); |
59 | 59 | ||
60 | /* Return number of sync point supported. */ | 60 | /* Return number of sync point supported. */ |
61 | int host1x_syncpt_nb_pts(struct host1x *host); | 61 | unsigned int host1x_syncpt_nb_pts(struct host1x *host); |
62 | 62 | ||
63 | /* Return number of wait bases supported. */ | 63 | /* Return number of wait bases supported. */ |
64 | int host1x_syncpt_nb_bases(struct host1x *host); | 64 | unsigned int host1x_syncpt_nb_bases(struct host1x *host); |
65 | 65 | ||
66 | /* Return number of mlocks supported. */ | 66 | /* Return number of mlocks supported. */ |
67 | int host1x_syncpt_nb_mlocks(struct host1x *host); | 67 | unsigned int host1x_syncpt_nb_mlocks(struct host1x *host); |
68 | 68 | ||
69 | /* | 69 | /* |
70 | * Check sync point sanity. If max is larger than min, there have too many | 70 | * Check sync point sanity. If max is larger than min, there have too many |
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index d5bf9fae2ddd..a87439ee4cdd 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c | |||
@@ -391,4 +391,12 @@ exit: | |||
391 | } | 391 | } |
392 | EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map); | 392 | EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map); |
393 | 393 | ||
394 | void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev, | ||
395 | struct pinctrl_map *map, | ||
396 | unsigned num_maps) | ||
397 | { | ||
398 | pinctrl_utils_free_map(pctldev, map, num_maps); | ||
399 | } | ||
400 | EXPORT_SYMBOL_GPL(pinconf_generic_dt_free_map); | ||
401 | |||
394 | #endif | 402 | #endif |
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index d921afd5f109..12343caa114e 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h | |||
@@ -175,6 +175,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, | |||
175 | int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, | 175 | int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, |
176 | struct device_node *np_config, struct pinctrl_map **map, | 176 | struct device_node *np_config, struct pinctrl_map **map, |
177 | unsigned *num_maps, enum pinctrl_map_type type); | 177 | unsigned *num_maps, enum pinctrl_map_type type); |
178 | void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev, | ||
179 | struct pinctrl_map *map, unsigned num_maps); | ||
178 | 180 | ||
179 | static inline int pinconf_generic_dt_node_to_map_group( | 181 | static inline int pinconf_generic_dt_node_to_map_group( |
180 | struct pinctrl_dev *pctldev, struct device_node *np_config, | 182 | struct pinctrl_dev *pctldev, struct device_node *np_config, |