1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd |
4 | * Copyright (C) STMicroelectronics SA 2017 |
5 | * |
6 | * Modified by Philippe Cornu <philippe.cornu@st.com> |
7 | * This generic Synopsys DesignWare MIPI DSI host driver is based on the |
8 | * Rockchip version from rockchip/dw-mipi-dsi.c with phy & bridge APIs. |
9 | */ |
10 | |
11 | #include <linux/clk.h> |
12 | #include <linux/component.h> |
13 | #include <linux/debugfs.h> |
14 | #include <linux/iopoll.h> |
15 | #include <linux/math64.h> |
16 | #include <linux/media-bus-format.h> |
17 | #include <linux/module.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/pm_runtime.h> |
20 | #include <linux/reset.h> |
21 | |
22 | #include <video/mipi_display.h> |
23 | |
24 | #include <drm/bridge/dw_mipi_dsi.h> |
25 | #include <drm/drm_atomic_helper.h> |
26 | #include <drm/drm_bridge.h> |
27 | #include <drm/drm_connector.h> |
28 | #include <drm/drm_crtc.h> |
29 | #include <drm/drm_mipi_dsi.h> |
30 | #include <drm/drm_modes.h> |
31 | #include <drm/drm_of.h> |
32 | #include <drm/drm_print.h> |
33 | |
34 | #define HWVER_131 0x31333100 /* IP version 1.31 */ |
35 | |
36 | #define DSI_VERSION 0x00 |
37 | #define VERSION GENMASK(31, 8) |
38 | |
39 | #define DSI_PWR_UP 0x04 |
40 | #define RESET 0 |
41 | #define POWERUP BIT(0) |
42 | |
43 | #define DSI_CLKMGR_CFG 0x08 |
44 | #define TO_CLK_DIVISION(div) (((div) & 0xff) << 8) |
45 | #define TX_ESC_CLK_DIVISION(div) ((div) & 0xff) |
46 | |
47 | #define DSI_DPI_VCID 0x0c |
48 | #define DPI_VCID(vcid) ((vcid) & 0x3) |
49 | |
50 | #define DSI_DPI_COLOR_CODING 0x10 |
51 | #define LOOSELY18_EN BIT(8) |
52 | #define DPI_COLOR_CODING_16BIT_1 0x0 |
53 | #define DPI_COLOR_CODING_16BIT_2 0x1 |
54 | #define DPI_COLOR_CODING_16BIT_3 0x2 |
55 | #define DPI_COLOR_CODING_18BIT_1 0x3 |
56 | #define DPI_COLOR_CODING_18BIT_2 0x4 |
57 | #define DPI_COLOR_CODING_24BIT 0x5 |
58 | |
59 | #define DSI_DPI_CFG_POL 0x14 |
60 | #define COLORM_ACTIVE_LOW BIT(4) |
61 | #define SHUTD_ACTIVE_LOW BIT(3) |
62 | #define HSYNC_ACTIVE_LOW BIT(2) |
63 | #define VSYNC_ACTIVE_LOW BIT(1) |
64 | #define DATAEN_ACTIVE_LOW BIT(0) |
65 | |
66 | #define DSI_DPI_LP_CMD_TIM 0x18 |
67 | #define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16) |
68 | #define INVACT_LPCMD_TIME(p) ((p) & 0xff) |
69 | |
70 | #define DSI_DBI_VCID 0x1c |
71 | #define DSI_DBI_CFG 0x20 |
72 | #define DSI_DBI_PARTITIONING_EN 0x24 |
73 | #define DSI_DBI_CMDSIZE 0x28 |
74 | |
75 | #define DSI_PCKHDL_CFG 0x2c |
76 | #define CRC_RX_EN BIT(4) |
77 | #define ECC_RX_EN BIT(3) |
78 | #define BTA_EN BIT(2) |
79 | #define EOTP_RX_EN BIT(1) |
80 | #define EOTP_TX_EN BIT(0) |
81 | |
82 | #define DSI_GEN_VCID 0x30 |
83 | |
84 | #define DSI_MODE_CFG 0x34 |
85 | #define ENABLE_VIDEO_MODE 0 |
86 | #define ENABLE_CMD_MODE BIT(0) |
87 | |
88 | #define DSI_VID_MODE_CFG 0x38 |
89 | #define ENABLE_LOW_POWER (0x3f << 8) |
90 | #define ENABLE_LOW_POWER_MASK (0x3f << 8) |
91 | #define VID_MODE_TYPE_NON_BURST_SYNC_PULSES 0x0 |
92 | #define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS 0x1 |
93 | #define VID_MODE_TYPE_BURST 0x2 |
94 | #define VID_MODE_TYPE_MASK 0x3 |
95 | #define ENABLE_LOW_POWER_CMD BIT(15) |
96 | #define VID_MODE_VPG_ENABLE BIT(16) |
97 | #define VID_MODE_VPG_MODE BIT(20) |
98 | #define VID_MODE_VPG_HORIZONTAL BIT(24) |
99 | |
100 | #define DSI_VID_PKT_SIZE 0x3c |
101 | #define VID_PKT_SIZE(p) ((p) & 0x3fff) |
102 | |
103 | #define DSI_VID_NUM_CHUNKS 0x40 |
104 | #define VID_NUM_CHUNKS(c) ((c) & 0x1fff) |
105 | |
106 | #define DSI_VID_NULL_SIZE 0x44 |
107 | #define VID_NULL_SIZE(b) ((b) & 0x1fff) |
108 | |
109 | #define DSI_VID_HSA_TIME 0x48 |
110 | #define DSI_VID_HBP_TIME 0x4c |
111 | #define DSI_VID_HLINE_TIME 0x50 |
112 | #define DSI_VID_VSA_LINES 0x54 |
113 | #define DSI_VID_VBP_LINES 0x58 |
114 | #define DSI_VID_VFP_LINES 0x5c |
115 | #define DSI_VID_VACTIVE_LINES 0x60 |
116 | #define DSI_EDPI_CMD_SIZE 0x64 |
117 | |
118 | #define DSI_CMD_MODE_CFG 0x68 |
119 | #define MAX_RD_PKT_SIZE_LP BIT(24) |
120 | #define DCS_LW_TX_LP BIT(19) |
121 | #define DCS_SR_0P_TX_LP BIT(18) |
122 | #define DCS_SW_1P_TX_LP BIT(17) |
123 | #define DCS_SW_0P_TX_LP BIT(16) |
124 | #define GEN_LW_TX_LP BIT(14) |
125 | #define GEN_SR_2P_TX_LP BIT(13) |
126 | #define GEN_SR_1P_TX_LP BIT(12) |
127 | #define GEN_SR_0P_TX_LP BIT(11) |
128 | #define GEN_SW_2P_TX_LP BIT(10) |
129 | #define GEN_SW_1P_TX_LP BIT(9) |
130 | #define GEN_SW_0P_TX_LP BIT(8) |
131 | #define ACK_RQST_EN BIT(1) |
132 | #define TEAR_FX_EN BIT(0) |
133 | |
134 | #define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \ |
135 | DCS_LW_TX_LP | \ |
136 | DCS_SR_0P_TX_LP | \ |
137 | DCS_SW_1P_TX_LP | \ |
138 | DCS_SW_0P_TX_LP | \ |
139 | GEN_LW_TX_LP | \ |
140 | GEN_SR_2P_TX_LP | \ |
141 | GEN_SR_1P_TX_LP | \ |
142 | GEN_SR_0P_TX_LP | \ |
143 | GEN_SW_2P_TX_LP | \ |
144 | GEN_SW_1P_TX_LP | \ |
145 | GEN_SW_0P_TX_LP) |
146 | |
147 | #define DSI_GEN_HDR 0x6c |
148 | #define DSI_GEN_PLD_DATA 0x70 |
149 | |
150 | #define DSI_CMD_PKT_STATUS 0x74 |
151 | #define GEN_RD_CMD_BUSY BIT(6) |
152 | #define GEN_PLD_R_FULL BIT(5) |
153 | #define GEN_PLD_R_EMPTY BIT(4) |
154 | #define GEN_PLD_W_FULL BIT(3) |
155 | #define GEN_PLD_W_EMPTY BIT(2) |
156 | #define GEN_CMD_FULL BIT(1) |
157 | #define GEN_CMD_EMPTY BIT(0) |
158 | |
159 | #define DSI_TO_CNT_CFG 0x78 |
160 | #define HSTX_TO_CNT(p) (((p) & 0xffff) << 16) |
161 | #define LPRX_TO_CNT(p) ((p) & 0xffff) |
162 | |
163 | #define DSI_HS_RD_TO_CNT 0x7c |
164 | #define DSI_LP_RD_TO_CNT 0x80 |
165 | #define DSI_HS_WR_TO_CNT 0x84 |
166 | #define DSI_LP_WR_TO_CNT 0x88 |
167 | #define DSI_BTA_TO_CNT 0x8c |
168 | |
169 | #define DSI_LPCLK_CTRL 0x94 |
170 | #define AUTO_CLKLANE_CTRL BIT(1) |
171 | #define PHY_TXREQUESTCLKHS BIT(0) |
172 | |
173 | #define DSI_PHY_TMR_LPCLK_CFG 0x98 |
174 | #define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16) |
175 | #define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff) |
176 | |
177 | #define DSI_PHY_TMR_CFG 0x9c |
178 | #define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24) |
179 | #define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16) |
180 | #define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff) |
181 | #define PHY_HS2LP_TIME_V131(lbcc) (((lbcc) & 0x3ff) << 16) |
182 | #define PHY_LP2HS_TIME_V131(lbcc) ((lbcc) & 0x3ff) |
183 | |
184 | #define DSI_PHY_RSTZ 0xa0 |
185 | #define PHY_DISFORCEPLL 0 |
186 | #define PHY_ENFORCEPLL BIT(3) |
187 | #define PHY_DISABLECLK 0 |
188 | #define PHY_ENABLECLK BIT(2) |
189 | #define PHY_RSTZ 0 |
190 | #define PHY_UNRSTZ BIT(1) |
191 | #define PHY_SHUTDOWNZ 0 |
192 | #define PHY_UNSHUTDOWNZ BIT(0) |
193 | |
194 | #define DSI_PHY_IF_CFG 0xa4 |
195 | #define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8) |
196 | #define N_LANES(n) (((n) - 1) & 0x3) |
197 | |
198 | #define DSI_PHY_ULPS_CTRL 0xa8 |
199 | #define DSI_PHY_TX_TRIGGERS 0xac |
200 | |
201 | #define DSI_PHY_STATUS 0xb0 |
202 | #define PHY_STOP_STATE_CLK_LANE BIT(2) |
203 | #define PHY_LOCK BIT(0) |
204 | |
205 | #define DSI_PHY_TST_CTRL0 0xb4 |
206 | #define PHY_TESTCLK BIT(1) |
207 | #define PHY_UNTESTCLK 0 |
208 | #define PHY_TESTCLR BIT(0) |
209 | #define PHY_UNTESTCLR 0 |
210 | |
211 | #define DSI_PHY_TST_CTRL1 0xb8 |
212 | #define PHY_TESTEN BIT(16) |
213 | #define PHY_UNTESTEN 0 |
214 | #define PHY_TESTDOUT(n) (((n) & 0xff) << 8) |
215 | #define PHY_TESTDIN(n) ((n) & 0xff) |
216 | |
217 | #define DSI_INT_ST0 0xbc |
218 | #define DSI_INT_ST1 0xc0 |
219 | #define DSI_INT_MSK0 0xc4 |
220 | #define DSI_INT_MSK1 0xc8 |
221 | |
222 | #define DSI_PHY_TMR_RD_CFG 0xf4 |
223 | #define MAX_RD_TIME_V131(lbcc) ((lbcc) & 0x7fff) |
224 | |
225 | #define PHY_STATUS_TIMEOUT_US 10000 |
226 | #define CMD_PKT_STATUS_TIMEOUT_US 20000 |
227 | |
228 | #ifdef CONFIG_DEBUG_FS |
229 | #define VPG_DEFS(name, dsi) \ |
230 | ((void __force *)&((*dsi).vpg_defs.name)) |
231 | |
232 | #define REGISTER(name, mask, dsi) \ |
233 | { #name, VPG_DEFS(name, dsi), mask, dsi } |
234 | |
235 | struct debugfs_entries { |
236 | const char *name; |
237 | bool *reg; |
238 | u32 mask; |
239 | struct dw_mipi_dsi *dsi; |
240 | }; |
241 | #endif /* CONFIG_DEBUG_FS */ |
242 | |
243 | struct dw_mipi_dsi { |
244 | struct drm_bridge bridge; |
245 | struct mipi_dsi_host dsi_host; |
246 | struct drm_bridge *panel_bridge; |
247 | struct device *dev; |
248 | void __iomem *base; |
249 | |
250 | struct clk *pclk; |
251 | |
252 | unsigned int lane_mbps; /* per lane */ |
253 | u32 channel; |
254 | u32 lanes; |
255 | u32 format; |
256 | unsigned long mode_flags; |
257 | |
258 | #ifdef CONFIG_DEBUG_FS |
259 | struct dentry *debugfs; |
260 | struct debugfs_entries *debugfs_vpg; |
261 | struct { |
262 | bool vpg; |
263 | bool vpg_horizontal; |
264 | bool vpg_ber_pattern; |
265 | } vpg_defs; |
266 | #endif /* CONFIG_DEBUG_FS */ |
267 | |
268 | struct dw_mipi_dsi *master; /* dual-dsi master ptr */ |
269 | struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */ |
270 | |
271 | struct drm_display_mode mode; |
272 | const struct dw_mipi_dsi_plat_data *plat_data; |
273 | }; |
274 | |
275 | /* |
276 | * Check if either a link to a master or slave is present |
277 | */ |
278 | static inline bool dw_mipi_is_dual_mode(struct dw_mipi_dsi *dsi) |
279 | { |
280 | return dsi->slave || dsi->master; |
281 | } |
282 | |
283 | /* |
284 | * The controller should generate 2 frames before |
285 | * preparing the peripheral. |
286 | */ |
287 | static void dw_mipi_dsi_wait_for_two_frames(const struct drm_display_mode *mode) |
288 | { |
289 | int refresh, two_frames; |
290 | |
291 | refresh = drm_mode_vrefresh(mode); |
292 | two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2; |
293 | msleep(msecs: two_frames); |
294 | } |
295 | |
296 | static inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host) |
297 | { |
298 | return container_of(host, struct dw_mipi_dsi, dsi_host); |
299 | } |
300 | |
301 | static inline struct dw_mipi_dsi *bridge_to_dsi(struct drm_bridge *bridge) |
302 | { |
303 | return container_of(bridge, struct dw_mipi_dsi, bridge); |
304 | } |
305 | |
306 | static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val) |
307 | { |
308 | writel(val, addr: dsi->base + reg); |
309 | } |
310 | |
311 | static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg) |
312 | { |
313 | return readl(addr: dsi->base + reg); |
314 | } |
315 | |
316 | static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, |
317 | struct mipi_dsi_device *device) |
318 | { |
319 | struct dw_mipi_dsi *dsi = host_to_dsi(host); |
320 | const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; |
321 | struct drm_bridge *bridge; |
322 | int ret; |
323 | |
324 | if (device->lanes > dsi->plat_data->max_data_lanes) { |
325 | dev_err(dsi->dev, "the number of data lanes(%u) is too many\n" , |
326 | device->lanes); |
327 | return -EINVAL; |
328 | } |
329 | |
330 | dsi->lanes = device->lanes; |
331 | dsi->channel = device->channel; |
332 | dsi->format = device->format; |
333 | dsi->mode_flags = device->mode_flags; |
334 | |
335 | bridge = devm_drm_of_get_bridge(dev: dsi->dev, node: dsi->dev->of_node, port: 1, endpoint: 0); |
336 | if (IS_ERR(ptr: bridge)) |
337 | return PTR_ERR(ptr: bridge); |
338 | |
339 | bridge->pre_enable_prev_first = true; |
340 | dsi->panel_bridge = bridge; |
341 | |
342 | drm_bridge_add(bridge: &dsi->bridge); |
343 | |
344 | if (pdata->host_ops && pdata->host_ops->attach) { |
345 | ret = pdata->host_ops->attach(pdata->priv_data, device); |
346 | if (ret < 0) |
347 | return ret; |
348 | } |
349 | |
350 | return 0; |
351 | } |
352 | |
353 | static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, |
354 | struct mipi_dsi_device *device) |
355 | { |
356 | struct dw_mipi_dsi *dsi = host_to_dsi(host); |
357 | const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; |
358 | int ret; |
359 | |
360 | if (pdata->host_ops && pdata->host_ops->detach) { |
361 | ret = pdata->host_ops->detach(pdata->priv_data, device); |
362 | if (ret < 0) |
363 | return ret; |
364 | } |
365 | |
366 | drm_of_panel_bridge_remove(np: host->dev->of_node, port: 1, endpoint: 0); |
367 | |
368 | drm_bridge_remove(bridge: &dsi->bridge); |
369 | |
370 | return 0; |
371 | } |
372 | |
373 | static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, |
374 | const struct mipi_dsi_msg *msg) |
375 | { |
376 | bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM; |
377 | u32 val = 0; |
378 | |
379 | /* |
380 | * TODO dw drv improvements |
381 | * largest packet sizes during hfp or during vsa/vpb/vfp |
382 | * should be computed according to byte lane, lane number and only |
383 | * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS) |
384 | */ |
385 | dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(16) |
386 | | INVACT_LPCMD_TIME(4)); |
387 | |
388 | if (msg->flags & MIPI_DSI_MSG_REQ_ACK) |
389 | val |= ACK_RQST_EN; |
390 | if (lpm) |
391 | val |= CMD_MODE_ALL_LP; |
392 | |
393 | dsi_write(dsi, DSI_CMD_MODE_CFG, val); |
394 | |
395 | val = dsi_read(dsi, DSI_VID_MODE_CFG); |
396 | if (lpm) |
397 | val |= ENABLE_LOW_POWER_CMD; |
398 | else |
399 | val &= ~ENABLE_LOW_POWER_CMD; |
400 | dsi_write(dsi, DSI_VID_MODE_CFG, val); |
401 | } |
402 | |
403 | static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) |
404 | { |
405 | int ret; |
406 | u32 val, mask; |
407 | |
408 | ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, |
409 | val, !(val & GEN_CMD_FULL), 1000, |
410 | CMD_PKT_STATUS_TIMEOUT_US); |
411 | if (ret) { |
412 | dev_err(dsi->dev, "failed to get available command FIFO\n" ); |
413 | return ret; |
414 | } |
415 | |
416 | dsi_write(dsi, DSI_GEN_HDR, val: hdr_val); |
417 | |
418 | mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY; |
419 | ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, |
420 | val, (val & mask) == mask, |
421 | 1000, CMD_PKT_STATUS_TIMEOUT_US); |
422 | if (ret) { |
423 | dev_err(dsi->dev, "failed to write command FIFO\n" ); |
424 | return ret; |
425 | } |
426 | |
427 | return 0; |
428 | } |
429 | |
430 | static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, |
431 | const struct mipi_dsi_packet *packet) |
432 | { |
433 | const u8 *tx_buf = packet->payload; |
434 | int len = packet->payload_length, pld_data_bytes = sizeof(u32), ret; |
435 | __le32 word; |
436 | u32 val; |
437 | |
438 | while (len) { |
439 | if (len < pld_data_bytes) { |
440 | word = 0; |
441 | memcpy(&word, tx_buf, len); |
442 | dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); |
443 | len = 0; |
444 | } else { |
445 | memcpy(&word, tx_buf, pld_data_bytes); |
446 | dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); |
447 | tx_buf += pld_data_bytes; |
448 | len -= pld_data_bytes; |
449 | } |
450 | |
451 | ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, |
452 | val, !(val & GEN_PLD_W_FULL), 1000, |
453 | CMD_PKT_STATUS_TIMEOUT_US); |
454 | if (ret) { |
455 | dev_err(dsi->dev, |
456 | "failed to get available write payload FIFO\n" ); |
457 | return ret; |
458 | } |
459 | } |
460 | |
461 | word = 0; |
462 | memcpy(&word, packet->header, sizeof(packet->header)); |
463 | return dw_mipi_dsi_gen_pkt_hdr_write(dsi, le32_to_cpu(word)); |
464 | } |
465 | |
466 | static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, |
467 | const struct mipi_dsi_msg *msg) |
468 | { |
469 | int i, j, ret, len = msg->rx_len; |
470 | u8 *buf = msg->rx_buf; |
471 | u32 val; |
472 | |
473 | /* Wait end of the read operation */ |
474 | ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, |
475 | val, !(val & GEN_RD_CMD_BUSY), |
476 | 1000, CMD_PKT_STATUS_TIMEOUT_US); |
477 | if (ret) { |
478 | dev_err(dsi->dev, "Timeout during read operation\n" ); |
479 | return ret; |
480 | } |
481 | |
482 | for (i = 0; i < len; i += 4) { |
483 | /* Read fifo must not be empty before all bytes are read */ |
484 | ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, |
485 | val, !(val & GEN_PLD_R_EMPTY), |
486 | 1000, CMD_PKT_STATUS_TIMEOUT_US); |
487 | if (ret) { |
488 | dev_err(dsi->dev, "Read payload FIFO is empty\n" ); |
489 | return ret; |
490 | } |
491 | |
492 | val = dsi_read(dsi, DSI_GEN_PLD_DATA); |
493 | for (j = 0; j < 4 && j + i < len; j++) |
494 | buf[i + j] = val >> (8 * j); |
495 | } |
496 | |
497 | return ret; |
498 | } |
499 | |
500 | static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, |
501 | const struct mipi_dsi_msg *msg) |
502 | { |
503 | struct dw_mipi_dsi *dsi = host_to_dsi(host); |
504 | struct mipi_dsi_packet packet; |
505 | int ret, nb_bytes; |
506 | |
507 | ret = mipi_dsi_create_packet(packet: &packet, msg); |
508 | if (ret) { |
509 | dev_err(dsi->dev, "failed to create packet: %d\n" , ret); |
510 | return ret; |
511 | } |
512 | |
513 | dw_mipi_message_config(dsi, msg); |
514 | if (dsi->slave) |
515 | dw_mipi_message_config(dsi: dsi->slave, msg); |
516 | |
517 | ret = dw_mipi_dsi_write(dsi, packet: &packet); |
518 | if (ret) |
519 | return ret; |
520 | if (dsi->slave) { |
521 | ret = dw_mipi_dsi_write(dsi: dsi->slave, packet: &packet); |
522 | if (ret) |
523 | return ret; |
524 | } |
525 | |
526 | if (msg->rx_buf && msg->rx_len) { |
527 | ret = dw_mipi_dsi_read(dsi, msg); |
528 | if (ret) |
529 | return ret; |
530 | nb_bytes = msg->rx_len; |
531 | } else { |
532 | nb_bytes = packet.size; |
533 | } |
534 | |
535 | return nb_bytes; |
536 | } |
537 | |
538 | static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = { |
539 | .attach = dw_mipi_dsi_host_attach, |
540 | .detach = dw_mipi_dsi_host_detach, |
541 | .transfer = dw_mipi_dsi_host_transfer, |
542 | }; |
543 | |
544 | static u32 * |
545 | dw_mipi_dsi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, |
546 | struct drm_bridge_state *bridge_state, |
547 | struct drm_crtc_state *crtc_state, |
548 | struct drm_connector_state *conn_state, |
549 | u32 output_fmt, |
550 | unsigned int *num_input_fmts) |
551 | { |
552 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
553 | const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; |
554 | u32 *input_fmts; |
555 | |
556 | if (pdata->get_input_bus_fmts) |
557 | return pdata->get_input_bus_fmts(pdata->priv_data, |
558 | bridge, bridge_state, |
559 | crtc_state, conn_state, |
560 | output_fmt, num_input_fmts); |
561 | |
562 | /* Fall back to MEDIA_BUS_FMT_FIXED as the only input format. */ |
563 | input_fmts = kmalloc(size: sizeof(*input_fmts), GFP_KERNEL); |
564 | if (!input_fmts) |
565 | return NULL; |
566 | input_fmts[0] = MEDIA_BUS_FMT_FIXED; |
567 | *num_input_fmts = 1; |
568 | |
569 | return input_fmts; |
570 | } |
571 | |
572 | static int dw_mipi_dsi_bridge_atomic_check(struct drm_bridge *bridge, |
573 | struct drm_bridge_state *bridge_state, |
574 | struct drm_crtc_state *crtc_state, |
575 | struct drm_connector_state *conn_state) |
576 | { |
577 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
578 | const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; |
579 | bool ret; |
580 | |
581 | bridge_state->input_bus_cfg.flags = |
582 | DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE; |
583 | |
584 | if (pdata->mode_fixup) { |
585 | ret = pdata->mode_fixup(pdata->priv_data, &crtc_state->mode, |
586 | &crtc_state->adjusted_mode); |
587 | if (!ret) { |
588 | DRM_DEBUG_DRIVER("failed to fixup mode " DRM_MODE_FMT "\n" , |
589 | DRM_MODE_ARG(&crtc_state->mode)); |
590 | return -EINVAL; |
591 | } |
592 | } |
593 | |
594 | return 0; |
595 | } |
596 | |
597 | static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) |
598 | { |
599 | u32 val; |
600 | |
601 | /* |
602 | * TODO dw drv improvements |
603 | * enabling low power is panel-dependent, we should use the |
604 | * panel configuration here... |
605 | */ |
606 | val = ENABLE_LOW_POWER; |
607 | |
608 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) |
609 | val |= VID_MODE_TYPE_BURST; |
610 | else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) |
611 | val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES; |
612 | else |
613 | val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS; |
614 | |
615 | #ifdef CONFIG_DEBUG_FS |
616 | if (dsi->vpg_defs.vpg) { |
617 | val |= VID_MODE_VPG_ENABLE; |
618 | val |= dsi->vpg_defs.vpg_horizontal ? |
619 | VID_MODE_VPG_HORIZONTAL : 0; |
620 | val |= dsi->vpg_defs.vpg_ber_pattern ? VID_MODE_VPG_MODE : 0; |
621 | } |
622 | #endif /* CONFIG_DEBUG_FS */ |
623 | |
624 | dsi_write(dsi, DSI_VID_MODE_CFG, val); |
625 | } |
626 | |
627 | static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, |
628 | unsigned long mode_flags) |
629 | { |
630 | u32 val; |
631 | |
632 | dsi_write(dsi, DSI_PWR_UP, RESET); |
633 | |
634 | if (mode_flags & MIPI_DSI_MODE_VIDEO) { |
635 | dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE); |
636 | dw_mipi_dsi_video_mode_config(dsi); |
637 | } else { |
638 | dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); |
639 | } |
640 | |
641 | val = PHY_TXREQUESTCLKHS; |
642 | if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) |
643 | val |= AUTO_CLKLANE_CTRL; |
644 | dsi_write(dsi, DSI_LPCLK_CTRL, val); |
645 | |
646 | dsi_write(dsi, DSI_PWR_UP, POWERUP); |
647 | } |
648 | |
649 | static void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi) |
650 | { |
651 | dsi_write(dsi, DSI_PWR_UP, RESET); |
652 | dsi_write(dsi, DSI_PHY_RSTZ, PHY_RSTZ); |
653 | } |
654 | |
655 | static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) |
656 | { |
657 | const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; |
658 | unsigned int esc_rate; /* in MHz */ |
659 | u32 esc_clk_division; |
660 | int ret; |
661 | |
662 | /* |
663 | * The maximum permitted escape clock is 20MHz and it is derived from |
664 | * lanebyteclk, which is running at "lane_mbps / 8". |
665 | */ |
666 | if (phy_ops->get_esc_clk_rate) { |
667 | ret = phy_ops->get_esc_clk_rate(dsi->plat_data->priv_data, |
668 | &esc_rate); |
669 | if (ret) |
670 | DRM_DEBUG_DRIVER("Phy get_esc_clk_rate() failed\n" ); |
671 | } else |
672 | esc_rate = 20; /* Default to 20MHz */ |
673 | |
674 | /* |
675 | * We want : |
676 | * (lane_mbps >> 3) / esc_clk_division < X |
677 | * which is: |
678 | * (lane_mbps >> 3) / X > esc_clk_division |
679 | */ |
680 | esc_clk_division = (dsi->lane_mbps >> 3) / esc_rate + 1; |
681 | |
682 | dsi_write(dsi, DSI_PWR_UP, RESET); |
683 | |
684 | /* |
685 | * TODO dw drv improvements |
686 | * timeout clock division should be computed with the |
687 | * high speed transmission counter timeout and byte lane... |
688 | */ |
689 | dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVISION(0) | |
690 | TX_ESC_CLK_DIVISION(esc_clk_division)); |
691 | } |
692 | |
693 | static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, |
694 | const struct drm_display_mode *mode) |
695 | { |
696 | u32 val = 0, color = 0; |
697 | |
698 | switch (dsi->format) { |
699 | case MIPI_DSI_FMT_RGB888: |
700 | color = DPI_COLOR_CODING_24BIT; |
701 | break; |
702 | case MIPI_DSI_FMT_RGB666: |
703 | color = DPI_COLOR_CODING_18BIT_2 | LOOSELY18_EN; |
704 | break; |
705 | case MIPI_DSI_FMT_RGB666_PACKED: |
706 | color = DPI_COLOR_CODING_18BIT_1; |
707 | break; |
708 | case MIPI_DSI_FMT_RGB565: |
709 | color = DPI_COLOR_CODING_16BIT_1; |
710 | break; |
711 | } |
712 | |
713 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
714 | val |= VSYNC_ACTIVE_LOW; |
715 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
716 | val |= HSYNC_ACTIVE_LOW; |
717 | |
718 | dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel)); |
719 | dsi_write(dsi, DSI_DPI_COLOR_CODING, val: color); |
720 | dsi_write(dsi, DSI_DPI_CFG_POL, val); |
721 | } |
722 | |
723 | static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi) |
724 | { |
725 | dsi_write(dsi, DSI_PCKHDL_CFG, CRC_RX_EN | ECC_RX_EN | BTA_EN); |
726 | } |
727 | |
728 | static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, |
729 | const struct drm_display_mode *mode) |
730 | { |
731 | /* |
732 | * TODO dw drv improvements |
733 | * only burst mode is supported here. For non-burst video modes, |
734 | * we should compute DSI_VID_PKT_SIZE, DSI_VCCR.NUMC & |
735 | * DSI_VNPCR.NPSIZE... especially because this driver supports |
736 | * non-burst video modes, see dw_mipi_dsi_video_mode_config()... |
737 | */ |
738 | |
739 | dsi_write(dsi, DSI_VID_PKT_SIZE, |
740 | val: dw_mipi_is_dual_mode(dsi) ? |
741 | VID_PKT_SIZE(mode->hdisplay / 2) : |
742 | VID_PKT_SIZE(mode->hdisplay)); |
743 | } |
744 | |
745 | static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) |
746 | { |
747 | /* |
748 | * TODO dw drv improvements |
749 | * compute high speed transmission counter timeout according |
750 | * to the timeout clock division (TO_CLK_DIVISION) and byte lane... |
751 | */ |
752 | dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(0) | LPRX_TO_CNT(0)); |
753 | /* |
754 | * TODO dw drv improvements |
755 | * the Bus-Turn-Around Timeout Counter should be computed |
756 | * according to byte lane... |
757 | */ |
758 | dsi_write(dsi, DSI_BTA_TO_CNT, val: 0xd00); |
759 | dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); |
760 | } |
761 | |
762 | static const u32 minimum_lbccs[] = {10, 5, 4, 3}; |
763 | |
764 | static inline u32 dw_mipi_dsi_get_minimum_lbcc(struct dw_mipi_dsi *dsi) |
765 | { |
766 | return minimum_lbccs[dsi->lanes - 1]; |
767 | } |
768 | |
769 | /* Get lane byte clock cycles. */ |
770 | static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, |
771 | const struct drm_display_mode *mode, |
772 | u32 hcomponent) |
773 | { |
774 | u32 frac, lbcc, minimum_lbcc; |
775 | int bpp; |
776 | |
777 | if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { |
778 | /* lbcc based on lane_mbps */ |
779 | lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8; |
780 | } else { |
781 | /* lbcc based on pixel clock rate */ |
782 | bpp = mipi_dsi_pixel_format_to_bpp(fmt: dsi->format); |
783 | if (bpp < 0) { |
784 | dev_err(dsi->dev, "failed to get bpp\n" ); |
785 | return 0; |
786 | } |
787 | |
788 | lbcc = div_u64(dividend: (u64)hcomponent * mode->clock * bpp, divisor: dsi->lanes * 8); |
789 | } |
790 | |
791 | frac = lbcc % mode->clock; |
792 | lbcc = lbcc / mode->clock; |
793 | if (frac) |
794 | lbcc++; |
795 | |
796 | minimum_lbcc = dw_mipi_dsi_get_minimum_lbcc(dsi); |
797 | |
798 | if (lbcc < minimum_lbcc) |
799 | lbcc = minimum_lbcc; |
800 | |
801 | return lbcc; |
802 | } |
803 | |
804 | static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi, |
805 | const struct drm_display_mode *mode) |
806 | { |
807 | u32 htotal, hsa, hbp, lbcc; |
808 | |
809 | htotal = mode->htotal; |
810 | hsa = mode->hsync_end - mode->hsync_start; |
811 | hbp = mode->htotal - mode->hsync_end; |
812 | |
813 | /* |
814 | * TODO dw drv improvements |
815 | * computations below may be improved... |
816 | */ |
817 | lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hcomponent: htotal); |
818 | dsi_write(dsi, DSI_VID_HLINE_TIME, val: lbcc); |
819 | |
820 | lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hcomponent: hsa); |
821 | dsi_write(dsi, DSI_VID_HSA_TIME, val: lbcc); |
822 | |
823 | lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hcomponent: hbp); |
824 | dsi_write(dsi, DSI_VID_HBP_TIME, val: lbcc); |
825 | } |
826 | |
827 | static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, |
828 | const struct drm_display_mode *mode) |
829 | { |
830 | u32 vactive, vsa, vfp, vbp; |
831 | |
832 | vactive = mode->vdisplay; |
833 | vsa = mode->vsync_end - mode->vsync_start; |
834 | vfp = mode->vsync_start - mode->vdisplay; |
835 | vbp = mode->vtotal - mode->vsync_end; |
836 | |
837 | dsi_write(dsi, DSI_VID_VACTIVE_LINES, val: vactive); |
838 | dsi_write(dsi, DSI_VID_VSA_LINES, val: vsa); |
839 | dsi_write(dsi, DSI_VID_VFP_LINES, val: vfp); |
840 | dsi_write(dsi, DSI_VID_VBP_LINES, val: vbp); |
841 | } |
842 | |
843 | static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) |
844 | { |
845 | const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; |
846 | struct dw_mipi_dsi_dphy_timing timing; |
847 | u32 hw_version; |
848 | int ret; |
849 | |
850 | ret = phy_ops->get_timing(dsi->plat_data->priv_data, |
851 | dsi->lane_mbps, &timing); |
852 | if (ret) |
853 | DRM_DEV_ERROR(dsi->dev, "Retrieving phy timings failed\n" ); |
854 | |
855 | /* |
856 | * TODO dw drv improvements |
857 | * data & clock lane timers should be computed according to panel |
858 | * blankings and to the automatic clock lane control mode... |
859 | * note: DSI_PHY_TMR_CFG.MAX_RD_TIME should be in line with |
860 | * DSI_CMD_MODE_CFG.MAX_RD_PKT_SIZE_LP (see CMD_MODE_ALL_LP) |
861 | */ |
862 | |
863 | hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; |
864 | |
865 | if (hw_version >= HWVER_131) { |
866 | dsi_write(dsi, DSI_PHY_TMR_CFG, |
867 | PHY_HS2LP_TIME_V131(timing.data_hs2lp) | |
868 | PHY_LP2HS_TIME_V131(timing.data_lp2hs)); |
869 | dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000)); |
870 | } else { |
871 | dsi_write(dsi, DSI_PHY_TMR_CFG, |
872 | PHY_HS2LP_TIME(timing.data_hs2lp) | |
873 | PHY_LP2HS_TIME(timing.data_lp2hs) | |
874 | MAX_RD_TIME(10000)); |
875 | } |
876 | |
877 | dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, |
878 | PHY_CLKHS2LP_TIME(timing.clk_hs2lp) | |
879 | PHY_CLKLP2HS_TIME(timing.clk_lp2hs)); |
880 | } |
881 | |
882 | static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi) |
883 | { |
884 | /* |
885 | * TODO dw drv improvements |
886 | * stop wait time should be the maximum between host dsi |
887 | * and panel stop wait times |
888 | */ |
889 | dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) | |
890 | N_LANES(dsi->lanes)); |
891 | } |
892 | |
893 | static void dw_mipi_dsi_dphy_init(struct dw_mipi_dsi *dsi) |
894 | { |
895 | /* Clear PHY state */ |
896 | dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK |
897 | | PHY_RSTZ | PHY_SHUTDOWNZ); |
898 | dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); |
899 | dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR); |
900 | dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); |
901 | } |
902 | |
903 | static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi) |
904 | { |
905 | u32 val; |
906 | int ret; |
907 | |
908 | dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | |
909 | PHY_UNRSTZ | PHY_UNSHUTDOWNZ); |
910 | |
911 | ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, |
912 | val & PHY_LOCK, 1000, PHY_STATUS_TIMEOUT_US); |
913 | if (ret) |
914 | DRM_DEBUG_DRIVER("failed to wait phy lock state\n" ); |
915 | |
916 | ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, |
917 | val, val & PHY_STOP_STATE_CLK_LANE, 1000, |
918 | PHY_STATUS_TIMEOUT_US); |
919 | if (ret) |
920 | DRM_DEBUG_DRIVER("failed to wait phy clk lane stop state\n" ); |
921 | } |
922 | |
923 | static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) |
924 | { |
925 | dsi_read(dsi, DSI_INT_ST0); |
926 | dsi_read(dsi, DSI_INT_ST1); |
927 | dsi_write(dsi, DSI_INT_MSK0, val: 0); |
928 | dsi_write(dsi, DSI_INT_MSK1, val: 0); |
929 | } |
930 | |
931 | static void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge, |
932 | struct drm_bridge_state *old_bridge_state) |
933 | { |
934 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
935 | const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; |
936 | |
937 | /* |
938 | * Switch to command mode before panel-bridge post_disable & |
939 | * panel unprepare. |
940 | * Note: panel-bridge disable & panel disable has been called |
941 | * before by the drm framework. |
942 | */ |
943 | dw_mipi_dsi_set_mode(dsi, mode_flags: 0); |
944 | |
945 | if (phy_ops->power_off) |
946 | phy_ops->power_off(dsi->plat_data->priv_data); |
947 | |
948 | if (dsi->slave) { |
949 | dw_mipi_dsi_disable(dsi: dsi->slave); |
950 | clk_disable_unprepare(clk: dsi->slave->pclk); |
951 | pm_runtime_put(dev: dsi->slave->dev); |
952 | } |
953 | dw_mipi_dsi_disable(dsi); |
954 | |
955 | clk_disable_unprepare(clk: dsi->pclk); |
956 | pm_runtime_put(dev: dsi->dev); |
957 | } |
958 | |
959 | static unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi) |
960 | { |
961 | /* this instance is the slave, so add the master's lanes */ |
962 | if (dsi->master) |
963 | return dsi->master->lanes + dsi->lanes; |
964 | |
965 | /* this instance is the master, so add the slave's lanes */ |
966 | if (dsi->slave) |
967 | return dsi->lanes + dsi->slave->lanes; |
968 | |
969 | /* single-dsi, so no other instance to consider */ |
970 | return dsi->lanes; |
971 | } |
972 | |
973 | static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi, |
974 | const struct drm_display_mode *adjusted_mode) |
975 | { |
976 | const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; |
977 | void *priv_data = dsi->plat_data->priv_data; |
978 | int ret; |
979 | u32 lanes = dw_mipi_dsi_get_lanes(dsi); |
980 | |
981 | clk_prepare_enable(clk: dsi->pclk); |
982 | |
983 | ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi->mode_flags, |
984 | lanes, dsi->format, &dsi->lane_mbps); |
985 | if (ret) |
986 | DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n" ); |
987 | |
988 | pm_runtime_get_sync(dev: dsi->dev); |
989 | dw_mipi_dsi_init(dsi); |
990 | dw_mipi_dsi_dpi_config(dsi, mode: adjusted_mode); |
991 | dw_mipi_dsi_packet_handler_config(dsi); |
992 | dw_mipi_dsi_video_mode_config(dsi); |
993 | dw_mipi_dsi_video_packet_config(dsi, mode: adjusted_mode); |
994 | dw_mipi_dsi_command_mode_config(dsi); |
995 | dw_mipi_dsi_line_timer_config(dsi, mode: adjusted_mode); |
996 | dw_mipi_dsi_vertical_timing_config(dsi, mode: adjusted_mode); |
997 | |
998 | dw_mipi_dsi_dphy_init(dsi); |
999 | dw_mipi_dsi_dphy_timing_config(dsi); |
1000 | dw_mipi_dsi_dphy_interface_config(dsi); |
1001 | |
1002 | dw_mipi_dsi_clear_err(dsi); |
1003 | |
1004 | ret = phy_ops->init(priv_data); |
1005 | if (ret) |
1006 | DRM_DEBUG_DRIVER("Phy init() failed\n" ); |
1007 | |
1008 | dw_mipi_dsi_dphy_enable(dsi); |
1009 | |
1010 | dw_mipi_dsi_wait_for_two_frames(mode: adjusted_mode); |
1011 | |
1012 | /* Switch to cmd mode for panel-bridge pre_enable & panel prepare */ |
1013 | dw_mipi_dsi_set_mode(dsi, mode_flags: 0); |
1014 | |
1015 | if (phy_ops->power_on) |
1016 | phy_ops->power_on(dsi->plat_data->priv_data); |
1017 | } |
1018 | |
1019 | static void dw_mipi_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge, |
1020 | struct drm_bridge_state *old_bridge_state) |
1021 | { |
1022 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
1023 | |
1024 | /* Power up the dsi ctl into a command mode */ |
1025 | dw_mipi_dsi_mode_set(dsi, adjusted_mode: &dsi->mode); |
1026 | if (dsi->slave) |
1027 | dw_mipi_dsi_mode_set(dsi: dsi->slave, adjusted_mode: &dsi->mode); |
1028 | } |
1029 | |
1030 | static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, |
1031 | const struct drm_display_mode *mode, |
1032 | const struct drm_display_mode *adjusted_mode) |
1033 | { |
1034 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
1035 | |
1036 | /* Store the display mode for later use in pre_enable callback */ |
1037 | drm_mode_copy(dst: &dsi->mode, src: adjusted_mode); |
1038 | } |
1039 | |
1040 | static void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge, |
1041 | struct drm_bridge_state *old_bridge_state) |
1042 | { |
1043 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
1044 | |
1045 | /* Switch to video mode for panel-bridge enable & panel enable */ |
1046 | dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); |
1047 | if (dsi->slave) |
1048 | dw_mipi_dsi_set_mode(dsi: dsi->slave, MIPI_DSI_MODE_VIDEO); |
1049 | } |
1050 | |
1051 | static enum drm_mode_status |
1052 | dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, |
1053 | const struct drm_display_info *info, |
1054 | const struct drm_display_mode *mode) |
1055 | { |
1056 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
1057 | const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; |
1058 | enum drm_mode_status mode_status = MODE_OK; |
1059 | |
1060 | if (pdata->mode_valid) |
1061 | mode_status = pdata->mode_valid(pdata->priv_data, mode, |
1062 | dsi->mode_flags, |
1063 | dw_mipi_dsi_get_lanes(dsi), |
1064 | dsi->format); |
1065 | |
1066 | return mode_status; |
1067 | } |
1068 | |
1069 | static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge, |
1070 | enum drm_bridge_attach_flags flags) |
1071 | { |
1072 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
1073 | |
1074 | if (!bridge->encoder) { |
1075 | DRM_ERROR("Parent encoder object not found\n" ); |
1076 | return -ENODEV; |
1077 | } |
1078 | |
1079 | /* Set the encoder type as caller does not know it */ |
1080 | bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI; |
1081 | |
1082 | /* Attach the panel-bridge to the dsi bridge */ |
1083 | return drm_bridge_attach(encoder: bridge->encoder, bridge: dsi->panel_bridge, previous: bridge, |
1084 | flags); |
1085 | } |
1086 | |
1087 | static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = { |
1088 | .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, |
1089 | .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, |
1090 | .atomic_get_input_bus_fmts = dw_mipi_dsi_bridge_atomic_get_input_bus_fmts, |
1091 | .atomic_check = dw_mipi_dsi_bridge_atomic_check, |
1092 | .atomic_reset = drm_atomic_helper_bridge_reset, |
1093 | .atomic_pre_enable = dw_mipi_dsi_bridge_atomic_pre_enable, |
1094 | .atomic_enable = dw_mipi_dsi_bridge_atomic_enable, |
1095 | .atomic_post_disable = dw_mipi_dsi_bridge_post_atomic_disable, |
1096 | .mode_set = dw_mipi_dsi_bridge_mode_set, |
1097 | .mode_valid = dw_mipi_dsi_bridge_mode_valid, |
1098 | .attach = dw_mipi_dsi_bridge_attach, |
1099 | }; |
1100 | |
1101 | #ifdef CONFIG_DEBUG_FS |
1102 | |
1103 | static int dw_mipi_dsi_debugfs_write(void *data, u64 val) |
1104 | { |
1105 | struct debugfs_entries *vpg = data; |
1106 | struct dw_mipi_dsi *dsi; |
1107 | u32 mode_cfg; |
1108 | |
1109 | if (!vpg) |
1110 | return -ENODEV; |
1111 | |
1112 | dsi = vpg->dsi; |
1113 | |
1114 | *vpg->reg = (bool)val; |
1115 | |
1116 | mode_cfg = dsi_read(dsi, DSI_VID_MODE_CFG); |
1117 | |
1118 | if (*vpg->reg) |
1119 | mode_cfg |= vpg->mask; |
1120 | else |
1121 | mode_cfg &= ~vpg->mask; |
1122 | |
1123 | dsi_write(dsi, DSI_VID_MODE_CFG, val: mode_cfg); |
1124 | |
1125 | return 0; |
1126 | } |
1127 | |
1128 | static int dw_mipi_dsi_debugfs_show(void *data, u64 *val) |
1129 | { |
1130 | struct debugfs_entries *vpg = data; |
1131 | |
1132 | if (!vpg) |
1133 | return -ENODEV; |
1134 | |
1135 | *val = *vpg->reg; |
1136 | |
1137 | return 0; |
1138 | } |
1139 | |
1140 | DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_mipi_dsi_debugfs_show, |
1141 | dw_mipi_dsi_debugfs_write, "%llu\n" ); |
1142 | |
1143 | static void debugfs_create_files(void *data) |
1144 | { |
1145 | struct dw_mipi_dsi *dsi = data; |
1146 | struct debugfs_entries debugfs[] = { |
1147 | REGISTER(vpg, VID_MODE_VPG_ENABLE, dsi), |
1148 | REGISTER(vpg_horizontal, VID_MODE_VPG_HORIZONTAL, dsi), |
1149 | REGISTER(vpg_ber_pattern, VID_MODE_VPG_MODE, dsi), |
1150 | }; |
1151 | int i; |
1152 | |
1153 | dsi->debugfs_vpg = kmemdup(p: debugfs, size: sizeof(debugfs), GFP_KERNEL); |
1154 | if (!dsi->debugfs_vpg) |
1155 | return; |
1156 | |
1157 | for (i = 0; i < ARRAY_SIZE(debugfs); i++) |
1158 | debugfs_create_file(name: dsi->debugfs_vpg[i].name, mode: 0644, |
1159 | parent: dsi->debugfs, data: &dsi->debugfs_vpg[i], |
1160 | fops: &fops_x32); |
1161 | } |
1162 | |
1163 | static void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi) |
1164 | { |
1165 | dsi->debugfs = debugfs_create_dir(name: dev_name(dev: dsi->dev), NULL); |
1166 | if (IS_ERR(ptr: dsi->debugfs)) { |
1167 | dev_err(dsi->dev, "failed to create debugfs root\n" ); |
1168 | return; |
1169 | } |
1170 | |
1171 | debugfs_create_files(data: dsi); |
1172 | } |
1173 | |
1174 | static void dw_mipi_dsi_debugfs_remove(struct dw_mipi_dsi *dsi) |
1175 | { |
1176 | debugfs_remove_recursive(dentry: dsi->debugfs); |
1177 | kfree(objp: dsi->debugfs_vpg); |
1178 | } |
1179 | |
1180 | #else |
1181 | |
1182 | static void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi) { } |
1183 | static void dw_mipi_dsi_debugfs_remove(struct dw_mipi_dsi *dsi) { } |
1184 | |
1185 | #endif /* CONFIG_DEBUG_FS */ |
1186 | |
1187 | static struct dw_mipi_dsi * |
1188 | __dw_mipi_dsi_probe(struct platform_device *pdev, |
1189 | const struct dw_mipi_dsi_plat_data *plat_data) |
1190 | { |
1191 | struct device *dev = &pdev->dev; |
1192 | struct reset_control *apb_rst; |
1193 | struct dw_mipi_dsi *dsi; |
1194 | int ret; |
1195 | |
1196 | dsi = devm_kzalloc(dev, size: sizeof(*dsi), GFP_KERNEL); |
1197 | if (!dsi) |
1198 | return ERR_PTR(error: -ENOMEM); |
1199 | |
1200 | dsi->dev = dev; |
1201 | dsi->plat_data = plat_data; |
1202 | |
1203 | if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps || |
1204 | !plat_data->phy_ops->get_timing) { |
1205 | DRM_ERROR("Phy not properly configured\n" ); |
1206 | return ERR_PTR(error: -ENODEV); |
1207 | } |
1208 | |
1209 | if (!plat_data->base) { |
1210 | dsi->base = devm_platform_ioremap_resource(pdev, index: 0); |
1211 | if (IS_ERR(ptr: dsi->base)) |
1212 | return ERR_PTR(error: -ENODEV); |
1213 | |
1214 | } else { |
1215 | dsi->base = plat_data->base; |
1216 | } |
1217 | |
1218 | dsi->pclk = devm_clk_get(dev, id: "pclk" ); |
1219 | if (IS_ERR(ptr: dsi->pclk)) { |
1220 | ret = PTR_ERR(ptr: dsi->pclk); |
1221 | dev_err(dev, "Unable to get pclk: %d\n" , ret); |
1222 | return ERR_PTR(error: ret); |
1223 | } |
1224 | |
1225 | /* |
1226 | * Note that the reset was not defined in the initial device tree, so |
1227 | * we have to be prepared for it not being found. |
1228 | */ |
1229 | apb_rst = devm_reset_control_get_optional_exclusive(dev, id: "apb" ); |
1230 | if (IS_ERR(ptr: apb_rst)) { |
1231 | ret = PTR_ERR(ptr: apb_rst); |
1232 | |
1233 | if (ret != -EPROBE_DEFER) |
1234 | dev_err(dev, "Unable to get reset control: %d\n" , ret); |
1235 | |
1236 | return ERR_PTR(error: ret); |
1237 | } |
1238 | |
1239 | if (apb_rst) { |
1240 | ret = clk_prepare_enable(clk: dsi->pclk); |
1241 | if (ret) { |
1242 | dev_err(dev, "%s: Failed to enable pclk\n" , __func__); |
1243 | return ERR_PTR(error: ret); |
1244 | } |
1245 | |
1246 | reset_control_assert(rstc: apb_rst); |
1247 | usleep_range(min: 10, max: 20); |
1248 | reset_control_deassert(rstc: apb_rst); |
1249 | |
1250 | clk_disable_unprepare(clk: dsi->pclk); |
1251 | } |
1252 | |
1253 | dw_mipi_dsi_debugfs_init(dsi); |
1254 | pm_runtime_enable(dev); |
1255 | |
1256 | dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; |
1257 | dsi->dsi_host.dev = dev; |
1258 | ret = mipi_dsi_host_register(host: &dsi->dsi_host); |
1259 | if (ret) { |
1260 | dev_err(dev, "Failed to register MIPI host: %d\n" , ret); |
1261 | pm_runtime_disable(dev); |
1262 | dw_mipi_dsi_debugfs_remove(dsi); |
1263 | return ERR_PTR(error: ret); |
1264 | } |
1265 | |
1266 | dsi->bridge.driver_private = dsi; |
1267 | dsi->bridge.funcs = &dw_mipi_dsi_bridge_funcs; |
1268 | dsi->bridge.of_node = pdev->dev.of_node; |
1269 | |
1270 | return dsi; |
1271 | } |
1272 | |
1273 | static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) |
1274 | { |
1275 | mipi_dsi_host_unregister(host: &dsi->dsi_host); |
1276 | |
1277 | pm_runtime_disable(dev: dsi->dev); |
1278 | dw_mipi_dsi_debugfs_remove(dsi); |
1279 | } |
1280 | |
1281 | void dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave) |
1282 | { |
1283 | /* introduce controllers to each other */ |
1284 | dsi->slave = slave; |
1285 | dsi->slave->master = dsi; |
1286 | |
1287 | /* migrate settings for already attached displays */ |
1288 | dsi->slave->lanes = dsi->lanes; |
1289 | dsi->slave->channel = dsi->channel; |
1290 | dsi->slave->format = dsi->format; |
1291 | dsi->slave->mode_flags = dsi->mode_flags; |
1292 | } |
1293 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_set_slave); |
1294 | |
1295 | struct drm_bridge *dw_mipi_dsi_get_bridge(struct dw_mipi_dsi *dsi) |
1296 | { |
1297 | return &dsi->bridge; |
1298 | } |
1299 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_get_bridge); |
1300 | |
1301 | /* |
1302 | * Probe/remove API, used from platforms based on the DRM bridge API. |
1303 | */ |
1304 | struct dw_mipi_dsi * |
1305 | dw_mipi_dsi_probe(struct platform_device *pdev, |
1306 | const struct dw_mipi_dsi_plat_data *plat_data) |
1307 | { |
1308 | return __dw_mipi_dsi_probe(pdev, plat_data); |
1309 | } |
1310 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_probe); |
1311 | |
1312 | void dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) |
1313 | { |
1314 | __dw_mipi_dsi_remove(dsi); |
1315 | } |
1316 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_remove); |
1317 | |
1318 | /* |
1319 | * Bind/unbind API, used from platforms based on the component framework. |
1320 | */ |
1321 | int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder) |
1322 | { |
1323 | return drm_bridge_attach(encoder, bridge: &dsi->bridge, NULL, flags: 0); |
1324 | } |
1325 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind); |
1326 | |
1327 | void dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi) |
1328 | { |
1329 | } |
1330 | EXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind); |
1331 | |
1332 | MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>" ); |
1333 | MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>" ); |
1334 | MODULE_DESCRIPTION("DW MIPI DSI host controller driver" ); |
1335 | MODULE_LICENSE("GPL" ); |
1336 | MODULE_ALIAS("platform:dw-mipi-dsi" ); |
1337 | |