tizen 2.4 release
[kernel/u-boot-tm1.git] / drivers / video / sprdfb / dsi_1_21a / mipi_dsih_dphy.c
1 /**\r
2  * @file mipi_dsih_dphy.c\r
3  * @brief D-PHY driver\r
4  *\r
5  *  Synopsys Inc.\r
6  *  SG DWC PT02\r
7  */\r
8 #include "mipi_dsih_dphy.h"\r
9 #define PRECISION_FACTOR                (1000)\r
10 /* Reference clock frequency divided by Input Frequency Division Ratio LIMITS */\r
11 #define DPHY_DIV_UPPER_LIMIT    (40000)\r
12 #ifdef GEN_2\r
13 #define DPHY_DIV_LOWER_LIMIT    (5000)\r
14 #else\r
15 #define DPHY_DIV_LOWER_LIMIT    (1000)\r
16 #endif\r
17 \r
18 #if ((defined DWC_MIPI_DPHY_BIDIR_TSMC40LP) || (defined GEN_2))\r
19 #define MIN_OUTPUT_FREQ                 (80)\r
20 #elif defined DPHY2Btql\r
21 #define MIN_OUTPUT_FREQ                 (200)\r
22 #undef GEN_2\r
23 #endif\r
24 \r
25 //#define SOFT_DPHY_CALIBRATION\r
26 \r
27 uint8_t mipi_dsih_dphy_calibration(dphy_t * phy)// tianci need check with thomas\r
28 {\r
29     uint8_t rd_data[3],sv_data[3];\r
30     uint8_t data[3];\r
31     uint8_t i = 0; /* iterator */\r
32     int8_t j = 0;\r
33     uint8_t sw_cnt;\r
34 \r
35 \r
36     /*phy calibration process */\r
37     sw_cnt = 0;\r
38     data[0] = 0x03;\r
39     mipi_dsih_dphy_write(phy, 0x21, data, 1);\r
40 \r
41     for(i =0; i<50; i++ );\r
42 \r
43     rd_data[0] = mipi_dsih_dphy_test_data_out(phy);\r
44     printf("data[0] = 0x03,rd_data[0] = %x \n",rd_data[0]);\r
45 \r
46     for(j=1; j<8; j++)\r
47     {\r
48 \r
49         data[0] = 0x03;\r
50         data[0] |= j<<2;\r
51         mipi_dsih_dphy_write(phy, 0x21, data, 1);\r
52 \r
53         for(i =0; i<50; i++) ;\r
54 \r
55         rd_data[1] = mipi_dsih_dphy_test_data_out(phy);\r
56         printf("data[%d] = %x,rd_data[1] = %x \n",j,data[0],rd_data[1]);\r
57         if((rd_data[1]&0x80) != (rd_data[0]&0x80))\r
58         {\r
59             sw_cnt++;\r
60             printf(" break--data[%d] = %x,rd_data[0] = %x,rd_data[1] = %x \n",j,data[0],rd_data[0],rd_data[1]);\r
61             if(sw_cnt>1)\r
62             {\r
63                 printf("phy calibration error,toggles times more than once \n");\r
64                 return 0x0f;\r
65             }\r
66             rd_data[0] = rd_data[1];\r
67             sv_data[0] = data[0];\r
68         }\r
69         if((7 == j) && (0 == sw_cnt))\r
70         {\r
71             if(0x80 == (rd_data[1]&0x80))\r
72                 return 0x1f;\r
73             if(0x0 == (rd_data[1]&0x80))\r
74                 return 0x3;\r
75         }\r
76     }\r
77 \r
78     for(j=6; j>=0; j--)\r
79     {\r
80 \r
81         data[0] = 0x03;\r
82         data[0] |= j<<2;\r
83         mipi_dsih_dphy_write(phy, 0x21, data, 1);\r
84 \r
85         for(i =0; i<50; i++ );\r
86 \r
87         rd_data[2] = mipi_dsih_dphy_test_data_out(phy);\r
88         printf("next-->data[%d] = %x,rd_data[2] = %x \n",j,data[0],rd_data[2]);\r
89         if((rd_data[2]&0x80) != (rd_data[0]&0x80))\r
90         {\r
91             printf("break--next-->data[%d] = %x,rd_data[2] = %x,rd_data[0] = %x \n",j,data[0],rd_data[2],rd_data[0]);\r
92             rd_data[0] = rd_data[2];\r
93             sv_data[1] = data[0];\r
94         }\r
95     }\r
96 \r
97     sv_data[0] =(sv_data[0]&0x1c) >>2;\r
98     sv_data[1] =(sv_data[1]&0x1c) >>2;\r
99     sv_data[0] = sv_data[0] + sv_data[1];\r
100     sv_data[1] = sv_data[0] / 2 + sv_data[0] % 2;\r
101     data[0] = (sv_data[1] <<2) | 0x03;\r
102 \r
103     return data[0];\r
104 \r
105 }\r
106 \r
107 /**\r
108  * Initialise D-PHY module and power up\r
109  * @param phy pointer to structure which holds information about the d-phy\r
110  * module\r
111  * @return error code\r
112  */\r
113 dsih_error_t mipi_dsih_dphy_open(dphy_t * phy)\r
114 {\r
115     if (phy == 0)\r
116     {\r
117         return ERR_DSI_PHY_INVALID;\r
118     }\r
119     else if ((phy->core_read_function == 0) || (phy->core_write_function == 0))\r
120     {\r
121         return ERR_DSI_INVALID_IO;\r
122     }\r
123     else if (phy->status == INITIALIZED)\r
124     {\r
125         return ERR_DSI_PHY_INVALID;\r
126     }\r
127     phy->status = NOT_INITIALIZED;\r
128 #if 0// tianci need check with thomas\r
129     mipi_dsih_dphy_reset(phy, 0);\r
130     mipi_dsih_dphy_stop_wait_time(phy, 0x1C);\r
131     mipi_dsih_dphy_no_of_lanes(phy, 1);\r
132     mipi_dsih_dphy_clock_en(phy, 1);\r
133     mipi_dsih_dphy_shutdown(phy, 1);\r
134     mipi_dsih_dphy_reset(phy, 1);\r
135 #endif\r
136     phy->status = INITIALIZED;\r
137     return OK;\r
138 }\r
139 /**\r
140  * Configure D-PHY and PLL module to desired operation mode\r
141  * @param phy pointer to structure which holds information about the d-phy\r
142  * module\r
143  * @param no_of_lanes active\r
144  * @param output_freq desired high speed frequency\r
145  * @return error code\r
146  */\r
147  #ifdef GEN_2\r
148 dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq)\r
149 {\r
150     uint32_t loop_divider = 0; /* (M) */\r
151     uint32_t input_divider = 1; /* (N) */\r
152     uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/\r
153     uint8_t no_of_bytes = 0;\r
154     uint8_t i = 0;\r
155     uint8_t n=0;/* iterator */\r
156     uint8_t range = 0; /* ranges iterator */\r
157     int flag = 0;\r
158         struct\r
159         {\r
160                 uint32_t loop_div; /* upper limit of loop divider range */\r
161                 uint8_t cp_current; /* icpctrl */\r
162                 uint8_t lpf_resistor; /* lpfctrl */\r
163         }\r
164         loop_bandwidth[] =\r
165 \r
166         {       /* gen 2 associates the charge pump current and LPF resistor with the\r
167                  output frequency ranges (and thus we simplify here to use the\r
168                  counter/pointer of the following structure) */\r
169                 {  90, 0x02, 0x02}, { 100, 0x02, 0x02}, { 110, 0x02, 0x02},\r
170                 { 130, 0x02, 0x01}, { 140, 0x02, 0x01}, { 150, 0x02, 0x01},\r
171                 { 170, 0x09, 0x00}, { 180, 0x09, 0x01}, { 200, 0x09, 0x01},\r
172                 { 220, 0x09, 0x04}, { 240, 0x09, 0x04}, { 250, 0x09, 0x04},\r
173                 { 270, 0x06, 0x04}, { 300, 0x06, 0x04}, { 330, 0x09, 0x04},\r
174                 { 360, 0x09, 0x04}, { 400, 0x09, 0x04}, { 450, 0x06, 0x04},\r
175                 { 500, 0x06, 0x04}, { 550, 0x06, 0x04}, { 600, 0x06, 0x04},\r
176                 { 650, 0x0A, 0x04}, { 700, 0x0A, 0x04}, { 750, 0x0A, 0x04},\r
177                 { 800, 0x0A, 0x04}, { 850, 0x0A, 0x04}, { 900, 0x0A, 0x04},\r
178                 { 950, 0x0B, 0x08}, {1000, 0x0B, 0x08}, {1050, 0x0B, 0x08},\r
179                 {1100, 0x0B, 0x08}, {1150, 0x0B, 0x08}, {1200, 0x0B, 0x08},\r
180                 {1250, 0x0B, 0x08}, {1300, 0x0B, 0x08}, {1350, 0x0B, 0x08},\r
181                 {1400, 0x0B, 0x08}, {1450, 0x0B, 0x08}, {1500, 0x0B, 0x08}\r
182         };\r
183         uint32_t delta = 0;\r
184         uint32_t tmp_loop_divider = 0;\r
185         unsigned step = 0;\r
186 \r
187     struct\r
188     {\r
189         uint32_t freq;  /* upper margin of frequency range */\r
190         uint8_t hs_freq; /* hsfreqrange */\r
191         uint8_t vco_range; /* vcorange */\r
192     }\r
193     ranges[] =\r
194         {\r
195                 {  90, 0x00, 0x00}, { 100, 0x10, 0x00}, { 110, 0x20, 0x00},\r
196                 { 130, 0x01, 0x00}, { 140, 0x11, 0x00}, { 150, 0x21, 0x00},\r
197                 { 170, 0x02, 0x00}, { 180, 0x12, 0x00}, { 200, 0x22, 0x00},\r
198                 { 220, 0x03, 0x01}, { 240, 0x13, 0x01}, { 250, 0x23, 0x01},\r
199                 { 270, 0x04, 0x01}, { 300, 0x14, 0x01}, { 330, 0x05, 0x02},\r
200                 { 360, 0x15, 0x02}, { 400, 0x25, 0x02}, { 450, 0x06, 0x02},\r
201                 { 500, 0x16, 0x02}, { 550, 0x07, 0x03}, { 600, 0x17, 0x03},\r
202                 { 650, 0x08, 0x03}, { 700, 0x18, 0x03}, { 750, 0x09, 0x04},\r
203                 { 800, 0x19, 0x04}, { 850, 0x29, 0x04}, { 900, 0x39, 0x04},\r
204                 { 950, 0x0A, 0x05}, {1000, 0x1A, 0x05}, {1050, 0x2A, 0x05},\r
205                 {1100, 0x3A, 0x05}, {1150, 0x0B, 0x06}, {1200, 0x1B, 0x06},\r
206                 {1250, 0x2B, 0x06}, {1300, 0x3B, 0x06}, {1350, 0x0C, 0x07},\r
207                 {1400, 0x1C, 0x07}, {1450, 0x2C, 0x07}, {1500, 0x3C, 0x07}\r
208         };\r
209 \r
210     if (phy == 0)\r
211     {\r
212         return ERR_DSI_INVALID_INSTANCE;\r
213     }\r
214     if (phy->status < INITIALIZED)\r
215     {\r
216         return ERR_DSI_INVALID_INSTANCE;\r
217     }\r
218     if (output_freq < MIN_OUTPUT_FREQ)\r
219     {\r
220         return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;\r
221     }\r
222 \r
223         loop_divider = ((output_freq * (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) / phy->reference_freq);\r
224         /* here delta will account for the rounding */\r
225         delta = ((loop_divider * phy->reference_freq) / (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) - output_freq;\r
226         for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++)\r
227         {\r
228                 tmp_loop_divider = ((output_freq * input_divider) / (phy->reference_freq));\r
229                 if ((tmp_loop_divider % 2) == 0)\r
230                 {       /* if even */\r
231                         if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider)))\r
232                         {       /* exact values found */\r
233                                 flag = 1;\r
234                                 loop_divider = tmp_loop_divider;\r
235                                 delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider));\r
236                                 /* variable was incremented before exiting the loop */\r
237                                 break;\r
238                         }\r
239                         else if ((output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider))) < delta)\r
240                         {       /* values found with smaller delta */\r
241                                 loop_divider = tmp_loop_divider;\r
242                                 delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider));\r
243                                 step = 1;\r
244                         }\r
245                 }\r
246                 else\r
247                 {\r
248                         tmp_loop_divider += 1;\r
249                         if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider)))\r
250                         {       /* exact values found */\r
251                                 flag = 1;\r
252                                 loop_divider = tmp_loop_divider;\r
253                                 delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq;\r
254                                 /* variable was incremented before exiting the loop */\r
255                                 break;\r
256                         }\r
257                         else if (((tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq) < delta)\r
258                         {       /* values found with smaller delta */\r
259                                 loop_divider = tmp_loop_divider;\r
260                                 delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq;\r
261                                 step = 0;\r
262                         }\r
263                 }\r
264         }\r
265         if (!flag)\r
266         {\r
267                 input_divider = step + (loop_divider * phy->reference_freq) / output_freq;\r
268                 printf("sprdfb: D-PHY: Approximated Frequency: %d KHz\n", (loop_divider * (phy->reference_freq / input_divider)));\r
269 //              phy->log_info("D-PHY: Approximated Frequency: %d KHz", (loop_divider * (phy->reference_freq / input_divider)));\r
270         }\r
271 \r
272     /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to\r
273     avoid transient periods in PHY operation during re-configuration procedures. */\r
274     mipi_dsih_dphy_reset(phy, 0);\r
275     mipi_dsih_dphy_clock_en(phy, 0);\r
276     mipi_dsih_dphy_shutdown(phy, 0);\r
277     /* provide an initial active-high test clear pulse in TESTCLR  */\r
278     mipi_dsih_dphy_test_clear(phy, 1);\r
279     mipi_dsih_dphy_test_clear(phy, 0);\r
280     for(n=0;n<100;n++){\r
281         ;\r
282     }\r
283     /* find ranges */\r
284     for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++)\r
285     {\r
286         ;\r
287     }\r
288     if (range >= (sizeof(ranges)/sizeof(ranges[0])))\r
289     {\r
290         return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;\r
291     }\r
292     /* set up board depending on environment if any */\r
293     if (phy->bsp_pre_config != 0)\r
294     {\r
295         phy->bsp_pre_config(phy, 0);\r
296     }\r
297 \r
298   /* Jessica add - begin*/\r
299     data[0] =  0x83;//0x44;//0x44;//0x40;                 //0x40: ok for 200    clock lane lpx /*about 52ns*/\r
300     mipi_dsih_dphy_write(phy, 0x60, data, 1);\r
301 //    data[0] =  0x0;//0xA6;//0xC6;//0xC6;//0x86;                 //0x48: ok for 200     prepare time\r
302 //    mipi_dsih_dphy_write(phy, 0x61, data, 1);\r
303 \r
304 //    data[0] =  0x0;//0x6a;//0x6a;//0x4a;                  //0x4a: ok for 200    zero time\r
305 //    mipi_dsih_dphy_write(phy, 0x62, data, 1);\r
306 \r
307     data[0] =  0x83;//0x44;//0x40;//0x40;              // 0x40: ok for 200          data lane lpx /*about 52ns*/\r
308     mipi_dsih_dphy_write(phy, 0x70, data, 1);\r
309 \r
310 //    data[0] =  0x0;//0x84;//0x96;//0x96;//0x86;                //0x48: ok for 200         prepare time\r
311 //    mipi_dsih_dphy_write(phy, 0x71, data, 1);\r
312 \r
313 //    data[0] =  0x0;;//0x44;//0x44;//0x40;               //0x4a: ok for 200          zero time\r
314 //   mipi_dsih_dphy_write(phy, 0x72, data, 1);\r
315 \r
316     //data[0] =  0x44;\r
317     //mipi_dsih_dphy_write(phy, 0x73, data, 1);\r
318 \r
319     //data[0] =  0x7F;\r
320     //mipi_dsih_dphy_write(phy, 0x74, data, 1);\r
321 \r
322   /* Jessica add - end*/\r
323 \r
324     data[0] =  0x70;\r
325     mipi_dsih_dphy_write(phy, 0x16, data, 1);\r
326 \r
327     /* setup digital part */\r
328     /* hs frequency range [7]|[6:1]|[0]*/\r
329     data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0;\r
330    //data[0] = (0 << 7) | (0x23 << 1) | 0;\r
331    /*From ASIC, we need unmask this code to make the frequency correct*/\r
332     mipi_dsih_dphy_write(phy, 0x44, data, 1);       //Jessica remove for more accurate frequency\r
333     /* setup PLL */\r
334     /* vco range  [7]|[6:3]|[2:1]|[0] */\r
335     data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0;\r
336     mipi_dsih_dphy_write(phy, 0x10, data, 1);                 //Jessica\r
337 #ifdef TESTCHIP\r
338         /* for all Gen2 testchips, bypass LP TX enable idle low power */\r
339         data[0] = 0x80;\r
340         mipi_dsih_dphy_write(phy, 0x32, data, 1);\r
341         mipi_dsih_dphy_write(phy, 0x42, data, 1);\r
342         mipi_dsih_dphy_write(phy, 0x52, data, 1);\r
343         mipi_dsih_dphy_write(phy, 0x82, data, 1);\r
344         mipi_dsih_dphy_write(phy, 0x92, data, 1);\r
345 #endif\r
346         if ((loop_divider % 2) != 0)\r
347         {       /* only odd integers are allowed (1 will be subtracted upon writing,\r
348                 see below) */\r
349                 loop_divider -= 1;\r
350 \r
351         }\r
352         /* gen 2 associates the charge pump current and LPF resistor with the\r
353          output frequency ranges (and thus we simplify here to use the\r
354          counter/pointer of the following structure) */\r
355         i = range;\r
356         data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4);\r
357 \r
358     mipi_dsih_dphy_write(phy, 0x19, data, 1);      //Jessica\r
359 \r
360     /* PLL Lock bypass|charge pump current [7:4]|[3:0] */\r
361     data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0);\r
362     mipi_dsih_dphy_write(phy, 0x11, data, 1);           //Jessica\r
363     /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */\r
364     data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0);\r
365     mipi_dsih_dphy_write(phy, 0x12, data, 1);\r
366     /* PLL input divider ratio [7:0] */\r
367     data[0] = input_divider - 1;\r
368     mipi_dsih_dphy_write(phy, 0x17, data, 1);           //Jessica\r
369 \r
370     data[0] =   0x04; //short the delay time before BTA\r
371     mipi_dsih_dphy_write(phy, 0x07, data, 1);\r
372 \r
373 //    data[0] = 1;\r
374 //    mipi_dsih_dphy_write(phy, 0xB0, data, 1);\r
375 \r
376     data[0] = 0x8B;\r
377     mipi_dsih_dphy_write(phy, 0x22, data, 1);\r
378 //    data[1] = mipi_dsih_dphy_test_data_out(phy);\r
379 //    MIPI_PRINT("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]);\r
380 \r
381 #ifdef SOFT_DPHY_CALIBRATION\r
382     data[0] = mipi_dsih_dphy_calibration(phy);\r
383 \r
384     mipi_dsih_dphy_write(phy, 0x21, data, 1);\r
385 \r
386     for(n =0;n<50;n++ );\r
387 \r
388     data[1] = mipi_dsih_dphy_test_data_out(phy);\r
389     MIPI_PRINT("sprdfb: mipi_dsih_dphy_calibration--> data[0]= %x,data[1] = %x \n",data[0],data[1]);\r
390 #endif\r
391 \r
392     no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */\r
393     for (i = 0; i < no_of_bytes; i++)\r
394     {\r
395         data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) ));\r
396         /* 7 is dependent on no_of_bytes\r
397         make sure 5 bits only of value are written at a time */\r
398     }\r
399 \r
400     /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */\r
401     mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes);\r
402     mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes);\r
403     mipi_dsih_dphy_stop_wait_time(phy, 0x1C);\r
404     mipi_dsih_dphy_clock_en(phy, 1);\r
405     for(n=0;n<100;n++){\r
406         ;\r
407     }\r
408     mipi_dsih_dphy_shutdown(phy, 1);\r
409     for(n=0;n<100;n++){\r
410         ;\r
411     }\r
412     mipi_dsih_dphy_reset(phy, 1);\r
413 \r
414     return OK;\r
415 }\r
416 #else\r
417 dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq)\r
418 {\r
419     uint32_t loop_divider = 0; /* (M) */\r
420     uint32_t input_divider = 1; /* (N) */\r
421     uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/\r
422     uint8_t no_of_bytes = 0;\r
423     uint8_t i = 0; /* iterator */\r
424     uint8_t n=0;/* iterator */\r
425     uint8_t range = 0; /* ranges iterator */\r
426     int flag = 0;\r
427 #ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP\r
428     struct\r
429     {\r
430         uint32_t freq;  /* upper margin of frequency range */\r
431         uint8_t hs_freq; /* hsfreqrange */\r
432         uint8_t vco_range; /* vcorange */\r
433     }\r
434     ranges[] =\r
435     {\r
436         {90, 0x00, 0x01}, {100, 0x10, 0x01}, {110, 0x20, 0x01},\r
437         {125, 0x01, 0x01}, {140, 0x11, 0x01}, {150, 0x21, 0x01},\r
438         {160, 0x02, 0x01}, {180, 0x12, 0x03}, {200, 0x22, 0x03},\r
439         {210, 0x03, 0x03}, {240, 0x13, 0x03}, {250, 0x23, 0x03},\r
440         {270, 0x04, 0x07}, {300, 0x14, 0x07}, {330, 0x24, 0x07},\r
441         {360, 0x15, 0x07}, {400, 0x25, 0x07}, {450, 0x06, 0x07},\r
442         {500, 0x16, 0x07}, {550, 0x07, 0x0f}, {600, 0x17, 0x0f},\r
443         {650, 0x08, 0x0f}, {700, 0x18, 0x0f}, {750, 0x09, 0x0f},\r
444         {800, 0x19, 0x0f}, {850, 0x0A, 0x0f}, {900, 0x1A, 0x0f},\r
445         {950, 0x2A, 0x0f}, {1000, 0x3A, 0x0f}\r
446     };\r
447     struct\r
448     {\r
449         uint32_t loop_div; /* upper limit of loop divider range */\r
450         uint8_t cp_current; /* icpctrl */\r
451         uint8_t lpf_resistor; /* lpfctrl */\r
452     }\r
453     loop_bandwidth[] =\r
454     {\r
455         {32, 0x06, 0x10}, {64, 0x06, 0x10}, {128, 0x0C, 0x08},\r
456         {256, 0x04, 0x04}, {512, 0x00, 0x01}, {768, 0x01, 0x01},\r
457         {1000, 0x02, 0x01}\r
458     };\r
459 #elif defined DPHY2Btql\r
460     struct\r
461     {\r
462         uint32_t loop_div; /* upper limit of loop divider range */\r
463         uint8_t cp_current; /* icpctrl */\r
464         uint8_t lpf_resistor; /* lpfctrl */\r
465     }\r
466     loop_bandwidth[] =\r
467     {\r
468         {32, 0x0B, 0x00}, {64, 0x0A, 0x00}, {128, 0x09, 0x01},\r
469         {256, 0x08, 0x03}, {512, 0x08, 0x07}, {768, 0x08, 0x0F},\r
470         {1000, 0x08, 0x1F}\r
471     };\r
472 #endif\r
473     if (phy == 0)\r
474     {\r
475         return ERR_DSI_INVALID_INSTANCE;\r
476     }\r
477     if (phy->status < INITIALIZED)\r
478     {\r
479         return ERR_DSI_INVALID_INSTANCE;\r
480     }\r
481     if (output_freq < MIN_OUTPUT_FREQ)\r
482     {\r
483         return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;\r
484     }\r
485     /* find M and N dividers */\r
486     for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++)\r
487     {   /* here the >= DPHY_DIV_LOWER_LIMIT is a phy constraint, formula should be above 1 MHz */\r
488         if (((output_freq * input_divider) % (phy->reference_freq )) == 0)\r
489         {   /* values found */\r
490             loop_divider = ((output_freq * input_divider) / (phy->reference_freq ));\r
491             if (loop_divider >= 12)\r
492             {\r
493                 flag = 1;\r
494             }\r
495         }\r
496     }\r
497     if ((!flag) || ((phy->reference_freq / input_divider) < DPHY_DIV_LOWER_LIMIT))\r
498     {   /* no exact value found in previous for loop */\r
499         /* this solution is not favourable as jitter would be maximum */\r
500         loop_divider = output_freq / DPHY_DIV_LOWER_LIMIT;\r
501         input_divider = phy->reference_freq / DPHY_DIV_LOWER_LIMIT;\r
502     }\r
503     else\r
504     {   /* variable was incremented before exiting the loop */\r
505         input_divider--;\r
506     }\r
507     for (i = 0; (i < (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0]))) && (loop_divider > loop_bandwidth[i].loop_div); i++)\r
508     {\r
509         ;\r
510     }\r
511     if (i >= (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0])))\r
512     {\r
513         return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;\r
514     }\r
515     printf("sprdfb: Gen1 D-PHY: Approximated Frequency: %d KHz\n", (loop_divider * (phy->reference_freq / input_divider)));\r
516     /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to\r
517     avoid transient periods in PHY operation during re-configuration procedures. */\r
518     mipi_dsih_dphy_reset(phy, 0);\r
519     mipi_dsih_dphy_clock_en(phy, 0);\r
520     mipi_dsih_dphy_shutdown(phy, 0);\r
521     /* provide an initial active-high test clear pulse in TESTCLR  */\r
522     mipi_dsih_dphy_test_clear(phy, 1);\r
523     mipi_dsih_dphy_test_clear(phy, 0);\r
524 #ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP\r
525     /* find ranges */\r
526     for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++)\r
527     {\r
528         ;\r
529     }\r
530     if (range >= (sizeof(ranges)/sizeof(ranges[0])))\r
531     {\r
532         return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;\r
533     }\r
534     /* set up board depending on environment if any */\r
535     if (phy->bsp_pre_config != 0)\r
536     {\r
537         phy->bsp_pre_config(phy, 0);\r
538     }\r
539 \r
540   /* Jessica add - begin*/\r
541     data[0] =  0x42;//0x44;//0x44;//0x40;                 //0x40: ok for 200    clock lane lpx /*about 52ns*/\r
542     mipi_dsih_dphy_write(phy, 0x60, data, 1);\r
543 //    data[0] =  0x0;//0xA6;//0xC6;//0xC6;//0x86;                 //0x48: ok for 200     prepare time\r
544 //    mipi_dsih_dphy_write(phy, 0x61, data, 1);\r
545 \r
546 //    data[0] =  0x0;//0x6a;//0x6a;//0x4a;                  //0x4a: ok for 200    zero time\r
547 //    mipi_dsih_dphy_write(phy, 0x62, data, 1);\r
548 \r
549     data[0] =  0x42;//0x44;//0x40;//0x40;              // 0x40: ok for 200          data lane lpx /*about 52ns*/\r
550     mipi_dsih_dphy_write(phy, 0x70, data, 1);\r
551 \r
552 //    data[0] =  0x0;//0x84;//0x96;//0x96;//0x86;                //0x48: ok for 200         prepare time\r
553 //    mipi_dsih_dphy_write(phy, 0x71, data, 1);\r
554 \r
555 //    data[0] =  0x0;;//0x44;//0x44;//0x40;               //0x4a: ok for 200          zero time\r
556 //    mipi_dsih_dphy_write(phy, 0x72, data, 1);\r
557 \r
558     //data[0] =  0x44;\r
559     //mipi_dsih_dphy_write(phy, 0x73, data, 1);\r
560 \r
561     //data[0] =  0x7F;\r
562     //mipi_dsih_dphy_write(phy, 0x74, data, 1);\r
563 \r
564   /* Jessica add - end*/\r
565 \r
566     /* setup digital part */\r
567     /* hs frequency range [7]|[6:1]|[0]*/\r
568     data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0;\r
569    //data[0] = (0 << 7) | (0x23 << 1) | 0;\r
570    /*From ASIC, we need unmask this code to make the frequency correct*/\r
571     mipi_dsih_dphy_write(phy, 0x44, data, 1);       //Jessica remove for more accurate frequency\r
572     /* setup PLL */\r
573     /* vco range  [7]|[6:3]|[2:1]|[0] */\r
574     data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0;\r
575     mipi_dsih_dphy_write(phy, 0x10, data, 1);                 //Jessica\r
576     /* PLL  reserved|Input divider control|Loop Divider Control|Post Divider Ratio [7:6]|[5]|[4]|[3:0] */\r
577     data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4) | (0x03 << 0); /* post divider default = 0x03 - it is only used for clock out 2*/\r
578     mipi_dsih_dphy_write(phy, 0x19, data, 1);      //Jessica\r
579 #elif defined DPHY2Btql\r
580     /* vco range  [7:5]|[4]|[3]|[2:1]|[0] */\r
581     data[0] =  ((((output_freq / 1000) > 500 )? 1: 0) << 4) | (1 << 3) | (0 << 1) | 0;\r
582     mipi_dsih_dphy_write(phy, 0x10, data, 1);\r
583 #endif\r
584     /* PLL Lock bypass|charge pump current [7:4]|[3:0] */\r
585     data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0);\r
586     mipi_dsih_dphy_write(phy, 0x11, data, 1);           //Jessica\r
587     /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */\r
588     data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0);\r
589     mipi_dsih_dphy_write(phy, 0x12, data, 1);\r
590     /* PLL input divider ratio [7:0] */\r
591    data[0] = input_divider - 1;\r
592    mipi_dsih_dphy_write(phy, 0x17, data, 1);           //Jessica\r
593 \r
594     data[0] =   0x04; //short the delay time before BTA\r
595     mipi_dsih_dphy_write(phy, 0x07, data, 1);\r
596 \r
597 //    data[0] = 1;\r
598 //    mipi_dsih_dphy_write(phy, 0xB0, data, 1);\r
599 \r
600     data[0] = 0x8B;\r
601     mipi_dsih_dphy_write(phy, 0x22, data, 1);\r
602 //    data[1] = mipi_dsih_dphy_test_data_out(phy);\r
603  //   MIPI_PRINT("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]);\r
604 \r
605 \r
606     no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */\r
607     for (i = 0; i < no_of_bytes; i++)\r
608     {\r
609         data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) ));\r
610         /* 7 is dependent on no_of_bytes\r
611         make sure 5 bits only of value are written at a time */\r
612     }\r
613     /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */\r
614     mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes);\r
615     mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes);\r
616     mipi_dsih_dphy_stop_wait_time(phy, 0x1C);\r
617     mipi_dsih_dphy_clock_en(phy, 1);\r
618     for(n=0;n<100;n++){\r
619             ;\r
620     }\r
621     mipi_dsih_dphy_shutdown(phy, 1);\r
622     for(n=0;n<100;n++){\r
623             ;\r
624     }\r
625     mipi_dsih_dphy_reset(phy, 1);\r
626     return OK;\r
627 }\r
628 #endif\r
629 /**\r
630  * Close and power down D-PHY module\r
631  * @param phy pointer to structure which holds information about the d-phy\r
632  * module\r
633  * @return error code\r
634  */\r
635 dsih_error_t mipi_dsih_dphy_close(dphy_t * phy)\r
636 {\r
637     if (phy == 0)\r
638     {\r
639         return ERR_DSI_INVALID_INSTANCE;\r
640     }\r
641     else if ((phy->core_read_function == 0) || (phy->core_write_function == 0))\r
642     {\r
643         return ERR_DSI_INVALID_IO;\r
644     }\r
645     if (phy->status < NOT_INITIALIZED)\r
646     {\r
647         return ERR_DSI_INVALID_INSTANCE;\r
648     }\r
649     mipi_dsih_dphy_reset(phy, 0);\r
650     mipi_dsih_dphy_reset(phy, 1);\r
651     mipi_dsih_dphy_shutdown(phy, 0);\r
652     phy->status = NOT_INITIALIZED;\r
653     return OK;\r
654 }\r
655 /**\r
656  * Enable clock lane module\r
657  * @param instance pointer to structure which holds information about the d-phy\r
658  * module\r
659  * @param en\r
660  */\r
661 void mipi_dsih_dphy_clock_en(dphy_t * instance, int en)\r
662 {\r
663     mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, en, 2, 1);\r
664 }\r
665 /**\r
666  * Reset D-PHY module\r
667  * @param instance pointer to structure which holds information about the d-phy\r
668  * module\r
669  * @param reset\r
670  */\r
671 void mipi_dsih_dphy_reset(dphy_t * instance, int reset)\r
672 {\r
673     mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, reset, 1, 1);\r
674 }\r
675 /**\r
676  * Power up/down D-PHY module\r
677  * @param instance pointer to structure which holds information about the d-phy\r
678  * module\r
679  * @param powerup (1) shutdown (0)\r
680  */\r
681 void mipi_dsih_dphy_shutdown(dphy_t * instance, int powerup)\r
682 {\r
683     mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, powerup, 0, 1);\r
684 }\r
685 /**\r
686  * Force D-PHY PLL to stay on while in ULPS\r
687  * @param instance pointer to structure which holds information about the d-phy\r
688  * module\r
689  * @param force (1) disable (0)\r
690  * @note To follow the programming model, use wakeup_pll function\r
691  */\r
692 void mipi_dsih_dphy_force_pll(dphy_t * instance, int force)\r
693 {\r
694     mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, force, 3, 1);\r
695 }\r
696 /**\r
697  * Get force D-PHY PLL module\r
698  * @param instance pointer to structure which holds information about the d-phy\r
699  * module\r
700  * @return force value\r
701  */\r
702 int mipi_dsih_dphy_get_force_pll(dphy_t * instance)\r
703 {\r
704     return mipi_dsih_dphy_read_part(instance, R_DPHY_RSTZ, 3, 1);\r
705 }\r
706 /**\r
707  * Wake up or make sure D-PHY PLL module is awake\r
708  * This function must be called after going into ULPS and before exiting it\r
709  * to force the DPHY PLLs to wake up. It will wait until the DPHY status is\r
710  * locked. It follows the procedure described in the user guide.\r
711  * This function should be used to make sure the PLL is awake, rather than\r
712  * the force_pll above.\r
713  * @param instance pointer to structure which holds information about the d-phy\r
714  * module\r
715  * @return error code\r
716  * @note this function has an active wait\r
717  */\r
718 int mipi_dsih_dphy_wakeup_pll(dphy_t * instance)\r
719 {\r
720     unsigned i = 0;\r
721     if (mipi_dsih_dphy_status(instance, 0x1) == 0)\r
722     {\r
723         mipi_dsih_dphy_force_pll(instance, 1);\r
724         for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++)\r
725         {\r
726             if(mipi_dsih_dphy_status(instance, 0x1))\r
727             {\r
728                 break;\r
729             }\r
730         }\r
731         if (mipi_dsih_dphy_status(instance, 0x1) == 0)\r
732         {\r
733             return ERR_DSI_PHY_PLL_NOT_LOCKED;\r
734         }\r
735     }\r
736     return OK;\r
737 }\r
738 /**\r
739  * Configure minimum wait period for HS transmission request after a stop state\r
740  * @param instance pointer to structure which holds information about the d-phy\r
741  * module\r
742  * @param no_of_byte_cycles [in byte (lane) clock cycles]\r
743  */\r
744 void mipi_dsih_dphy_stop_wait_time(dphy_t * instance, uint8_t no_of_byte_cycles)\r
745 {\r
746     mipi_dsih_dphy_write_part(instance, R_DPHY_IF_CFG, no_of_byte_cycles, 8, 8);\r
747 }\r
748 /**\r
749  * Set number of active lanes\r
750  * @param instance pointer to structure which holds information about the d-phy\r
751  * module\r
752  * @param no_of_lanes\r
753  */\r
754 void mipi_dsih_dphy_no_of_lanes(dphy_t * instance, uint8_t no_of_lanes)\r
755 {\r
756     mipi_dsih_dphy_write_part(instance, R_DPHY_IF_CFG, no_of_lanes - 1, 0, 2);\r
757 }\r
758 /**\r
759  * Get number of currently active lanes\r
760  * @param instance pointer to structure which holds information about the d-phy\r
761  *  module\r
762  * @return number of active lanes\r
763  */\r
764 uint8_t mipi_dsih_dphy_get_no_of_lanes(dphy_t * instance)\r
765 {\r
766     return mipi_dsih_dphy_read_part(instance, R_DPHY_IF_CFG, 0, 2);\r
767 }\r
768 /**\r
769  * SPRD ADD\r
770  * Set non-continuous clock mode\r
771  * @param instance pointer to structure which holds information about the d-phy\r
772  * module\r
773  * @param enable\r
774  */\r
775 void mipi_dsih_dphy_enable_nc_clk(dphy_t * instance, int enable)\r
776 {\r
777         mipi_dsih_dphy_write_part(instance, R_DPHY_LPCLK_CTRL, enable, 1, 1);\r
778 }\r
779 \r
780 /**\r
781  * Request the PHY module to start transmission of high speed clock.\r
782  * This causes the clock lane to start transmitting DDR clock on the\r
783  * lane interconnect.\r
784  * @param instance pointer to structure which holds information about the d-phy\r
785  * module\r
786  * @param enable\r
787  * @note this function should be called explicitly by user always except for\r
788  * transmitting\r
789  */\r
790 void mipi_dsih_dphy_enable_hs_clk(dphy_t * instance, int enable)\r
791 {\r
792     mipi_dsih_dphy_write_part(instance, R_DPHY_LPCLK_CTRL, enable, 0, 1);\r
793 }\r
794 /**\r
795  * One bit is asserted in the trigger_request (4bits) to cause the lane module\r
796  * to cause the associated trigger to be sent across the lane interconnect.\r
797  * The trigger request is synchronous with the rising edge of the clock.\r
798  * @note: Only one bit of the trigger_request is asserted at any given time, the\r
799  * remaining must be left set to 0, and only when not in LPDT or ULPS modes\r
800  * @param instance pointer to structure which holds information about the d-phy\r
801  * module\r
802  * @param trigger_request 4 bit request\r
803  */\r
804 dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t * instance, uint8_t trigger_request)\r
805 {\r
806     uint8_t sum = 0;\r
807     int i = 0;\r
808     for (i = 0; i < 4; i++)\r
809     {\r
810         sum += ((trigger_request >> i) & 1);\r
811     }\r
812     if (sum == 1)\r
813     {\r
814         /* clear old trigger */\r
815         mipi_dsih_dphy_write_part(instance, R_DPHY_TX_TRIGGERS, 0x00, 0, 4);\r
816         mipi_dsih_dphy_write_part(instance, R_DPHY_TX_TRIGGERS, trigger_request, 0, 4);\r
817         for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++)\r
818         {\r
819             if(mipi_dsih_dphy_status(instance, 0x0010))\r
820             {\r
821                 break;\r
822             }\r
823         }\r
824         mipi_dsih_dphy_write_part(instance, R_DPHY_TX_TRIGGERS, 0x00, 0, 4);\r
825         if (i >= DSIH_PHY_ACTIVE_WAIT)\r
826         {\r
827             return ERR_DSI_TIMEOUT;\r
828         }\r
829         return OK;\r
830     }\r
831     return ERR_DSI_INVALID_COMMAND;\r
832 }\r
833 /**\r
834  * ULPS mode request/exit on all active data lanes.\r
835  * @param instance pointer to structure which holds information about the d-phy\r
836  * module\r
837  * @param enable (request 1/ exit 0)\r
838  * @return error code\r
839  * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms\r
840  */\r
841 #ifdef GEN_2\r
842 dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable)\r
843 {\r
844     int timeout;\r
845     /* mask 1 0101 0010 0000 */\r
846     uint16_t data_lanes_mask = 0;\r
847     if (enable)\r
848     {\r
849         mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 2, 1);\r
850         return OK;\r
851     }\r
852     else\r
853     {\r
854         if (mipi_dsih_dphy_status(instance, 0x1) == 0)\r
855         {\r
856             return ERR_DSI_PHY_PLL_NOT_LOCKED;\r
857         }\r
858         mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 3, 1);\r
859         switch (mipi_dsih_dphy_get_no_of_lanes(instance))\r
860         {\r
861         case 3:\r
862             data_lanes_mask |= (1 << 12);\r
863         case 2:\r
864             data_lanes_mask |= (1 << 10);\r
865         case 1:\r
866             data_lanes_mask |= (1 << 8);\r
867         case 0:\r
868             data_lanes_mask |= (1 << 5);\r
869             break;\r
870         default:\r
871             data_lanes_mask = 0;\r
872             break;\r
873         }\r
874         for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)\r
875         {\r
876             /* verify that the DPHY has left ULPM */\r
877             /* mask 1010100100000 */\r
878             if (mipi_dsih_dphy_status(instance, data_lanes_mask) == data_lanes_mask)\r
879             {\r
880                 /* wait at least 1ms */\r
881                 break;\r
882             }\r
883             /* wait at least 1ms */\r
884             for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)\r
885             {\r
886                 ;\r
887             }\r
888         }\r
889         if (mipi_dsih_dphy_status(instance, data_lanes_mask) != data_lanes_mask)\r
890         {\r
891 //                      instance->log_info("stat %x, mask %x", mipi_dsih_dphy_status(instance, data_lanes_mask), data_lanes_mask);\r
892             return ERR_DSI_TIMEOUT;\r
893         }\r
894         mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 2, 1);\r
895         mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 3, 1);\r
896     }\r
897     return OK;\r
898 }\r
899 #else\r
900 void mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable)\r
901 {\r
902     int timeout;\r
903     if (enable)\r
904     {\r
905         mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 3, 1);\r
906     }\r
907     else\r
908     {\r
909         mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 4, 1);\r
910         for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)\r
911         {\r
912             /* verify that the DPHY has left ULPM */\r
913             /* mask 1010100100000 */\r
914             if (mipi_dsih_dphy_status(instance, 0x1520) == 0)\r
915             {\r
916                 /* wait at least 1ms */\r
917                 for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)\r
918                 {\r
919                     ;\r
920                 }\r
921                 break;\r
922             }\r
923         }\r
924         mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 3, 1);\r
925         mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 4, 1);\r
926     }\r
927 }\r
928 #endif\r
929 /**\r
930  * ULPS mode request/exit on Clock Lane.\r
931  * @param instance pointer to structure which holds information about the\r
932  * d-phy module\r
933  * @param enable 1 or disable 0 of the Ultra Low Power State of the clock lane\r
934  * @return error code\r
935  * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms\r
936  */\r
937 #ifdef GEN_2\r
938 dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable)\r
939 {\r
940     int timeout;\r
941     /* mask 1000 */\r
942     uint16_t clk_lane_mask = 0x0008;\r
943     if (enable)\r
944     {\r
945         /* mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 0, 1); */\r
946         mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 0, 1);\r
947     }\r
948     else\r
949     {\r
950         if (mipi_dsih_dphy_status(instance, 0x1) == 0)\r
951         {\r
952             return ERR_DSI_PHY_PLL_NOT_LOCKED;\r
953         }\r
954         mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 1, 1);\r
955         for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)\r
956         {\r
957             /* verify that the DPHY has left ULPM */\r
958             /* mask 1010100100000 */\r
959             if (mipi_dsih_dphy_status(instance, clk_lane_mask) == clk_lane_mask)\r
960             {\r
961                 /* wait at least 1ms */\r
962                 instance->log_info("stat %x, mask %x", mipi_dsih_dphy_status(instance, clk_lane_mask), clk_lane_mask);\r
963                 break;\r
964             }\r
965             /* wait at least 1ms */\r
966             for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)\r
967             {\r
968                 /* dummy operation for the loop not to be optimised */\r
969                 enable = mipi_dsih_dphy_status(instance, clk_lane_mask);\r
970             }\r
971         }\r
972         if (mipi_dsih_dphy_status(instance, clk_lane_mask) != clk_lane_mask)\r
973         {\r
974             return ERR_DSI_TIMEOUT;\r
975         }\r
976         mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 0, 1);\r
977         mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 1, 1);\r
978     }\r
979     return OK;\r
980 }\r
981 #else\r
982 void mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable)\r
983 {\r
984     int timeout;\r
985     if (enable)\r
986     {\r
987         mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 0, 1);\r
988         mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 1, 1);\r
989     }\r
990     else\r
991     {\r
992         mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 2, 1);\r
993         for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)\r
994         {\r
995             /* verify that the DPHY has left ULPM */\r
996             /* mask 1010100100000 */\r
997             if (mipi_dsih_dphy_status(instance, 0x0004) == 0)\r
998             {\r
999                 /* wait at least 1ms */\r
1000                 for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)\r
1001                 {\r
1002                     ;\r
1003                 }\r
1004                 break;\r
1005             }\r
1006         }\r
1007         mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 1, 1);\r
1008         mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 2, 1);\r
1009     }\r
1010 }\r
1011 #endif\r
1012 /**\r
1013  * Get D-PHY PPI status\r
1014  * @param instance pointer to structure which holds information about the d-phy\r
1015  * module\r
1016  * @param mask\r
1017  * @return status\r
1018  */\r
1019 uint32_t mipi_dsih_dphy_status(dphy_t * instance, uint16_t mask)\r
1020 {\r
1021     return mipi_dsih_dphy_read_word(instance, R_DPHY_STATUS) & mask;\r
1022 }\r
1023 /**\r
1024  * @param instance pointer to structure which holds information about the d-phy\r
1025  * module\r
1026  * @param value\r
1027  */\r
1028 void mipi_dsih_dphy_test_clock(dphy_t * instance, int value)\r
1029 {\r
1030     mipi_dsih_dphy_write_part(instance, R_DPHY_TST_CRTL0, value, 1, 1);\r
1031 }\r
1032 /**\r
1033  * @param instance pointer to structure which holds information about the d-phy\r
1034  * module\r
1035  * @param value\r
1036  */\r
1037 void mipi_dsih_dphy_test_clear(dphy_t * instance, int value)\r
1038 {\r
1039     mipi_dsih_dphy_write_part(instance, R_DPHY_TST_CRTL0, value, 0, 1);\r
1040 }\r
1041 /**\r
1042  * @param instance pointer to structure which holds information about the d-phy\r
1043  * module\r
1044  * @param on_falling_edge\r
1045  */\r
1046 void mipi_dsih_dphy_test_en(dphy_t * instance, uint8_t on_falling_edge)\r
1047 {\r
1048     mipi_dsih_dphy_write_part(instance, R_DPHY_TST_CRTL1, on_falling_edge, 16, 1);\r
1049 }\r
1050 /**\r
1051  * @param instance pointer to structure which holds information about the d-phy\r
1052  * module\r
1053  */\r
1054 uint8_t mipi_dsih_dphy_test_data_out(dphy_t * instance)\r
1055 {\r
1056     return mipi_dsih_dphy_read_part(instance, R_DPHY_TST_CRTL1, 8, 8);\r
1057 }\r
1058 /**\r
1059  * @param instance pointer to structure which holds information about the d-phy\r
1060  * module\r
1061  * @param test_data\r
1062  */\r
1063 void mipi_dsih_dphy_test_data_in(dphy_t * instance, uint8_t test_data)\r
1064 {\r
1065     mipi_dsih_dphy_write_word(instance, R_DPHY_TST_CRTL1, test_data);\r
1066 }\r
1067 /**\r
1068  * Write to D-PHY module (encapsulating the digital interface)\r
1069  * @param instance pointer to structure which holds information about the d-phy\r
1070  * module\r
1071  * @param address offset inside the D-PHY digital interface\r
1072  * @param data array of bytes to be written to D-PHY\r
1073  * @param data_length of the data array\r
1074  */\r
1075 void mipi_dsih_dphy_write(dphy_t * instance, uint8_t address, uint8_t * data, uint8_t data_length)\r
1076 {\r
1077     unsigned i = 0;\r
1078     if (data != 0)\r
1079     {\r
1080 #if ((defined DWC_MIPI_DPHY_BIDIR_TSMC40LP) || (defined DPHY2Btql) || (defined GEN_2))\r
1081         /* set the TESTCLK input high in preparation to latch in the desired test mode */\r
1082         mipi_dsih_dphy_test_clock(instance, 1);\r
1083         /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */\r
1084         mipi_dsih_dphy_test_data_in(instance, address);\r
1085         /* set TESTEN input high  */\r
1086         mipi_dsih_dphy_test_en(instance, 1);\r
1087         /* drive the TESTCLK input low; the falling edge captures the chosen test code into the transceiver */\r
1088         mipi_dsih_dphy_test_clock(instance, 0);\r
1089         /* set TESTEN input low to disable further test mode code latching  */\r
1090         mipi_dsih_dphy_test_en(instance, 0);\r
1091         /* start writing MSB first */\r
1092         for (i = data_length; i > 0; i--)\r
1093         {\r
1094             /* set TESTDIN[7:0] to the desired test data appropriate to the chosen test mode */\r
1095             mipi_dsih_dphy_test_data_in(instance, data[i - 1]);\r
1096             /* pulse TESTCLK high to capture this test data into the macrocell; repeat these two steps as necessary */\r
1097             mipi_dsih_dphy_test_clock(instance, 1);\r
1098             mipi_dsih_dphy_test_clock(instance, 0);\r
1099         }\r
1100 #endif\r
1101     }\r
1102 }\r
1103 \r
1104 \r
1105 \r
1106 /* abstracting BSP */\r
1107 /**\r
1108  * Write to whole register to D-PHY module (encapsulating the bus interface)\r
1109  * @param instance pointer to structure which holds information about the d-phy\r
1110  * module\r
1111  * @param reg_address offset\r
1112  * @param data 32-bit word\r
1113  */\r
1114 void mipi_dsih_dphy_write_word(dphy_t * instance, uint32_t reg_address, uint32_t data)\r
1115 {\r
1116     if (instance->core_write_function != 0)\r
1117     {\r
1118         instance->core_write_function(instance->address, reg_address, data);\r
1119     }\r
1120 }\r
1121 /**\r
1122  * Write bit field to D-PHY module (encapsulating the bus interface)\r
1123  * @param instance pointer to structure which holds information about the d-phy\r
1124  * module\r
1125  * @param reg_address offset\r
1126  * @param data bits to be written to D-PHY\r
1127  * @param shift from the right hand side of the register (big endian)\r
1128  * @param width of the bit field\r
1129  */\r
1130 void mipi_dsih_dphy_write_part(dphy_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width)\r
1131 {\r
1132     uint32_t mask = 0;\r
1133     uint32_t temp = 0;\r
1134     if (instance->core_read_function != 0)\r
1135     {\r
1136         mask = (1 << width) - 1;\r
1137         temp = mipi_dsih_dphy_read_word(instance, reg_address);\r
1138         temp &= ~(mask << shift);\r
1139         temp |= (data & mask) << shift;\r
1140         mipi_dsih_dphy_write_word(instance, reg_address, temp);\r
1141     }\r
1142 }\r
1143 /**\r
1144  * Read whole register from D-PHY module (encapsulating the bus interface)\r
1145  * @param instance pointer to structure which holds information about the d-phy\r
1146  * module\r
1147  * @param reg_address offset\r
1148  * @return data 32-bit word\r
1149  */\r
1150 uint32_t mipi_dsih_dphy_read_word(dphy_t * instance, uint32_t reg_address)\r
1151 {\r
1152     if (instance->core_read_function == 0)\r
1153     {\r
1154         return ERR_DSI_INVALID_IO;\r
1155     }\r
1156     return instance->core_read_function(instance->address, reg_address);\r
1157 }\r
1158 /**\r
1159  * Read bit field from D-PHY module (encapsulating the bus interface)\r
1160  * @param instance pointer to structure which holds information about the d-phy\r
1161  * module\r
1162  * @param reg_address offset\r
1163  * @param shift from the right hand side of the register (big endian)\r
1164  * @param width of the bit field\r
1165  * @return data bits to be written to D-PHY\r
1166  */\r
1167 uint32_t mipi_dsih_dphy_read_part(dphy_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width)\r
1168 {\r
1169     return (mipi_dsih_dphy_read_word(instance, reg_address) >> shift) & ((1 << width) - 1);\r
1170 }\r