Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
| 3 | #include <assert.h> |
| 4 | #include <console/console.h> |
| 5 | #include <delay.h> |
| 6 | #include <soc/mt6359p.h> |
| 7 | #include <soc/pmif.h> |
| 8 | #include <timer.h> |
| 9 | |
| 10 | static const struct pmic_setting key_protect_setting[] = { |
| 11 | {0x3A8, 0x9CA6, 0xFFFF, 0}, |
| 12 | {0x44A, 0xBADE, 0xFFFF, 0}, |
| 13 | {0xA3A, 0x4729, 0xFFFF, 0}, |
| 14 | {0xC58, 0x1605, 0xFFFF, 0}, |
| 15 | {0xC5A, 0x1706, 0xFFFF, 0}, |
| 16 | {0xC5C, 0x1807, 0xFFFF, 0}, |
| 17 | {0xFB4, 0x6359, 0xFFFF, 0}, |
| 18 | {0x1432, 0x5543, 0xFFFF, 0}, |
| 19 | }; |
| 20 | |
| 21 | static const struct pmic_efuse efuse_setting[] = { |
| 22 | {79, 0xa0e, 0x1, 0xf}, |
| 23 | {886, 0x198c, 0xf, 0x8}, |
| 24 | {890, 0x198e, 0xf, 0x0}, |
| 25 | {902, 0x1998, 0xf, 0x8}, |
| 26 | {906, 0x1998, 0xf, 0xc}, |
| 27 | {918, 0x19a2, 0xf, 0x8}, |
| 28 | {922, 0x19a2, 0xf, 0xc}, |
| 29 | {1014, 0x19ae, 0xf, 0x7}, |
| 30 | {1018, 0x19ae, 0xf, 0xb}, |
| 31 | {1158, 0x1a0a, 0xf, 0x7}, |
| 32 | {1162, 0x1a0a, 0xf, 0xb}, |
| 33 | {1206, 0x1a16, 0xf, 0x7}, |
| 34 | {1210, 0x1a16, 0xf, 0xb}, |
| 35 | {1254, 0x1a22, 0xf, 0x7}, |
| 36 | {1258, 0x1a22, 0xf, 0xb}, |
| 37 | {1304, 0x1a2c, 0x7, 0x4}, |
| 38 | {1307, 0x1a32, 0x7, 0x8}, |
| 39 | {1336, 0x1a34, 0x7, 0x4}, |
| 40 | {1339, 0x1a3a, 0x7, 0x8}, |
| 41 | {1683, 0x79c, 0xf, 0x4}, |
| 42 | {1688, 0xc8a, 0x1, 0x3}, |
| 43 | {1689, 0xc88, 0x1, 0x3}, |
| 44 | {1690, 0xc88, 0x7, 0x0}, |
| 45 | }; |
| 46 | |
| 47 | static struct pmif *pmif_arb = NULL; |
| 48 | static void mt6359p_write(u32 reg, u32 data) |
| 49 | { |
| 50 | pmif_arb->write(pmif_arb, 0, reg, data); |
| 51 | } |
| 52 | |
| 53 | static u32 mt6359p_read_field(u32 reg, u32 mask, u32 shift) |
| 54 | { |
| 55 | return pmif_arb->read_field(pmif_arb, 0, reg, mask, shift); |
| 56 | } |
| 57 | |
| 58 | void mt6359p_write_field(u32 reg, u32 val, u32 mask, u32 shift) |
| 59 | { |
| 60 | pmif_arb->write_field(pmif_arb, 0, reg, val, mask, shift); |
| 61 | } |
| 62 | |
| 63 | static void pmic_set_power_hold(void) |
| 64 | { |
| 65 | mt6359p_write_field(PMIC_PWRHOLD, 0x1, 0x1, 0); |
| 66 | } |
| 67 | |
| 68 | static void pmic_wdt_set(void) |
| 69 | { |
| 70 | /* [5]=1, RG_WDTRSTB_DEB */ |
| 71 | mt6359p_write_field(PMIC_TOP_RST_MISC_SET, 0x20, 0xFFFF, 0); |
| 72 | /* [1]=0, RG_WDTRSTB_MODE */ |
| 73 | mt6359p_write_field(PMIC_TOP_RST_MISC_CLR, 0x02, 0xFFFF, 0); |
| 74 | /* [0]=1, RG_WDTRSTB_EN */ |
| 75 | mt6359p_write_field(PMIC_TOP_RST_MISC_SET, 0x01, 0xFFFF, 0); |
| 76 | } |
| 77 | |
| 78 | static void pmic_protect_key_setting(bool lock) |
| 79 | { |
| 80 | for (int i = 0; i < ARRAY_SIZE(key_protect_setting); i++) |
| 81 | mt6359p_write(key_protect_setting[i].addr, |
| 82 | lock ? 0 : key_protect_setting[i].val); |
| 83 | } |
| 84 | |
| 85 | static int check_idle(u32 timeout, u32 addr, u32 mask) |
| 86 | { |
| 87 | if (!wait_us(timeout, !mt6359p_read_field(addr, mask, 0))) |
| 88 | return -1; |
| 89 | |
| 90 | return 0; |
| 91 | } |
| 92 | |
| 93 | static u32 pmic_read_efuse(u32 efuse_bit, u32 mask) |
| 94 | { |
| 95 | u32 efuse_data; |
| 96 | int index, shift; |
| 97 | |
| 98 | index = efuse_bit / 16; |
| 99 | shift = efuse_bit % 16; |
| 100 | mt6359p_write_field(PMIC_TOP_CKHWEN_CON0, 0, 0x1, 2); |
| 101 | mt6359p_write_field(PMIC_TOP_CKPDN_CON0, 0, 0x1, 4); |
| 102 | mt6359p_write_field(PMIC_OTP_CON11, 1, 0x1, 0); |
| 103 | mt6359p_write_field(PMIC_OTP_CON0, index * 2, 0xFF, 0); |
| 104 | if (mt6359p_read_field(PMIC_OTP_CON8, 1, 0)) |
| 105 | mt6359p_write_field(PMIC_OTP_CON8, 0, 1, 0); |
| 106 | else |
| 107 | mt6359p_write_field(PMIC_OTP_CON8, 1, 1, 0); |
| 108 | |
| 109 | udelay(300); |
| 110 | if (check_idle(EFUSE_WAIT_US, PMIC_OTP_CON13, EFUSE_BUSY)) |
| 111 | die("[%s] timeout after %d usecs\n", __func__, EFUSE_WAIT_US); |
| 112 | |
| 113 | udelay(100); |
| 114 | |
| 115 | efuse_data = mt6359p_read_field(PMIC_OTP_CON12, 0xFFFF, 0); |
| 116 | efuse_data = (efuse_data >> shift) & mask; |
| 117 | |
| 118 | mt6359p_write_field(PMIC_TOP_CKHWEN_CON0, 1, 0x1, 2); |
| 119 | mt6359p_write_field(PMIC_TOP_CKPDN_CON0, 1, 0x1, 4); |
| 120 | |
| 121 | return efuse_data; |
| 122 | } |
| 123 | |
| 124 | static void pmic_efuse_setting(void) |
| 125 | { |
| 126 | u32 efuse_data; |
| 127 | struct stopwatch sw; |
| 128 | |
| 129 | stopwatch_init(&sw); |
| 130 | |
| 131 | for (int i = 0; i < ARRAY_SIZE(efuse_setting); i++) { |
| 132 | efuse_data = pmic_read_efuse(efuse_setting[i].efuse_bit, efuse_setting[i].mask); |
| 133 | mt6359p_write_field(efuse_setting[i].addr, efuse_data, |
| 134 | efuse_setting[i].mask, efuse_setting[i].shift); |
| 135 | } |
| 136 | |
| 137 | efuse_data = pmic_read_efuse(EFUSE_RG_VPA_OC_FT, 0x1); |
| 138 | if (efuse_data) { |
| 139 | /* restore VPA_DLC initial setting */ |
| 140 | mt6359p_write(PMIC_BUCK_VPA_DLC_CON0, 0x2810); |
| 141 | mt6359p_write(PMIC_BUCK_VPA_DLC_CON1, 0x800); |
| 142 | } |
| 143 | |
Rob Barnes | d522f38 | 2022-09-12 06:31:47 -0600 | [diff] [blame] | 144 | printk(BIOS_DEBUG, "%s: Set efuses in %lld msecs\n", |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 145 | __func__, stopwatch_duration_msecs(&sw)); |
| 146 | } |
| 147 | |
| 148 | static void pmic_wk_vs2_voter_setting(void) |
| 149 | { |
| 150 | /* |
| 151 | * 1. Set VS2_VOTER_VOSEL = 1.35V |
| 152 | * 2. Clear VS2_VOTER |
| 153 | * 3. Set VS2_VOSEL = 1.4V |
| 154 | */ |
| 155 | mt6359p_write_field(PMIC_VS2_VOTER_CFG, 0x2C, 0x7F, 0); |
| 156 | mt6359p_write_field(PMIC_VS2_VOTER, 0, 0xFFF, 0); |
| 157 | mt6359p_write_field(PMIC_VS2_ELR0, 0x30, 0x7F, 0); |
| 158 | } |
| 159 | |
| 160 | void mt6359p_buck_set_voltage(u32 buck_id, u32 buck_uv) |
| 161 | { |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 162 | u32 vol_offset, vol_reg, vol, vol_step; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 163 | |
| 164 | if (!pmif_arb) |
| 165 | die("ERROR: pmif_arb not initialized"); |
| 166 | |
| 167 | switch (buck_id) { |
| 168 | case MT6359P_GPU11: |
| 169 | vol_offset = 400000; |
| 170 | vol_reg = PMIC_VGPU11_ELR0; |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 171 | vol_step = 6250; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 172 | break; |
| 173 | case MT6359P_SRAM_PROC1: |
| 174 | vol_offset = 500000; |
| 175 | vol_reg = PMIC_VSRAM_PROC1_ELR; |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 176 | vol_step = 6250; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 177 | break; |
| 178 | case MT6359P_SRAM_PROC2: |
| 179 | vol_offset = 500000; |
| 180 | vol_reg = PMIC_VSRAM_PROC2_ELR; |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 181 | vol_step = 6250; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 182 | break; |
James Lo | 55c98c3 | 2021-08-04 14:17:16 +0800 | [diff] [blame] | 183 | case MT6359P_CORE: |
| 184 | vol_offset = 506250; |
| 185 | vol_reg = PMIC_VCORE_ELR0; |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 186 | vol_step = 6250; |
| 187 | break; |
| 188 | case MT6359P_PA: |
| 189 | vol_offset = 500000; |
| 190 | vol_reg = PMIC_VPA_CON1; |
| 191 | vol_step = 50000; |
James Lo | 55c98c3 | 2021-08-04 14:17:16 +0800 | [diff] [blame] | 192 | break; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 193 | default: |
| 194 | die("ERROR: Unknown buck_id %u", buck_id); |
| 195 | return; |
| 196 | }; |
| 197 | |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 198 | vol = (buck_uv - vol_offset) / vol_step; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 199 | mt6359p_write_field(vol_reg, vol, 0x7F, 0); |
| 200 | } |
| 201 | |
| 202 | u32 mt6359p_buck_get_voltage(u32 buck_id) |
| 203 | { |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 204 | u32 vol_shift, vol_offset, vol_reg, vol, vol_step; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 205 | |
| 206 | if (!pmif_arb) |
| 207 | die("ERROR: pmif_arb not initialized"); |
| 208 | |
| 209 | switch (buck_id) { |
| 210 | case MT6359P_GPU11: |
| 211 | vol_shift = 0; |
| 212 | vol_offset = 400000; |
| 213 | vol_reg = PMIC_VGPU11_DBG0; |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 214 | vol_step = 6250; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 215 | break; |
| 216 | case MT6359P_SRAM_PROC1: |
| 217 | vol_shift = 8; |
| 218 | vol_offset = 500000; |
| 219 | vol_reg = PMIC_VSRAM_PROC1_VOSEL1; |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 220 | vol_step = 6250; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 221 | break; |
| 222 | case MT6359P_SRAM_PROC2: |
| 223 | vol_shift = 8; |
| 224 | vol_offset = 500000; |
| 225 | vol_reg = PMIC_VSRAM_PROC2_VOSEL1; |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 226 | vol_step = 6250; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 227 | break; |
James Lo | 55c98c3 | 2021-08-04 14:17:16 +0800 | [diff] [blame] | 228 | case MT6359P_CORE: |
| 229 | vol_shift = 0; |
| 230 | vol_offset = 506250; |
| 231 | vol_reg = PMIC_VCORE_DBG0; |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 232 | vol_step = 6250; |
| 233 | break; |
| 234 | case MT6359P_PA: |
| 235 | vol_shift = 0; |
| 236 | vol_offset = 500000; |
| 237 | vol_reg = PMIC_VPA_DBG0; |
| 238 | vol_step = 50000; |
James Lo | 55c98c3 | 2021-08-04 14:17:16 +0800 | [diff] [blame] | 239 | break; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 240 | default: |
| 241 | die("ERROR: Unknown buck_id %u", buck_id); |
| 242 | return 0; |
| 243 | }; |
| 244 | |
| 245 | vol = mt6359p_read_field(vol_reg, 0x7F, vol_shift); |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 246 | return vol_offset + vol * vol_step; |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 247 | } |
| 248 | |
| 249 | void mt6359p_set_vm18_voltage(u32 vm18_uv) |
| 250 | { |
| 251 | u32 reg_vol, reg_cali; |
| 252 | |
| 253 | if (!pmif_arb) |
| 254 | die("ERROR: pmif_arb not initialized"); |
| 255 | |
| 256 | assert(vm18_uv >= 1700000); |
| 257 | assert(vm18_uv < 2000000); |
| 258 | |
| 259 | reg_vol = (vm18_uv / 1000 - VM18_VOL_OFFSET) / 100; |
| 260 | reg_cali = ((vm18_uv / 1000) % 100) / 10; |
| 261 | mt6359p_write(PMIC_VM18_ANA_CON0, (reg_vol << VM18_VOL_REG_SHIFT) | reg_cali); |
| 262 | } |
| 263 | |
| 264 | u32 mt6359p_get_vm18_voltage(void) |
| 265 | { |
| 266 | u32 reg_vol, reg_cali; |
| 267 | |
| 268 | if (!pmif_arb) |
| 269 | die("ERROR: pmif_arb not initialized"); |
| 270 | |
| 271 | reg_vol = 100 * mt6359p_read_field(PMIC_VM18_ANA_CON0, 0xF, VM18_VOL_REG_SHIFT); |
| 272 | reg_cali = 10 * mt6359p_read_field(PMIC_VM18_ANA_CON0, 0xF, 0); |
| 273 | return 1000 * (VM18_VOL_OFFSET + reg_vol + reg_cali); |
| 274 | } |
| 275 | |
Hui Liu | 8ba3e34 | 2022-07-15 13:58:09 +0800 | [diff] [blame] | 276 | void mt6359p_set_vsim1_voltage(u32 vsim1_uv) |
| 277 | { |
| 278 | u32 reg_vol, reg_cali; |
| 279 | |
| 280 | if (!pmif_arb) |
| 281 | die("ERROR: pmif_arb not initialized"); |
| 282 | |
| 283 | if ((vsim1_uv >= 1700000) && (vsim1_uv <= 1900000)) |
| 284 | reg_vol = (vsim1_uv / 1000 - VSIM1_VOL_OFFSET_1) / 100; |
| 285 | else if ((vsim1_uv >= 2700000) && (vsim1_uv <= 2800000)) |
| 286 | reg_vol = (vsim1_uv / 1000 - VSIM1_VOL_OFFSET_2) / 100; |
| 287 | else if ((vsim1_uv >= 3000000) && (vsim1_uv <= 3200000)) |
| 288 | reg_vol = (vsim1_uv / 1000 - VSIM1_VOL_OFFSET_2) / 100; |
| 289 | else |
| 290 | die("ERROR: Unknown vsim1 voltage %u", vsim1_uv); |
| 291 | |
| 292 | reg_cali = ((vsim1_uv / 1000) % 100) / 10; |
| 293 | mt6359p_write(PMIC_VSIM1_ANA_CON0, (reg_vol << VSIM1_VOL_REG_SHIFT) | reg_cali); |
| 294 | } |
| 295 | |
| 296 | u32 mt6359p_get_vsim1_voltage(void) |
| 297 | { |
| 298 | u32 reg_vol, reg_cali, reg_offset; |
| 299 | |
| 300 | if (!pmif_arb) |
| 301 | die("ERROR: pmif_arb not initialized"); |
| 302 | |
| 303 | reg_vol = 100 * mt6359p_read_field(PMIC_VSIM1_ANA_CON0, 0xF, |
| 304 | VSIM1_VOL_REG_SHIFT); |
| 305 | reg_cali = 10 * mt6359p_read_field(PMIC_VSIM1_ANA_CON0, 0xF, 0); |
| 306 | |
| 307 | if ((reg_vol == 300) || (reg_vol == 400)) |
| 308 | reg_offset = VSIM1_VOL_OFFSET_1; |
| 309 | else if ((reg_vol == 800) || (reg_vol == 1100) || (reg_vol == 1200)) |
| 310 | reg_offset = VSIM1_VOL_OFFSET_2; |
| 311 | else |
| 312 | die("ERROR: Unknown vsim1 reg_vol %x", reg_vol); |
| 313 | |
| 314 | return 1000 * (reg_offset + reg_vol + reg_cali); |
| 315 | } |
| 316 | |
| 317 | void mt6359p_enable_vpa(bool enable) |
| 318 | { |
| 319 | mt6359p_write_field(PMIC_VPA_CON0, !!enable, 0x1, 0); |
| 320 | } |
| 321 | |
| 322 | void mt6359p_enable_vsim1(bool enable) |
| 323 | { |
| 324 | mt6359p_write_field(PMIC_VSIM1_CON0, !!enable, 0x1, 0); |
| 325 | } |
| 326 | |
Yidi Lin | 2368a31 | 2021-02-02 21:00:36 +0800 | [diff] [blame] | 327 | static void init_pmif_arb(void) |
| 328 | { |
| 329 | if (!pmif_arb) { |
| 330 | pmif_arb = get_pmif_controller(PMIF_SPI, 0); |
| 331 | if (!pmif_arb) |
| 332 | die("ERROR: No spi device"); |
| 333 | } |
| 334 | |
| 335 | if (pmif_arb->is_pmif_init_done(pmif_arb)) |
| 336 | die("ERROR - Failed to initialize pmif spi"); |
| 337 | } |
| 338 | |
| 339 | void mt6359p_init(void) |
| 340 | { |
| 341 | init_pmif_arb(); |
| 342 | pmic_set_power_hold(); |
| 343 | pmic_wdt_set(); |
| 344 | pmic_protect_key_setting(false); |
| 345 | pmic_init_setting(); |
| 346 | pmic_lp_setting(); |
| 347 | pmic_efuse_setting(); |
| 348 | pmic_protect_key_setting(true); |
| 349 | pmic_wk_vs2_voter_setting(); |
| 350 | } |