cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dsi_phy.c (26583B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <linux/clk-provider.h>
      7#include <linux/platform_device.h>
      8#include <dt-bindings/phy/phy.h>
      9
     10#include "dsi_phy.h"
     11
     12#define S_DIV_ROUND_UP(n, d)	\
     13	(((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
     14
     15static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
     16				s32 min_result, bool even)
     17{
     18	s32 v;
     19
     20	v = (tmax - tmin) * percent;
     21	v = S_DIV_ROUND_UP(v, 100) + tmin;
     22	if (even && (v & 0x1))
     23		return max_t(s32, min_result, v - 1);
     24	else
     25		return max_t(s32, min_result, v);
     26}
     27
     28static void dsi_dphy_timing_calc_clk_zero(struct msm_dsi_dphy_timing *timing,
     29					s32 ui, s32 coeff, s32 pcnt)
     30{
     31	s32 tmax, tmin, clk_z;
     32	s32 temp;
     33
     34	/* reset */
     35	temp = 300 * coeff - ((timing->clk_prepare >> 1) + 1) * 2 * ui;
     36	tmin = S_DIV_ROUND_UP(temp, ui) - 2;
     37	if (tmin > 255) {
     38		tmax = 511;
     39		clk_z = linear_inter(2 * tmin, tmin, pcnt, 0, true);
     40	} else {
     41		tmax = 255;
     42		clk_z = linear_inter(tmax, tmin, pcnt, 0, true);
     43	}
     44
     45	/* adjust */
     46	temp = (timing->hs_rqst + timing->clk_prepare + clk_z) & 0x7;
     47	timing->clk_zero = clk_z + 8 - temp;
     48}
     49
     50int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
     51			     struct msm_dsi_phy_clk_request *clk_req)
     52{
     53	const unsigned long bit_rate = clk_req->bitclk_rate;
     54	const unsigned long esc_rate = clk_req->escclk_rate;
     55	s32 ui, lpx;
     56	s32 tmax, tmin;
     57	s32 pcnt0 = 10;
     58	s32 pcnt1 = (bit_rate > 1200000000) ? 15 : 10;
     59	s32 pcnt2 = 10;
     60	s32 pcnt3 = (bit_rate > 180000000) ? 10 : 40;
     61	s32 coeff = 1000; /* Precision, should avoid overflow */
     62	s32 temp;
     63
     64	if (!bit_rate || !esc_rate)
     65		return -EINVAL;
     66
     67	ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
     68	lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
     69
     70	tmax = S_DIV_ROUND_UP(95 * coeff, ui) - 2;
     71	tmin = S_DIV_ROUND_UP(38 * coeff, ui) - 2;
     72	timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, true);
     73
     74	temp = lpx / ui;
     75	if (temp & 0x1)
     76		timing->hs_rqst = temp;
     77	else
     78		timing->hs_rqst = max_t(s32, 0, temp - 2);
     79
     80	/* Calculate clk_zero after clk_prepare and hs_rqst */
     81	dsi_dphy_timing_calc_clk_zero(timing, ui, coeff, pcnt2);
     82
     83	temp = 105 * coeff + 12 * ui - 20 * coeff;
     84	tmax = S_DIV_ROUND_UP(temp, ui) - 2;
     85	tmin = S_DIV_ROUND_UP(60 * coeff, ui) - 2;
     86	timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
     87
     88	temp = 85 * coeff + 6 * ui;
     89	tmax = S_DIV_ROUND_UP(temp, ui) - 2;
     90	temp = 40 * coeff + 4 * ui;
     91	tmin = S_DIV_ROUND_UP(temp, ui) - 2;
     92	timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, true);
     93
     94	tmax = 255;
     95	temp = ((timing->hs_prepare >> 1) + 1) * 2 * ui + 2 * ui;
     96	temp = 145 * coeff + 10 * ui - temp;
     97	tmin = S_DIV_ROUND_UP(temp, ui) - 2;
     98	timing->hs_zero = linear_inter(tmax, tmin, pcnt2, 24, true);
     99
    100	temp = 105 * coeff + 12 * ui - 20 * coeff;
    101	tmax = S_DIV_ROUND_UP(temp, ui) - 2;
    102	temp = 60 * coeff + 4 * ui;
    103	tmin = DIV_ROUND_UP(temp, ui) - 2;
    104	timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
    105
    106	tmax = 255;
    107	tmin = S_DIV_ROUND_UP(100 * coeff, ui) - 2;
    108	timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, true);
    109
    110	tmax = 63;
    111	temp = ((timing->hs_exit >> 1) + 1) * 2 * ui;
    112	temp = 60 * coeff + 52 * ui - 24 * ui - temp;
    113	tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
    114	timing->shared_timings.clk_post = linear_inter(tmax, tmin, pcnt2, 0,
    115						       false);
    116	tmax = 63;
    117	temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui;
    118	temp += ((timing->clk_zero >> 1) + 1) * 2 * ui;
    119	temp += 8 * ui + lpx;
    120	tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
    121	if (tmin > tmax) {
    122		temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false);
    123		timing->shared_timings.clk_pre = temp >> 1;
    124		timing->shared_timings.clk_pre_inc_by_2 = true;
    125	} else {
    126		timing->shared_timings.clk_pre =
    127				linear_inter(tmax, tmin, pcnt2, 0, false);
    128		timing->shared_timings.clk_pre_inc_by_2 = false;
    129	}
    130
    131	timing->ta_go = 3;
    132	timing->ta_sure = 0;
    133	timing->ta_get = 4;
    134
    135	DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
    136		timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
    137		timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
    138		timing->clk_trail, timing->clk_prepare, timing->hs_exit,
    139		timing->hs_zero, timing->hs_prepare, timing->hs_trail,
    140		timing->hs_rqst);
    141
    142	return 0;
    143}
    144
    145int msm_dsi_dphy_timing_calc_v2(struct msm_dsi_dphy_timing *timing,
    146				struct msm_dsi_phy_clk_request *clk_req)
    147{
    148	const unsigned long bit_rate = clk_req->bitclk_rate;
    149	const unsigned long esc_rate = clk_req->escclk_rate;
    150	s32 ui, ui_x8;
    151	s32 tmax, tmin;
    152	s32 pcnt0 = 50;
    153	s32 pcnt1 = 50;
    154	s32 pcnt2 = 10;
    155	s32 pcnt3 = 30;
    156	s32 pcnt4 = 10;
    157	s32 pcnt5 = 2;
    158	s32 coeff = 1000; /* Precision, should avoid overflow */
    159	s32 hb_en, hb_en_ckln, pd_ckln, pd;
    160	s32 val, val_ckln;
    161	s32 temp;
    162
    163	if (!bit_rate || !esc_rate)
    164		return -EINVAL;
    165
    166	timing->hs_halfbyte_en = 0;
    167	hb_en = 0;
    168	timing->hs_halfbyte_en_ckln = 0;
    169	hb_en_ckln = 0;
    170	timing->hs_prep_dly_ckln = (bit_rate > 100000000) ? 0 : 3;
    171	pd_ckln = timing->hs_prep_dly_ckln;
    172	timing->hs_prep_dly = (bit_rate > 120000000) ? 0 : 1;
    173	pd = timing->hs_prep_dly;
    174
    175	val = (hb_en << 2) + (pd << 1);
    176	val_ckln = (hb_en_ckln << 2) + (pd_ckln << 1);
    177
    178	ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
    179	ui_x8 = ui << 3;
    180
    181	temp = S_DIV_ROUND_UP(38 * coeff - val_ckln * ui, ui_x8);
    182	tmin = max_t(s32, temp, 0);
    183	temp = (95 * coeff - val_ckln * ui) / ui_x8;
    184	tmax = max_t(s32, temp, 0);
    185	timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false);
    186
    187	temp = 300 * coeff - ((timing->clk_prepare << 3) + val_ckln) * ui;
    188	tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3;
    189	tmax = (tmin > 255) ? 511 : 255;
    190	timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false);
    191
    192	tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
    193	temp = 105 * coeff + 12 * ui - 20 * coeff;
    194	tmax = (temp + 3 * ui) / ui_x8;
    195	timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
    196
    197	temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui - val * ui, ui_x8);
    198	tmin = max_t(s32, temp, 0);
    199	temp = (85 * coeff + 6 * ui - val * ui) / ui_x8;
    200	tmax = max_t(s32, temp, 0);
    201	timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false);
    202
    203	temp = 145 * coeff + 10 * ui - ((timing->hs_prepare << 3) + val) * ui;
    204	tmin = S_DIV_ROUND_UP(temp - 11 * ui, ui_x8) - 3;
    205	tmax = 255;
    206	timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false);
    207
    208	tmin = DIV_ROUND_UP(60 * coeff + 4 * ui + 3 * ui, ui_x8);
    209	temp = 105 * coeff + 12 * ui - 20 * coeff;
    210	tmax = (temp + 3 * ui) / ui_x8;
    211	timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
    212
    213	temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
    214	timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
    215
    216	tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
    217	tmax = 255;
    218	timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false);
    219
    220	temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui;
    221	timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8);
    222
    223	temp = 60 * coeff + 52 * ui - 43 * ui;
    224	tmin = DIV_ROUND_UP(temp, ui_x8) - 1;
    225	tmax = 63;
    226	timing->shared_timings.clk_post =
    227				linear_inter(tmax, tmin, pcnt2, 0, false);
    228
    229	temp = 8 * ui + ((timing->clk_prepare << 3) + val_ckln) * ui;
    230	temp += (((timing->clk_zero + 3) << 3) + 11 - (pd_ckln << 1)) * ui;
    231	temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) :
    232				(((timing->hs_rqst_ckln << 3) + 8) * ui);
    233	tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
    234	tmax = 63;
    235	if (tmin > tmax) {
    236		temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false);
    237		timing->shared_timings.clk_pre = temp >> 1;
    238		timing->shared_timings.clk_pre_inc_by_2 = 1;
    239	} else {
    240		timing->shared_timings.clk_pre =
    241				linear_inter(tmax, tmin, pcnt2, 0, false);
    242		timing->shared_timings.clk_pre_inc_by_2 = 0;
    243	}
    244
    245	timing->ta_go = 3;
    246	timing->ta_sure = 0;
    247	timing->ta_get = 4;
    248
    249	DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
    250	    timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
    251	    timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
    252	    timing->clk_trail, timing->clk_prepare, timing->hs_exit,
    253	    timing->hs_zero, timing->hs_prepare, timing->hs_trail,
    254	    timing->hs_rqst, timing->hs_rqst_ckln, timing->hs_halfbyte_en,
    255	    timing->hs_halfbyte_en_ckln, timing->hs_prep_dly,
    256	    timing->hs_prep_dly_ckln);
    257
    258	return 0;
    259}
    260
    261int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing,
    262	struct msm_dsi_phy_clk_request *clk_req)
    263{
    264	const unsigned long bit_rate = clk_req->bitclk_rate;
    265	const unsigned long esc_rate = clk_req->escclk_rate;
    266	s32 ui, ui_x8;
    267	s32 tmax, tmin;
    268	s32 pcnt0 = 50;
    269	s32 pcnt1 = 50;
    270	s32 pcnt2 = 10;
    271	s32 pcnt3 = 30;
    272	s32 pcnt4 = 10;
    273	s32 pcnt5 = 2;
    274	s32 coeff = 1000; /* Precision, should avoid overflow */
    275	s32 hb_en, hb_en_ckln;
    276	s32 temp;
    277
    278	if (!bit_rate || !esc_rate)
    279		return -EINVAL;
    280
    281	timing->hs_halfbyte_en = 0;
    282	hb_en = 0;
    283	timing->hs_halfbyte_en_ckln = 0;
    284	hb_en_ckln = 0;
    285
    286	ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
    287	ui_x8 = ui << 3;
    288
    289	temp = S_DIV_ROUND_UP(38 * coeff, ui_x8);
    290	tmin = max_t(s32, temp, 0);
    291	temp = (95 * coeff) / ui_x8;
    292	tmax = max_t(s32, temp, 0);
    293	timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, false);
    294
    295	temp = 300 * coeff - (timing->clk_prepare << 3) * ui;
    296	tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
    297	tmax = (tmin > 255) ? 511 : 255;
    298	timing->clk_zero = linear_inter(tmax, tmin, pcnt5, 0, false);
    299
    300	tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
    301	temp = 105 * coeff + 12 * ui - 20 * coeff;
    302	tmax = (temp + 3 * ui) / ui_x8;
    303	timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
    304
    305	temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui, ui_x8);
    306	tmin = max_t(s32, temp, 0);
    307	temp = (85 * coeff + 6 * ui) / ui_x8;
    308	tmax = max_t(s32, temp, 0);
    309	timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, false);
    310
    311	temp = 145 * coeff + 10 * ui - (timing->hs_prepare << 3) * ui;
    312	tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
    313	tmax = 255;
    314	timing->hs_zero = linear_inter(tmax, tmin, pcnt4, 0, false);
    315
    316	tmin = DIV_ROUND_UP(60 * coeff + 4 * ui, ui_x8) - 1;
    317	temp = 105 * coeff + 12 * ui - 20 * coeff;
    318	tmax = (temp / ui_x8) - 1;
    319	timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, false);
    320
    321	temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
    322	timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
    323
    324	tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
    325	tmax = 255;
    326	timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, false);
    327
    328	temp = 50 * coeff + ((hb_en_ckln << 2) - 8) * ui;
    329	timing->hs_rqst_ckln = S_DIV_ROUND_UP(temp, ui_x8);
    330
    331	temp = 60 * coeff + 52 * ui - 43 * ui;
    332	tmin = DIV_ROUND_UP(temp, ui_x8) - 1;
    333	tmax = 63;
    334	timing->shared_timings.clk_post =
    335		linear_inter(tmax, tmin, pcnt2, 0, false);
    336
    337	temp = 8 * ui + (timing->clk_prepare << 3) * ui;
    338	temp += (((timing->clk_zero + 3) << 3) + 11) * ui;
    339	temp += hb_en_ckln ? (((timing->hs_rqst_ckln << 3) + 4) * ui) :
    340		(((timing->hs_rqst_ckln << 3) + 8) * ui);
    341	tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
    342	tmax = 63;
    343	if (tmin > tmax) {
    344		temp = linear_inter(tmax << 1, tmin, pcnt2, 0, false);
    345		timing->shared_timings.clk_pre = temp >> 1;
    346		timing->shared_timings.clk_pre_inc_by_2 = 1;
    347	} else {
    348		timing->shared_timings.clk_pre =
    349			linear_inter(tmax, tmin, pcnt2, 0, false);
    350			timing->shared_timings.clk_pre_inc_by_2 = 0;
    351	}
    352
    353	timing->ta_go = 3;
    354	timing->ta_sure = 0;
    355	timing->ta_get = 4;
    356
    357	DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
    358		timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
    359		timing->shared_timings.clk_pre_inc_by_2, timing->clk_zero,
    360		timing->clk_trail, timing->clk_prepare, timing->hs_exit,
    361		timing->hs_zero, timing->hs_prepare, timing->hs_trail,
    362		timing->hs_rqst, timing->hs_rqst_ckln, timing->hs_halfbyte_en,
    363		timing->hs_halfbyte_en_ckln, timing->hs_prep_dly,
    364		timing->hs_prep_dly_ckln);
    365
    366	return 0;
    367}
    368
    369int msm_dsi_dphy_timing_calc_v4(struct msm_dsi_dphy_timing *timing,
    370	struct msm_dsi_phy_clk_request *clk_req)
    371{
    372	const unsigned long bit_rate = clk_req->bitclk_rate;
    373	const unsigned long esc_rate = clk_req->escclk_rate;
    374	s32 ui, ui_x8;
    375	s32 tmax, tmin;
    376	s32 pcnt_clk_prep = 50;
    377	s32 pcnt_clk_zero = 2;
    378	s32 pcnt_clk_trail = 30;
    379	s32 pcnt_hs_prep = 50;
    380	s32 pcnt_hs_zero = 10;
    381	s32 pcnt_hs_trail = 30;
    382	s32 pcnt_hs_exit = 10;
    383	s32 coeff = 1000; /* Precision, should avoid overflow */
    384	s32 hb_en;
    385	s32 temp;
    386
    387	if (!bit_rate || !esc_rate)
    388		return -EINVAL;
    389
    390	hb_en = 0;
    391
    392	ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
    393	ui_x8 = ui << 3;
    394
    395	/* TODO: verify these calculations against latest downstream driver
    396	 * everything except clk_post/clk_pre uses calculations from v3 based
    397	 * on the downstream driver having the same calculations for v3 and v4
    398	 */
    399
    400	temp = S_DIV_ROUND_UP(38 * coeff, ui_x8);
    401	tmin = max_t(s32, temp, 0);
    402	temp = (95 * coeff) / ui_x8;
    403	tmax = max_t(s32, temp, 0);
    404	timing->clk_prepare = linear_inter(tmax, tmin, pcnt_clk_prep, 0, false);
    405
    406	temp = 300 * coeff - (timing->clk_prepare << 3) * ui;
    407	tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
    408	tmax = (tmin > 255) ? 511 : 255;
    409	timing->clk_zero = linear_inter(tmax, tmin, pcnt_clk_zero, 0, false);
    410
    411	tmin = DIV_ROUND_UP(60 * coeff + 3 * ui, ui_x8);
    412	temp = 105 * coeff + 12 * ui - 20 * coeff;
    413	tmax = (temp + 3 * ui) / ui_x8;
    414	timing->clk_trail = linear_inter(tmax, tmin, pcnt_clk_trail, 0, false);
    415
    416	temp = S_DIV_ROUND_UP(40 * coeff + 4 * ui, ui_x8);
    417	tmin = max_t(s32, temp, 0);
    418	temp = (85 * coeff + 6 * ui) / ui_x8;
    419	tmax = max_t(s32, temp, 0);
    420	timing->hs_prepare = linear_inter(tmax, tmin, pcnt_hs_prep, 0, false);
    421
    422	temp = 145 * coeff + 10 * ui - (timing->hs_prepare << 3) * ui;
    423	tmin = S_DIV_ROUND_UP(temp, ui_x8) - 1;
    424	tmax = 255;
    425	timing->hs_zero = linear_inter(tmax, tmin, pcnt_hs_zero, 0, false);
    426
    427	tmin = DIV_ROUND_UP(60 * coeff + 4 * ui, ui_x8) - 1;
    428	temp = 105 * coeff + 12 * ui - 20 * coeff;
    429	tmax = (temp / ui_x8) - 1;
    430	timing->hs_trail = linear_inter(tmax, tmin, pcnt_hs_trail, 0, false);
    431
    432	temp = 50 * coeff + ((hb_en << 2) - 8) * ui;
    433	timing->hs_rqst = S_DIV_ROUND_UP(temp, ui_x8);
    434
    435	tmin = DIV_ROUND_UP(100 * coeff, ui_x8) - 1;
    436	tmax = 255;
    437	timing->hs_exit = linear_inter(tmax, tmin, pcnt_hs_exit, 0, false);
    438
    439	/* recommended min
    440	 * = roundup((mipi_min_ns + t_hs_trail_ns)/(16*bit_clk_ns), 0) - 1
    441	 */
    442	temp = 60 * coeff + 52 * ui + + (timing->hs_trail + 1) * ui_x8;
    443	tmin = DIV_ROUND_UP(temp, 16 * ui) - 1;
    444	tmax = 255;
    445	timing->shared_timings.clk_post = linear_inter(tmax, tmin, 5, 0, false);
    446
    447	/* recommended min
    448	 * val1 = (tlpx_ns + clk_prepare_ns + clk_zero_ns + hs_rqst_ns)
    449	 * val2 = (16 * bit_clk_ns)
    450	 * final = roundup(val1/val2, 0) - 1
    451	 */
    452	temp = 52 * coeff + (timing->clk_prepare + timing->clk_zero + 1) * ui_x8 + 54 * coeff;
    453	tmin = DIV_ROUND_UP(temp, 16 * ui) - 1;
    454	tmax = 255;
    455	timing->shared_timings.clk_pre = DIV_ROUND_UP((tmax - tmin) * 125, 10000) + tmin;
    456
    457	DBG("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
    458		timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
    459		timing->clk_zero, timing->clk_trail, timing->clk_prepare, timing->hs_exit,
    460		timing->hs_zero, timing->hs_prepare, timing->hs_trail, timing->hs_rqst);
    461
    462	return 0;
    463}
    464
    465int msm_dsi_cphy_timing_calc_v4(struct msm_dsi_dphy_timing *timing,
    466	struct msm_dsi_phy_clk_request *clk_req)
    467{
    468	const unsigned long bit_rate = clk_req->bitclk_rate;
    469	const unsigned long esc_rate = clk_req->escclk_rate;
    470	s32 ui, ui_x7;
    471	s32 tmax, tmin;
    472	s32 coeff = 1000; /* Precision, should avoid overflow */
    473	s32 temp;
    474
    475	if (!bit_rate || !esc_rate)
    476		return -EINVAL;
    477
    478	ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
    479	ui_x7 = ui * 7;
    480
    481	temp = S_DIV_ROUND_UP(38 * coeff, ui_x7);
    482	tmin = max_t(s32, temp, 0);
    483	temp = (95 * coeff) / ui_x7;
    484	tmax = max_t(s32, temp, 0);
    485	timing->clk_prepare = linear_inter(tmax, tmin, 50, 0, false);
    486
    487	tmin = DIV_ROUND_UP(50 * coeff, ui_x7);
    488	tmax = 255;
    489	timing->hs_rqst = linear_inter(tmax, tmin, 1, 0, false);
    490
    491	tmin = DIV_ROUND_UP(100 * coeff, ui_x7) - 1;
    492	tmax = 255;
    493	timing->hs_exit = linear_inter(tmax, tmin, 10, 0, false);
    494
    495	tmin = 1;
    496	tmax = 32;
    497	timing->shared_timings.clk_post = linear_inter(tmax, tmin, 80, 0, false);
    498
    499	tmin = min_t(s32, 64, S_DIV_ROUND_UP(262 * coeff, ui_x7) - 1);
    500	tmax = 64;
    501	timing->shared_timings.clk_pre = linear_inter(tmax, tmin, 20, 0, false);
    502
    503	DBG("%d, %d, %d, %d, %d",
    504		timing->shared_timings.clk_pre, timing->shared_timings.clk_post,
    505		timing->clk_prepare, timing->hs_exit, timing->hs_rqst);
    506
    507	return 0;
    508}
    509
    510static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
    511{
    512	struct regulator_bulk_data *s = phy->supplies;
    513	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
    514	struct device *dev = &phy->pdev->dev;
    515	int num = phy->cfg->reg_cfg.num;
    516	int i, ret;
    517
    518	for (i = 0; i < num; i++)
    519		s[i].supply = regs[i].name;
    520
    521	ret = devm_regulator_bulk_get(dev, num, s);
    522	if (ret < 0) {
    523		if (ret != -EPROBE_DEFER) {
    524			DRM_DEV_ERROR(dev,
    525				      "%s: failed to init regulator, ret=%d\n",
    526				      __func__, ret);
    527		}
    528
    529		return ret;
    530	}
    531
    532	return 0;
    533}
    534
    535static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
    536{
    537	struct regulator_bulk_data *s = phy->supplies;
    538	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
    539	int num = phy->cfg->reg_cfg.num;
    540	int i;
    541
    542	DBG("");
    543	for (i = num - 1; i >= 0; i--)
    544		if (regs[i].disable_load >= 0)
    545			regulator_set_load(s[i].consumer, regs[i].disable_load);
    546
    547	regulator_bulk_disable(num, s);
    548}
    549
    550static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
    551{
    552	struct regulator_bulk_data *s = phy->supplies;
    553	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
    554	struct device *dev = &phy->pdev->dev;
    555	int num = phy->cfg->reg_cfg.num;
    556	int ret, i;
    557
    558	DBG("");
    559	for (i = 0; i < num; i++) {
    560		if (regs[i].enable_load >= 0) {
    561			ret = regulator_set_load(s[i].consumer,
    562							regs[i].enable_load);
    563			if (ret < 0) {
    564				DRM_DEV_ERROR(dev,
    565					"regulator %d set op mode failed, %d\n",
    566					i, ret);
    567				goto fail;
    568			}
    569		}
    570	}
    571
    572	ret = regulator_bulk_enable(num, s);
    573	if (ret < 0) {
    574		DRM_DEV_ERROR(dev, "regulator enable failed, %d\n", ret);
    575		goto fail;
    576	}
    577
    578	return 0;
    579
    580fail:
    581	for (i--; i >= 0; i--)
    582		regulator_set_load(s[i].consumer, regs[i].disable_load);
    583	return ret;
    584}
    585
    586static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
    587{
    588	struct device *dev = &phy->pdev->dev;
    589	int ret;
    590
    591	pm_runtime_get_sync(dev);
    592
    593	ret = clk_prepare_enable(phy->ahb_clk);
    594	if (ret) {
    595		DRM_DEV_ERROR(dev, "%s: can't enable ahb clk, %d\n", __func__, ret);
    596		pm_runtime_put_sync(dev);
    597	}
    598
    599	return ret;
    600}
    601
    602static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
    603{
    604	clk_disable_unprepare(phy->ahb_clk);
    605	pm_runtime_put(&phy->pdev->dev);
    606}
    607
    608static const struct of_device_id dsi_phy_dt_match[] = {
    609#ifdef CONFIG_DRM_MSM_DSI_28NM_PHY
    610	{ .compatible = "qcom,dsi-phy-28nm-hpm",
    611	  .data = &dsi_phy_28nm_hpm_cfgs },
    612	{ .compatible = "qcom,dsi-phy-28nm-hpm-fam-b",
    613	  .data = &dsi_phy_28nm_hpm_famb_cfgs },
    614	{ .compatible = "qcom,dsi-phy-28nm-lp",
    615	  .data = &dsi_phy_28nm_lp_cfgs },
    616#endif
    617#ifdef CONFIG_DRM_MSM_DSI_20NM_PHY
    618	{ .compatible = "qcom,dsi-phy-20nm",
    619	  .data = &dsi_phy_20nm_cfgs },
    620#endif
    621#ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY
    622	{ .compatible = "qcom,dsi-phy-28nm-8960",
    623	  .data = &dsi_phy_28nm_8960_cfgs },
    624#endif
    625#ifdef CONFIG_DRM_MSM_DSI_14NM_PHY
    626	{ .compatible = "qcom,dsi-phy-14nm",
    627	  .data = &dsi_phy_14nm_cfgs },
    628	{ .compatible = "qcom,dsi-phy-14nm-660",
    629	  .data = &dsi_phy_14nm_660_cfgs },
    630	{ .compatible = "qcom,dsi-phy-14nm-8953",
    631	  .data = &dsi_phy_14nm_8953_cfgs },
    632#endif
    633#ifdef CONFIG_DRM_MSM_DSI_10NM_PHY
    634	{ .compatible = "qcom,dsi-phy-10nm",
    635	  .data = &dsi_phy_10nm_cfgs },
    636	{ .compatible = "qcom,dsi-phy-10nm-8998",
    637	  .data = &dsi_phy_10nm_8998_cfgs },
    638#endif
    639#ifdef CONFIG_DRM_MSM_DSI_7NM_PHY
    640	{ .compatible = "qcom,dsi-phy-7nm",
    641	  .data = &dsi_phy_7nm_cfgs },
    642	{ .compatible = "qcom,dsi-phy-7nm-8150",
    643	  .data = &dsi_phy_7nm_8150_cfgs },
    644	{ .compatible = "qcom,sc7280-dsi-phy-7nm",
    645	  .data = &dsi_phy_7nm_7280_cfgs },
    646#endif
    647	{}
    648};
    649
    650/*
    651 * Currently, we only support one SoC for each PHY type. When we have multiple
    652 * SoCs for the same PHY, we can try to make the index searching a bit more
    653 * clever.
    654 */
    655static int dsi_phy_get_id(struct msm_dsi_phy *phy)
    656{
    657	struct platform_device *pdev = phy->pdev;
    658	const struct msm_dsi_phy_cfg *cfg = phy->cfg;
    659	struct resource *res;
    660	int i;
    661
    662	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dsi_phy");
    663	if (!res)
    664		return -EINVAL;
    665
    666	for (i = 0; i < cfg->num_dsi_phy; i++) {
    667		if (cfg->io_start[i] == res->start)
    668			return i;
    669	}
    670
    671	return -EINVAL;
    672}
    673
    674static int dsi_phy_driver_probe(struct platform_device *pdev)
    675{
    676	struct msm_dsi_phy *phy;
    677	struct device *dev = &pdev->dev;
    678	u32 phy_type;
    679	int ret;
    680
    681	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
    682	if (!phy)
    683		return -ENOMEM;
    684
    685	phy->provided_clocks = devm_kzalloc(dev,
    686			struct_size(phy->provided_clocks, hws, NUM_PROVIDED_CLKS),
    687			GFP_KERNEL);
    688	if (!phy->provided_clocks)
    689		return -ENOMEM;
    690
    691	phy->provided_clocks->num = NUM_PROVIDED_CLKS;
    692
    693	phy->cfg = of_device_get_match_data(&pdev->dev);
    694	if (!phy->cfg)
    695		return -ENODEV;
    696
    697	phy->pdev = pdev;
    698
    699	phy->id = dsi_phy_get_id(phy);
    700	if (phy->id < 0) {
    701		ret = phy->id;
    702		DRM_DEV_ERROR(dev, "%s: couldn't identify PHY index, %d\n",
    703			__func__, ret);
    704		goto fail;
    705	}
    706
    707	phy->regulator_ldo_mode = of_property_read_bool(dev->of_node,
    708				"qcom,dsi-phy-regulator-ldo-mode");
    709	if (!of_property_read_u32(dev->of_node, "phy-type", &phy_type))
    710		phy->cphy_mode = (phy_type == PHY_TYPE_CPHY);
    711
    712	phy->base = msm_ioremap_size(pdev, "dsi_phy", &phy->base_size);
    713	if (IS_ERR(phy->base)) {
    714		DRM_DEV_ERROR(dev, "%s: failed to map phy base\n", __func__);
    715		ret = -ENOMEM;
    716		goto fail;
    717	}
    718
    719	phy->pll_base = msm_ioremap_size(pdev, "dsi_pll", &phy->pll_size);
    720	if (IS_ERR(phy->pll_base)) {
    721		DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__);
    722		ret = -ENOMEM;
    723		goto fail;
    724	}
    725
    726	if (phy->cfg->has_phy_lane) {
    727		phy->lane_base = msm_ioremap_size(pdev, "dsi_phy_lane", &phy->lane_size);
    728		if (IS_ERR(phy->lane_base)) {
    729			DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy lane base\n", __func__);
    730			ret = -ENOMEM;
    731			goto fail;
    732		}
    733	}
    734
    735	if (phy->cfg->has_phy_regulator) {
    736		phy->reg_base = msm_ioremap_size(pdev, "dsi_phy_regulator", &phy->reg_size);
    737		if (IS_ERR(phy->reg_base)) {
    738			DRM_DEV_ERROR(&pdev->dev, "%s: failed to map phy regulator base\n", __func__);
    739			ret = -ENOMEM;
    740			goto fail;
    741		}
    742	}
    743
    744	if (phy->cfg->ops.parse_dt_properties) {
    745		ret = phy->cfg->ops.parse_dt_properties(phy);
    746		if (ret)
    747			goto fail;
    748	}
    749
    750	ret = dsi_phy_regulator_init(phy);
    751	if (ret)
    752		goto fail;
    753
    754	phy->ahb_clk = msm_clk_get(pdev, "iface");
    755	if (IS_ERR(phy->ahb_clk)) {
    756		DRM_DEV_ERROR(dev, "%s: Unable to get ahb clk\n", __func__);
    757		ret = PTR_ERR(phy->ahb_clk);
    758		goto fail;
    759	}
    760
    761	/* PLL init will call into clk_register which requires
    762	 * register access, so we need to enable power and ahb clock.
    763	 */
    764	ret = dsi_phy_enable_resource(phy);
    765	if (ret)
    766		goto fail;
    767
    768	if (phy->cfg->ops.pll_init) {
    769		ret = phy->cfg->ops.pll_init(phy);
    770		if (ret) {
    771			DRM_DEV_INFO(dev,
    772				"%s: pll init failed: %d, need separate pll clk driver\n",
    773				__func__, ret);
    774			goto fail;
    775		}
    776	}
    777
    778	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
    779				     phy->provided_clocks);
    780	if (ret) {
    781		DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret);
    782		goto fail;
    783	}
    784
    785	dsi_phy_disable_resource(phy);
    786
    787	platform_set_drvdata(pdev, phy);
    788
    789	return 0;
    790
    791fail:
    792	return ret;
    793}
    794
    795static struct platform_driver dsi_phy_platform_driver = {
    796	.probe      = dsi_phy_driver_probe,
    797	.driver     = {
    798		.name   = "msm_dsi_phy",
    799		.of_match_table = dsi_phy_dt_match,
    800	},
    801};
    802
    803void __init msm_dsi_phy_driver_register(void)
    804{
    805	platform_driver_register(&dsi_phy_platform_driver);
    806}
    807
    808void __exit msm_dsi_phy_driver_unregister(void)
    809{
    810	platform_driver_unregister(&dsi_phy_platform_driver);
    811}
    812
    813int msm_dsi_phy_enable(struct msm_dsi_phy *phy,
    814			struct msm_dsi_phy_clk_request *clk_req,
    815			struct msm_dsi_phy_shared_timings *shared_timings)
    816{
    817	struct device *dev;
    818	int ret;
    819
    820	if (!phy || !phy->cfg->ops.enable)
    821		return -EINVAL;
    822
    823	dev = &phy->pdev->dev;
    824
    825	ret = dsi_phy_enable_resource(phy);
    826	if (ret) {
    827		DRM_DEV_ERROR(dev, "%s: resource enable failed, %d\n",
    828			__func__, ret);
    829		goto res_en_fail;
    830	}
    831
    832	ret = dsi_phy_regulator_enable(phy);
    833	if (ret) {
    834		DRM_DEV_ERROR(dev, "%s: regulator enable failed, %d\n",
    835			__func__, ret);
    836		goto reg_en_fail;
    837	}
    838
    839	ret = phy->cfg->ops.enable(phy, clk_req);
    840	if (ret) {
    841		DRM_DEV_ERROR(dev, "%s: phy enable failed, %d\n", __func__, ret);
    842		goto phy_en_fail;
    843	}
    844
    845	memcpy(shared_timings, &phy->timing.shared_timings,
    846	       sizeof(*shared_timings));
    847
    848	/*
    849	 * Resetting DSI PHY silently changes its PLL registers to reset status,
    850	 * which will confuse clock driver and result in wrong output rate of
    851	 * link clocks. Restore PLL status if its PLL is being used as clock
    852	 * source.
    853	 */
    854	if (phy->usecase != MSM_DSI_PHY_SLAVE) {
    855		ret = msm_dsi_phy_pll_restore_state(phy);
    856		if (ret) {
    857			DRM_DEV_ERROR(dev, "%s: failed to restore phy state, %d\n",
    858				__func__, ret);
    859			goto pll_restor_fail;
    860		}
    861	}
    862
    863	return 0;
    864
    865pll_restor_fail:
    866	if (phy->cfg->ops.disable)
    867		phy->cfg->ops.disable(phy);
    868phy_en_fail:
    869	dsi_phy_regulator_disable(phy);
    870reg_en_fail:
    871	dsi_phy_disable_resource(phy);
    872res_en_fail:
    873	return ret;
    874}
    875
    876void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
    877{
    878	if (!phy || !phy->cfg->ops.disable)
    879		return;
    880
    881	phy->cfg->ops.disable(phy);
    882
    883	dsi_phy_regulator_disable(phy);
    884	dsi_phy_disable_resource(phy);
    885}
    886
    887void msm_dsi_phy_set_usecase(struct msm_dsi_phy *phy,
    888			     enum msm_dsi_phy_usecase uc)
    889{
    890	if (phy)
    891		phy->usecase = uc;
    892}
    893
    894/* Returns true if we have to clear DSI_LANE_CTRL.HS_REQ_SEL_PHY */
    895bool msm_dsi_phy_set_continuous_clock(struct msm_dsi_phy *phy, bool enable)
    896{
    897	if (!phy || !phy->cfg->ops.set_continuous_clock)
    898		return false;
    899
    900	return phy->cfg->ops.set_continuous_clock(phy, enable);
    901}
    902
    903void msm_dsi_phy_pll_save_state(struct msm_dsi_phy *phy)
    904{
    905	if (phy->cfg->ops.save_pll_state) {
    906		phy->cfg->ops.save_pll_state(phy);
    907		phy->state_saved = true;
    908	}
    909}
    910
    911int msm_dsi_phy_pll_restore_state(struct msm_dsi_phy *phy)
    912{
    913	int ret;
    914
    915	if (phy->cfg->ops.restore_pll_state && phy->state_saved) {
    916		ret = phy->cfg->ops.restore_pll_state(phy);
    917		if (ret)
    918			return ret;
    919
    920		phy->state_saved = false;
    921	}
    922
    923	return 0;
    924}
    925
    926void msm_dsi_phy_snapshot(struct msm_disp_state *disp_state, struct msm_dsi_phy *phy)
    927{
    928	msm_disp_snapshot_add_block(disp_state,
    929			phy->base_size, phy->base,
    930			"dsi%d_phy", phy->id);
    931
    932	/* Do not try accessing PLL registers if it is switched off */
    933	if (phy->pll_on)
    934		msm_disp_snapshot_add_block(disp_state,
    935			phy->pll_size, phy->pll_base,
    936			"dsi%d_pll", phy->id);
    937
    938	if (phy->lane_base)
    939		msm_disp_snapshot_add_block(disp_state,
    940			phy->lane_size, phy->lane_base,
    941			"dsi%d_lane", phy->id);
    942
    943	if (phy->reg_base)
    944		msm_disp_snapshot_add_block(disp_state,
    945			phy->reg_size, phy->reg_base,
    946			"dsi%d_reg", phy->id);
    947}