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