Angel Pons | e67ab18 | 2020-04-04 18:51:11 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Hsin-Hsiung Wang | a6db8f3 | 2018-10-24 17:57:55 +0800 | [diff] [blame] | 2 | |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 3 | #include <device/mmio.h> |
Hsin-Hsiung Wang | a6db8f3 | 2018-10-24 17:57:55 +0800 | [diff] [blame] | 4 | #include <soc/infracfg.h> |
| 5 | #include <soc/pll.h> |
| 6 | #include <soc/pmic_wrap.h> |
Elyes HAOUAS | add76f9 | 2019-03-21 09:55:49 +0100 | [diff] [blame] | 7 | #include <timer.h> |
Hsin-Hsiung Wang | a6db8f3 | 2018-10-24 17:57:55 +0800 | [diff] [blame] | 8 | |
| 9 | #define PRIORITY_FIELD(x) ((x % 4) * 8) |
| 10 | #define PRIORITY_IN(id, priority) (id << PRIORITY_FIELD(priority)) |
| 11 | #define PRIORITY_OUT(id, priority) (priority << PRIORITY_FIELD(id)) |
| 12 | |
| 13 | enum { |
| 14 | MD_ADCINF0 = 8, |
| 15 | MD_ADCINF1 = 9, |
| 16 | STAUPD = 10, |
| 17 | GPSINF0 = 11, |
| 18 | |
| 19 | PRIORITY_IN_SEL_2 = PRIORITY_IN(MD_ADCINF0, 9) | |
| 20 | PRIORITY_IN(MD_ADCINF1, 10) | |
| 21 | PRIORITY_IN(STAUPD, 8) | |
| 22 | PRIORITY_IN(GPSINF0, 11), |
| 23 | |
| 24 | PRIORITY_OUT_SEL_2 = PRIORITY_OUT(MD_ADCINF0, 9) | |
| 25 | PRIORITY_OUT(MD_ADCINF1, 10) | |
| 26 | PRIORITY_OUT(STAUPD, 8) | |
| 27 | PRIORITY_OUT(GPSINF0, 11), |
| 28 | }; |
| 29 | |
| 30 | #define PENDING_US(x) x |
| 31 | enum { |
| 32 | STARVE_ENABLE = 0x1 << 10, |
| 33 | COUNTER0_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x2), |
| 34 | COUNTER1_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x3), |
| 35 | COUNTER2_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x3), |
| 36 | COUNTER3_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x3), |
| 37 | COUNTER4_PENDING_THRES = STARVE_ENABLE | PENDING_US(0xf), |
| 38 | COUNTER5_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x20), |
| 39 | COUNTER6_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x28), |
| 40 | COUNTER7_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x28), |
| 41 | COUNTER8_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x13), |
| 42 | COUNTER9_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x17), |
| 43 | COUNTER10_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x17), |
| 44 | COUNTER11_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x7c), |
| 45 | COUNTER12_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x7c), |
| 46 | COUNTER13_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x340), |
| 47 | COUNTER16_PENDING_THRES = STARVE_ENABLE | PENDING_US(0x340), |
| 48 | }; |
| 49 | |
Hsin-Hsiung Wang | a6db8f3 | 2018-10-24 17:57:55 +0800 | [diff] [blame] | 50 | static void pwrap_soft_reset(void) |
| 51 | { |
| 52 | write32(&mt8183_infracfg->infra_globalcon_rst2_set, 0x1); |
| 53 | write32(&mt8183_infracfg->infra_globalcon_rst2_clr, 0x1); |
| 54 | } |
| 55 | |
| 56 | static void pwrap_spi_clk_set(void) |
| 57 | { |
| 58 | write32(&mtk_topckgen->clk_cfg_5_clr, |
| 59 | ULPOSC_OFF | ULPOSC_INV | ULPOSC_SEL_1 | ULPOSC_SEL_2); |
| 60 | write32(&mtk_topckgen->clk_cfg_5_set, ULPOSC_SEL_1); |
| 61 | write32(&mtk_topckgen->clk_cfg_update, ULPOSC_CLK); |
| 62 | |
| 63 | write32(&mt8183_infracfg->module_sw_cg_0_set, |
| 64 | TIMER_CG | AP_CG | MD_CG | CONN_CG); |
| 65 | write32(&mt8183_infracfg->module_sw_cg_2_set, MODEM_TEMP_SHARE_CG); |
| 66 | |
| 67 | pwrap_soft_reset(); |
| 68 | |
| 69 | write32(&mt8183_infracfg->module_sw_cg_0_clr, |
| 70 | TIMER_CG | AP_CG | MD_CG | CONN_CG); |
| 71 | write32(&mt8183_infracfg->module_sw_cg_2_clr, MODEM_TEMP_SHARE_CG); |
| 72 | } |
| 73 | |
| 74 | static s32 pwrap_init_dio(u16 dio_en) |
| 75 | { |
| 76 | pwrap_write_nochk(PMIC_DEW_DIO_EN, dio_en); |
| 77 | |
| 78 | if (!wait_us(100, |
| 79 | !wait_for_idle_and_sync(read32(&mtk_pwrap->wacs2_rdata)))) |
| 80 | return -1; |
| 81 | |
| 82 | write32(&mtk_pwrap->dio_en, dio_en); |
| 83 | return 0; |
| 84 | } |
| 85 | |
| 86 | static void pwrap_lock_spislvreg(void) |
| 87 | { |
| 88 | pwrap_write_nochk(PMIC_SPISLV_KEY, 0x0); |
| 89 | } |
| 90 | |
| 91 | static void pwrap_initstaupd(void) |
| 92 | { |
| 93 | write32(&mtk_pwrap->staupd_grpen, |
| 94 | SIG_PMIC_0 | INT_STA_PMIC_0 | MD_ADC_DATA0 | |
| 95 | MD_ADC_DATA1 | GPS_ADC_DATA0 | GPS_ADC_DATA1); |
| 96 | |
| 97 | /* CRC */ |
| 98 | pwrap_write_nochk(PMIC_DEW_CRC_EN, 0x1); |
| 99 | write32(&mtk_pwrap->crc_en, 0x1); |
| 100 | write32(&mtk_pwrap->sig_adr, PMIC_DEW_CRC_VAL); |
| 101 | |
| 102 | write32(&mtk_pwrap->eint_sta0_adr, PMIC_CPU_INT_STA); |
| 103 | |
| 104 | /* MD ADC Interface */ |
| 105 | write32(&mtk_pwrap->md_auxadc_rdata_latest_addr, |
| 106 | (PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31); |
| 107 | write32(&mtk_pwrap->md_auxadc_rdata_wp_addr, |
| 108 | (PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31); |
| 109 | for (size_t i = 0; i < 32; i++) |
| 110 | write32(&mtk_pwrap->md_auxadc_rdata[i], |
| 111 | (PMIC_AUXADC_ADC35 << 16) + PMIC_AUXADC_ADC31); |
| 112 | |
| 113 | write32(&mtk_pwrap->int_gps_auxadc_cmd_addr, |
| 114 | (PMIC_AUXADC_RQST1 << 16) + PMIC_AUXADC_RQST0); |
| 115 | write32(&mtk_pwrap->int_gps_auxadc_cmd, (GPS_MAIN << 16) + GPS_SUBSYS); |
| 116 | write32(&mtk_pwrap->int_gps_auxadc_rdata_addr, |
| 117 | (PMIC_AUXADC_ADC32 << 16) + PMIC_AUXADC_ADC17); |
| 118 | |
| 119 | write32(&mtk_pwrap->ext_gps_auxadc_rdata_addr, PMIC_AUXADC_ADC31); |
| 120 | } |
| 121 | |
| 122 | static void pwrap_starve_set(void) |
| 123 | { |
| 124 | write32(&mtk_pwrap->harb_hprio, ARB_PRIORITY); |
| 125 | write32(&mtk_pwrap->starv_counter_0, COUNTER0_PENDING_THRES); |
| 126 | write32(&mtk_pwrap->starv_counter_1, COUNTER1_PENDING_THRES); |
| 127 | write32(&mtk_pwrap->starv_counter_2, COUNTER2_PENDING_THRES); |
| 128 | write32(&mtk_pwrap->starv_counter_3, COUNTER3_PENDING_THRES); |
| 129 | write32(&mtk_pwrap->starv_counter_4, COUNTER4_PENDING_THRES); |
| 130 | write32(&mtk_pwrap->starv_counter_5, COUNTER5_PENDING_THRES); |
| 131 | write32(&mtk_pwrap->starv_counter_6, COUNTER6_PENDING_THRES); |
| 132 | write32(&mtk_pwrap->starv_counter_7, COUNTER7_PENDING_THRES); |
| 133 | write32(&mtk_pwrap->starv_counter_8, COUNTER8_PENDING_THRES); |
| 134 | write32(&mtk_pwrap->starv_counter_9, COUNTER9_PENDING_THRES); |
| 135 | write32(&mtk_pwrap->starv_counter_10, COUNTER10_PENDING_THRES); |
| 136 | write32(&mtk_pwrap->starv_counter_11, COUNTER11_PENDING_THRES); |
| 137 | write32(&mtk_pwrap->starv_counter_12, COUNTER12_PENDING_THRES); |
| 138 | write32(&mtk_pwrap->starv_counter_13, COUNTER13_PENDING_THRES); |
| 139 | write32(&mtk_pwrap->starv_counter_16, COUNTER16_PENDING_THRES); |
| 140 | } |
| 141 | |
| 142 | static void pwrap_enable(void) |
| 143 | { |
| 144 | write32(&mtk_pwrap->hiprio_arb_en, ARB_USER_EN); |
| 145 | write32(&mtk_pwrap->wacs0_en, 0x1); |
| 146 | write32(&mtk_pwrap->wacs2_en, 0x1); |
| 147 | write32(&mtk_pwrap->wacs_p2p_en, 0x1); |
| 148 | write32(&mtk_pwrap->wacs_md32_en, 0x1); |
| 149 | write32(&mtk_pwrap->staupd_ctrl, STA_PD_98_5_US); |
| 150 | write32(&mtk_pwrap->wdt_unit, WATCHDOG_TIMER_7_5_MS); |
| 151 | write32(&mtk_pwrap->wdt_src_en_0, WDT_MONITOR_ALL); |
| 152 | write32(&mtk_pwrap->wdt_src_en_1, WDT_MONITOR_ALL); |
| 153 | write32(&mtk_pwrap->timer_en, 0x1); |
| 154 | write32(&mtk_pwrap->int0_en, INT0_MONITOR); |
| 155 | write32(&mtk_pwrap->int1_en, INT1_MONITOR); |
| 156 | } |
| 157 | |
| 158 | static s32 pwrap_init_sistrobe(void) |
| 159 | { |
| 160 | u16 rdata; |
| 161 | int si_sample_ctrl; |
| 162 | int test_data[30] = { |
| 163 | 0x6996, 0x9669, 0x6996, 0x9669, 0x6996, 0x9669, 0x6996, |
| 164 | 0x9669, 0x6996, 0x9669, 0x5AA5, 0xA55A, 0x5AA5, 0xA55A, |
| 165 | 0x5AA5, 0xA55A, 0x5AA5, 0xA55A, 0x5AA5, 0xA55A, 0x1B27, |
| 166 | 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, 0x1B27, |
| 167 | 0x1B27, 0x1B27}; |
| 168 | |
| 169 | for (si_sample_ctrl = 0; si_sample_ctrl < 16; si_sample_ctrl++) { |
| 170 | write32(&mtk_pwrap->si_sample_ctrl, si_sample_ctrl << 5); |
| 171 | |
| 172 | pwrap_read_nochk(PMIC_DEW_READ_TEST, &rdata); |
| 173 | if (rdata == DEFAULT_VALUE_READ_TEST) |
| 174 | break; |
| 175 | } |
| 176 | |
| 177 | if (si_sample_ctrl == 16) |
| 178 | return E_CLK_EDGE; |
| 179 | |
| 180 | if (si_sample_ctrl == 15) |
| 181 | return E_CLK_LAST_SETTING; |
| 182 | |
| 183 | /* |
| 184 | * Add the delay time of SPI data from PMIC to align the start boundary |
| 185 | * to current sampling clock edge. |
| 186 | */ |
| 187 | for (int si_dly = 0; si_dly < 10; si_dly++) { |
| 188 | pwrap_write_nochk(PMIC_RG_SPI_CON2, si_dly); |
| 189 | |
| 190 | int start_boundary_found = 0; |
| 191 | for (size_t i = 0; i < 30; i++) { |
| 192 | pwrap_write_nochk(PMIC_DEW_WRITE_TEST, test_data[i]); |
| 193 | pwrap_read_nochk(PMIC_DEW_WRITE_TEST, &rdata); |
| 194 | if ((rdata & 0x7fff) != (test_data[i] & 0x7fff)) { |
| 195 | start_boundary_found = 1; |
| 196 | break; |
| 197 | } |
| 198 | } |
| 199 | if (start_boundary_found == 1) |
| 200 | break; |
| 201 | } |
| 202 | |
| 203 | /* |
| 204 | * Change the sampling clock edge to the next one which is the middle |
| 205 | * of SPI data window. |
| 206 | */ |
| 207 | write32(&mtk_pwrap->si_sample_ctrl, ++si_sample_ctrl << 5); |
| 208 | |
| 209 | /* Read Test */ |
| 210 | pwrap_read_nochk(PMIC_DEW_READ_TEST, &rdata); |
| 211 | if (rdata != DEFAULT_VALUE_READ_TEST) { |
| 212 | pwrap_err("rdata = %#x, exp = %#x\n", rdata, |
| 213 | DEFAULT_VALUE_READ_TEST); |
| 214 | return E_PWR_READ_TEST_FAIL; |
| 215 | } |
| 216 | |
| 217 | return 0; |
| 218 | } |
| 219 | |
| 220 | static void pwrap_init_spislv(void) |
| 221 | { |
| 222 | /* Turn on IO filter function */ |
| 223 | pwrap_write_nochk(PMIC_FILTER_CON0, SPI_FILTER); |
| 224 | /* Turn on IO SMT function to improve noise immunity */ |
| 225 | pwrap_write_nochk(PMIC_SMT_CON1, SPI_SMT); |
| 226 | /* Turn off IO pull function for power saving */ |
| 227 | pwrap_write_nochk(PMIC_GPIO_PULLEN0_CLR, SPI_PULL_DISABLE); |
| 228 | /* Enable SPI R/W in suspend mode */ |
| 229 | pwrap_write_nochk(PMIC_RG_SPI_CON0, 0x1); |
| 230 | /* Set PMIC GPIO driving current to 4mA */ |
| 231 | pwrap_write_nochk(PMIC_DRV_CON1, SPI_DRIVING); |
| 232 | } |
| 233 | |
| 234 | static void pwrap_init_reg_clock(void) |
| 235 | { |
| 236 | write32(&mtk_pwrap->ext_ck_write, 0x1); |
| 237 | |
| 238 | pwrap_write_nochk(PMIC_DEW_RDDMY_NO, DUMMY_READ_CYCLES); |
| 239 | write32(&mtk_pwrap->rddmy, DUMMY_READ_CYCLES); |
| 240 | |
| 241 | write32(&mtk_pwrap->cshext_write, 0); |
| 242 | write32(&mtk_pwrap->cshext_read, 0); |
| 243 | write32(&mtk_pwrap->cslext_write, 0); |
| 244 | write32(&mtk_pwrap->cslext_read, 0); |
| 245 | } |
| 246 | |
| 247 | s32 pwrap_init(void) |
| 248 | { |
| 249 | s32 sub_return = 0, sub_return1 = 0; |
| 250 | u16 rdata; |
| 251 | |
| 252 | pwrap_spi_clk_set(); |
| 253 | |
| 254 | /* Reset spislv */ |
| 255 | sub_return = pwrap_reset_spislv(); |
| 256 | if (sub_return != 0) { |
| 257 | pwrap_err("reset_spislv fail, ret=%d\n", sub_return); |
| 258 | return E_PWR_INIT_RESET_SPI; |
| 259 | } |
| 260 | |
| 261 | /* Enable WRAP */ |
| 262 | write32(&mtk_pwrap->wrap_en, 0x1); |
| 263 | |
| 264 | /* Enable WACS2 */ |
| 265 | write32(&mtk_pwrap->wacs2_en, 0x1); |
| 266 | write32(&mtk_pwrap->hiprio_arb_en, WACS2); /* ONLY WACS2 */ |
| 267 | |
| 268 | /* SPI Waveform Configuration */ |
| 269 | pwrap_init_reg_clock(); |
| 270 | |
| 271 | /* SPI Slave Configuration */ |
| 272 | pwrap_init_spislv(); |
| 273 | |
| 274 | /* Enable DIO mode */ |
| 275 | sub_return = pwrap_init_dio(1); |
| 276 | if (sub_return != 0) { |
| 277 | pwrap_err("dio test error, ret=%d\n", sub_return); |
| 278 | return E_PWR_INIT_DIO; |
| 279 | } |
| 280 | |
| 281 | /* Input data calibration flow; */ |
| 282 | sub_return = pwrap_init_sistrobe(); |
| 283 | if (sub_return != 0) { |
| 284 | pwrap_err("InitSiStrobe fail,ret=%d\n", sub_return); |
| 285 | return E_PWR_INIT_SIDLY; |
| 286 | } |
| 287 | |
| 288 | /* |
| 289 | * Write test using WACS2, |
| 290 | * make sure the read/write function ready. |
| 291 | */ |
| 292 | sub_return = pwrap_write_nochk(PMIC_DEW_WRITE_TEST, WRITE_TEST_VALUE); |
| 293 | sub_return1 = pwrap_read_nochk(PMIC_DEW_WRITE_TEST, &rdata); |
| 294 | if (rdata != WRITE_TEST_VALUE || sub_return || sub_return1) { |
| 295 | pwrap_err("write error, rdata=%#x, return=%d, return1=%d\n", |
| 296 | rdata, sub_return, sub_return1); |
| 297 | return E_PWR_INIT_WRITE_TEST; |
| 298 | } |
| 299 | |
| 300 | /* |
| 301 | * Status update function initialization |
| 302 | * 1. Signature Checking using CRC (CRC 0 only) |
| 303 | * 2. EINT update |
| 304 | * 3. Read back Auxadc thermal data for GPS |
| 305 | */ |
| 306 | pwrap_initstaupd(); |
| 307 | |
| 308 | write32(&mtk_pwrap->priority_user_sel_2, PRIORITY_IN_SEL_2); |
| 309 | write32(&mtk_pwrap->arbiter_out_sel_2, PRIORITY_OUT_SEL_2); |
| 310 | |
| 311 | pwrap_starve_set(); |
| 312 | |
| 313 | pwrap_enable(); |
| 314 | |
| 315 | /* Initialization Done */ |
| 316 | write32(&mtk_pwrap->init_done0, 0x1); |
| 317 | write32(&mtk_pwrap->init_done2, 0x1); |
| 318 | write32(&mtk_pwrap->init_done_p2p, 0x1); |
| 319 | write32(&mtk_pwrap->init_done_md32, 0x1); |
| 320 | |
| 321 | /* Lock SPISLV Registers */ |
| 322 | pwrap_lock_spislvreg(); |
| 323 | |
| 324 | return 0; |
| 325 | } |