• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_mipi_dsi_phy_drv.h"
9 
10 typedef struct mipi_phy_clk_reg {
11     uint32_t rate; /*!< rate[2:0] */
12     uint32_t pll_div; /*!< pll_div[14:0] */
13 } mipi_phy_clk_reg_t;
14 
15 #define MIPI_DSI_PHY_RATE_MAX 4
16 #define MIPI_DSI_PHY_REFCLK_FREQ_MHZ 24UL
17 #define MIPI_DSI_PHY_VCO_FREQ_MAX 4000UL
18 #define MIPI_DSI_PHY_PHY_VCO_FREQ_MIN 1600UL
19 
mipi_pll_get_cfg(uint32_t lane_mbps,mipi_phy_clk_reg_t * reg)20 hpm_stat_t mipi_pll_get_cfg(uint32_t lane_mbps, mipi_phy_clk_reg_t *reg)
21 {
22     uint32_t fvco_freq_mhz = lane_mbps;
23     uint32_t fvco_fraction_freq_mhz;
24     uint32_t rate = 0;
25     uint32_t pll_div_integer; /*pll_div[14:10]*/
26     uint32_t pll_div_fraction; /*pll_div[9:0]*/
27 
28     while (fvco_freq_mhz < MIPI_DSI_PHY_PHY_VCO_FREQ_MIN) {
29         rate++;
30         fvco_freq_mhz = lane_mbps * (1<<rate);
31     }
32 
33     if (rate > 4) {
34         return status_invalid_argument;
35     }
36 
37     pll_div_integer = fvco_freq_mhz / 8 / MIPI_DSI_PHY_REFCLK_FREQ_MHZ;
38     fvco_fraction_freq_mhz = fvco_freq_mhz - (pll_div_integer * 8 * MIPI_DSI_PHY_REFCLK_FREQ_MHZ);
39     pll_div_fraction = (fvco_fraction_freq_mhz * 1024 + (8 * MIPI_DSI_PHY_REFCLK_FREQ_MHZ) / 2) /\
40                          (8 * MIPI_DSI_PHY_REFCLK_FREQ_MHZ);
41 
42     reg->rate = rate;
43     reg->pll_div = pll_div_integer<<10 | pll_div_fraction;
44 
45     return status_success;
46 }
47 
mipi_dsi_phy_pll_init(MIPI_DSI_PHY_Type * ptr,uint32_t lane_mbps)48 static bool mipi_dsi_phy_pll_init(MIPI_DSI_PHY_Type *ptr, uint32_t lane_mbps)
49 {
50     hpm_stat_t state;
51     mipi_phy_clk_reg_t reg;
52     state = mipi_pll_get_cfg(lane_mbps, &reg);
53     if (state == status_invalid_argument)
54         return false;
55 
56 
57     ptr->PLL_CTRL_PARA0 = (HPM_MIPI_DSI_PHY0->PLL_CTRL_PARA0 &\
58                             ~(MIPI_DSI_PHY_PLL_CTRL_PARA0_RATE_MASK |
59                                 MIPI_DSI_PHY_PLL_CTRL_PARA0_REFCLK_DIV_MASK |
60                                 MIPI_DSI_PHY_PLL_CTRL_PARA0_PLL_DIV_MASK)) |
61                                 MIPI_DSI_PHY_PLL_CTRL_PARA0_RATE_SET(reg.rate) |
62                                 MIPI_DSI_PHY_PLL_CTRL_PARA0_REFCLK_DIV_SET(0) |
63                                 MIPI_DSI_PHY_PLL_CTRL_PARA0_PLL_DIV_SET(reg.pll_div);
64     return true;
65 }
66 
mipi_dsi_phy_init(MIPI_DSI_PHY_Type * ptr,mipi_dsi_phy_config_t * cfg)67 void mipi_dsi_phy_init(MIPI_DSI_PHY_Type *ptr, mipi_dsi_phy_config_t *cfg)
68 {
69     uint32_t byteclk_period_ps = 1000000u / (cfg->lane_mbps / 8);
70     uint32_t ui_ps = 1000000u / cfg->lane_mbps;
71 
72     ptr->TEST_PARA0 |= 1u<<3;
73     mipi_dsi_phy_pll_init(ptr, cfg->lane_mbps);
74     ptr->MISC_PARA = (ptr->MISC_PARA & ~(MIPI_DSI_PHY_MISC_PARA_LANE_NUM_MASK)) |
75                         MIPI_DSI_PHY_MISC_PARA_LANE_NUM_SET(cfg->lanes - 1);
76 
77     uint32_t tlpx_ps = 50 * 1000; /* min: 50ns */
78     ptr->COMMON_PARA0 = HPM_DIV_ROUND_UP(tlpx_ps, byteclk_period_ps) - 1;
79 
80     uint32_t tclk_prepare_ps = (38 + 95) * 1000 / 2; /* min: 38ns, max: 95ns */
81     uint32_t tclk_zero_ps = 300 * 1000 - tclk_prepare_ps; /* min: 300ns */
82     uint32_t tclk_pre_ps = 8* ui_ps; /* min: 8 * UI */
83     uint32_t t_clk_post_ps = 60 * 1000 + 52 * ui_ps; /* min: 60ns + 52 * UI */
84     uint32_t t_clk_trail_ps = 60 * 1000; /* min: 60ns */
85     uint32_t t_hs_exit_ps = 100 * 1000; /* min: 100ns */
86 
87     ptr->CLANE_PARA2 = MIPI_DSI_PHY_CLANE_PARA2_T_CLKPREPARE_C_SET(HPM_DIV_ROUND_UP(tclk_prepare_ps, byteclk_period_ps) - 1) |
88             MIPI_DSI_PHY_CLANE_PARA2_T_CLKZERO_C_SET(HPM_DIV_ROUND_UP(tclk_zero_ps, byteclk_period_ps) - 1) |
89             MIPI_DSI_PHY_CLANE_PARA2_T_CLKPRE_C_SET(HPM_DIV_ROUND_UP(tclk_pre_ps, byteclk_period_ps) - 1);
90 
91     ptr->CLANE_PARA3 = MIPI_DSI_PHY_CLANE_PARA3_T_CLKPOST_C_SET(HPM_DIV_ROUND_UP(t_clk_post_ps, byteclk_period_ps) - 1) |
92             MIPI_DSI_PHY_CLANE_PARA3_T_CLKTRIAL_C_SET(HPM_DIV_ROUND_UP(t_clk_trail_ps, byteclk_period_ps) - 1);
93 
94 
95     uint32_t dlane0_para2;
96     uint32_t ths_prepare_ps = (40 + 85) / 2 * 1000 + (4 + 6) / 2 * ui_ps; /* min: 40ns + 4 * UI, max: 85ns + 6 * UI */
97     uint32_t ths_zero_ps = 145 * 1000 + 10 * ui_ps - ths_prepare_ps; /* min: 145ns + 10 * UI */
98     uint32_t ths_trail_ps0 = 8 * ui_ps;
99     uint32_t ths_trail_ps1 = 60 * 1000 * 4 * ui_ps;
100     uint32_t ths_trail_ps = ths_trail_ps0 > ths_trail_ps1 ? ths_trail_ps0 : ths_trail_ps1;
101 
102     dlane0_para2 = MIPI_DSI_PHY_DLANE0_PARA2_T_HSPREPARE_D0_SET(HPM_DIV_ROUND_UP(ths_prepare_ps, byteclk_period_ps) - 1) |
103                     MIPI_DSI_PHY_DLANE0_PARA2_T_HSZERO_D0_SET(HPM_DIV_ROUND_UP(ths_zero_ps, byteclk_period_ps) - 1) |
104                     MIPI_DSI_PHY_DLANE0_PARA2_T_HSTRAIL_D0_SET(HPM_DIV_ROUND_UP(ths_trail_ps, byteclk_period_ps) - 1) |
105                     MIPI_DSI_PHY_DLANE0_PARA2_T_HSEXIT_D0_SET(HPM_DIV_ROUND_UP(t_hs_exit_ps, byteclk_period_ps) - 1);
106 
107     ptr->DLANE0_PARA2 = dlane0_para2;
108     ptr->DLANE1_PARA2 = dlane0_para2;
109     ptr->DLANE2_PARA2 = dlane0_para2;
110     ptr->DLANE3_PARA2 = dlane0_para2;
111 
112     uint32_t ta_go_ps = 4 * tlpx_ps; /* 4 * Tlpx */
113     uint32_t ta_sure_ps = tlpx_ps; /* min: Tlpx, max: 2 * Tlpx */
114     uint32_t ta_get_ps = 5 * tlpx_ps; /* 4 * Tlpx */
115 
116     ptr->DLANE0_PARA4 = MIPI_DSI_PHY_DLANE0_PARA4_T_TAGO_D0_SET(HPM_DIV_ROUND_UP(ta_go_ps, byteclk_period_ps) - 1) |
117                             MIPI_DSI_PHY_DLANE0_PARA4_T_TASURE_D0_SET(HPM_DIV_ROUND_UP(ta_sure_ps, byteclk_period_ps) - 1) |
118                             MIPI_DSI_PHY_DLANE0_PARA4_T_TAGET_D0_SET(HPM_DIV_ROUND_UP(ta_get_ps, byteclk_period_ps) - 1);
119 
120 }