Chris Packham | eaab461 | 2022-11-05 17:23:59 +1300 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Copyright (C) 2018 Marvell International Ltd. |
| 4 | */ |
| 5 | |
| 6 | #include <common.h> |
| 7 | #include <asm/arch-armada8k/cache_llc.h> |
| 8 | #include <asm/io.h> |
| 9 | #include <asm/arch/cpu.h> |
| 10 | #include <asm/arch/soc.h> |
| 11 | #include <dm/device.h> |
| 12 | |
| 13 | #define DEVICE_ID_REG 0x7F90004C |
| 14 | #define DEVICE_ID_MASK 0xffff0 |
| 15 | #define REV_ID_MASK 0xf |
| 16 | #define DEVICE_ID_OFFSET 4 |
| 17 | #define REV_ID_OFFSET 0 |
| 18 | |
| 19 | #define DEVICE_SAR_REG 0x944F8204 |
| 20 | |
| 21 | #define DEVICE_ID_SUB_REV (MVEBU_REGISTER(0x2400230)) |
| 22 | #define DEVICE_ID_SUB_REV_OFFSET 7 |
| 23 | #define DEVICE_ID_SUB_REV_MASK (0xffff << DEVICE_ID_SUB_REV_OFFSET) |
| 24 | |
| 25 | #define AC5X_DEV_ID 0x9800 |
| 26 | |
| 27 | struct soc_info { |
| 28 | u32 dev_id; |
| 29 | u32 rev_id; |
| 30 | char *soc_name; |
| 31 | }; |
| 32 | |
| 33 | static struct soc_info soc_info_table[] = { |
| 34 | /* Two reserved entries for unidentified devices - don't change */ |
| 35 | { 0xB4FF, 0x0, "Unidentified Alleycat5"}, |
| 36 | { 0x98FF, 0x0, "Unidentified Alleycat5x"}, |
| 37 | |
| 38 | { 0xB400, 0x2, "Alleycat5-plus 98DX2538-A2"}, |
| 39 | { 0xB401, 0x2, "Alleycat5-plus 98DX2535-A2"}, |
| 40 | { 0xB402, 0x2, "Alleycat5-plus 98DX2532-A2"}, |
| 41 | { 0xB403, 0x2, "Alleycat5-plus 98DX2531-A2"}, |
| 42 | { 0xB408, 0x2, "Alleycat5 98DX2528-A2"}, |
| 43 | { 0xB409, 0x2, "Alleycat5 98DX2525-A2"}, |
| 44 | { 0xB40A, 0x2, "Alleycat5 98DX2522-A2"}, |
| 45 | { 0xB40B, 0x2, "Alleycat5 98DX2521-A2"}, |
| 46 | { 0xB410, 0x2, "Alleycat5-lite 98DX2518-A2"}, |
| 47 | { 0xB411, 0x2, "Alleycat5-lite 98DX2515-A2"}, |
| 48 | { 0xB412, 0x2, "Alleycat5-lite 98DX2512-A2"}, |
| 49 | { 0xB413, 0x2, "Alleycat5-lite 98DX2511-A2"}, |
| 50 | |
| 51 | { 0xB400, 0x1, "Alleycat5-plus 98DX2538-A1"}, |
| 52 | { 0xB401, 0x1, "Alleycat5-plus 98DX2535-A1"}, |
| 53 | { 0xB402, 0x1, "Alleycat5-plus 98DX2532-A1"}, |
| 54 | { 0xB403, 0x1, "Alleycat5-plus 98DX2531-A1"}, |
| 55 | { 0xB408, 0x1, "Alleycat5 98DX2528-A1"}, |
| 56 | { 0xB409, 0x1, "Alleycat5 98DX2525-A1"}, |
| 57 | { 0xB40A, 0x1, "Alleycat5 98DX2522-A1"}, |
| 58 | { 0xB40B, 0x1, "Alleycat5 98DX2521-A1"}, |
| 59 | { 0xB410, 0x1, "Alleycat5-lite 98DX2518-A1"}, |
| 60 | { 0xB411, 0x1, "Alleycat5-lite 98DX2515-A1"}, |
| 61 | { 0xB412, 0x1, "Alleycat5-lite 98DX2512-A1"}, |
| 62 | { 0xB413, 0x1, "Alleycat5-lite 98DX2511-A1"}, |
| 63 | { 0x9800, 0x1, "Alleycat5X 98DX3500M-A1"}, |
| 64 | { 0x9806, 0x1, "Alleycat5X 98DX3501M-A1"}, |
| 65 | { 0x9801, 0x1, "Alleycat5X 98DX3510M-A1"}, |
| 66 | { 0x9802, 0x1, "Alleycat5X 98DX3520M-A1"}, |
| 67 | { 0x9803, 0x1, "Alleycat5X 98DX3530M-A1"}, |
| 68 | { 0x9804, 0x1, "Alleycat5X 98DX3540M-A1"}, |
| 69 | { 0x9805, 0x1, "Alleycat5X 98DX3550M-A1"}, |
| 70 | { 0x9820, 0x1, "Alleycat5X 98DX3500-A1"}, |
| 71 | { 0x9826, 0x1, "Alleycat5X 98DX3501-A1"}, |
| 72 | { 0x9821, 0x1, "Alleycat5X 98DX3510-A1"}, |
| 73 | { 0x9861, 0x1, "Alleycat5X 98DX3510H-A1"}, |
| 74 | { 0x9841, 0x1, "Alleycat5X 98DX3510MH-A1"}, |
| 75 | { 0x9822, 0x1, "Alleycat5X 98DX3520-A1"}, |
| 76 | { 0x9823, 0x1, "Alleycat5X 98DX3530-A1"}, |
| 77 | { 0x9863, 0x1, "Alleycat5X 98DX3530H-A1"}, |
| 78 | { 0x9824, 0x1, "Alleycat5X 98DX3540-A1"}, |
| 79 | { 0x9825, 0x1, "Alleycat5X 98DX3550-A1"}, |
| 80 | |
| 81 | { 0xB400, 0x0, "Alleycat5-plus 98DX2538-A0"}, |
| 82 | { 0xB401, 0x0, "Alleycat5-plus 98DX2535-A0"}, |
| 83 | { 0xB402, 0x0, "Alleycat5-plus 98DX2532-A0"}, |
| 84 | { 0xB403, 0x0, "Alleycat5-plus 98DX2531-A0"}, |
| 85 | { 0xB408, 0x0, "Alleycat5 98DX2528-A0"}, |
| 86 | { 0xB409, 0x0, "Alleycat5 98DX2525-A0"}, |
| 87 | { 0xB40A, 0x0, "Alleycat5 98DX2522-A0"}, |
| 88 | { 0xB40B, 0x0, "Alleycat5 98DX2521-A0"}, |
| 89 | { 0xB410, 0x0, "Alleycat5-lite 98DX2518-A0"}, |
| 90 | { 0xB411, 0x0, "Alleycat5-lite 98DX2515-A0"}, |
| 91 | { 0xB412, 0x0, "Alleycat5-lite 98DX2512-A0"}, |
| 92 | { 0xB413, 0x0, "Alleycat5-lite 98DX2511-A0"}, |
| 93 | { 0x9800, 0x0, "Alleycat5X 98DX3500M-A0"}, |
| 94 | { 0x9806, 0x0, "Alleycat5X 98DX3501M-A0"}, |
| 95 | { 0x9801, 0x0, "Alleycat5X 98DX3510M-A0"}, |
| 96 | { 0x9802, 0x0, "Alleycat5X 98DX3520M-A0"}, |
| 97 | { 0x9803, 0x0, "Alleycat5X 98DX3530M-A0"}, |
| 98 | { 0x9804, 0x0, "Alleycat5X 98DX3540M-A0"}, |
| 99 | { 0x9805, 0x0, "Alleycat5X 98DX3550M-A0"}, |
| 100 | { 0x9820, 0x0, "Alleycat5X 98DX3500-A0"}, |
| 101 | { 0x9826, 0x0, "Alleycat5X 98DX3501-A0"}, |
| 102 | { 0x9821, 0x0, "Alleycat5X 98DX3510-A0"}, |
| 103 | { 0x9861, 0x0, "Alleycat5X 98DX3510H-A0"}, |
| 104 | { 0x9841, 0x0, "Alleycat5X 98DX3510MH-A0"}, |
| 105 | { 0x9822, 0x0, "Alleycat5X 98DX3520-A0"}, |
| 106 | { 0x9823, 0x0, "Alleycat5X 98DX3530-A0"}, |
| 107 | { 0x9863, 0x0, "Alleycat5X 98DX3530H-A0"}, |
| 108 | { 0x9824, 0x0, "Alleycat5X 98DX3540-A0"}, |
| 109 | { 0x9825, 0x0, "Alleycat5X 98DX3550-A0"}, |
| 110 | }; |
| 111 | |
| 112 | #define BIT_VAL(b) ((1ULL << ((b) + 1)) - 1) |
| 113 | #define BIT_RANGE(bl, bh) (BIT_VAL(bh) - BIT_VAL((bl) - 1)) |
| 114 | |
| 115 | #define PLL_MAX_CHOICE 4 |
| 116 | |
| 117 | #define CPU_TYPE_AC5 0 |
| 118 | #define CPU_TYPE_AC5x 1 |
| 119 | #define CPU_TYPE_LAST 2 |
| 120 | |
| 121 | enum mvebu_sar_opts { |
| 122 | SAR_CPU_FREQ = 0, |
| 123 | SAR_DDR_FREQ, |
| 124 | SAR_AP_FABRIC_FREQ, |
| 125 | SAR_CP_FABRIC_FREQ, |
| 126 | SAR_CP0_PCIE0_CLK, |
| 127 | SAR_CP0_PCIE1_CLK, |
| 128 | SAR_CP1_PCIE0_CLK, |
| 129 | SAR_CP1_PCIE1_CLK, |
| 130 | SAR_BOOT_SRC, |
| 131 | SAR_MAX_IDX |
| 132 | }; |
| 133 | |
| 134 | static const u32 pll_freq_tbl[CPU_TYPE_LAST][SAR_AP_FABRIC_FREQ + 1][PLL_MAX_CHOICE] = { |
| 135 | [CPU_TYPE_AC5] = { |
| 136 | [SAR_CPU_FREQ] = { |
| 137 | 800, 1200, 1400, 1000 |
| 138 | }, |
| 139 | [SAR_DDR_FREQ] = { |
| 140 | 1200, 800, 0, 0 |
| 141 | }, |
| 142 | [SAR_AP_FABRIC_FREQ] = { |
| 143 | 396, 290, 197, 0 |
| 144 | }, |
| 145 | }, |
| 146 | [CPU_TYPE_AC5x] = { |
| 147 | [SAR_CPU_FREQ] = { |
| 148 | 800, 1200, 1500, 1600 |
| 149 | }, |
| 150 | [SAR_DDR_FREQ] = { |
| 151 | 1200, 800, 0, 0 |
| 152 | }, |
| 153 | [SAR_AP_FABRIC_FREQ] = { |
| 154 | 0, 0, 0, 0 |
| 155 | } |
| 156 | } |
| 157 | }; |
| 158 | |
| 159 | static const u32 soc_sar_masks_tbl[CPU_TYPE_LAST][SAR_AP_FABRIC_FREQ + 1] = { |
| 160 | [CPU_TYPE_AC5] = { |
| 161 | [SAR_CPU_FREQ] = BIT_RANGE(18, 20), |
| 162 | [SAR_DDR_FREQ] = BIT_RANGE(16, 17), |
| 163 | [SAR_AP_FABRIC_FREQ] = BIT_RANGE(22, 23), |
| 164 | }, |
| 165 | [CPU_TYPE_AC5x] = { |
| 166 | [SAR_CPU_FREQ] = BIT_RANGE(8, 10), |
| 167 | [SAR_DDR_FREQ] = BIT_RANGE(6, 7), |
| 168 | [SAR_AP_FABRIC_FREQ] = 1, |
| 169 | }, |
| 170 | }; |
| 171 | |
| 172 | static int get_soc_type_rev(u32 *type, u32 *rev) |
| 173 | { |
| 174 | *type = (readl(DEVICE_ID_REG) & DEVICE_ID_MASK) >> DEVICE_ID_OFFSET; |
| 175 | *rev = (readl(DEVICE_ID_REG) & REV_ID_MASK) >> REV_ID_OFFSET; |
| 176 | |
| 177 | return 0; |
| 178 | } |
| 179 | |
| 180 | static void get_one_sar_freq(int cpu_type, u32 sar_reg_val, enum mvebu_sar_opts sar_opt, u32 *freq) |
| 181 | { |
| 182 | u32 mask; |
| 183 | unsigned char choice; |
| 184 | |
| 185 | mask = soc_sar_masks_tbl[cpu_type][sar_opt]; |
| 186 | choice = (sar_reg_val & mask) >> (__builtin_ffs(mask) - 1); |
| 187 | *freq = pll_freq_tbl[cpu_type][sar_opt][choice]; |
| 188 | } |
| 189 | |
| 190 | void get_sar_freq(struct sar_freq_modes *sar_freq) |
| 191 | { |
| 192 | int cpu_type; |
| 193 | u32 soc_type, rev; |
| 194 | u32 sar_reg_val = readl(DEVICE_SAR_REG); |
| 195 | |
| 196 | get_soc_type_rev(&soc_type, &rev); |
| 197 | cpu_type = (soc_type & 0xFF00) == AC5X_DEV_ID ? CPU_TYPE_AC5x : CPU_TYPE_AC5; |
| 198 | |
| 199 | get_one_sar_freq(cpu_type, sar_reg_val, SAR_CPU_FREQ, &sar_freq->p_clk); |
| 200 | get_one_sar_freq(cpu_type, sar_reg_val, SAR_AP_FABRIC_FREQ, &sar_freq->nb_clk); |
| 201 | get_one_sar_freq(cpu_type, sar_reg_val, SAR_DDR_FREQ, &sar_freq->d_clk); |
| 202 | } |
| 203 | |
| 204 | static int get_soc_table_index(u32 *index) |
| 205 | { |
| 206 | u32 soc_type; |
| 207 | u32 rev, i, ret = 1; |
| 208 | |
| 209 | *index = 0; |
| 210 | get_soc_type_rev(&soc_type, &rev); |
| 211 | |
| 212 | for (i = 0; i < ARRAY_SIZE(soc_info_table) && ret != 0; i++) { |
| 213 | if (soc_type != soc_info_table[i].dev_id || |
| 214 | rev != soc_info_table[i].rev_id) |
| 215 | continue; |
| 216 | |
| 217 | *index = i; |
| 218 | ret = 0; |
| 219 | } |
| 220 | |
| 221 | if (ret && ((soc_type & 0xFF00) == AC5X_DEV_ID)) |
| 222 | *index = 1; |
| 223 | |
| 224 | return ret; |
| 225 | } |
| 226 | |
| 227 | static int get_soc_name(char **soc_name) |
| 228 | { |
| 229 | u32 index; |
| 230 | |
| 231 | get_soc_table_index(&index); |
| 232 | *soc_name = soc_info_table[index].soc_name; |
| 233 | |
| 234 | return 0; |
| 235 | } |
| 236 | |
| 237 | /* Print device's SoC name and AP & CP information */ |
| 238 | void soc_print_device_info(void) |
| 239 | { |
| 240 | char *soc_name = NULL; |
| 241 | |
| 242 | get_soc_name(&soc_name); |
| 243 | |
| 244 | printf("SoC: %s\n", soc_name); |
| 245 | } |
| 246 | |
| 247 | void soc_print_clock_info(void) |
| 248 | { |
| 249 | struct sar_freq_modes sar_freq; |
| 250 | |
| 251 | get_sar_freq(&sar_freq); |
| 252 | printf("Clock: CPU %4d MHz\n", sar_freq.p_clk); |
| 253 | printf("\tDDR %4d MHz\n", sar_freq.d_clk); |
| 254 | printf("\tFABRIC %4d MHz\n", sar_freq.nb_clk); |
| 255 | printf("\tMSS %4d MHz\n", 200); |
| 256 | } |
| 257 | |
Chris Packham | 01be672 | 2023-07-10 10:47:33 +1200 | [diff] [blame] | 258 | /* Return NAND clock in Hz */ |
| 259 | u32 mvebu_get_nand_clock(void) |
| 260 | { |
| 261 | return 400 * 1000000; |
| 262 | } |
| 263 | |
Chris Packham | eaab461 | 2022-11-05 17:23:59 +1300 | [diff] [blame] | 264 | /* |
| 265 | * Override of __weak int mach_cpu_init(void) : |
| 266 | * SoC/machine dependent CPU setup |
| 267 | */ |
| 268 | int mach_cpu_init(void) |
| 269 | { |
| 270 | u32 phy_i; |
| 271 | u64 new_val, phy_base = 0x7F080800; |
| 272 | |
| 273 | /* Init USB PHY */ |
| 274 | #define USB_STEPPING 0x20000 |
| 275 | #define WRITE_MASK(addr, mask, val) \ |
| 276 | { new_val = (readl(addr) & (~(mask))) | (val);\ |
| 277 | writel(new_val, addr); } |
| 278 | |
| 279 | for (phy_i = 0; phy_i < 2; phy_i++, phy_base += USB_STEPPING) { |
| 280 | WRITE_MASK(phy_base + 0x4, 0x3, 0x2); |
| 281 | WRITE_MASK(phy_base + 0xC, 0x3000000, 0x2000000); |
| 282 | WRITE_MASK(phy_base + 0x1C, 0x3, 0x2); |
| 283 | WRITE_MASK(phy_base + 0x0, 0x1FF007F, 0x600005); |
| 284 | WRITE_MASK(phy_base + 0xC, 0x000F000, 0x0002000); |
| 285 | /* Calibration Threshold Setting = 4*/ |
| 286 | WRITE_MASK(phy_base + 0x8, 0x700, 0x400) |
| 287 | WRITE_MASK(phy_base + 0x14, 0x000000F, 0x000000a); |
| 288 | /* Change AMP to 4*/ |
| 289 | WRITE_MASK(phy_base + 0xC, 0x3700000, 0x3400000); |
| 290 | WRITE_MASK(phy_base + 0x4, 0x3, 0x3); |
| 291 | /* Impedance calibration triggering is performed by USB probe */ |
| 292 | } |
| 293 | |
| 294 | return 0; |
| 295 | } |