aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0476-drm-vc4-Release-workaround-buffer-and-DMA-in-error-p.patch
blob: 457d3d097457ba0bb340cd424e74f54c4dfa3332 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
From 51f5523151d8de2b1476482e575bb5989e55ba16 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Tue, 6 Jul 2021 18:53:28 +0100
Subject: [PATCH] drm/vc4: Release workaround buffer and DMA in error
 paths and unbind

On Pi0-3 the driver allocates a buffer and requests a DMA channel
because the ARM can't write to DSI1's registers directly.
However unbind and the error paths in bind don't release the buffer or
the DMA channel.

Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
 drivers/gpu/drm/vc4/vc4_dsi.c | 51 ++++++++++++++++++++++++++---------
 1 file changed, 39 insertions(+), 12 deletions(-)

--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -1612,7 +1612,7 @@ static int vc4_dsi_bind(struct device *d
 			if (ret != -EPROBE_DEFER)
 				DRM_ERROR("Failed to get DMA channel: %d\n",
 					  ret);
-			return ret;
+			goto err_free_dma_mem;
 		}
 
 		/* Get the physical address of the device's registers.  The
@@ -1641,7 +1641,7 @@ static int vc4_dsi_bind(struct device *d
 	if (ret) {
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "Failed to get interrupt: %d\n", ret);
-		return ret;
+		goto err_free_dma;
 	}
 
 	dsi->escape_clock = devm_clk_get(dev, "escape");
@@ -1649,7 +1649,7 @@ static int vc4_dsi_bind(struct device *d
 		ret = PTR_ERR(dsi->escape_clock);
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "Failed to get escape clock: %d\n", ret);
-		return ret;
+		goto err_free_dma;
 	}
 
 	dsi->pll_phy_clock = devm_clk_get(dev, "phy");
@@ -1657,7 +1657,7 @@ static int vc4_dsi_bind(struct device *d
 		ret = PTR_ERR(dsi->pll_phy_clock);
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "Failed to get phy clock: %d\n", ret);
-		return ret;
+		goto err_free_dma;
 	}
 
 	dsi->pixel_clock = devm_clk_get(dev, "pixel");
@@ -1665,7 +1665,7 @@ static int vc4_dsi_bind(struct device *d
 		ret = PTR_ERR(dsi->pixel_clock);
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "Failed to get pixel clock: %d\n", ret);
-		return ret;
+		goto err_free_dma;
 	}
 
 	ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
@@ -1680,33 +1680,37 @@ static int vc4_dsi_bind(struct device *d
 		if (ret == -ENODEV)
 			return 0;
 
-		return ret;
+		goto err_free_dma;
 	}
 
 	if (panel) {
 		dsi->bridge = devm_drm_panel_bridge_add_typed(dev, panel,
 							      DRM_MODE_CONNECTOR_DSI);
-		if (IS_ERR(dsi->bridge))
-			return PTR_ERR(dsi->bridge);
+		if (IS_ERR(dsi->bridge)) {
+			ret = PTR_ERR(dsi->bridge);
+			goto err_free_dma;
+		}
 	}
 
 	/* The esc clock rate is supposed to always be 100Mhz. */
 	ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
 	if (ret) {
 		dev_err(dev, "Failed to set esc clock: %d\n", ret);
-		return ret;
+		goto err_free_dma;
 	}
 
 	ret = vc4_dsi_init_phy_clocks(dsi);
 	if (ret)
-		return ret;
+		goto err_free_dma;
 
 	drm_simple_encoder_init(drm, dsi->encoder, DRM_MODE_ENCODER_DSI);
 	drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
 
 	ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL, 0);
-	if (ret)
-		return ret;
+	if (ret) {
+		dev_err(dev, "bridge attach failed: %d\n", ret);
+		goto err_free_dma;
+	}
 	/* Disable the atomic helper calls into the bridge.  We
 	 * manually call the bridge pre_enable / enable / etc. calls
 	 * from our driver, since we need to sequence them within the
@@ -1719,6 +1723,19 @@ static int vc4_dsi_bind(struct device *d
 	pm_runtime_enable(dev);
 
 	return 0;
+
+err_free_dma:
+	if (dsi->reg_dma_chan) {
+		dma_release_channel(dsi->reg_dma_chan);
+		dsi->reg_dma_chan = NULL;
+	}
+err_free_dma_mem:
+	if (dsi->reg_dma_mem) {
+		dma_free_coherent(dev, 4, dsi->reg_dma_mem, dsi->reg_dma_paddr);
+		dsi->reg_dma_mem = NULL;
+	}
+
+	return ret;
 }
 
 static void vc4_dsi_unbind(struct device *dev, struct device *master,
@@ -1735,6 +1752,16 @@ static void vc4_dsi_unbind(struct device
 	 */
 	list_splice_init(&dsi->bridge_chain, &dsi->encoder->bridge_chain);
 	drm_encoder_cleanup(dsi->encoder);
+
+	if (dsi->reg_dma_chan) {
+		dma_release_channel(dsi->reg_dma_chan);
+		dsi->reg_dma_chan = NULL;
+	}
+
+	if (dsi->reg_dma_mem) {
+		dma_free_coherent(dev, 4, dsi->reg_dma_mem, dsi->reg_dma_paddr);
+		dsi->reg_dma_mem = NULL;
+	}
 }
 
 static const struct component_ops vc4_dsi_ops = {