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_mipi_dsi1_set_data_type(pixelmux_mipi_dsi_data_type_t type)95void pixelmux_mipi_dsi1_set_data_type(pixelmux_mipi_dsi_data_type_t type) 96 { 97 98 HPM_PIXEL_MUX->DSI_SETTING[1] = PIXELMUX_DSI_SETTING_DSI_DATA_ENABLE_SET(0x01u<<type) | 99 PIXELMUX_DSI_SETTING_DSI_DATA_TYPE_SET(type); 100 } 101 pixelmux_mipi_dsi0_set_data_type(pixelmux_mipi_dsi_data_type_t type)102void pixelmux_mipi_dsi0_set_data_type(pixelmux_mipi_dsi_data_type_t type) 103 { 104 105 HPM_PIXEL_MUX->DSI_SETTING[0] = PIXELMUX_DSI_SETTING_DSI_DATA_ENABLE_SET(0x01u<<type) | 106 PIXELMUX_DSI_SETTING_DSI_DATA_TYPE_SET(type); 107 } 108 pixelmux_cam1_data_source_enable(pixelmux_cam1_select_t src)109void pixelmux_cam1_data_source_enable(pixelmux_cam1_select_t src) 110 { 111 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_CAM1_SEL_MASK) | 112 PIXELMUX_PIXMUX_CAM1_EN_MASK | PIXELMUX_PIXMUX_CAM1_SEL_SET(src); 113 HPM_PIXEL_MUX->PIXMUX = reg_val; 114 } 115 pixelmux_cam1_data_source_disable(void)116void pixelmux_cam1_data_source_disable(void) 117 { 118 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_CAM1_EN_MASK; 119 } 120 pixelmux_cam0_data_source_enable(pixelmux_cam0_select_t src)121void pixelmux_cam0_data_source_enable(pixelmux_cam0_select_t src) 122 { 123 uint32_t reg_val = (HPM_PIXEL_MUX->PIXMUX & ~PIXELMUX_PIXMUX_CAM0_SEL_MASK) | 124 PIXELMUX_PIXMUX_CAM0_EN_MASK | PIXELMUX_PIXMUX_CAM0_SEL_SET(src); 125 HPM_PIXEL_MUX->PIXMUX = reg_val; 126 } 127 pixelmux_cam0_data_source_disable(void)128void pixelmux_cam0_data_source_disable(void) 129 { 130 HPM_PIXEL_MUX->PIXMUX &= ~PIXELMUX_PIXMUX_CAM0_EN_MASK; 131 } 132 pixelmux_lvds_phy_calc_pll_cfg(uint32_t pixel_freq_hz,bool is_split,lvds_phy_clk_param_t * param)133hpm_stat_t pixelmux_lvds_phy_calc_pll_cfg(uint32_t pixel_freq_hz, bool is_split, lvds_phy_clk_param_t *param) 134 { 135 uint32_t hsclk_freq_hz; 136 uint32_t data_rate_div4; 137 uint64_t fvco_freq_hz; 138 uint32_t fvco_fraction_freq_hz; 139 uint32_t lvds_rpck = is_split ? pixel_freq_hz / 2 : pixel_freq_hz; 140 uint32_t lane_data_rate_hz = lvds_rpck * 7; 141 uint32_t rate_lvds; 142 uint32_t pfd_freq_hz; 143 uint32_t pll_div_integer; /*pll_div[14:10]*/ 144 uint32_t pll_div_fraction; /*pll_div[9:0]*/ 145 int refclk_div; 146 147 if (lvds_rpck / 16 > PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MAX || 148 lvds_rpck < PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MIN) { 149 return status_invalid_argument; 150 } 151 152 if (lane_data_rate_hz < PIXELMUX_LVDS_TX_PHY_VCO_FREQ_MIN / (8 * 4) || 153 lane_data_rate_hz > PIXELMUX_LVDS_TX_PHY_DATA_LANE_FREQ_MAX) { 154 return status_invalid_argument; 155 } 156 157 data_rate_div4 = 1; 158 if (lane_data_rate_hz > PIXELMUX_LVDS_TX_PHY_VCO_FREQ_MAX / 4) { 159 data_rate_div4 = 0; 160 } 161 162 hsclk_freq_hz = data_rate_div4 ? lane_data_rate_hz * 4 : lane_data_rate_hz; 163 rate_lvds = 0; 164 fvco_freq_hz = 0; 165 while (rate_lvds <= 3) { 166 fvco_freq_hz = (uint64_t)hsclk_freq_hz * (1<<rate_lvds); 167 if (fvco_freq_hz >= PIXELMUX_LVDS_TX_PHY_VCO_FREQ_MIN) { 168 break; 169 } 170 rate_lvds++; 171 } 172 173 if (rate_lvds > 3 || fvco_freq_hz > PIXELMUX_LVDS_TX_PHY_VCO_FREQ_MAX) { 174 return status_invalid_argument; 175 } 176 177 refclk_div = 15; 178 pfd_freq_hz = 0; 179 while (refclk_div >= 0) { 180 pfd_freq_hz = lvds_rpck / (refclk_div + 1); 181 if (pfd_freq_hz >= PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MIN) { 182 break; 183 } 184 refclk_div--; 185 } 186 187 if (refclk_div < 0 || pfd_freq_hz < PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MIN) { 188 return status_invalid_argument; 189 } 190 191 while (refclk_div >= 0 && pfd_freq_hz < PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MAX) { 192 pfd_freq_hz = lvds_rpck / (refclk_div + 1); 193 if (fvco_freq_hz / 8 / pfd_freq_hz <= 23) { 194 break; 195 } 196 refclk_div--; 197 } 198 199 if (refclk_div < 0 || pfd_freq_hz > PIXELMUX_LVDS_TX_PHY_PFD_FREQ_MAX || 200 (fvco_freq_hz / 8 / pfd_freq_hz) > 23 || (fvco_freq_hz / 8 / pfd_freq_hz) < 6) { 201 return status_invalid_argument; 202 } 203 204 pll_div_integer = fvco_freq_hz / 8 / pfd_freq_hz; 205 fvco_fraction_freq_hz = fvco_freq_hz - pfd_freq_hz * pll_div_integer * 8; 206 pll_div_fraction = (fvco_fraction_freq_hz * 1024) / 8 / pfd_freq_hz; 207 208 param->reg.rate_lvds = rate_lvds; 209 param->reg.data_rate_div4 = data_rate_div4; 210 param->reg.refclk_div = refclk_div; 211 param->reg.pll_div = pll_div_integer<<10 | pll_div_fraction; 212 param->fvco_freq_hz = fvco_freq_hz; 213 param->pfd_freq_hz = pfd_freq_hz; 214 param->lane_data_rate_hz = lane_data_rate_hz; 215 param->hsclk_freq_hz = hsclk_freq_hz; 216 217 return status_success; 218 } 219 pixelmux_config_tx_phy0_mode(pixelmux_tx_phy_mode_t mode)220void pixelmux_config_tx_phy0_mode(pixelmux_tx_phy_mode_t mode) 221 { 222 HPM_PIXEL_MUX->GPR_WR_D2 = (HPM_PIXEL_MUX->GPR_WR_D2 & 223 ~PIXELMUX_GPR_WR_D2_TX_PHY0_PHY_MODE_MASK) | 224 PIXELMUX_GPR_WR_D2_TX_PHY0_PHY_MODE_SET(mode); 225 } 226 pixelmux_config_tx_phy1_mode(pixelmux_tx_phy_mode_t mode)227void pixelmux_config_tx_phy1_mode(pixelmux_tx_phy_mode_t mode) 228 { 229 HPM_PIXEL_MUX->GPR_WR_D5 = (HPM_PIXEL_MUX->GPR_WR_D5 & 230 ~PIXELMUX_GPR_WR_D5_TX_PHY1_PHY_MODE_MASK) | 231 PIXELMUX_GPR_WR_D5_TX_PHY1_PHY_MODE_SET(mode); 232 } 233 pixelmux_config_lvds_tx_phy0_clk(const lvds_phy_clk_reg_t * clk_reg)234void pixelmux_config_lvds_tx_phy0_clk(const lvds_phy_clk_reg_t *clk_reg) 235 { 236 HPM_PIXEL_MUX->GPR_WR_D2 = (HPM_PIXEL_MUX->GPR_WR_D2 & 237 ~(PIXELMUX_GPR_WR_D2_TX_PHY0_PORT_PLL_RDY_SEL_MASK | 238 PIXELMUX_GPR_WR_D2_TX_PHY0_RATE_LVDS_MASK | 239 PIXELMUX_GPR_WR_D2_TX_PHY0_PLL_DIV_MASK | 240 PIXELMUX_GPR_WR_D2_TX_PHY0_REFCLK_DIV_MASK)) | 241 PIXELMUX_GPR_WR_D2_TX_PHY0_RATE_LVDS_SET(clk_reg->rate_lvds) | 242 PIXELMUX_GPR_WR_D2_TX_PHY0_REFCLK_DIV_SET(clk_reg->refclk_div) | 243 PIXELMUX_GPR_WR_D2_TX_PHY0_PLL_DIV_SET(clk_reg->pll_div); 244 245 /* 246 * lvds_rpck/refclk control signal 247 * 0: normal 248 * 1: inverter 249 */ 250 HPM_PIXEL_MUX->GPR_WR_D3 &= ~(0x01ul<<29); 251 252 /* 253 * ckphy_ctl[2:0]:CLK_PHY divide ratio select, must be 010:div7 254 * ckphy_ctl[8]:div4 enable signal 255 */ 256 HPM_PIXEL_MUX->GPR_WR_D4 = (HPM_PIXEL_MUX->GPR_WR_D4 & ~PIXELMUX_GPR_WR_D4_TX_PHY0_CKPHY_CTL_MASK) | 257 PIXELMUX_GPR_WR_D4_TX_PHY0_CKPHY_CTL_SET((clk_reg->data_rate_div4 & 0x01)<<8 | 0x02); 258 } 259 pixelmux_config_lvds_tx_phy1_clk(const lvds_phy_clk_reg_t * clk_reg)260void pixelmux_config_lvds_tx_phy1_clk(const lvds_phy_clk_reg_t *clk_reg) 261 { 262 HPM_PIXEL_MUX->GPR_WR_D5 = (HPM_PIXEL_MUX->GPR_WR_D5 & 263 ~(PIXELMUX_GPR_WR_D5_TX_PHY1_PORT_PLL_RDY_SEL_MASK | 264 PIXELMUX_GPR_WR_D5_TX_PHY1_RATE_LVDS_MASK | 265 PIXELMUX_GPR_WR_D5_TX_PHY1_PLL_DIV_MASK | 266 PIXELMUX_GPR_WR_D5_TX_PHY1_REFCLK_DIV_MASK)) | 267 PIXELMUX_GPR_WR_D5_TX_PHY1_RATE_LVDS_SET(clk_reg->rate_lvds) | 268 PIXELMUX_GPR_WR_D5_TX_PHY1_REFCLK_DIV_SET(clk_reg->refclk_div) | 269 PIXELMUX_GPR_WR_D5_TX_PHY1_PLL_DIV_SET(clk_reg->pll_div); 270 /* 271 * lvds_rpck/refclk control signal 272 * 0: normal 273 * 1: inverter 274 */ 275 HPM_PIXEL_MUX->GPR_WR_D6 &= ~(0x01ul<<29); 276 277 /* 278 * ckphy_ctl[2:0]:CLK_PHY divide ratio select, must be 010:div7 279 * ckphy_ctl[8]:div4 enable signal 280 */ 281 HPM_PIXEL_MUX->GPR_WR_D7 = (HPM_PIXEL_MUX->GPR_WR_D7 & ~PIXELMUX_GPR_WR_D7_TX_PHY1_CKPHY_CTL_MASK) | 282 PIXELMUX_GPR_WR_D7_TX_PHY1_CKPHY_CTL_SET((clk_reg->data_rate_div4 & 0x01)<<8 | 0x02); 283 } 284 pixelmux_config_rx_phy0_mode(pixelmux_rx_phy_mode_t mode)285void pixelmux_config_rx_phy0_mode(pixelmux_rx_phy_mode_t mode) 286 { 287 HPM_PIXEL_MUX->GPR_WR_D8 = (HPM_PIXEL_MUX->GPR_WR_D8 & 288 ~PIXELMUX_GPR_WR_D8_RX_PHY0_PHY_MODE_MASK) | 289 PIXELMUX_GPR_WR_D8_RX_PHY0_PHY_MODE_SET(mode); 290 } 291 pixelmux_config_rx_phy1_mode(pixelmux_rx_phy_mode_t mode)292void pixelmux_config_rx_phy1_mode(pixelmux_rx_phy_mode_t mode) 293 { 294 HPM_PIXEL_MUX->GPR_WR_D9 = (HPM_PIXEL_MUX->GPR_WR_D9 & 295 ~PIXELMUX_GPR_WR_D9_RX_PHY1_PHY_MODE_MASK) | 296 PIXELMUX_GPR_WR_D9_RX_PHY1_PHY_MODE_SET(mode); 297 }