2 * @file mipi_dsih_dphy.c
\r
3 * @brief D-PHY driver
\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
13 #define DPHY_DIV_LOWER_LIMIT (5000)
\r
15 #define DPHY_DIV_LOWER_LIMIT (1000)
\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
25 //#define SOFT_DPHY_CALIBRATION
\r
27 uint8_t mipi_dsih_dphy_calibration(dphy_t * phy)// tianci need check with thomas
\r
29 uint8_t rd_data[3],sv_data[3];
\r
31 uint8_t i = 0; /* iterator */
\r
36 /*phy calibration process */
\r
39 mipi_dsih_dphy_write(phy, 0x21, data, 1);
\r
41 for(i =0; i<50; i++ );
\r
43 rd_data[0] = mipi_dsih_dphy_test_data_out(phy);
\r
44 printf("data[0] = 0x03,rd_data[0] = %x \n",rd_data[0]);
\r
51 mipi_dsih_dphy_write(phy, 0x21, data, 1);
\r
53 for(i =0; i<50; i++) ;
\r
55 rd_data[1] = mipi_dsih_dphy_test_data_out(phy);
\r
56 printf("data[%d] = %x,rd_data[1] = %x \n",j,data[0],rd_data[1]);
\r
57 if((rd_data[1]&0x80) != (rd_data[0]&0x80))
\r
60 printf(" break--data[%d] = %x,rd_data[0] = %x,rd_data[1] = %x \n",j,data[0],rd_data[0],rd_data[1]);
\r
63 printf("phy calibration error,toggles times more than once \n");
\r
66 rd_data[0] = rd_data[1];
\r
67 sv_data[0] = data[0];
\r
69 if((7 == j) && (0 == sw_cnt))
\r
71 if(0x80 == (rd_data[1]&0x80))
\r
73 if(0x0 == (rd_data[1]&0x80))
\r
83 mipi_dsih_dphy_write(phy, 0x21, data, 1);
\r
85 for(i =0; i<50; i++ );
\r
87 rd_data[2] = mipi_dsih_dphy_test_data_out(phy);
\r
88 printf("next-->data[%d] = %x,rd_data[2] = %x \n",j,data[0],rd_data[2]);
\r
89 if((rd_data[2]&0x80) != (rd_data[0]&0x80))
\r
91 printf("break--next-->data[%d] = %x,rd_data[2] = %x,rd_data[0] = %x \n",j,data[0],rd_data[2],rd_data[0]);
\r
92 rd_data[0] = rd_data[2];
\r
93 sv_data[1] = data[0];
\r
97 sv_data[0] =(sv_data[0]&0x1c) >>2;
\r
98 sv_data[1] =(sv_data[1]&0x1c) >>2;
\r
99 sv_data[0] = sv_data[0] + sv_data[1];
\r
100 sv_data[1] = sv_data[0] / 2 + sv_data[0] % 2;
\r
101 data[0] = (sv_data[1] <<2) | 0x03;
\r
108 * Initialise D-PHY module and power up
\r
109 * @param phy pointer to structure which holds information about the d-phy
\r
111 * @return error code
\r
113 dsih_error_t mipi_dsih_dphy_open(dphy_t * phy)
\r
117 return ERR_DSI_PHY_INVALID;
\r
119 else if ((phy->core_read_function == 0) || (phy->core_write_function == 0))
\r
121 return ERR_DSI_INVALID_IO;
\r
123 else if (phy->status == INITIALIZED)
\r
125 return ERR_DSI_PHY_INVALID;
\r
127 phy->status = NOT_INITIALIZED;
\r
128 #if 0// tianci need check with thomas
\r
129 mipi_dsih_dphy_reset(phy, 0);
\r
130 mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
\r
131 mipi_dsih_dphy_no_of_lanes(phy, 1);
\r
132 mipi_dsih_dphy_clock_en(phy, 1);
\r
133 mipi_dsih_dphy_shutdown(phy, 1);
\r
134 mipi_dsih_dphy_reset(phy, 1);
\r
136 phy->status = INITIALIZED;
\r
140 * Configure D-PHY and PLL module to desired operation mode
\r
141 * @param phy pointer to structure which holds information about the d-phy
\r
143 * @param no_of_lanes active
\r
144 * @param output_freq desired high speed frequency
\r
145 * @return error code
\r
148 dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq)
\r
150 uint32_t loop_divider = 0; /* (M) */
\r
151 uint32_t input_divider = 1; /* (N) */
\r
152 uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/
\r
153 uint8_t no_of_bytes = 0;
\r
155 uint8_t n=0;/* iterator */
\r
156 uint8_t range = 0; /* ranges iterator */
\r
160 uint32_t loop_div; /* upper limit of loop divider range */
\r
161 uint8_t cp_current; /* icpctrl */
\r
162 uint8_t lpf_resistor; /* lpfctrl */
\r
166 { /* gen 2 associates the charge pump current and LPF resistor with the
\r
167 output frequency ranges (and thus we simplify here to use the
\r
168 counter/pointer of the following structure) */
\r
169 { 90, 0x02, 0x02}, { 100, 0x02, 0x02}, { 110, 0x02, 0x02},
\r
170 { 130, 0x02, 0x01}, { 140, 0x02, 0x01}, { 150, 0x02, 0x01},
\r
171 { 170, 0x09, 0x00}, { 180, 0x09, 0x01}, { 200, 0x09, 0x01},
\r
172 { 220, 0x09, 0x04}, { 240, 0x09, 0x04}, { 250, 0x09, 0x04},
\r
173 { 270, 0x06, 0x04}, { 300, 0x06, 0x04}, { 330, 0x09, 0x04},
\r
174 { 360, 0x09, 0x04}, { 400, 0x09, 0x04}, { 450, 0x06, 0x04},
\r
175 { 500, 0x06, 0x04}, { 550, 0x06, 0x04}, { 600, 0x06, 0x04},
\r
176 { 650, 0x0A, 0x04}, { 700, 0x0A, 0x04}, { 750, 0x0A, 0x04},
\r
177 { 800, 0x0A, 0x04}, { 850, 0x0A, 0x04}, { 900, 0x0A, 0x04},
\r
178 { 950, 0x0B, 0x08}, {1000, 0x0B, 0x08}, {1050, 0x0B, 0x08},
\r
179 {1100, 0x0B, 0x08}, {1150, 0x0B, 0x08}, {1200, 0x0B, 0x08},
\r
180 {1250, 0x0B, 0x08}, {1300, 0x0B, 0x08}, {1350, 0x0B, 0x08},
\r
181 {1400, 0x0B, 0x08}, {1450, 0x0B, 0x08}, {1500, 0x0B, 0x08}
\r
183 uint32_t delta = 0;
\r
184 uint32_t tmp_loop_divider = 0;
\r
189 uint32_t freq; /* upper margin of frequency range */
\r
190 uint8_t hs_freq; /* hsfreqrange */
\r
191 uint8_t vco_range; /* vcorange */
\r
195 { 90, 0x00, 0x00}, { 100, 0x10, 0x00}, { 110, 0x20, 0x00},
\r
196 { 130, 0x01, 0x00}, { 140, 0x11, 0x00}, { 150, 0x21, 0x00},
\r
197 { 170, 0x02, 0x00}, { 180, 0x12, 0x00}, { 200, 0x22, 0x00},
\r
198 { 220, 0x03, 0x01}, { 240, 0x13, 0x01}, { 250, 0x23, 0x01},
\r
199 { 270, 0x04, 0x01}, { 300, 0x14, 0x01}, { 330, 0x05, 0x02},
\r
200 { 360, 0x15, 0x02}, { 400, 0x25, 0x02}, { 450, 0x06, 0x02},
\r
201 { 500, 0x16, 0x02}, { 550, 0x07, 0x03}, { 600, 0x17, 0x03},
\r
202 { 650, 0x08, 0x03}, { 700, 0x18, 0x03}, { 750, 0x09, 0x04},
\r
203 { 800, 0x19, 0x04}, { 850, 0x29, 0x04}, { 900, 0x39, 0x04},
\r
204 { 950, 0x0A, 0x05}, {1000, 0x1A, 0x05}, {1050, 0x2A, 0x05},
\r
205 {1100, 0x3A, 0x05}, {1150, 0x0B, 0x06}, {1200, 0x1B, 0x06},
\r
206 {1250, 0x2B, 0x06}, {1300, 0x3B, 0x06}, {1350, 0x0C, 0x07},
\r
207 {1400, 0x1C, 0x07}, {1450, 0x2C, 0x07}, {1500, 0x3C, 0x07}
\r
212 return ERR_DSI_INVALID_INSTANCE;
\r
214 if (phy->status < INITIALIZED)
\r
216 return ERR_DSI_INVALID_INSTANCE;
\r
218 if (output_freq < MIN_OUTPUT_FREQ)
\r
220 return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
\r
223 loop_divider = ((output_freq * (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) / phy->reference_freq);
\r
224 /* here delta will account for the rounding */
\r
225 delta = ((loop_divider * phy->reference_freq) / (phy->reference_freq / DPHY_DIV_LOWER_LIMIT)) - output_freq;
\r
226 for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++)
\r
228 tmp_loop_divider = ((output_freq * input_divider) / (phy->reference_freq));
\r
229 if ((tmp_loop_divider % 2) == 0)
\r
231 if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider)))
\r
232 { /* exact values found */
\r
234 loop_divider = tmp_loop_divider;
\r
235 delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider));
\r
236 /* variable was incremented before exiting the loop */
\r
239 else if ((output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider))) < delta)
\r
240 { /* values found with smaller delta */
\r
241 loop_divider = tmp_loop_divider;
\r
242 delta = output_freq - (tmp_loop_divider * (phy->reference_freq / input_divider));
\r
248 tmp_loop_divider += 1;
\r
249 if (output_freq == (tmp_loop_divider * (phy->reference_freq / input_divider)))
\r
250 { /* exact values found */
\r
252 loop_divider = tmp_loop_divider;
\r
253 delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq;
\r
254 /* variable was incremented before exiting the loop */
\r
257 else if (((tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq) < delta)
\r
258 { /* values found with smaller delta */
\r
259 loop_divider = tmp_loop_divider;
\r
260 delta = (tmp_loop_divider * (phy->reference_freq / input_divider)) - output_freq;
\r
267 input_divider = step + (loop_divider * phy->reference_freq) / output_freq;
\r
268 printf("sprdfb: D-PHY: Approximated Frequency: %d KHz\n", (loop_divider * (phy->reference_freq / input_divider)));
\r
269 // phy->log_info("D-PHY: Approximated Frequency: %d KHz", (loop_divider * (phy->reference_freq / input_divider)));
\r
272 /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to
\r
273 avoid transient periods in PHY operation during re-configuration procedures. */
\r
274 mipi_dsih_dphy_reset(phy, 0);
\r
275 mipi_dsih_dphy_clock_en(phy, 0);
\r
276 mipi_dsih_dphy_shutdown(phy, 0);
\r
277 /* provide an initial active-high test clear pulse in TESTCLR */
\r
278 mipi_dsih_dphy_test_clear(phy, 1);
\r
279 mipi_dsih_dphy_test_clear(phy, 0);
\r
280 for(n=0;n<100;n++){
\r
284 for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++)
\r
288 if (range >= (sizeof(ranges)/sizeof(ranges[0])))
\r
290 return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
\r
292 /* set up board depending on environment if any */
\r
293 if (phy->bsp_pre_config != 0)
\r
295 phy->bsp_pre_config(phy, 0);
\r
298 /* Jessica add - begin*/
\r
299 data[0] = 0x83;//0x44;//0x44;//0x40; //0x40: ok for 200 clock lane lpx /*about 52ns*/
\r
300 mipi_dsih_dphy_write(phy, 0x60, data, 1);
\r
301 // data[0] = 0x0;//0xA6;//0xC6;//0xC6;//0x86; //0x48: ok for 200 prepare time
\r
302 // mipi_dsih_dphy_write(phy, 0x61, data, 1);
\r
304 // data[0] = 0x0;//0x6a;//0x6a;//0x4a; //0x4a: ok for 200 zero time
\r
305 // mipi_dsih_dphy_write(phy, 0x62, data, 1);
\r
307 data[0] = 0x83;//0x44;//0x40;//0x40; // 0x40: ok for 200 data lane lpx /*about 52ns*/
\r
308 mipi_dsih_dphy_write(phy, 0x70, data, 1);
\r
310 // data[0] = 0x0;//0x84;//0x96;//0x96;//0x86; //0x48: ok for 200 prepare time
\r
311 // mipi_dsih_dphy_write(phy, 0x71, data, 1);
\r
313 // data[0] = 0x0;;//0x44;//0x44;//0x40; //0x4a: ok for 200 zero time
\r
314 // mipi_dsih_dphy_write(phy, 0x72, data, 1);
\r
317 //mipi_dsih_dphy_write(phy, 0x73, data, 1);
\r
320 //mipi_dsih_dphy_write(phy, 0x74, data, 1);
\r
322 /* Jessica add - end*/
\r
325 mipi_dsih_dphy_write(phy, 0x16, data, 1);
\r
327 /* setup digital part */
\r
328 /* hs frequency range [7]|[6:1]|[0]*/
\r
329 data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0;
\r
330 //data[0] = (0 << 7) | (0x23 << 1) | 0;
\r
331 /*From ASIC, we need unmask this code to make the frequency correct*/
\r
332 mipi_dsih_dphy_write(phy, 0x44, data, 1); //Jessica remove for more accurate frequency
\r
334 /* vco range [7]|[6:3]|[2:1]|[0] */
\r
335 data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0;
\r
336 mipi_dsih_dphy_write(phy, 0x10, data, 1); //Jessica
\r
338 /* for all Gen2 testchips, bypass LP TX enable idle low power */
\r
340 mipi_dsih_dphy_write(phy, 0x32, data, 1);
\r
341 mipi_dsih_dphy_write(phy, 0x42, data, 1);
\r
342 mipi_dsih_dphy_write(phy, 0x52, data, 1);
\r
343 mipi_dsih_dphy_write(phy, 0x82, data, 1);
\r
344 mipi_dsih_dphy_write(phy, 0x92, data, 1);
\r
346 if ((loop_divider % 2) != 0)
\r
347 { /* only odd integers are allowed (1 will be subtracted upon writing,
\r
352 /* gen 2 associates the charge pump current and LPF resistor with the
\r
353 output frequency ranges (and thus we simplify here to use the
\r
354 counter/pointer of the following structure) */
\r
356 data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4);
\r
358 mipi_dsih_dphy_write(phy, 0x19, data, 1); //Jessica
\r
360 /* PLL Lock bypass|charge pump current [7:4]|[3:0] */
\r
361 data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0);
\r
362 mipi_dsih_dphy_write(phy, 0x11, data, 1); //Jessica
\r
363 /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */
\r
364 data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0);
\r
365 mipi_dsih_dphy_write(phy, 0x12, data, 1);
\r
366 /* PLL input divider ratio [7:0] */
\r
367 data[0] = input_divider - 1;
\r
368 mipi_dsih_dphy_write(phy, 0x17, data, 1); //Jessica
\r
370 data[0] = 0x04; //short the delay time before BTA
\r
371 mipi_dsih_dphy_write(phy, 0x07, data, 1);
\r
374 // mipi_dsih_dphy_write(phy, 0xB0, data, 1);
\r
377 mipi_dsih_dphy_write(phy, 0x22, data, 1);
\r
378 // data[1] = mipi_dsih_dphy_test_data_out(phy);
\r
379 // MIPI_PRINT("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]);
\r
381 #ifdef SOFT_DPHY_CALIBRATION
\r
382 data[0] = mipi_dsih_dphy_calibration(phy);
\r
384 mipi_dsih_dphy_write(phy, 0x21, data, 1);
\r
386 for(n =0;n<50;n++ );
\r
388 data[1] = mipi_dsih_dphy_test_data_out(phy);
\r
389 MIPI_PRINT("sprdfb: mipi_dsih_dphy_calibration--> data[0]= %x,data[1] = %x \n",data[0],data[1]);
\r
392 no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */
\r
393 for (i = 0; i < no_of_bytes; i++)
\r
395 data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) ));
\r
396 /* 7 is dependent on no_of_bytes
\r
397 make sure 5 bits only of value are written at a time */
\r
400 /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */
\r
401 mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes);
\r
402 mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes);
\r
403 mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
\r
404 mipi_dsih_dphy_clock_en(phy, 1);
\r
405 for(n=0;n<100;n++){
\r
408 mipi_dsih_dphy_shutdown(phy, 1);
\r
409 for(n=0;n<100;n++){
\r
412 mipi_dsih_dphy_reset(phy, 1);
\r
417 dsih_error_t mipi_dsih_dphy_configure(dphy_t * phy, uint8_t no_of_lanes, uint32_t output_freq)
\r
419 uint32_t loop_divider = 0; /* (M) */
\r
420 uint32_t input_divider = 1; /* (N) */
\r
421 uint8_t data[4]; /* maximum data for now are 4 bytes per test mode*/
\r
422 uint8_t no_of_bytes = 0;
\r
423 uint8_t i = 0; /* iterator */
\r
424 uint8_t n=0;/* iterator */
\r
425 uint8_t range = 0; /* ranges iterator */
\r
427 #ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP
\r
430 uint32_t freq; /* upper margin of frequency range */
\r
431 uint8_t hs_freq; /* hsfreqrange */
\r
432 uint8_t vco_range; /* vcorange */
\r
436 {90, 0x00, 0x01}, {100, 0x10, 0x01}, {110, 0x20, 0x01},
\r
437 {125, 0x01, 0x01}, {140, 0x11, 0x01}, {150, 0x21, 0x01},
\r
438 {160, 0x02, 0x01}, {180, 0x12, 0x03}, {200, 0x22, 0x03},
\r
439 {210, 0x03, 0x03}, {240, 0x13, 0x03}, {250, 0x23, 0x03},
\r
440 {270, 0x04, 0x07}, {300, 0x14, 0x07}, {330, 0x24, 0x07},
\r
441 {360, 0x15, 0x07}, {400, 0x25, 0x07}, {450, 0x06, 0x07},
\r
442 {500, 0x16, 0x07}, {550, 0x07, 0x0f}, {600, 0x17, 0x0f},
\r
443 {650, 0x08, 0x0f}, {700, 0x18, 0x0f}, {750, 0x09, 0x0f},
\r
444 {800, 0x19, 0x0f}, {850, 0x0A, 0x0f}, {900, 0x1A, 0x0f},
\r
445 {950, 0x2A, 0x0f}, {1000, 0x3A, 0x0f}
\r
449 uint32_t loop_div; /* upper limit of loop divider range */
\r
450 uint8_t cp_current; /* icpctrl */
\r
451 uint8_t lpf_resistor; /* lpfctrl */
\r
455 {32, 0x06, 0x10}, {64, 0x06, 0x10}, {128, 0x0C, 0x08},
\r
456 {256, 0x04, 0x04}, {512, 0x00, 0x01}, {768, 0x01, 0x01},
\r
459 #elif defined DPHY2Btql
\r
462 uint32_t loop_div; /* upper limit of loop divider range */
\r
463 uint8_t cp_current; /* icpctrl */
\r
464 uint8_t lpf_resistor; /* lpfctrl */
\r
468 {32, 0x0B, 0x00}, {64, 0x0A, 0x00}, {128, 0x09, 0x01},
\r
469 {256, 0x08, 0x03}, {512, 0x08, 0x07}, {768, 0x08, 0x0F},
\r
475 return ERR_DSI_INVALID_INSTANCE;
\r
477 if (phy->status < INITIALIZED)
\r
479 return ERR_DSI_INVALID_INSTANCE;
\r
481 if (output_freq < MIN_OUTPUT_FREQ)
\r
483 return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
\r
485 /* find M and N dividers */
\r
486 for (input_divider = 1 + (phy->reference_freq / DPHY_DIV_UPPER_LIMIT); ((phy->reference_freq / input_divider) >= DPHY_DIV_LOWER_LIMIT) && (!flag); input_divider++)
\r
487 { /* here the >= DPHY_DIV_LOWER_LIMIT is a phy constraint, formula should be above 1 MHz */
\r
488 if (((output_freq * input_divider) % (phy->reference_freq )) == 0)
\r
489 { /* values found */
\r
490 loop_divider = ((output_freq * input_divider) / (phy->reference_freq ));
\r
491 if (loop_divider >= 12)
\r
497 if ((!flag) || ((phy->reference_freq / input_divider) < DPHY_DIV_LOWER_LIMIT))
\r
498 { /* no exact value found in previous for loop */
\r
499 /* this solution is not favourable as jitter would be maximum */
\r
500 loop_divider = output_freq / DPHY_DIV_LOWER_LIMIT;
\r
501 input_divider = phy->reference_freq / DPHY_DIV_LOWER_LIMIT;
\r
504 { /* variable was incremented before exiting the loop */
\r
507 for (i = 0; (i < (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0]))) && (loop_divider > loop_bandwidth[i].loop_div); i++)
\r
511 if (i >= (sizeof(loop_bandwidth)/sizeof(loop_bandwidth[0])))
\r
513 return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
\r
515 printf("sprdfb: Gen1 D-PHY: Approximated Frequency: %d KHz\n", (loop_divider * (phy->reference_freq / input_divider)));
\r
516 /* get the PHY in power down mode (shutdownz=0) and reset it (rstz=0) to
\r
517 avoid transient periods in PHY operation during re-configuration procedures. */
\r
518 mipi_dsih_dphy_reset(phy, 0);
\r
519 mipi_dsih_dphy_clock_en(phy, 0);
\r
520 mipi_dsih_dphy_shutdown(phy, 0);
\r
521 /* provide an initial active-high test clear pulse in TESTCLR */
\r
522 mipi_dsih_dphy_test_clear(phy, 1);
\r
523 mipi_dsih_dphy_test_clear(phy, 0);
\r
524 #ifdef DWC_MIPI_DPHY_BIDIR_TSMC40LP
\r
526 for (range = 0; (range < (sizeof(ranges)/sizeof(ranges[0]))) && ((output_freq / 1000) > ranges[range].freq); range++)
\r
530 if (range >= (sizeof(ranges)/sizeof(ranges[0])))
\r
532 return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
\r
534 /* set up board depending on environment if any */
\r
535 if (phy->bsp_pre_config != 0)
\r
537 phy->bsp_pre_config(phy, 0);
\r
540 /* Jessica add - begin*/
\r
541 data[0] = 0x42;//0x44;//0x44;//0x40; //0x40: ok for 200 clock lane lpx /*about 52ns*/
\r
542 mipi_dsih_dphy_write(phy, 0x60, data, 1);
\r
543 // data[0] = 0x0;//0xA6;//0xC6;//0xC6;//0x86; //0x48: ok for 200 prepare time
\r
544 // mipi_dsih_dphy_write(phy, 0x61, data, 1);
\r
546 // data[0] = 0x0;//0x6a;//0x6a;//0x4a; //0x4a: ok for 200 zero time
\r
547 // mipi_dsih_dphy_write(phy, 0x62, data, 1);
\r
549 data[0] = 0x42;//0x44;//0x40;//0x40; // 0x40: ok for 200 data lane lpx /*about 52ns*/
\r
550 mipi_dsih_dphy_write(phy, 0x70, data, 1);
\r
552 // data[0] = 0x0;//0x84;//0x96;//0x96;//0x86; //0x48: ok for 200 prepare time
\r
553 // mipi_dsih_dphy_write(phy, 0x71, data, 1);
\r
555 // data[0] = 0x0;;//0x44;//0x44;//0x40; //0x4a: ok for 200 zero time
\r
556 // mipi_dsih_dphy_write(phy, 0x72, data, 1);
\r
559 //mipi_dsih_dphy_write(phy, 0x73, data, 1);
\r
562 //mipi_dsih_dphy_write(phy, 0x74, data, 1);
\r
564 /* Jessica add - end*/
\r
566 /* setup digital part */
\r
567 /* hs frequency range [7]|[6:1]|[0]*/
\r
568 data[0] = (0 << 7) | (ranges[range].hs_freq << 1) | 0;
\r
569 //data[0] = (0 << 7) | (0x23 << 1) | 0;
\r
570 /*From ASIC, we need unmask this code to make the frequency correct*/
\r
571 mipi_dsih_dphy_write(phy, 0x44, data, 1); //Jessica remove for more accurate frequency
\r
573 /* vco range [7]|[6:3]|[2:1]|[0] */
\r
574 data[0] = (1 << 7) | (ranges[range].vco_range << 3) | (0 << 1) | 0;
\r
575 mipi_dsih_dphy_write(phy, 0x10, data, 1); //Jessica
\r
576 /* PLL reserved|Input divider control|Loop Divider Control|Post Divider Ratio [7:6]|[5]|[4]|[3:0] */
\r
577 data[0] = (0x00 << 6) | (0x01 << 5) | (0x01 << 4) | (0x03 << 0); /* post divider default = 0x03 - it is only used for clock out 2*/
\r
578 mipi_dsih_dphy_write(phy, 0x19, data, 1); //Jessica
\r
579 #elif defined DPHY2Btql
\r
580 /* vco range [7:5]|[4]|[3]|[2:1]|[0] */
\r
581 data[0] = ((((output_freq / 1000) > 500 )? 1: 0) << 4) | (1 << 3) | (0 << 1) | 0;
\r
582 mipi_dsih_dphy_write(phy, 0x10, data, 1);
\r
584 /* PLL Lock bypass|charge pump current [7:4]|[3:0] */
\r
585 data[0] = (0x00 << 4) | (loop_bandwidth[i].cp_current << 0);
\r
586 mipi_dsih_dphy_write(phy, 0x11, data, 1); //Jessica
\r
587 /* bypass CP default|bypass LPF default| LPF resistor [7]|[6]|[5:0] */
\r
588 data[0] = (0x01 << 7) | (0x01 << 6) |(loop_bandwidth[i].lpf_resistor << 0);
\r
589 mipi_dsih_dphy_write(phy, 0x12, data, 1);
\r
590 /* PLL input divider ratio [7:0] */
\r
591 data[0] = input_divider - 1;
\r
592 mipi_dsih_dphy_write(phy, 0x17, data, 1); //Jessica
\r
594 data[0] = 0x04; //short the delay time before BTA
\r
595 mipi_dsih_dphy_write(phy, 0x07, data, 1);
\r
598 // mipi_dsih_dphy_write(phy, 0xB0, data, 1);
\r
601 mipi_dsih_dphy_write(phy, 0x22, data, 1);
\r
602 // data[1] = mipi_dsih_dphy_test_data_out(phy);
\r
603 // MIPI_PRINT("sprdfb:mipi dphy config-->0x22 write:%x,read:%x \n",data[0],data[1]);
\r
606 no_of_bytes = 2; /* pll loop divider (code 0x18) takes only 2 bytes (10 bits in data) */
\r
607 for (i = 0; i < no_of_bytes; i++)
\r
609 data[i] = ((uint8_t)((((loop_divider - 1) >> (5 * i)) & 0x1F) | (i << 7) ));
\r
610 /* 7 is dependent on no_of_bytes
\r
611 make sure 5 bits only of value are written at a time */
\r
613 /* PLL loop divider ratio - SET no|reserved|feedback divider [7]|[6:5]|[4:0] */
\r
614 mipi_dsih_dphy_write(phy, 0x18, data, no_of_bytes);
\r
615 mipi_dsih_dphy_no_of_lanes(phy, no_of_lanes);
\r
616 mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
\r
617 mipi_dsih_dphy_clock_en(phy, 1);
\r
618 for(n=0;n<100;n++){
\r
621 mipi_dsih_dphy_shutdown(phy, 1);
\r
622 for(n=0;n<100;n++){
\r
625 mipi_dsih_dphy_reset(phy, 1);
\r
630 * Close and power down D-PHY module
\r
631 * @param phy pointer to structure which holds information about the d-phy
\r
633 * @return error code
\r
635 dsih_error_t mipi_dsih_dphy_close(dphy_t * phy)
\r
639 return ERR_DSI_INVALID_INSTANCE;
\r
641 else if ((phy->core_read_function == 0) || (phy->core_write_function == 0))
\r
643 return ERR_DSI_INVALID_IO;
\r
645 if (phy->status < NOT_INITIALIZED)
\r
647 return ERR_DSI_INVALID_INSTANCE;
\r
649 mipi_dsih_dphy_reset(phy, 0);
\r
650 mipi_dsih_dphy_reset(phy, 1);
\r
651 mipi_dsih_dphy_shutdown(phy, 0);
\r
652 phy->status = NOT_INITIALIZED;
\r
656 * Enable clock lane module
\r
657 * @param instance pointer to structure which holds information about the d-phy
\r
661 void mipi_dsih_dphy_clock_en(dphy_t * instance, int en)
\r
663 mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, en, 2, 1);
\r
666 * Reset D-PHY module
\r
667 * @param instance pointer to structure which holds information about the d-phy
\r
671 void mipi_dsih_dphy_reset(dphy_t * instance, int reset)
\r
673 mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, reset, 1, 1);
\r
676 * Power up/down D-PHY module
\r
677 * @param instance pointer to structure which holds information about the d-phy
\r
679 * @param powerup (1) shutdown (0)
\r
681 void mipi_dsih_dphy_shutdown(dphy_t * instance, int powerup)
\r
683 mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, powerup, 0, 1);
\r
686 * Force D-PHY PLL to stay on while in ULPS
\r
687 * @param instance pointer to structure which holds information about the d-phy
\r
689 * @param force (1) disable (0)
\r
690 * @note To follow the programming model, use wakeup_pll function
\r
692 void mipi_dsih_dphy_force_pll(dphy_t * instance, int force)
\r
694 mipi_dsih_dphy_write_part(instance, R_DPHY_RSTZ, force, 3, 1);
\r
697 * Get force D-PHY PLL module
\r
698 * @param instance pointer to structure which holds information about the d-phy
\r
700 * @return force value
\r
702 int mipi_dsih_dphy_get_force_pll(dphy_t * instance)
\r
704 return mipi_dsih_dphy_read_part(instance, R_DPHY_RSTZ, 3, 1);
\r
707 * Wake up or make sure D-PHY PLL module is awake
\r
708 * This function must be called after going into ULPS and before exiting it
\r
709 * to force the DPHY PLLs to wake up. It will wait until the DPHY status is
\r
710 * locked. It follows the procedure described in the user guide.
\r
711 * This function should be used to make sure the PLL is awake, rather than
\r
712 * the force_pll above.
\r
713 * @param instance pointer to structure which holds information about the d-phy
\r
715 * @return error code
\r
716 * @note this function has an active wait
\r
718 int mipi_dsih_dphy_wakeup_pll(dphy_t * instance)
\r
721 if (mipi_dsih_dphy_status(instance, 0x1) == 0)
\r
723 mipi_dsih_dphy_force_pll(instance, 1);
\r
724 for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++)
\r
726 if(mipi_dsih_dphy_status(instance, 0x1))
\r
731 if (mipi_dsih_dphy_status(instance, 0x1) == 0)
\r
733 return ERR_DSI_PHY_PLL_NOT_LOCKED;
\r
739 * Configure minimum wait period for HS transmission request after a stop state
\r
740 * @param instance pointer to structure which holds information about the d-phy
\r
742 * @param no_of_byte_cycles [in byte (lane) clock cycles]
\r
744 void mipi_dsih_dphy_stop_wait_time(dphy_t * instance, uint8_t no_of_byte_cycles)
\r
746 mipi_dsih_dphy_write_part(instance, R_DPHY_IF_CFG, no_of_byte_cycles, 8, 8);
\r
749 * Set number of active lanes
\r
750 * @param instance pointer to structure which holds information about the d-phy
\r
752 * @param no_of_lanes
\r
754 void mipi_dsih_dphy_no_of_lanes(dphy_t * instance, uint8_t no_of_lanes)
\r
756 mipi_dsih_dphy_write_part(instance, R_DPHY_IF_CFG, no_of_lanes - 1, 0, 2);
\r
759 * Get number of currently active lanes
\r
760 * @param instance pointer to structure which holds information about the d-phy
\r
762 * @return number of active lanes
\r
764 uint8_t mipi_dsih_dphy_get_no_of_lanes(dphy_t * instance)
\r
766 return mipi_dsih_dphy_read_part(instance, R_DPHY_IF_CFG, 0, 2);
\r
770 * Set non-continuous clock mode
\r
771 * @param instance pointer to structure which holds information about the d-phy
\r
775 void mipi_dsih_dphy_enable_nc_clk(dphy_t * instance, int enable)
\r
777 mipi_dsih_dphy_write_part(instance, R_DPHY_LPCLK_CTRL, enable, 1, 1);
\r
781 * Request the PHY module to start transmission of high speed clock.
\r
782 * This causes the clock lane to start transmitting DDR clock on the
\r
783 * lane interconnect.
\r
784 * @param instance pointer to structure which holds information about the d-phy
\r
787 * @note this function should be called explicitly by user always except for
\r
790 void mipi_dsih_dphy_enable_hs_clk(dphy_t * instance, int enable)
\r
792 mipi_dsih_dphy_write_part(instance, R_DPHY_LPCLK_CTRL, enable, 0, 1);
\r
795 * One bit is asserted in the trigger_request (4bits) to cause the lane module
\r
796 * to cause the associated trigger to be sent across the lane interconnect.
\r
797 * The trigger request is synchronous with the rising edge of the clock.
\r
798 * @note: Only one bit of the trigger_request is asserted at any given time, the
\r
799 * remaining must be left set to 0, and only when not in LPDT or ULPS modes
\r
800 * @param instance pointer to structure which holds information about the d-phy
\r
802 * @param trigger_request 4 bit request
\r
804 dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t * instance, uint8_t trigger_request)
\r
808 for (i = 0; i < 4; i++)
\r
810 sum += ((trigger_request >> i) & 1);
\r
814 /* clear old trigger */
\r
815 mipi_dsih_dphy_write_part(instance, R_DPHY_TX_TRIGGERS, 0x00, 0, 4);
\r
816 mipi_dsih_dphy_write_part(instance, R_DPHY_TX_TRIGGERS, trigger_request, 0, 4);
\r
817 for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++)
\r
819 if(mipi_dsih_dphy_status(instance, 0x0010))
\r
824 mipi_dsih_dphy_write_part(instance, R_DPHY_TX_TRIGGERS, 0x00, 0, 4);
\r
825 if (i >= DSIH_PHY_ACTIVE_WAIT)
\r
827 return ERR_DSI_TIMEOUT;
\r
831 return ERR_DSI_INVALID_COMMAND;
\r
834 * ULPS mode request/exit on all active data lanes.
\r
835 * @param instance pointer to structure which holds information about the d-phy
\r
837 * @param enable (request 1/ exit 0)
\r
838 * @return error code
\r
839 * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
\r
842 dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable)
\r
845 /* mask 1 0101 0010 0000 */
\r
846 uint16_t data_lanes_mask = 0;
\r
849 mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 2, 1);
\r
854 if (mipi_dsih_dphy_status(instance, 0x1) == 0)
\r
856 return ERR_DSI_PHY_PLL_NOT_LOCKED;
\r
858 mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 3, 1);
\r
859 switch (mipi_dsih_dphy_get_no_of_lanes(instance))
\r
862 data_lanes_mask |= (1 << 12);
\r
864 data_lanes_mask |= (1 << 10);
\r
866 data_lanes_mask |= (1 << 8);
\r
868 data_lanes_mask |= (1 << 5);
\r
871 data_lanes_mask = 0;
\r
874 for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
\r
876 /* verify that the DPHY has left ULPM */
\r
877 /* mask 1010100100000 */
\r
878 if (mipi_dsih_dphy_status(instance, data_lanes_mask) == data_lanes_mask)
\r
880 /* wait at least 1ms */
\r
883 /* wait at least 1ms */
\r
884 for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
\r
889 if (mipi_dsih_dphy_status(instance, data_lanes_mask) != data_lanes_mask)
\r
891 // instance->log_info("stat %x, mask %x", mipi_dsih_dphy_status(instance, data_lanes_mask), data_lanes_mask);
\r
892 return ERR_DSI_TIMEOUT;
\r
894 mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 2, 1);
\r
895 mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 3, 1);
\r
900 void mipi_dsih_dphy_ulps_data_lanes(dphy_t * instance, int enable)
\r
905 mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 3, 1);
\r
909 mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 4, 1);
\r
910 for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
\r
912 /* verify that the DPHY has left ULPM */
\r
913 /* mask 1010100100000 */
\r
914 if (mipi_dsih_dphy_status(instance, 0x1520) == 0)
\r
916 /* wait at least 1ms */
\r
917 for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
\r
924 mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 3, 1);
\r
925 mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 4, 1);
\r
930 * ULPS mode request/exit on Clock Lane.
\r
931 * @param instance pointer to structure which holds information about the
\r
933 * @param enable 1 or disable 0 of the Ultra Low Power State of the clock lane
\r
934 * @return error code
\r
935 * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
\r
938 dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable)
\r
942 uint16_t clk_lane_mask = 0x0008;
\r
945 /* mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 0, 1); */
\r
946 mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 0, 1);
\r
950 if (mipi_dsih_dphy_status(instance, 0x1) == 0)
\r
952 return ERR_DSI_PHY_PLL_NOT_LOCKED;
\r
954 mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 1, 1, 1);
\r
955 for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
\r
957 /* verify that the DPHY has left ULPM */
\r
958 /* mask 1010100100000 */
\r
959 if (mipi_dsih_dphy_status(instance, clk_lane_mask) == clk_lane_mask)
\r
961 /* wait at least 1ms */
\r
962 instance->log_info("stat %x, mask %x", mipi_dsih_dphy_status(instance, clk_lane_mask), clk_lane_mask);
\r
965 /* wait at least 1ms */
\r
966 for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
\r
968 /* dummy operation for the loop not to be optimised */
\r
969 enable = mipi_dsih_dphy_status(instance, clk_lane_mask);
\r
972 if (mipi_dsih_dphy_status(instance, clk_lane_mask) != clk_lane_mask)
\r
974 return ERR_DSI_TIMEOUT;
\r
976 mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 0, 1);
\r
977 mipi_dsih_dphy_write_part(instance, R_DPHY_ULPS_CTRL, 0, 1, 1);
\r
982 void mipi_dsih_dphy_ulps_clk_lane(dphy_t * instance, int enable)
\r
987 mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 0, 1);
\r
988 mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 1, 1);
\r
992 mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 1, 2, 1);
\r
993 for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++)
\r
995 /* verify that the DPHY has left ULPM */
\r
996 /* mask 1010100100000 */
\r
997 if (mipi_dsih_dphy_status(instance, 0x0004) == 0)
\r
999 /* wait at least 1ms */
\r
1000 for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
\r
1007 mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 1, 1);
\r
1008 mipi_dsih_dphy_write_part(instance, R_DSI_HOST_PHY_IF_CTRL, 0, 2, 1);
\r
1013 * Get D-PHY PPI status
\r
1014 * @param instance pointer to structure which holds information about the d-phy
\r
1019 uint32_t mipi_dsih_dphy_status(dphy_t * instance, uint16_t mask)
\r
1021 return mipi_dsih_dphy_read_word(instance, R_DPHY_STATUS) & mask;
\r
1024 * @param instance pointer to structure which holds information about the d-phy
\r
1028 void mipi_dsih_dphy_test_clock(dphy_t * instance, int value)
\r
1030 mipi_dsih_dphy_write_part(instance, R_DPHY_TST_CRTL0, value, 1, 1);
\r
1033 * @param instance pointer to structure which holds information about the d-phy
\r
1037 void mipi_dsih_dphy_test_clear(dphy_t * instance, int value)
\r
1039 mipi_dsih_dphy_write_part(instance, R_DPHY_TST_CRTL0, value, 0, 1);
\r
1042 * @param instance pointer to structure which holds information about the d-phy
\r
1044 * @param on_falling_edge
\r
1046 void mipi_dsih_dphy_test_en(dphy_t * instance, uint8_t on_falling_edge)
\r
1048 mipi_dsih_dphy_write_part(instance, R_DPHY_TST_CRTL1, on_falling_edge, 16, 1);
\r
1051 * @param instance pointer to structure which holds information about the d-phy
\r
1054 uint8_t mipi_dsih_dphy_test_data_out(dphy_t * instance)
\r
1056 return mipi_dsih_dphy_read_part(instance, R_DPHY_TST_CRTL1, 8, 8);
\r
1059 * @param instance pointer to structure which holds information about the d-phy
\r
1061 * @param test_data
\r
1063 void mipi_dsih_dphy_test_data_in(dphy_t * instance, uint8_t test_data)
\r
1065 mipi_dsih_dphy_write_word(instance, R_DPHY_TST_CRTL1, test_data);
\r
1068 * Write to D-PHY module (encapsulating the digital interface)
\r
1069 * @param instance pointer to structure which holds information about the d-phy
\r
1071 * @param address offset inside the D-PHY digital interface
\r
1072 * @param data array of bytes to be written to D-PHY
\r
1073 * @param data_length of the data array
\r
1075 void mipi_dsih_dphy_write(dphy_t * instance, uint8_t address, uint8_t * data, uint8_t data_length)
\r
1080 #if ((defined DWC_MIPI_DPHY_BIDIR_TSMC40LP) || (defined DPHY2Btql) || (defined GEN_2))
\r
1081 /* set the TESTCLK input high in preparation to latch in the desired test mode */
\r
1082 mipi_dsih_dphy_test_clock(instance, 1);
\r
1083 /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */
\r
1084 mipi_dsih_dphy_test_data_in(instance, address);
\r
1085 /* set TESTEN input high */
\r
1086 mipi_dsih_dphy_test_en(instance, 1);
\r
1087 /* drive the TESTCLK input low; the falling edge captures the chosen test code into the transceiver */
\r
1088 mipi_dsih_dphy_test_clock(instance, 0);
\r
1089 /* set TESTEN input low to disable further test mode code latching */
\r
1090 mipi_dsih_dphy_test_en(instance, 0);
\r
1091 /* start writing MSB first */
\r
1092 for (i = data_length; i > 0; i--)
\r
1094 /* set TESTDIN[7:0] to the desired test data appropriate to the chosen test mode */
\r
1095 mipi_dsih_dphy_test_data_in(instance, data[i - 1]);
\r
1096 /* pulse TESTCLK high to capture this test data into the macrocell; repeat these two steps as necessary */
\r
1097 mipi_dsih_dphy_test_clock(instance, 1);
\r
1098 mipi_dsih_dphy_test_clock(instance, 0);
\r
1106 /* abstracting BSP */
\r
1108 * Write to whole register to D-PHY module (encapsulating the bus interface)
\r
1109 * @param instance pointer to structure which holds information about the d-phy
\r
1111 * @param reg_address offset
\r
1112 * @param data 32-bit word
\r
1114 void mipi_dsih_dphy_write_word(dphy_t * instance, uint32_t reg_address, uint32_t data)
\r
1116 if (instance->core_write_function != 0)
\r
1118 instance->core_write_function(instance->address, reg_address, data);
\r
1122 * Write bit field to D-PHY module (encapsulating the bus interface)
\r
1123 * @param instance pointer to structure which holds information about the d-phy
\r
1125 * @param reg_address offset
\r
1126 * @param data bits to be written to D-PHY
\r
1127 * @param shift from the right hand side of the register (big endian)
\r
1128 * @param width of the bit field
\r
1130 void mipi_dsih_dphy_write_part(dphy_t * instance, uint32_t reg_address, uint32_t data, uint8_t shift, uint8_t width)
\r
1132 uint32_t mask = 0;
\r
1133 uint32_t temp = 0;
\r
1134 if (instance->core_read_function != 0)
\r
1136 mask = (1 << width) - 1;
\r
1137 temp = mipi_dsih_dphy_read_word(instance, reg_address);
\r
1138 temp &= ~(mask << shift);
\r
1139 temp |= (data & mask) << shift;
\r
1140 mipi_dsih_dphy_write_word(instance, reg_address, temp);
\r
1144 * Read whole register from D-PHY module (encapsulating the bus interface)
\r
1145 * @param instance pointer to structure which holds information about the d-phy
\r
1147 * @param reg_address offset
\r
1148 * @return data 32-bit word
\r
1150 uint32_t mipi_dsih_dphy_read_word(dphy_t * instance, uint32_t reg_address)
\r
1152 if (instance->core_read_function == 0)
\r
1154 return ERR_DSI_INVALID_IO;
\r
1156 return instance->core_read_function(instance->address, reg_address);
\r
1159 * Read bit field from D-PHY module (encapsulating the bus interface)
\r
1160 * @param instance pointer to structure which holds information about the d-phy
\r
1162 * @param reg_address offset
\r
1163 * @param shift from the right hand side of the register (big endian)
\r
1164 * @param width of the bit field
\r
1165 * @return data bits to be written to D-PHY
\r
1167 uint32_t mipi_dsih_dphy_read_part(dphy_t * instance, uint32_t reg_address, uint8_t shift, uint8_t width)
\r
1169 return (mipi_dsih_dphy_read_word(instance, reg_address) >> shift) & ((1 << width) - 1);
\r