1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (C) 2013 NVIDIA Corporation
4 * Copyright (C) 2018 Cadence Design Systems Inc.
7 #include <linux/errno.h>
8 #include <linux/export.h>
9 #include <linux/kernel.h>
10 #include <linux/time64.h>
12 #include <linux/phy/phy.h>
13 #include <linux/phy/phy-mipi-dphy.h>
15 #define PSEC_PER_SEC 1000000000000LL
18 * Minimum D-PHY timings based on MIPI D-PHY specification. Derived
19 * from the valid ranges specified in Section 6.9, Table 14, Page 41
20 * of the D-PHY specification (v2.1).
22 int phy_mipi_dphy_get_default_config(unsigned long pixel_clock
,
25 struct phy_configure_opts_mipi_dphy
*cfg
)
27 unsigned long long hs_clk_rate
;
28 unsigned long long ui
;
33 hs_clk_rate
= pixel_clock
* bpp
;
34 do_div(hs_clk_rate
, lanes
);
36 ui
= ALIGN(PSEC_PER_SEC
, hs_clk_rate
);
37 do_div(ui
, hs_clk_rate
);
40 cfg
->clk_post
= 60000 + 52 * ui
;
42 cfg
->clk_prepare
= 38000;
43 cfg
->clk_settle
= 95000;
45 cfg
->clk_trail
= 60000;
46 cfg
->clk_zero
= 262000;
49 cfg
->hs_exit
= 100000;
50 cfg
->hs_prepare
= 40000 + 4 * ui
;
51 cfg
->hs_zero
= 105000 + 6 * ui
;
52 cfg
->hs_settle
= 85000 + 6 * ui
;
56 * The MIPI D-PHY specification (Section 6.9, v1.2, Table 14, Page 40)
57 * contains this formula as:
59 * T_HS-TRAIL = max(n * 8 * ui, 60 + n * 4 * ui)
61 * where n = 1 for forward-direction HS mode and n = 4 for reverse-
62 * direction HS mode. There's only one setting and this function does
63 * not parameterize on anything other that ui, so this code will
64 * assumes that reverse-direction HS mode is supported and uses n = 4.
66 cfg
->hs_trail
= max(4 * 8 * ui
, 60000 + 4 * 4 * ui
);
68 cfg
->init
= 100000000;
70 cfg
->ta_get
= 5 * cfg
->lpx
;
71 cfg
->ta_go
= 4 * cfg
->lpx
;
72 cfg
->ta_sure
= 2 * cfg
->lpx
;
73 cfg
->wakeup
= 1000000000;
75 cfg
->hs_clk_rate
= hs_clk_rate
;
80 EXPORT_SYMBOL(phy_mipi_dphy_get_default_config
);
83 * Validate D-PHY configuration according to MIPI D-PHY specification
84 * (v1.2, Section Section 6.9 "Global Operation Timing Parameters").
86 int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy
*cfg
)
88 unsigned long long ui
;
93 ui
= ALIGN(PSEC_PER_SEC
, cfg
->hs_clk_rate
);
94 do_div(ui
, cfg
->hs_clk_rate
);
96 if (cfg
->clk_miss
> 60000)
99 if (cfg
->clk_post
< (60000 + 52 * ui
))
102 if (cfg
->clk_pre
< 8000)
105 if (cfg
->clk_prepare
< 38000 || cfg
->clk_prepare
> 95000)
108 if (cfg
->clk_settle
< 95000 || cfg
->clk_settle
> 300000)
111 if (cfg
->clk_term_en
> 38000)
114 if (cfg
->clk_trail
< 60000)
117 if ((cfg
->clk_prepare
+ cfg
->clk_zero
) < 300000)
120 if (cfg
->d_term_en
> (35000 + 4 * ui
))
123 if (cfg
->eot
> (105000 + 12 * ui
))
126 if (cfg
->hs_exit
< 100000)
129 if (cfg
->hs_prepare
< (40000 + 4 * ui
) ||
130 cfg
->hs_prepare
> (85000 + 6 * ui
))
133 if ((cfg
->hs_prepare
+ cfg
->hs_zero
) < (145000 + 10 * ui
))
136 if ((cfg
->hs_settle
< (85000 + 6 * ui
)) ||
137 (cfg
->hs_settle
> (145000 + 10 * ui
)))
140 if (cfg
->hs_skip
< 40000 || cfg
->hs_skip
> (55000 + 4 * ui
))
143 if (cfg
->hs_trail
< max(8 * ui
, 60000 + 4 * ui
))
146 if (cfg
->init
< 100000000)
149 if (cfg
->lpx
< 50000)
152 if (cfg
->ta_get
!= (5 * cfg
->lpx
))
155 if (cfg
->ta_go
!= (4 * cfg
->lpx
))
158 if (cfg
->ta_sure
< cfg
->lpx
|| cfg
->ta_sure
> (2 * cfg
->lpx
))
161 if (cfg
->wakeup
< 1000000000)
166 EXPORT_SYMBOL(phy_mipi_dphy_config_validate
);