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, ®);
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 }