74cae273f833f928f8cd7e2285b26da6dd648a02
[openwrt/staging/blocktrron.git] /
1 From 3e6793632310f9991b75c3095a9795b6a8d1d859 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Wed, 15 Dec 2021 17:57:45 +0000
4 Subject: [PATCH] drm/vc4: Convert vc4_dsi to using a bridge instead of
5 encoder.
6
7 Remove the encoder functions, and create a bridge attached to
8 this dumb encoder which implements the same functionality.
9
10 As a bridge has state which an encoder doesn't, we need to
11 add the state management functions as well.
12
13 As there is no bridge atomic_mode_set, move the initialisation
14 code that was in mode_set into _pre_enable.
15 The code to actually enable and disable sending video are split
16 from the general control into _enable and _disable.
17
18 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
19 ---
20 drivers/gpu/drm/vc4/vc4_dsi.c | 124 ++++++++++++++++++++++++----------
21 1 file changed, 90 insertions(+), 34 deletions(-)
22
23 --- a/drivers/gpu/drm/vc4/vc4_dsi.c
24 +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
25 @@ -554,6 +554,7 @@ struct vc4_dsi {
26 struct mipi_dsi_host dsi_host;
27 struct drm_encoder *encoder;
28 struct drm_bridge *out_bridge;
29 + struct drm_bridge bridge;
30
31 void __iomem *regs;
32
33 @@ -655,6 +656,12 @@ to_vc4_dsi_encoder(struct drm_encoder *e
34 return container_of(encoder, struct vc4_dsi_encoder, base.base);
35 }
36
37 +static inline struct vc4_dsi *
38 +bridge_to_vc4_dsi(struct drm_bridge *bridge)
39 +{
40 + return container_of(bridge, struct vc4_dsi, bridge);
41 +}
42 +
43 static const struct debugfs_reg32 dsi0_regs[] = {
44 VC4_REG32(DSI0_CTRL),
45 VC4_REG32(DSI0_STAT),
46 @@ -792,11 +799,21 @@ dsi_esc_timing(u32 ns)
47 return DIV_ROUND_UP(ns, ESC_TIME_NS);
48 }
49
50 -static void vc4_dsi_encoder_disable(struct drm_encoder *encoder,
51 - struct drm_atomic_state *state)
52 +static void vc4_dsi_bridge_disable(struct drm_bridge *bridge,
53 + struct drm_bridge_state *state)
54 +{
55 + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
56 + u32 disp0_ctrl;
57 +
58 + disp0_ctrl = DSI_PORT_READ(DISP0_CTRL);
59 + disp0_ctrl &= ~DSI_DISP0_ENABLE;
60 + DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl);
61 +}
62 +
63 +static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge,
64 + struct drm_bridge_state *state)
65 {
66 - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
67 - struct vc4_dsi *dsi = vc4_encoder->dsi;
68 + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
69 struct device *dev = &dsi->pdev->dev;
70
71 vc4_dsi_ulps(dsi, true);
72 @@ -821,12 +838,11 @@ static void vc4_dsi_encoder_disable(stru
73 * higher-than-expected clock rate to the panel, but that's what the
74 * firmware does too.
75 */
76 -static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
77 - const struct drm_display_mode *mode,
78 - struct drm_display_mode *adjusted_mode)
79 +static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
80 + const struct drm_display_mode *mode,
81 + struct drm_display_mode *adjusted_mode)
82 {
83 - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
84 - struct vc4_dsi *dsi = vc4_encoder->dsi;
85 + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
86 struct clk *phy_parent = clk_get_parent(dsi->pll_phy_clock);
87 unsigned long parent_rate = clk_get_rate(phy_parent);
88 unsigned long pixel_clock_hz = mode->clock * 1000;
89 @@ -858,16 +874,18 @@ static bool vc4_dsi_encoder_mode_fixup(s
90 return true;
91 }
92
93 -static void vc4_dsi_encoder_mode_set(struct drm_encoder *encoder,
94 - struct drm_crtc_state *crtc_state,
95 - struct drm_connector_state *conn_state)
96 +static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge,
97 + struct drm_bridge_state *old_state)
98 {
99 - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
100 - struct vc4_dsi *dsi = vc4_encoder->dsi;
101 + struct drm_atomic_state *state = old_state->base.state;
102 + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
103 + const struct drm_crtc_state *crtc_state;
104 struct device *dev = &dsi->pdev->dev;
105 const struct drm_display_mode *mode;
106 + struct drm_connector *connector;
107 bool debug_dump_regs = false;
108 unsigned long hs_clock;
109 + struct drm_crtc *crtc;
110 u32 ui_ns;
111 /* Minimum LP state duration in escape clock cycles. */
112 u32 lpx = dsi_esc_timing(60);
113 @@ -888,6 +906,14 @@ static void vc4_dsi_encoder_mode_set(str
114 drm_print_regset32(&p, &dsi->regset);
115 }
116
117 + /*
118 + * Retrieve the CRTC adjusted mode. This requires a little dance to go
119 + * from the bridge to the encoder, to the connector and to the CRTC.
120 + */
121 + connector = drm_atomic_get_new_connector_for_encoder(state,
122 + bridge->encoder);
123 + crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
124 + crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
125 mode = &crtc_state->adjusted_mode;
126
127 pixel_clock_hz = mode->clock * 1000;
128 @@ -1102,14 +1128,6 @@ static void vc4_dsi_encoder_mode_set(str
129 ~DSI_PORT_BIT(PHY_AFEC0_RESET));
130
131 vc4_dsi_ulps(dsi, false);
132 -}
133 -
134 -static void vc4_dsi_encoder_enable(struct drm_encoder *encoder,
135 - struct drm_atomic_state *state)
136 -{
137 - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
138 - struct vc4_dsi *dsi = vc4_encoder->dsi;
139 - bool debug_dump_regs = false;
140
141 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
142 DSI_PORT_WRITE(DISP0_CTRL,
143 @@ -1118,13 +1136,23 @@ static void vc4_dsi_encoder_enable(struc
144 VC4_SET_FIELD(dsi->format, DSI_DISP0_PFORMAT) |
145 VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME,
146 DSI_DISP0_LP_STOP_CTRL) |
147 - DSI_DISP0_ST_END |
148 - DSI_DISP0_ENABLE);
149 + DSI_DISP0_ST_END);
150 } else {
151 DSI_PORT_WRITE(DISP0_CTRL,
152 - DSI_DISP0_COMMAND_MODE |
153 - DSI_DISP0_ENABLE);
154 + DSI_DISP0_COMMAND_MODE);
155 }
156 +}
157 +
158 +static void vc4_dsi_bridge_enable(struct drm_bridge *bridge,
159 + struct drm_bridge_state *old_state)
160 +{
161 + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
162 + bool debug_dump_regs = false;
163 + u32 disp0_ctrl;
164 +
165 + disp0_ctrl = DSI_PORT_READ(DISP0_CTRL);
166 + disp0_ctrl |= DSI_DISP0_ENABLE;
167 + DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl);
168
169 if (debug_dump_regs) {
170 struct drm_printer p = drm_info_printer(&dsi->pdev->dev);
171 @@ -1133,6 +1161,16 @@ static void vc4_dsi_encoder_enable(struc
172 }
173 }
174
175 +static int vc4_dsi_bridge_attach(struct drm_bridge *bridge,
176 + enum drm_bridge_attach_flags flags)
177 +{
178 + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
179 +
180 + /* Attach the panel or bridge to the dsi bridge */
181 + return drm_bridge_attach(bridge->encoder, dsi->out_bridge,
182 + &dsi->bridge, flags);
183 +}
184 +
185 static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
186 const struct mipi_dsi_msg *msg)
187 {
188 @@ -1309,6 +1347,7 @@ static int vc4_dsi_host_attach(struct mi
189 struct mipi_dsi_device *device)
190 {
191 struct vc4_dsi *dsi = host_to_dsi(host);
192 + int ret;
193
194 dsi->lanes = device->lanes;
195 dsi->channel = device->channel;
196 @@ -1343,7 +1382,15 @@ static int vc4_dsi_host_attach(struct mi
197 return 0;
198 }
199
200 - return component_add(&dsi->pdev->dev, &vc4_dsi_ops);
201 + drm_bridge_add(&dsi->bridge);
202 +
203 + ret = component_add(&dsi->pdev->dev, &vc4_dsi_ops);
204 + if (ret) {
205 + drm_bridge_remove(&dsi->bridge);
206 + return ret;
207 + }
208 +
209 + return 0;
210 }
211
212 static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
213 @@ -1352,6 +1399,7 @@ static int vc4_dsi_host_detach(struct mi
214 struct vc4_dsi *dsi = host_to_dsi(host);
215
216 component_del(&dsi->pdev->dev, &vc4_dsi_ops);
217 + drm_bridge_remove(&dsi->bridge);
218 return 0;
219 }
220
221 @@ -1361,11 +1409,16 @@ static const struct mipi_dsi_host_ops vc
222 .transfer = vc4_dsi_host_transfer,
223 };
224
225 -static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = {
226 - .atomic_disable = vc4_dsi_encoder_disable,
227 - .atomic_enable = vc4_dsi_encoder_enable,
228 - .mode_fixup = vc4_dsi_encoder_mode_fixup,
229 - .atomic_mode_set = vc4_dsi_encoder_mode_set,
230 +static const struct drm_bridge_funcs vc4_dsi_bridge_funcs = {
231 + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
232 + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
233 + .atomic_reset = drm_atomic_helper_bridge_reset,
234 + .atomic_pre_enable = vc4_dsi_bridge_pre_enable,
235 + .atomic_enable = vc4_dsi_bridge_enable,
236 + .atomic_disable = vc4_dsi_bridge_disable,
237 + .atomic_post_disable = vc4_dsi_bridge_post_disable,
238 + .attach = vc4_dsi_bridge_attach,
239 + .mode_fixup = vc4_dsi_bridge_mode_fixup,
240 };
241
242 static const struct vc4_dsi_variant bcm2711_dsi1_variant = {
243 @@ -1691,9 +1744,8 @@ static int vc4_dsi_bind(struct device *d
244 goto err_free_dma;
245
246 drm_simple_encoder_init(drm, dsi->encoder, DRM_MODE_ENCODER_DSI);
247 - drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
248
249 - ret = drm_bridge_attach(dsi->encoder, dsi->out_bridge, NULL, 0);
250 + ret = drm_bridge_attach(dsi->encoder, &dsi->bridge, NULL, 0);
251 if (ret) {
252 dev_err(dev, "bridge attach failed: %d\n", ret);
253 goto err_free_dma;
254 @@ -1755,6 +1807,10 @@ static int vc4_dsi_dev_probe(struct plat
255 return -ENOMEM;
256 dev_set_drvdata(dev, dsi);
257
258 + dsi->bridge.funcs = &vc4_dsi_bridge_funcs;
259 + dsi->bridge.of_node = dev->of_node;
260 + dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
261 +
262 dsi->pdev = pdev;
263 dsi->dsi_host.ops = &vc4_dsi_host_ops;
264 dsi->dsi_host.dev = dev;