1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STMicroelectronics SA 2017
5 * Authors: Philippe Cornu <philippe.cornu@st.com>
6 * Yannick Fertre <yannick.fertre@st.com>
10 #include <linux/iopoll.h>
11 #include <linux/module.h>
13 #include <drm/drm_mipi_dsi.h>
14 #include <drm/bridge/dw_mipi_dsi.h>
15 #include <video/mipi_display.h>
17 /* DSI wrapper register & bit definitions */
18 /* Note: registers are named as in the Reference Manual */
19 #define DSI_WCFGR 0x0400 /* Wrapper ConFiGuration Reg */
20 #define WCFGR_DSIM BIT(0) /* DSI Mode */
21 #define WCFGR_COLMUX GENMASK(3, 1) /* COLor MUltipleXing */
23 #define DSI_WCR 0x0404 /* Wrapper Control Reg */
24 #define WCR_DSIEN BIT(3) /* DSI ENable */
26 #define DSI_WISR 0x040C /* Wrapper Interrupt and Status Reg */
27 #define WISR_PLLLS BIT(8) /* PLL Lock Status */
28 #define WISR_RRS BIT(12) /* Regulator Ready Status */
30 #define DSI_WPCR0 0x0418 /* Wrapper Phy Conf Reg 0 */
31 #define WPCR0_UIX4 GENMASK(5, 0) /* Unit Interval X 4 */
32 #define WPCR0_TDDL BIT(16) /* Turn Disable Data Lanes */
34 #define DSI_WRPCR 0x0430 /* Wrapper Regulator & Pll Ctrl Reg */
35 #define WRPCR_PLLEN BIT(0) /* PLL ENable */
36 #define WRPCR_NDIV GENMASK(8, 2) /* pll loop DIVision Factor */
37 #define WRPCR_IDF GENMASK(14, 11) /* pll Input Division Factor */
38 #define WRPCR_ODF GENMASK(17, 16) /* pll Output Division Factor */
39 #define WRPCR_REGEN BIT(24) /* REGulator ENable */
40 #define WRPCR_BGREN BIT(28) /* BandGap Reference ENable */
48 /* dsi color format coding according to the datasheet */
58 #define LANE_MIN_KBPS 31250
59 #define LANE_MAX_KBPS 500000
61 /* Sleep & timeout for regulator on/off, pll lock/unlock & fifo empty */
63 #define TIMEOUT_US 200000
65 struct dw_mipi_dsi_stm
{
67 struct clk
*pllref_clk
;
70 static inline void dsi_write(struct dw_mipi_dsi_stm
*dsi
, u32 reg
, u32 val
)
72 writel(val
, dsi
->base
+ reg
);
75 static inline u32
dsi_read(struct dw_mipi_dsi_stm
*dsi
, u32 reg
)
77 return readl(dsi
->base
+ reg
);
80 static inline void dsi_set(struct dw_mipi_dsi_stm
*dsi
, u32 reg
, u32 mask
)
82 dsi_write(dsi
, reg
, dsi_read(dsi
, reg
) | mask
);
85 static inline void dsi_clear(struct dw_mipi_dsi_stm
*dsi
, u32 reg
, u32 mask
)
87 dsi_write(dsi
, reg
, dsi_read(dsi
, reg
) & ~mask
);
90 static inline void dsi_update_bits(struct dw_mipi_dsi_stm
*dsi
, u32 reg
,
93 dsi_write(dsi
, reg
, (dsi_read(dsi
, reg
) & ~mask
) | val
);
96 static enum dsi_color
dsi_color_from_mipi(enum mipi_dsi_pixel_format fmt
)
99 case MIPI_DSI_FMT_RGB888
:
101 case MIPI_DSI_FMT_RGB666
:
102 return DSI_RGB666_CONF2
;
103 case MIPI_DSI_FMT_RGB666_PACKED
:
104 return DSI_RGB666_CONF1
;
105 case MIPI_DSI_FMT_RGB565
:
106 return DSI_RGB565_CONF1
;
108 DRM_DEBUG_DRIVER("MIPI color invalid, so we use rgb888\n");
113 static int dsi_pll_get_clkout_khz(int clkin_khz
, int idf
, int ndiv
, int odf
)
115 int divisor
= idf
* odf
;
117 /* prevent from division by 0 */
121 return DIV_ROUND_CLOSEST(clkin_khz
* ndiv
, divisor
);
124 static int dsi_pll_get_params(int clkin_khz
, int clkout_khz
,
125 int *idf
, int *ndiv
, int *odf
)
127 int i
, o
, n
, n_min
, n_max
;
128 int fvco_min
, fvco_max
, delta
, best_delta
; /* all in khz */
130 /* Early checks preventing division by 0 & odd results */
131 if (clkin_khz
<= 0 || clkout_khz
<= 0)
134 fvco_min
= LANE_MIN_KBPS
* 2 * ODF_MAX
;
135 fvco_max
= LANE_MAX_KBPS
* 2 * ODF_MIN
;
137 best_delta
= 1000000; /* big started value (1000000khz) */
139 for (i
= IDF_MIN
; i
<= IDF_MAX
; i
++) {
140 /* Compute ndiv range according to Fvco */
141 n_min
= ((fvco_min
* i
) / (2 * clkin_khz
)) + 1;
142 n_max
= (fvco_max
* i
) / (2 * clkin_khz
);
144 /* No need to continue idf loop if we reach ndiv max */
145 if (n_min
>= NDIV_MAX
)
148 /* Clamp ndiv to valid values */
149 if (n_min
< NDIV_MIN
)
151 if (n_max
> NDIV_MAX
)
154 for (o
= ODF_MIN
; o
<= ODF_MAX
; o
*= 2) {
155 n
= DIV_ROUND_CLOSEST(i
* o
* clkout_khz
, clkin_khz
);
156 /* Check ndiv according to vco range */
157 if (n
< n_min
|| n
> n_max
)
159 /* Check if new delta is better & saves parameters */
160 delta
= dsi_pll_get_clkout_khz(clkin_khz
, i
, n
, o
) -
164 if (delta
< best_delta
) {
170 /* fast return in case of "perfect result" */
179 static int dw_mipi_dsi_phy_init(void *priv_data
)
181 struct dw_mipi_dsi_stm
*dsi
= priv_data
;
185 /* Enable the regulator */
186 dsi_set(dsi
, DSI_WRPCR
, WRPCR_REGEN
| WRPCR_BGREN
);
187 ret
= readl_poll_timeout(dsi
->base
+ DSI_WISR
, val
, val
& WISR_RRS
,
188 SLEEP_US
, TIMEOUT_US
);
190 DRM_DEBUG_DRIVER("!TIMEOUT! waiting REGU, let's continue\n");
192 /* Enable the DSI PLL & wait for its lock */
193 dsi_set(dsi
, DSI_WRPCR
, WRPCR_PLLEN
);
194 ret
= readl_poll_timeout(dsi
->base
+ DSI_WISR
, val
, val
& WISR_PLLLS
,
195 SLEEP_US
, TIMEOUT_US
);
197 DRM_DEBUG_DRIVER("!TIMEOUT! waiting PLL, let's continue\n");
199 /* Enable the DSI wrapper */
200 dsi_set(dsi
, DSI_WCR
, WCR_DSIEN
);
206 dw_mipi_dsi_get_lane_mbps(void *priv_data
, struct drm_display_mode
*mode
,
207 unsigned long mode_flags
, u32 lanes
, u32 format
,
208 unsigned int *lane_mbps
)
210 struct dw_mipi_dsi_stm
*dsi
= priv_data
;
211 unsigned int idf
, ndiv
, odf
, pll_in_khz
, pll_out_khz
;
215 pll_in_khz
= (unsigned int)(clk_get_rate(dsi
->pllref_clk
) / 1000);
217 /* Compute requested pll out */
218 bpp
= mipi_dsi_pixel_format_to_bpp(format
);
219 pll_out_khz
= mode
->clock
* bpp
/ lanes
;
220 /* Add 20% to pll out to be higher than pixel bw (burst mode only) */
221 pll_out_khz
= (pll_out_khz
* 12) / 10;
222 if (pll_out_khz
> LANE_MAX_KBPS
) {
223 pll_out_khz
= LANE_MAX_KBPS
;
224 DRM_WARN("Warning max phy mbps is used\n");
226 if (pll_out_khz
< LANE_MIN_KBPS
) {
227 pll_out_khz
= LANE_MIN_KBPS
;
228 DRM_WARN("Warning min phy mbps is used\n");
231 /* Compute best pll parameters */
235 ret
= dsi_pll_get_params(pll_in_khz
, pll_out_khz
, &idf
, &ndiv
, &odf
);
237 DRM_WARN("Warning dsi_pll_get_params(): bad params\n");
239 /* Get the adjusted pll out value */
240 pll_out_khz
= dsi_pll_get_clkout_khz(pll_in_khz
, idf
, ndiv
, odf
);
242 /* Set the PLL division factors */
243 dsi_update_bits(dsi
, DSI_WRPCR
, WRPCR_NDIV
| WRPCR_IDF
| WRPCR_ODF
,
244 (ndiv
<< 2) | (idf
<< 11) | ((ffs(odf
) - 1) << 16));
246 /* Compute uix4 & set the bit period in high-speed mode */
247 val
= 4000000 / pll_out_khz
;
248 dsi_update_bits(dsi
, DSI_WPCR0
, WPCR0_UIX4
, val
);
250 /* Select video mode by resetting DSIM bit */
251 dsi_clear(dsi
, DSI_WCFGR
, WCFGR_DSIM
);
253 /* Select the color coding */
254 dsi_update_bits(dsi
, DSI_WCFGR
, WCFGR_COLMUX
,
255 dsi_color_from_mipi(format
) << 1);
257 *lane_mbps
= pll_out_khz
/ 1000;
259 DRM_DEBUG_DRIVER("pll_in %ukHz pll_out %ukHz lane_mbps %uMHz\n",
260 pll_in_khz
, pll_out_khz
, *lane_mbps
);
265 static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops
= {
266 .init
= dw_mipi_dsi_phy_init
,
267 .get_lane_mbps
= dw_mipi_dsi_get_lane_mbps
,
270 static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data
= {
272 .phy_ops
= &dw_mipi_dsi_stm_phy_ops
,
275 static const struct of_device_id dw_mipi_dsi_stm_dt_ids
[] = {
276 { .compatible
= "st,stm32-dsi", .data
= &dw_mipi_dsi_stm_plat_data
, },
279 MODULE_DEVICE_TABLE(of
, dw_mipi_dsi_stm_dt_ids
);
281 static int dw_mipi_dsi_stm_probe(struct platform_device
*pdev
)
283 struct device
*dev
= &pdev
->dev
;
284 struct dw_mipi_dsi_stm
*dsi
;
285 struct resource
*res
;
288 dsi
= devm_kzalloc(dev
, sizeof(*dsi
), GFP_KERNEL
);
292 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
293 dsi
->base
= devm_ioremap_resource(dev
, res
);
294 if (IS_ERR(dsi
->base
)) {
295 DRM_ERROR("Unable to get dsi registers\n");
296 return PTR_ERR(dsi
->base
);
299 dsi
->pllref_clk
= devm_clk_get(dev
, "ref");
300 if (IS_ERR(dsi
->pllref_clk
)) {
301 ret
= PTR_ERR(dsi
->pllref_clk
);
302 dev_err(dev
, "Unable to get pll reference clock: %d\n", ret
);
306 ret
= clk_prepare_enable(dsi
->pllref_clk
);
308 dev_err(dev
, "%s: Failed to enable pllref_clk\n", __func__
);
312 dw_mipi_dsi_stm_plat_data
.base
= dsi
->base
;
313 dw_mipi_dsi_stm_plat_data
.priv_data
= dsi
;
315 ret
= dw_mipi_dsi_probe(pdev
, &dw_mipi_dsi_stm_plat_data
);
317 DRM_ERROR("Failed to initialize mipi dsi host\n");
318 clk_disable_unprepare(dsi
->pllref_clk
);
324 static int dw_mipi_dsi_stm_remove(struct platform_device
*pdev
)
326 struct dw_mipi_dsi_stm
*dsi
= dw_mipi_dsi_stm_plat_data
.priv_data
;
328 clk_disable_unprepare(dsi
->pllref_clk
);
329 dw_mipi_dsi_remove(pdev
);
334 static struct platform_driver dw_mipi_dsi_stm_driver
= {
335 .probe
= dw_mipi_dsi_stm_probe
,
336 .remove
= dw_mipi_dsi_stm_remove
,
338 .of_match_table
= dw_mipi_dsi_stm_dt_ids
,
339 .name
= "stm32-display-dsi",
343 module_platform_driver(dw_mipi_dsi_stm_driver
);
345 MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
346 MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
347 MODULE_DESCRIPTION("STMicroelectronics DW MIPI DSI host controller driver");
348 MODULE_LICENSE("GPL v2");