2 * Copyright (C) 2014 Spreadtrum Communications Inc.
4 * modules/DISPC/dsi_1.21a/mipi_api_dsihost/mipi_dsih_dphy_megacores.c
6 * Author: Haibing.Yang <haibing.yang@spreadtrum.com>
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
20 #include "mipi_dsih_dphy.h"
28 #define INFINITY 0xffffffff
31 #define MIN_OUTPUT_FREQ (100)
35 #define ROUND_UP(a, b) (((a) + (b) - 1) / (b))
39 #define MAX(a, b) ((a) > (b) ? (a) : (b))
40 #define MIN(a, b) ((a) > (b) ? (b) : (a))
45 * abs() should not be used for 64-bit types
46 * (s64, u64, long long) - use abs64() for those.
50 if (sizeof((x)) == sizeof(long)) { \
52 ret = (__x < 0) ? - __x : __x; \
55 ret = (__x < 0) ? - __x : __x; \
61 #define AVERAGE(a, b) (MIN(a, b) + abs((b) - (a)) / 2)
63 typedef unsigned int u32;
64 typedef unsigned short u16;
65 typedef unsigned char u8;
167 u8 refin; /* Pre-divider control signal */
168 u8 cp_s; /* 00: SDM_EN=1, 10: SDM_EN=0 */
169 u8 fdk_s; /* PLL mode control: integer or fraction */
171 u8 mod_en; /* ssc enable */
174 u8 int_n; /* integer N PLL */
175 u32 ref_clk; /* dphy reference clock, unit: MHz */
176 u32 freq; /* panel config, unit: KHz */
178 u32 potential_fvco; /* MHz */
179 u32 nint; /* sigma delta modulator NINT control */
180 u32 kint; /* sigma delta modulator KINT control */
184 u8 lpf_sel; /* low pass filter control */
185 u8 out_sel; /* post divider control */
186 u8 vco_band; /* vco range */
190 * Initialise D-PHY module and power up
191 * @param phy: pointer to structure
192 * which holds information about the d-phy module
195 dsih_error_t mipi_dsih_dphy_open(dphy_t *phy)
197 if (!phy || !phy->core_read_function || !phy->core_write_function)
198 return ERR_DSI_PHY_INVALID;
199 else if (phy->status == INITIALIZED)
200 return ERR_DSI_PHY_INVALID;
202 phy->status = INITIALIZED;
206 u8 mipi_dsih_dphy_test_data_read(dphy_t *phy, u8 address)
208 mipi_dsih_dphy_test_clock(phy, 1);
209 /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */
210 mipi_dsih_dphy_test_data_in(phy, address);
211 /* set TESTEN input high */
212 mipi_dsih_dphy_test_en(phy, 1);
215 * drive the TESTCLK input low;
216 * the falling edge captures the
217 * chosen test code into the transceiver.
219 mipi_dsih_dphy_test_clock(phy, 0);
221 /* set TESTEN input low to disable further test mode code latching */
222 mipi_dsih_dphy_test_en(phy, 0);
226 return mipi_dsih_dphy_test_data_out(phy);
229 static inline int mipi_dsih_if_dphy_keep_work(dphy_t *phy)
233 #ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING
234 keep_work = phy->phy_keep_work;
241 static int mipi_dsih_dphy_calc_pll_param(dphy_t *phy, struct dphy_pll *pll)
244 const u32 hopping_period = 200;
245 const u32 khz = 1000;
246 const u32 mhz = 1000000;
248 static u32 origin_freq = 0;
249 const unsigned long long factor = 100;
250 unsigned long long tmp;
252 if (!pll || !pll->freq)
255 pll->potential_fvco = pll->freq / khz; /* MHz */
256 pll->ref_clk = phy->reference_freq / khz; /* MHz */
258 for (i = 0; i < 4; ++i) {
259 if (pll->potential_fvco >= 750 && pll->potential_fvco <= 1500) {
260 pll->fvco = pll->potential_fvco;
261 pll->out_sel = BIT(i);
264 pll->potential_fvco <<= 1;
269 if (pll->fvco >= 750 && pll->fvco <= 1100) {
270 /* vco band control */
272 /* low pass filter control */
274 } else if (pll->fvco > 1100 && pll->fvco <= 1500) {
280 pll->nint = pll->fvco / pll->ref_clk;
281 tmp = pll->fvco * factor * mhz;
282 do_div(tmp, pll->ref_clk);
283 tmp = tmp - pll->nint * factor * mhz;
285 do_div(tmp, 100000000);
286 pll->kint = (u32)tmp;
287 pll->refin = 0x3; /* pre-divider bypass */
288 pll->sdm_en = TRUE; /* use fraction N PLL */
289 pll->fdk_s = 0x1; /* fraction */
299 if (origin_freq == 0)
302 delta_freq = (int)pll->freq - (int)origin_freq;
303 if (delta_freq < 0) {
304 delta_freq = - delta_freq;
307 pll->kstep = pll->ref_clk * hopping_period;
308 pll->kdelta = (1 << 20) * delta_freq * pll->out_sel
309 / pll->kstep / pll->ref_clk;
311 origin_freq = pll->freq;
319 phy->log_error("sprdfb: failed to calculate dphy pll parameters\n");
320 return ERR_DSI_PHY_PLL_NOT_LOCKED;
323 static int mipi_dsih_dphy_set_pll_reg(dphy_t *phy, struct dphy_pll *pll)
328 struct pll_regs regs;
330 0x03, 0x04, 0x06, 0x07, 0x08, 0x09,
331 0x0a, 0x0b, 0x0c, 0x0d, 0x0e
334 if (!pll || !pll->fvco)
337 memset((u8 *)®s, '\0', sizeof(regs));
338 regs._03.bits.prbs_bist = 1;
339 regs._03.bits.en_lp_treot = TRUE;
340 regs._03.bits.lpf_sel = pll->lpf_sel;
341 regs._03.bits.txfifo_bypass = 0;
342 regs._03.bits.freq_hopping = pll->hop_en;
343 regs._04.bits.div = pll->div;
344 regs._04.bits.cp_s = pll->cp_s;
345 regs._04.bits.fdk_s = pll->fdk_s;
346 regs._06.bits.nint = pll->nint;
347 regs._06.bits.mod_en = pll->mod_en;
348 regs._07.bits.kdelta_h = pll->kdelta >> 4;
349 regs._07.bits.kdelta_h |= pll->sign << 7;
350 regs._08.bits.vco_band = pll->vco_band;
351 regs._08.bits.sdm_en = pll->sdm_en;
352 regs._08.bits.refin = pll->refin;
353 regs._08.bits.kdelta_l = pll->kdelta & 0xf;
354 regs._09.bits.kint_h = pll->kint >> 12;
355 regs._0a.bits.kint_m = (pll->kint >> 4) & 0xff;
356 regs._0b.bits.out_sel = pll->out_sel;
357 regs._0b.bits.kint_l = pll->kint & 0xf;
358 regs._0c.bits.kstep_h = pll->kstep >> 11;
359 regs._0d.bits.kstep_m = (pll->kstep >> 3) & 0xff;
360 regs._0e.bits.pll_pu_byp = 0;
361 regs._0e.bits.pll_pu = 0;
362 regs._0e.bits.kstep_l = pll->kstep & 0x7;
366 for (i = 0; i < sizeof(regs_addr); ++i)
367 mipi_dsih_dphy_write(phy, regs_addr[i], &val[i], 1);
372 phy->log_error("sprdfb: failed to set dphy pll registers\n");
373 return ERR_DSI_PHY_PLL_NOT_LOCKED;
376 static int mipi_dsih_dphy_config_pll(dphy_t *phy, u32 freq)
379 struct dphy_pll pll = {0};
383 /* FREQ = 26M * (NINT + KINT / 2^20) / out_sel */
384 ret = mipi_dsih_dphy_calc_pll_param(phy, &pll);
387 ret = mipi_dsih_dphy_set_pll_reg(phy, &pll);
394 phy->log_error("sprdfb: failed to config dphy pll\n");
395 return ERR_DSI_PHY_PLL_NOT_LOCKED;
398 static int mipi_dsih_dphy_set_timing_regs(dphy_t *phy, int type, u8 val[])
402 if (!mipi_dsih_if_dphy_keep_work(phy)) {
403 mipi_dsih_dphy_write(phy, 0x31, &val[CLK], 1);
404 mipi_dsih_dphy_write(phy, 0x41, &val[DATA], 1);
405 mipi_dsih_dphy_write(phy, 0x51, &val[DATA], 1);
407 mipi_dsih_dphy_write(phy, 0x90, &val[CLK], 1);
408 mipi_dsih_dphy_write(phy, 0xa0, &val[DATA], 1);
409 mipi_dsih_dphy_write(phy, 0xb0, &val[DATA], 1);
413 if (!mipi_dsih_if_dphy_keep_work(phy)) {
414 mipi_dsih_dphy_write(phy, 0x32, &val[CLK], 1);
415 mipi_dsih_dphy_write(phy, 0x42, &val[DATA], 1);
416 mipi_dsih_dphy_write(phy, 0x52, &val[DATA], 1);
418 mipi_dsih_dphy_write(phy, 0x91, &val[CLK], 1);
419 mipi_dsih_dphy_write(phy, 0xa1, &val[DATA], 1);
420 mipi_dsih_dphy_write(phy, 0xb1, &val[DATA], 1);
424 if (!mipi_dsih_if_dphy_keep_work(phy)) {
425 mipi_dsih_dphy_write(phy, 0x33, &val[CLK], 1);
426 mipi_dsih_dphy_write(phy, 0x43, &val[DATA], 1);
427 mipi_dsih_dphy_write(phy, 0x53, &val[DATA], 1);
429 mipi_dsih_dphy_write(phy, 0x92, &val[CLK], 1);
430 mipi_dsih_dphy_write(phy, 0xa2, &val[DATA], 1);
431 mipi_dsih_dphy_write(phy, 0xb2, &val[DATA], 1);
435 if (!mipi_dsih_if_dphy_keep_work(phy)) {
436 mipi_dsih_dphy_write(phy, 0x34, &val[CLK], 1);
437 mipi_dsih_dphy_write(phy, 0x44, &val[DATA], 1);
438 mipi_dsih_dphy_write(phy, 0x54, &val[DATA], 1);
440 mipi_dsih_dphy_write(phy, 0x93, &val[CLK], 1);
441 mipi_dsih_dphy_write(phy, 0xa3, &val[DATA], 1);
442 mipi_dsih_dphy_write(phy, 0xb3, &val[DATA], 1);
446 if (!mipi_dsih_if_dphy_keep_work(phy)) {
447 mipi_dsih_dphy_write(phy, 0x36, &val[CLK], 1);
448 mipi_dsih_dphy_write(phy, 0x46, &val[DATA], 1);
449 mipi_dsih_dphy_write(phy, 0x56, &val[DATA], 1);
451 mipi_dsih_dphy_write(phy, 0x95, &val[CLK], 1);
452 mipi_dsih_dphy_write(phy, 0xA5, &val[DATA], 1);
453 mipi_dsih_dphy_write(phy, 0xB5, &val[DATA], 1);
457 if (!mipi_dsih_if_dphy_keep_work(phy))
458 mipi_dsih_dphy_write(phy, 0x35, &val[CLK], 1);
460 mipi_dsih_dphy_write(phy, 0x94, &val[CLK], 1);
463 /* the following just use default value */
475 static int mipi_dsih_dphy_config_lane_timing(dphy_t *phy,
476 u32 bitclk, int type)
480 u32 range[2], constant;
481 u32 t_ui, t_byteck, t_half_byteck;
482 const u32 factor = 2;
483 const u32 scale = 100;
485 /* t_ui: 1 ui, byteck: 8 ui, half byteck: 4 ui */
486 t_ui = 1000 * scale / (bitclk / 1000);
487 t_byteck = t_ui << 3;
488 t_half_byteck = t_ui << 2;
489 constant = t_ui << 1;
493 case REQUEST_TIME: /* HS T-LPX: LP-01 */
496 * For T-LPX, mipi spec defined min value is 50ns,
497 * but maybe it shouldn't be too small, because BTA,
498 * LP-10, LP-00, LP-01, all of this is related to T-LPX.
500 range[L] = 50 * scale;
502 val[CLK] = ROUND_UP(range[L] * (factor << 1), t_byteck) - 2;
503 val[DATA] = val[CLK];
504 mipi_dsih_dphy_set_timing_regs(phy, REQUEST_TIME, val);
506 case PREPARE_TIME: /* HS sequence: LP-00 */
507 range[L] = 38 * scale; /* clock */
508 range[H] = 95 * scale;
509 tmp = AVERAGE(range[L], range[H]);
510 val[CLK] = ROUND_UP(AVERAGE(range[L], range[H]),
512 range[L] = 40 * scale + 4 * t_ui; /* data */
513 range[H] = 85 * scale + 6 * t_ui;
514 tmp |= AVERAGE(range[L], range[H]) << 16;
515 val[DATA] = ROUND_UP(AVERAGE(range[L], range[H]),
517 mipi_dsih_dphy_set_timing_regs(phy, PREPARE_TIME, val);
519 case ZERO_TIME: /* HS-ZERO */
520 range[L] = 300 * scale; /* clock */
522 val[CLK] = ROUND_UP(range[L] * factor + (tmp & 0xffff)
523 - 525 * t_byteck / 100, t_byteck) - 2;
524 range[L] = 145 * scale + 10 * t_ui; /* data */
525 val[DATA] = ROUND_UP(range[L] * factor
526 + ((tmp >> 16) & 0xffff) - 525 * t_byteck / 100,
528 mipi_dsih_dphy_set_timing_regs(phy, ZERO_TIME, val);
530 case TRAIL_TIME: /* HS-TRAIL */
531 range[L] = 60 * scale;
533 val[CLK] = ROUND_UP(range[L] * factor - constant, t_half_byteck);
534 range[L] = MAX(8 * t_ui, 60 * scale + 4 * t_ui);
535 val[DATA] = ROUND_UP(range[L] * factor / 2 - constant, t_half_byteck);
536 mipi_dsih_dphy_set_timing_regs(phy, TRAIL_TIME, val);
539 range[L] = 100 * scale;
541 val[CLK] = ROUND_UP(range[L] * factor, t_byteck) - 2;
542 val[DATA] = val[CLK];
543 mipi_dsih_dphy_set_timing_regs(phy, EXIT_TIME, val);
546 range[L] = 60 * scale + 52 * t_ui;
548 val[CLK] = ROUND_UP(range[L] * factor, t_byteck) - 2;
549 val[DATA] = val[CLK];
550 mipi_dsih_dphy_set_timing_regs(phy, CLKPOST_TIME, val);
554 * This time is used for receiver. So for transmitter,
559 * transmitter drives bridge state(LP-00) before releasing control,
560 * reg 0x1f default value: 0x04, which is good.
564 * After LP-10 state and before bridge state(LP-00),
565 * reg 0x20 default value: 0x01, which is good.
569 * receiver drives Bridge state(LP-00) before releasing control
570 * reg 0x21 default value: 0x03, which is good.
579 static int mipi_dsih_dphy_powerup(dphy_t *phy, int enable)
582 * Make sure that DSI IP is connected to TestChip IO
584 * get the PHY in power down mode (shutdownz = 0) and
585 * reset it (rstz = 0) to avoid transient periods in
586 * PHY operation during re-configuration procedures.
589 mipi_dsih_dphy_clock_en(phy, TRUE);
590 mipi_dsih_dphy_stop_wait_time(phy, 0x1C);
591 mipi_dsih_dphy_clock_en(phy, TRUE);
592 mipi_dsih_dphy_shutdown(phy, FALSE);
593 mipi_dsih_dphy_reset(phy, FALSE);
595 mipi_dsih_dphy_reset(phy, TRUE);
596 mipi_dsih_dphy_shutdown(phy, TRUE);
597 mipi_dsih_dphy_clock_en(phy, FALSE);
598 /* provide an initial active-high test clear pulse in TESTCLR */
599 /* DPHY registers will be reset after test clear is set to high */
600 mipi_dsih_dphy_test_clear(phy, 0);
601 mipi_dsih_dphy_test_clear(phy, 1);
602 mipi_dsih_dphy_test_clear(phy, 0);
608 * Configure D-PHY and PLL module to desired operation mode
609 * @param phy: pointer to structure
610 * which holds information about the d-phy module
611 * @param no_of_lanes active
612 * @param output_freq desired high speed frequency
615 dsih_error_t mipi_dsih_dphy_configure(dphy_t *phy,
620 return ERR_DSI_INVALID_INSTANCE;
621 if (phy->status < INITIALIZED)
622 return ERR_DSI_INVALID_INSTANCE;
623 if (output_freq < MIN_OUTPUT_FREQ)
624 return ERR_DSI_PHY_FREQ_OUT_OF_BOUND;
626 if (!mipi_dsih_if_dphy_keep_work(phy))
627 mipi_dsih_dphy_powerup(phy, FALSE);
629 /* set up board depending on environment if any */
630 if (phy->bsp_pre_config)
631 phy->bsp_pre_config(phy, 0);
633 mipi_dsih_dphy_config_pll(phy, output_freq);
634 mipi_dsih_dphy_config_lane_timing(phy, output_freq, NONE);
635 mipi_dsih_dphy_no_of_lanes(phy, lane_num);
637 if (!mipi_dsih_if_dphy_keep_work(phy))
638 mipi_dsih_dphy_powerup(phy, TRUE);
644 * Close and power down D-PHY module
645 * @param phy pointer to structure which holds information about the d-phy
649 dsih_error_t mipi_dsih_dphy_close(dphy_t *phy)
652 return ERR_DSI_INVALID_INSTANCE;
654 if (!phy->core_read_function || !phy->core_write_function)
655 return ERR_DSI_INVALID_IO;
657 if (phy->status < INITIALIZED)
658 return ERR_DSI_INVALID_INSTANCE;
660 mipi_dsih_dphy_reset(phy, TRUE);
661 mipi_dsih_dphy_shutdown(phy, TRUE);
662 mipi_dsih_dphy_reset(phy, FALSE);
663 phy->status = NOT_INITIALIZED;
669 * Enable clock lane module
670 * @param phy pointer to structure
671 * which holds information about the d-phy module
674 void mipi_dsih_dphy_clock_en(dphy_t *phy, int en)
676 mipi_dsih_dphy_write_part(phy, R_DPHY_RSTZ, en, 2, 1);
681 * Set non-continuous clock mode
682 * @param phy pointer to structure
683 * which holds information about the d-phy module
684 * @param enable 1: enable non continuous clock
686 void mipi_dsih_dphy_enable_nc_clk(dphy_t *phy, int enable)
688 mipi_dsih_dphy_write_part(phy, R_DPHY_LPCLK_CTRL, enable, 1, 1);
693 * @param phy: pointer to structure
694 * which holds information about the d-phy module
697 void mipi_dsih_dphy_reset(dphy_t *phy, int enable)
699 mipi_dsih_dphy_write_part(phy, R_DPHY_RSTZ, !!!enable, 1, 1);
703 * Power up/down D-PHY module
704 * @param phy: pointer to structure
705 * which holds information about the d-phy module
706 * @param enable (1: shutdown)
708 void mipi_dsih_dphy_shutdown(dphy_t *phy, int enable)
710 mipi_dsih_dphy_write_part(phy, R_DPHY_RSTZ, !!!enable, 0, 1);
714 * Force D-PHY PLL to stay on while in ULPS
715 * @param phy: pointer to structure
716 * which holds information about the d-phy module
717 * @param force (1) disable (0)
718 * @note To follow the programming model, use wakeup_pll function
720 void mipi_dsih_dphy_force_pll(dphy_t *phy, int force)
729 /* for megocores, to force pll, dphy register should be set */
730 mipi_dsih_dphy_write(phy, 0x0e, &data, 1);
732 mipi_dsih_dphy_write_part(phy, R_DPHY_RSTZ, force, 3, 1);
736 * Get force D-PHY PLL module
737 * @param phy pointer to structure
738 * which holds information about the d-phy module
739 * @return force value
741 int mipi_dsih_dphy_get_force_pll(dphy_t *phy)
743 /* FIXME: TODO: for megacores, this status is not true */
744 return mipi_dsih_dphy_read_part(phy, R_DPHY_RSTZ, 3, 1);
748 * Wake up or make sure D-PHY PLL module is awake
749 * This function must be called after going into ULPS and before exiting it
750 * to force the DPHY PLLs to wake up. It will wait until the DPHY status is
751 * locked. It follows the procedure described in the user guide.
752 * This function should be used to make sure the PLL is awake, rather than
753 * the force_pll above.
754 * @param phy pointer to structure which holds information about the d-phy
757 * @note this function has an active wait
759 int mipi_dsih_dphy_wakeup_pll(dphy_t *phy)
763 if (mipi_dsih_dphy_status(phy, 0x1))
766 mipi_dsih_dphy_force_pll(phy, 1);
768 for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++) {
769 if (mipi_dsih_dphy_status(phy, 0x1))
773 if (mipi_dsih_dphy_status(phy, 0x1) == 0)
774 return ERR_DSI_PHY_PLL_NOT_LOCKED;
780 * Configure minimum wait period for HS transmission request after a stop state
781 * @param phy pointer to structure which holds information about the d-phy
783 * @param no_of_byte_cycles [in byte (lane) clock cycles]
785 void mipi_dsih_dphy_stop_wait_time(dphy_t *phy,
786 u8 no_of_byte_cycles)
788 mipi_dsih_dphy_write_part(phy,
795 * Set number of active lanes
796 * @param phy: pointer to structure
797 * which holds information about the d-phy module
800 void mipi_dsih_dphy_no_of_lanes(dphy_t *phy, u8 no_of_lanes)
802 /* currently, dphy only support 2 lanes */
803 if (no_of_lanes > MAX_LANES)
804 no_of_lanes = MAX_LANES;
806 mipi_dsih_dphy_write_part(phy, R_DPHY_IF_CFG,
807 no_of_lanes - 1, 0, 2);
811 * Get number of currently active lanes
812 * @param phy: pointer to structure
813 * which holds information about the d-phy module
814 * @return number of active lanes
816 u8 mipi_dsih_dphy_get_no_of_lanes(dphy_t *phy)
818 return mipi_dsih_dphy_read_part(phy, R_DPHY_IF_CFG, 0, 2);
822 * Request the PHY module to start transmission of high speed clock.
823 * This causes the clock lane to start transmitting DDR clock on the
825 * @param phy pointer to structure which holds information about the d-phy
828 * @note this function should be called explicitly by user always except for
831 void mipi_dsih_dphy_enable_hs_clk(dphy_t *phy, int enable)
833 mipi_dsih_dphy_write_part(phy, R_DPHY_LPCLK_CTRL, enable, 0, 1);
837 * One bit is asserted in the trigger_request (4bits) to cause the lane module
838 * to cause the associated trigger to be sent across the lane interconnect.
839 * The trigger request is synchronous with the rising edge of the clock.
840 * @note: Only one bit of the trigger_request is asserted at any given time, the
841 * remaining must be left set to 0, and only when not in LPDT or ULPS modes
842 * @param phy pointer to structure which holds information about the d-phy
844 * @param trigger_request 4 bit request
846 dsih_error_t mipi_dsih_dphy_escape_mode_trigger(dphy_t *phy,
851 for (i = 0; i < 4; i++) {
852 sum += ((trigger_request >> i) & 1);
855 if (sum == 1) { /* clear old trigger */
856 mipi_dsih_dphy_write_part(phy, R_DPHY_TX_TRIGGERS,
858 mipi_dsih_dphy_write_part(phy, R_DPHY_TX_TRIGGERS,
859 trigger_request, 0, 4);
861 for (i = 0; i < DSIH_PHY_ACTIVE_WAIT; i++) {
862 if (mipi_dsih_dphy_status(phy, 0x0010)) {
866 mipi_dsih_dphy_write_part(phy, R_DPHY_TX_TRIGGERS, 0x00, 0, 4);
867 if (i >= DSIH_PHY_ACTIVE_WAIT)
868 return ERR_DSI_TIMEOUT;
872 return ERR_DSI_INVALID_COMMAND;
876 * ULPS mode request/exit on all active data lanes.
877 * @param phy pointer to structure which holds information about the d-phy
879 * @param enable (request 1/ exit 0)
881 * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
883 dsih_error_t mipi_dsih_dphy_ulps_data_lanes(dphy_t *phy, int enable)
886 /* mask 1 0101 0010 0000 */
887 u16 data_lanes_mask = 0;
890 mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 1, 2, 1);
893 if (!mipi_dsih_dphy_status(phy, 0x1))
894 return ERR_DSI_PHY_PLL_NOT_LOCKED;
896 mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 1, 3, 1);
897 switch (mipi_dsih_dphy_get_no_of_lanes(phy)) {
900 data_lanes_mask |= (1 << 12);
903 data_lanes_mask |= (1 << 10);
906 data_lanes_mask |= (1 << 8);
909 data_lanes_mask |= (1 << 5);
915 /* verify that the DPHY has left ULPM */
916 for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++) {
917 if (mipi_dsih_dphy_status(phy, data_lanes_mask)
920 /* wait at least 1ms */
921 for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
925 if (mipi_dsih_dphy_status(phy, data_lanes_mask)
926 != data_lanes_mask) {
927 phy->log_info("stat %x, mask %x",
928 mipi_dsih_dphy_status(phy, data_lanes_mask),
930 return ERR_DSI_TIMEOUT;
932 mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 0, 2, 1);
933 mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 0, 3, 1);
939 * ULPS mode request/exit on Clock Lane.
940 * @param phy pointer to structure which holds information about the
942 * @param enable 1 or disable 0 of the Ultra Low Power State of the clock lane
944 * @note this is a blocking function. wait upon exiting the ULPS will exceed 1ms
946 dsih_error_t mipi_dsih_dphy_ulps_clk_lane(dphy_t *phy, int enable)
950 u16 clk_lane_mask = 0x0008;
952 mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 1, 0, 1);
954 if (!mipi_dsih_dphy_status(phy, 0x1))
955 return ERR_DSI_PHY_PLL_NOT_LOCKED;
957 mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 1, 1, 1);
958 /* verify that the DPHY has left ULPM */
959 for (timeout = 0; timeout < DSIH_PHY_ACTIVE_WAIT; timeout++) {
960 if (mipi_dsih_dphy_status(phy, clk_lane_mask)
962 phy->log_info("stat %x, mask %x",
963 mipi_dsih_dphy_status(phy, clk_lane_mask),
967 /* wait at least 1ms */
968 /* dummy operation for the loop not to be optimised */
969 for (timeout = 0; timeout < ONE_MS_ACTIVE_WAIT; timeout++)
970 enable = mipi_dsih_dphy_status(phy, clk_lane_mask);
972 if (mipi_dsih_dphy_status(phy, clk_lane_mask) != clk_lane_mask)
973 return ERR_DSI_TIMEOUT;
975 mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 0, 0, 1);
976 mipi_dsih_dphy_write_part(phy, R_DPHY_ULPS_CTRL, 0, 1, 1);
982 * Get D-PHY PPI status
983 * @param phy pointer to structure which holds information about the d-phy
988 u32 mipi_dsih_dphy_status(dphy_t *phy, u16 mask)
990 return mipi_dsih_dphy_read_word(phy, R_DPHY_STATUS) & mask;
994 * @param phy pointer to structure which holds information about the d-phy
998 void mipi_dsih_dphy_test_clock(dphy_t *phy, int value)
1000 mipi_dsih_dphy_write_part(phy, R_DPHY_TST_CRTL0, value, 1, 1);
1004 * @param phy pointer to structure which holds information about the d-phy
1008 void mipi_dsih_dphy_test_clear(dphy_t *phy, int value)
1010 mipi_dsih_dphy_write_part(phy, R_DPHY_TST_CRTL0, value, 0, 1);
1014 * @param phy pointer to structure which holds information about the d-phy
1016 * @param on_falling_edge
1018 void mipi_dsih_dphy_test_en(dphy_t *phy, u8 on_falling_edge)
1020 mipi_dsih_dphy_write_part(phy, R_DPHY_TST_CRTL1,
1021 on_falling_edge, 16, 1);
1025 * @param phy pointer to structure which holds information about the d-phy
1028 u8 mipi_dsih_dphy_test_data_out(dphy_t *phy)
1030 return mipi_dsih_dphy_read_part(phy, R_DPHY_TST_CRTL1, 8, 8);
1034 * @param phy pointer to structure which holds information about the d-phy
1038 void mipi_dsih_dphy_test_data_in(dphy_t *phy, u8 test_data)
1040 mipi_dsih_dphy_write_word(phy, R_DPHY_TST_CRTL1, test_data);
1044 * Write to D-PHY module (encapsulating the digital interface)
1045 * @param phy pointer to structure which holds information about the d-phy
1047 * @param address offset inside the D-PHY digital interface
1048 * @param data array of bytes to be written to D-PHY
1049 * @param data_length of the data array
1051 void mipi_dsih_dphy_write(dphy_t *phy, u8 address,
1052 u8 *data, u8 data_length)
1058 * set the TESTCLK input high in preparation
1059 * to latch in the desired test mode
1061 mipi_dsih_dphy_test_clock(phy, 1);
1062 /* set the desired test code in the input 8-bit bus TESTDIN[7:0] */
1063 mipi_dsih_dphy_test_data_in(phy, address);
1064 /* set TESTEN input high */
1065 mipi_dsih_dphy_test_en(phy, 1);
1067 * drive the TESTCLK input low;
1068 * the falling edge captures the chosen test code
1069 * into the transceiver
1071 mipi_dsih_dphy_test_clock(phy, 0);
1073 * set TESTEN input low
1074 * to disable further test mode code latching
1076 mipi_dsih_dphy_test_en(phy, 0);
1079 * start writing MSB first
1080 * set TESTDIN[7:0] to the desired test data appropriate
1081 * to the chosen test mode
1083 for (i = data_length; i > 0; i--) {
1084 mipi_dsih_dphy_test_data_in(phy, data[i - 1]);
1086 * pulse TESTCLK high to capture this test data
1087 * into the macrocell; repeat these two steps as necessary
1089 mipi_dsih_dphy_test_clock(phy, 1);
1090 mipi_dsih_dphy_test_clock(phy, 0);
1096 * Write to whole register to D-PHY module (encapsulating the bus interface)
1097 * @param phy pointer to structure which holds information about the d-phy
1099 * @param reg_address offset
1100 * @param data 32-bit word
1102 void mipi_dsih_dphy_write_word(dphy_t *phy,
1103 u32 reg_address, u32 data)
1105 if (phy->core_write_function)
1106 phy->core_write_function(phy->address,
1111 * Write bit field to D-PHY module (encapsulating the bus interface)
1112 * @param phy pointer to structure which holds information about the d-phy
1114 * @param reg_address offset
1115 * @param data bits to be written to D-PHY
1116 * @param shift from the right hand side of the register (big endian)
1117 * @param width of the bit field
1119 void mipi_dsih_dphy_write_part(dphy_t *phy,
1120 u32 reg_address, u32 data,
1126 if (phy->core_read_function) {
1127 mask = (1 << width) - 1;
1128 temp = mipi_dsih_dphy_read_word(phy, reg_address);
1129 temp &= ~(mask << shift);
1130 temp |= (data & mask) << shift;
1131 mipi_dsih_dphy_write_word(phy, reg_address, temp);
1136 * Read whole register from D-PHY module (encapsulating the bus interface)
1137 * @param phy pointer to structure which holds information about the d-phy
1139 * @param reg_address offset
1140 * @return data 32-bit word
1142 u32 mipi_dsih_dphy_read_word(dphy_t *phy, u32 reg_address)
1144 if (!phy->core_read_function)
1145 return ERR_DSI_INVALID_IO;
1147 return phy->core_read_function(phy->address, reg_address);
1151 * Read bit field from D-PHY module (encapsulating the bus interface)
1152 * @param phy pointer to structure which holds information about the d-phy
1154 * @param reg_address offset
1155 * @param shift from the right hand side of the register (big endian)
1156 * @param width of the bit field
1157 * @return data bits to be written to D-PHY
1159 u32 mipi_dsih_dphy_read_part(dphy_t *phy,
1164 return (mipi_dsih_dphy_read_word(phy, reg_address) >> shift)
1165 & ((1 << width) - 1);