1 /* 2 * Copyright (c) 2023 HPMicro 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 */ 7 8 #include "hpm_common.h" 9 #include "hpm_pixelmux_drv.h" 10 pixelmux_rgb_data_source_enable(pixelmux_rgb_select_t src)11void pixelmux_rgb_data_source_enable(pixelmux_rgb_select_t src) 12 { 13 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_RGB_SEL_MASK) | 14 PIXELMUX_PIXMUX_RGB_EN_MASK | PIXELMUX_PIXMUX_RGB_SEL_SET(src); 15 HPM_PIXEL_MUX->PIXMUX = reg_val; 16 } 17 pixelmux_rgb_data_source_disable(void)18void pixelmux_rgb_data_source_disable(void) 19 { 20 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_RGB_SEL_MASK; 21 } 22 pixelmux_gwc1_data_source_enable(pixelmux_gwc1_select_t src)23void pixelmux_gwc1_data_source_enable(pixelmux_gwc1_select_t src) 24 { 25 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_GWC1_SEL_MASK) | 26 PIXELMUX_PIXMUX_GWC1_EN_MASK | PIXELMUX_PIXMUX_GWC1_SEL_SET(src); 27 HPM_PIXEL_MUX->PIXMUX = reg_val; 28 } 29 pixelmux_gwc1_data_source_disable(void)30void pixelmux_gwc1_data_source_disable(void) 31 { 32 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_GWC1_EN_MASK; 33 } 34 pixelmux_gwc0_data_source_enable(pixelmux_gwc0_select_t src)35void pixelmux_gwc0_data_source_enable(pixelmux_gwc0_select_t src) 36 { 37 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_GWC0_SEL_MASK) | 38 PIXELMUX_PIXMUX_GWC0_EN_MASK | PIXELMUX_PIXMUX_GWC0_SEL_SET(src); 39 HPM_PIXEL_MUX->PIXMUX = reg_val; 40 } 41 pixelmux_gwc0_data_source_disable(void)42void pixelmux_gwc0_data_source_disable(void) 43 { 44 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_GWC0_EN_MASK; 45 } 46 pixelmux_lvb_di1_data_source_enable(pixelmux_lvb_di1_select_t src)47void pixelmux_lvb_di1_data_source_enable(pixelmux_lvb_di1_select_t src) 48 { 49 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_LVB_DI1_SEL_MASK) | 50 PIXELMUX_PIXMUX_LVB_DI1_EN_MASK | PIXELMUX_PIXMUX_LVB_DI1_SEL_SET(src); 51 HPM_PIXEL_MUX->PIXMUX = reg_val; 52 } 53 pixelmux_lvb_di1_data_source_disable(void)54void pixelmux_lvb_di1_data_source_disable(void) 55 { 56 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_LVB_DI1_EN_MASK; 57 } 58 pixelmux_lvb_di0_data_source_enable(pixelmux_lvb_di0_select_t src)59void pixelmux_lvb_di0_data_source_enable(pixelmux_lvb_di0_select_t src) 60 { 61 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_LVB_DI0_SEL_MASK) | 62 PIXELMUX_PIXMUX_LVB_DI0_EN_MASK | PIXELMUX_PIXMUX_LVB_DI0_SEL_SET(src); 63 HPM_PIXEL_MUX->PIXMUX = reg_val; 64 } 65 pixelmux_lvb_di0_data_source_disable(void)66void pixelmux_lvb_di0_data_source_disable(void) 67 { 68 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_LVB_DI0_EN_MASK; 69 } 70 pixelmux_mipi_dsi1_data_source_enable(pixelmux_mipi_dsi1_select_t src)71void pixelmux_mipi_dsi1_data_source_enable(pixelmux_mipi_dsi1_select_t src) 72 { 73 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_DSI1_SEL_MASK) | 74 PIXELMUX_PIXMUX_DSI1_EN_MASK | PIXELMUX_PIXMUX_DSI1_SEL_SET(src); 75 HPM_PIXEL_MUX->PIXMUX = reg_val; 76 } 77 pixelmux_mipi_dsi1_data_source_disable(void)78void pixelmux_mipi_dsi1_data_source_disable(void) 79 { 80 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_DSI1_EN_MASK; 81 } 82 pixelmux_mipi_dsi0_data_source_enable(pixelmux_mipi_dsi0_select_t src)83void pixelmux_mipi_dsi0_data_source_enable(pixelmux_mipi_dsi0_select_t src) 84 { 85 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_DSI0_SEL_MASK) | 86 PIXELMUX_PIXMUX_DSI0_EN_MASK | PIXELMUX_PIXMUX_DSI0_SEL_SET(src); 87 HPM_PIXEL_MUX->PIXMUX = reg_val; 88 } 89 pixelmux_mipi_dsi0_data_source_disable(void)90void pixelmux_mipi_dsi0_data_source_disable(void) 91 { 92 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_DSI0_EN_MASK; 93 } 94 pixelmux_cam1_data_source_enable(pixelmux_cam1_select_t src)95void pixelmux_cam1_data_source_enable(pixelmux_cam1_select_t src) 96 { 97 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_CAM1_SEL_MASK) | 98 PIXELMUX_PIXMUX_CAM1_EN_MASK | PIXELMUX_PIXMUX_CAM1_SEL_SET(src); 99 HPM_PIXEL_MUX->PIXMUX = reg_val; 100 } 101 pixelmux_cam1_data_source_disable(void)102void pixelmux_cam1_data_source_disable(void) 103 { 104 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_CAM1_EN_MASK; 105 } 106 pixelmux_cam0_data_source_enable(pixelmux_cam0_select_t src)107void pixelmux_cam0_data_source_enable(pixelmux_cam0_select_t src) 108 { 109 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_CAM0_SEL_MASK) | 110 PIXELMUX_PIXMUX_CAM0_EN_MASK | PIXELMUX_PIXMUX_CAM0_SEL_SET(src); 111 HPM_PIXEL_MUX->PIXMUX = reg_val; 112 } 113 pixelmux_cam0_data_source_disable(void)114void pixelmux_cam0_data_source_disable(void) 115 { 116 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_CAM0_EN_MASK; 117 } 118 pixelmux_lvds_phy_calc_pll_cfg(uint32_t pixel_freq_hz,bool is_split,lvds_phy_clk_param_t * param)119hpm_stat_t pixelmux_lvds_phy_calc_pll_cfg(uint32_t pixel_freq_hz, bool is_split, lvds_phy_clk_param_t *param) 120 { 121 uint32_t hsclk_freq_hz; 122 uint32_t data_rate_div4; 123 uint64_t fvco_freq_hz; 124 uint32_t fvco_fraction_freq_hz; 125 uint32_t lvds_rpck = is_split ? pixel_freq_hz / 2 : pixel_freq_hz; 126 uint32_t lane_data_rate_hz = lvds_rpck * 7; 127 uint32_t rate_lvds; 128 uint32_t pfd_freq_hz; 129 uint32_t pll_div_integer; /*pll_div[14:10]*/ 130 uint32_t pll_div_fraction; /*pll_div[9:0]*/ 131 int refclk_div; 132 133 if (lvds_rpck / 16 > PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MAX || 134 lvds_rpck < PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MIN) { 135 return status_invalid_argument; 136 } 137 138 if (lane_data_rate_hz < PIXELMUX_LVDS_TX_PHY_VCO_FREQ_MIN / (8 * 4) || 139 lane_data_rate_hz > PIXELMUX_LVDS_TX_PHY_DATA_LANE_FREQ_MAX) { 140 return status_invalid_argument; 141 } 142 143 data_rate_div4 = 1; 144 if (lane_data_rate_hz > PIXELMUX_LVDS_TX_PHY_VCO_FREQ_MAX / 4) { 145 data_rate_div4 = 0; 146 } 147 148 hsclk_freq_hz = data_rate_div4 ? lane_data_rate_hz * 4 : lane_data_rate_hz; 149 rate_lvds = 0; 150 fvco_freq_hz = 0; 151 while (rate_lvds <= 3) { 152 fvco_freq_hz = (uint64_t)hsclk_freq_hz * (1<<rate_lvds); 153 if (fvco_freq_hz >= PIXELMUX_LVDS_TX_PHY_VCO_FREQ_MIN) { 154 break; 155 } 156 rate_lvds++; 157 } 158 159 if (rate_lvds > 3 || fvco_freq_hz > PIXELMUX_LVDS_TX_PHY_VCO_FREQ_MAX) { 160 return status_invalid_argument; 161 } 162 163 refclk_div = 15; 164 pfd_freq_hz = 0; 165 while (refclk_div >= 0) { 166 pfd_freq_hz = lvds_rpck / (refclk_div + 1); 167 if (pfd_freq_hz >= PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MIN) { 168 break; 169 } 170 refclk_div--; 171 } 172 173 if (refclk_div < 0 || pfd_freq_hz < PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MIN) { 174 return status_invalid_argument; 175 } 176 177 while (refclk_div >= 0 && pfd_freq_hz < PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MAX) { 178 pfd_freq_hz = lvds_rpck / (refclk_div + 1); 179 if (fvco_freq_hz / 8 / pfd_freq_hz <= 23) { 180 break; 181 } 182 refclk_div--; 183 } 184 185 if (refclk_div < 0 || pfd_freq_hz > PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MAX || 186 (fvco_freq_hz / 8 / pfd_freq_hz) > 23 || (fvco_freq_hz / 8 / pfd_freq_hz) < 6) { 187 return status_invalid_argument; 188 } 189 190 pll_div_integer = fvco_freq_hz / 8 / pfd_freq_hz; 191 fvco_fraction_freq_hz = fvco_freq_hz - pfd_freq_hz * pll_div_integer * 8; 192 pll_div_fraction = (fvco_fraction_freq_hz * 1024) / 8 / pfd_freq_hz; 193 194 param->reg.rate_lvds = rate_lvds; 195 param->reg.data_rate_div4 = data_rate_div4; 196 param->reg.refclk_div = refclk_div; 197 param->reg.pll_div = pll_div_integer<<10 | pll_div_fraction; 198 param->fvco_freq_hz = fvco_freq_hz; 199 param->pfd_freq_hz = pfd_freq_hz; 200 param->lane_data_rate_hz = lane_data_rate_hz; 201 param->hsclk_freq_hz = hsclk_freq_hz; 202 203 return status_success; 204 } 205 pixelmux_config_tx_phy0_mode(pixelmux_tx_phy_mode_t mode)206void pixelmux_config_tx_phy0_mode(pixelmux_tx_phy_mode_t mode) 207 { 208 HPM_PIXEL_MUX->GPR_WR_D2 = (HPM_PIXEL_MUX->GPR_WR_D2 & 209 ~PIXELMUX_GPR_WR_D2_TX_PHY0_PHY_MODE_MASK) | 210 PIXELMUX_GPR_WR_D2_TX_PHY0_PHY_MODE_SET(mode); 211 } 212 pixelmux_config_tx_phy1_mode(pixelmux_tx_phy_mode_t mode)213void pixelmux_config_tx_phy1_mode(pixelmux_tx_phy_mode_t mode) 214 { 215 HPM_PIXEL_MUX->GPR_WR_D5 = (HPM_PIXEL_MUX->GPR_WR_D5 & 216 ~PIXELMUX_GPR_WR_D5_TX_PHY1_PHY_MODE_MASK) | 217 PIXELMUX_GPR_WR_D5_TX_PHY1_PHY_MODE_SET(mode); 218 } 219 pixelmux_config_lvds_tx_phy0_clk(const lvds_phy_clk_reg_t * clk_reg)220void pixelmux_config_lvds_tx_phy0_clk(const lvds_phy_clk_reg_t *clk_reg) 221 { 222 HPM_PIXEL_MUX->GPR_WR_D2 = (HPM_PIXEL_MUX->GPR_WR_D2 & 223 ~(PIXELMUX_GPR_WR_D2_TX_PHY0_PORT_PLL_RDY_SEL_MASK | 224 PIXELMUX_GPR_WR_D2_TX_PHY0_RATE_LVDS_MASK | 225 PIXELMUX_GPR_WR_D2_TX_PHY0_PLL_DIV_MASK | 226 PIXELMUX_GPR_WR_D2_TX_PHY0_REFCLK_DIV_MASK)) | 227 PIXELMUX_GPR_WR_D2_TX_PHY0_RATE_LVDS_SET(clk_reg->rate_lvds) | 228 PIXELMUX_GPR_WR_D2_TX_PHY0_REFCLK_DIV_SET(clk_reg->refclk_div) | 229 PIXELMUX_GPR_WR_D2_TX_PHY0_PLL_DIV_SET(clk_reg->pll_div); 230 231 /* 232 * lvds_rpck/refclk control signal 233 * 0: normal 234 * 1: inverter 235 */ 236 HPM_PIXEL_MUX->GPR_WR_D3 &= ~(0x01ul<<29); 237 238 /* 239 * ckphy_ctl[2:0]:CLK_PHY divide ratio select, must be 010:div7 240 * ckphy_ctl[8]:div4 enable signal 241 */ 242 HPM_PIXEL_MUX->GPR_WR_D4 = (HPM_PIXEL_MUX->GPR_WR_D4 & ~PIXELMUX_GPR_WR_D4_TX_PHY0_CKPHY_CTL_MASK) | 243 PIXELMUX_GPR_WR_D4_TX_PHY0_CKPHY_CTL_SET((clk_reg->data_rate_div4 & 0x01)<<8 | 0x02); 244 } 245 pixelmux_config_lvds_tx_phy1_clk(const lvds_phy_clk_reg_t * clk_reg)246void pixelmux_config_lvds_tx_phy1_clk(const lvds_phy_clk_reg_t *clk_reg) 247 { 248 HPM_PIXEL_MUX->GPR_WR_D5 = (HPM_PIXEL_MUX->GPR_WR_D5 & 249 ~(PIXELMUX_GPR_WR_D5_TX_PHY1_PORT_PLL_RDY_SEL_MASK | 250 PIXELMUX_GPR_WR_D5_TX_PHY1_RATE_LVDS_MASK | 251 PIXELMUX_GPR_WR_D5_TX_PHY1_PLL_DIV_MASK | 252 PIXELMUX_GPR_WR_D5_TX_PHY1_REFCLK_DIV_MASK)) | 253 PIXELMUX_GPR_WR_D5_TX_PHY1_RATE_LVDS_SET(clk_reg->rate_lvds) | 254 PIXELMUX_GPR_WR_D5_TX_PHY1_REFCLK_DIV_SET(clk_reg->refclk_div) | 255 PIXELMUX_GPR_WR_D5_TX_PHY1_PLL_DIV_SET(clk_reg->pll_div); 256 /* 257 * lvds_rpck/refclk control signal 258 * 0: normal 259 * 1: inverter 260 */ 261 HPM_PIXEL_MUX->GPR_WR_D6 &= ~(0x01ul<<29); 262 263 /* 264 * ckphy_ctl[2:0]:CLK_PHY divide ratio select, must be 010:div7 265 * ckphy_ctl[8]:div4 enable signal 266 */ 267 HPM_PIXEL_MUX->GPR_WR_D7 = (HPM_PIXEL_MUX->GPR_WR_D7 & ~PIXELMUX_GPR_WR_D7_TX_PHY1_CKPHY_CTL_MASK) | 268 PIXELMUX_GPR_WR_D7_TX_PHY1_CKPHY_CTL_SET((clk_reg->data_rate_div4 & 0x01)<<8 | 0x02); 269 } 270 pixelmux_config_rx_phy0_mode(pixelmux_rx_phy_mode_t mode)271void pixelmux_config_rx_phy0_mode(pixelmux_rx_phy_mode_t mode) 272 { 273 HPM_PIXEL_MUX->GPR_WR_D8 = (HPM_PIXEL_MUX->GPR_WR_D8 & 274 ~PIXELMUX_GPR_WR_D8_RX_PHY0_PHY_MODE_MASK) | 275 PIXELMUX_GPR_WR_D8_RX_PHY0_PHY_MODE_SET(mode); 276 } 277 pixelmux_config_rx_phy1_mode(pixelmux_rx_phy_mode_t mode)278void pixelmux_config_rx_phy1_mode(pixelmux_rx_phy_mode_t mode) 279 { 280 HPM_PIXEL_MUX->GPR_WR_D9 = (HPM_PIXEL_MUX->GPR_WR_D9 & 281 ~PIXELMUX_GPR_WR_D9_RX_PHY1_PHY_MODE_MASK) | 282 PIXELMUX_GPR_WR_D9_RX_PHY1_PHY_MODE_SET(mode); 283 }