diff options
author | Hai Li <hali@codeaurora.org> | 2017-01-03 09:01:16 -0500 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2017-02-06 11:28:45 -0500 |
commit | a4df68fa232e979fb74b2efe6997d0f38cbfc626 (patch) | |
tree | 63a78511b4570fe87898e1e5646c5102f3c0472e | |
parent | b62aa70a98c5401ada63657eee7c88da70bdbb27 (diff) |
drm/msm/dsi: Add new method to calculate 14nm PHY timings
The 14nm DSI PHY on 8x96 (called PHY v2 downstream) requires a different
set of calculations for computing D-PHY timing params. Create a
timing_calc_v2 func for the newer v2 PHYs.
Signed-off-by: Hai Li <hali@codeaurora.org>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r-- | drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 117 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 11 |
2 files changed, 127 insertions, 1 deletions
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index a761531ec04c..541d7dfa13c0 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | |||
@@ -148,6 +148,123 @@ int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing, | |||
148 | return 0; | 148 | return 0; |
149 | } | 149 | } |
150 | 150 | ||
151 | int msm_dsi_dphy_timing_calc_v2(struct msm_dsi_dphy_timing *timing, | ||
152 | struct msm_dsi_phy_clk_request *clk_req) | ||
153 | { | ||
154 | const unsigned long bit_rate = clk_req->bitclk_rate; | ||
155 | const unsigned long esc_rate = clk_req->escclk_rate; | ||
156 | s32 ui, ui_x8, lpx; | ||
157 | s32 tmax, tmin; | ||
158 | s32 pcnt0 = 50; | ||
159 | s32 pcnt1 = 50; | ||
160 | s32 pcnt2 = 10; | ||
161 | s32 pcnt3 = 30; | ||
162 | s32 pcnt4 = 10; | ||
163 | s32 pcnt5 = 2; | ||
164 | s32 coeff = 1000; /* Precision, should avoid overflow */ | ||
165 | s32 hb_en, hb_en_ckln, pd_ckln, pd; | ||
166 | s32 val, val_ckln; | ||
167 | s32 temp; | ||
168 | |||
169 | if (!bit_rate || !esc_rate) | ||
170 | return -EINVAL; | ||
171 | |||
172 | timing->hs_halfbyte_en = 0; | ||
173 | hb_en = 0; | ||
174 | timing->hs_halfbyte_en_ckln = 0; | ||
175 | hb_en_ckln = 0; | ||
176 | timing->hs_prep_dly_ckln = (bit_rate > 100000000) ? 0 : 3; | ||
177 | pd_ckln = timing->hs_prep_dly_ckln; | ||
178 | timing->hs_prep_dly = (bit_rate > 120000000) ? 0 : 1; | ||
179 | pd = timing->hs_prep_dly; | ||
180 | |||
181 | val = (hb_en << 2) + (pd << 1); | ||
182 | val_ckln = (hb_en_ckln << 2) + (pd_ckln << 1); | ||
183 | |||
184 | ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000); | ||
185 | ui_x8 = ui << 3; | ||
186 | lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000); | ||
187 | |||
188 | temp = S_DIV_ROUND_UP(38 * coeff - val_ckln * ui, ui_x8); | ||
189 | tmin = max_t(s32, temp, 0); | ||
190 | temp = (95 * coeff - val_ckln * ui) / ui_x8; | ||
191 | tmax = max_t(s32, temp, 0); | ||
192 | timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false); | ||
193 | |||
194 | temp = 300 * coeff - ((timing->clk_prepare << 3) + val_ckln) * ui; | ||
195 | tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3; | ||
196 | tmax = (tmin > 255) ? 511 : 255; | ||
197 | timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false); | ||
198 | |||
199 | tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8); | ||
200 | temp = 105 * coeff + 12 * ui - 20 * coeff; | ||
201 | tmax = (temp + 3 * ui) / ui_x8; | ||
202 | timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false); | ||
203 | |||
204 | temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui - val * ui, ui_x8); | ||
205 | tmin = max_t(s32, temp, 0); | ||
206 | temp = (85 * coeff + 6 * ui - val * ui) / ui_x8; | ||
207 | tmax = max_t(s32, temp, 0); | ||
208 | timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false); | ||
209 | |||
210 | temp = 145 * coeff + 10 * ui - ((timing->hs_prepare << 3) + val) * ui; | ||
211 | tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3; | ||
212 | tmax = 255; | ||
213 | timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false); | ||
214 | |||
215 | tmin = DIV_ROUND_UP(60 * coeff + 4 * ui + 3 * ui, ui_x8); | ||
216 | temp = 105 * coeff + 12 * ui - 20 * coeff; | ||
217 | tmax = (temp + 3 * ui) / ui_x8; | ||
218 | timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false); | ||
219 | |||
220 | temp = 50 * coeff + ((hb_en << 2) - 8) * ui; | ||
221 | timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8); | ||
222 | |||
223 | tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1; | ||
224 | tmax = 255; | ||
225 | timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false); | ||
226 | |||
227 | temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui; | ||
228 | timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8); | ||
229 | |||
230 | temp = 60 * coeff + 52 * ui - 43 * ui; | ||
231 | tmin = DIV_ROUND_UP(temp, ui_x8) - 1; | ||
232 | tmax = 63; | ||
233 | timing->shared_timings.clk_post = | ||
234 | linear_inter(tmax, tmin, pcnt2, 0, false); | ||
235 | |||
236 | temp = 8 * ui + ((timing->clk_prepare << 3) + val_ckln) * ui; | ||
237 | temp += (((timing->clk_zero + 3) << 3) + 11 - (pd_ckln << 1)) * ui; | ||
238 | temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) : | ||
239 | (((timing->hs_rqst_ckln << 3) + 8) * ui); | ||
240 | tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1; | ||
241 | tmax = 63; | ||
242 | if (tmin > tmax) { | ||
243 | temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false); | ||
244 | timing->shared_timings.clk_pre = temp >> 1; | ||
245 | timing->shared_timings.clk_pre_inc_by_2 = 1; | ||
246 | } else { | ||
247 | timing->shared_timings.clk_pre = | ||
248 | linear_inter(tmax, tmin, pcnt2, 0, false); | ||
249 | timing->shared_timings.clk_pre_inc_by_2 = 0; | ||
250 | } | ||
251 | |||
252 | timing->ta_go = 3; | ||
253 | timing->ta_sure = 0; | ||
254 | timing->ta_get = 4; | ||
255 | |||
256 | DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", | ||
257 | timing->shared_timings.clk_pre, timing->shared_timings.clk_post, | ||
258 | timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero, | ||
259 | timing->clk_trail, timing->clk_prepare, timing->hs_exit, | ||
260 | timing->hs_zero, timing->hs_prepare, timing->hs_trail, | ||
261 | timing->hs_rqst, timing->hs_rqst_ckln, timing->hs_halfbyte_en, | ||
262 | timing->hs_halfbyte_en_ckln, timing->hs_prep_dly, | ||
263 | timing->hs_prep_dly_ckln); | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
151 | void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg, | 268 | void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg, |
152 | u32 bit_mask) | 269 | u32 bit_mask) |
153 | { | 270 | { |
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 6472b600ac41..feee87094ef5 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | |||
@@ -64,6 +64,13 @@ struct msm_dsi_dphy_timing { | |||
64 | u32 ta_get; | 64 | u32 ta_get; |
65 | 65 | ||
66 | struct msm_dsi_phy_shared_timings shared_timings; | 66 | struct msm_dsi_phy_shared_timings shared_timings; |
67 | |||
68 | /* For PHY v2 only */ | ||
69 | u32 hs_rqst_ckln; | ||
70 | u32 hs_prep_dly; | ||
71 | u32 hs_prep_dly_ckln; | ||
72 | u8 hs_halfbyte_en; | ||
73 | u8 hs_halfbyte_en_ckln; | ||
67 | }; | 74 | }; |
68 | 75 | ||
69 | struct msm_dsi_phy { | 76 | struct msm_dsi_phy { |
@@ -88,7 +95,9 @@ struct msm_dsi_phy { | |||
88 | * PHY internal functions | 95 | * PHY internal functions |
89 | */ | 96 | */ |
90 | int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing, | 97 | int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing, |
91 | struct msm_dsi_phy_clk_request *clk_req); | 98 | struct msm_dsi_phy_clk_request *clk_req); |
99 | int msm_dsi_dphy_timing_calc_v2(struct msm_dsi_dphy_timing *timing, | ||
100 | struct msm_dsi_phy_clk_request *clk_req); | ||
92 | void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg, | 101 | void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg, |
93 | u32 bit_mask); | 102 | u32 bit_mask); |
94 | int msm_dsi_phy_init_common(struct msm_dsi_phy *phy); | 103 | int msm_dsi_phy_init_common(struct msm_dsi_phy *phy); |