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