1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2022 StarFive Technology Co., Ltd. 4 * Author: Yanhong Wang<yanhong.wang@starfivetech.com> 5 */ 6 7#include <asm/arch/eeprom.h> 8#include <asm/arch/gpio.h> 9#include <asm/arch/regs.h> 10#include <asm/arch/spl.h> 11#include <asm/io.h> 12#include <dt-bindings/clock/starfive,jh7110-crg.h> 13#include <fdt_support.h> 14#include <linux/libfdt.h> 15#include <log.h> 16#include <spl.h> 17 18DECLARE_GLOBAL_DATA_PTR; 19#define JH7110_CLK_CPU_ROOT_OFFSET 0x0U 20#define JH7110_CLK_CPU_ROOT_SHIFT 24 21#define JH7110_CLK_CPU_ROOT_MASK GENMASK(29, 24) 22 23struct starfive_vf2_pro { 24 const char *path; 25 const char *name; 26 const char *value; 27}; 28 29static const struct starfive_vf2_pro milk_v_mars[] = { 30 {"/soc/ethernet@16030000", "starfive,tx-use-rgmii-clk", NULL}, 31 {"/soc/ethernet@16040000", "starfive,tx-use-rgmii-clk", NULL}, 32 33 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 34 "motorcomm,tx-clk-adj-enabled", NULL}, 35 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 36 "motorcomm,tx-clk-100-inverted", NULL}, 37 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 38 "motorcomm,tx-clk-1000-inverted", NULL}, 39 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 40 "motorcomm,rx-clk-drv-microamp", "3970"}, 41 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 42 "motorcomm,rx-data-drv-microamp", "2910"}, 43 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 44 "rx-internal-delay-ps", "1900"}, 45 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 46 "tx-internal-delay-ps", "1500"}, 47}; 48 49static const struct starfive_vf2_pro starfive_vera[] = { 50 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", "rx-internal-delay-ps", 51 "1900"}, 52 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", "tx-internal-delay-ps", 53 "1350"} 54}; 55 56static const struct starfive_vf2_pro starfive_verb[] = { 57 {"/soc/ethernet@16030000", "starfive,tx-use-rgmii-clk", NULL}, 58 {"/soc/ethernet@16040000", "starfive,tx-use-rgmii-clk", NULL}, 59 60 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 61 "motorcomm,tx-clk-adj-enabled", NULL}, 62 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 63 "motorcomm,tx-clk-100-inverted", NULL}, 64 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 65 "motorcomm,tx-clk-1000-inverted", NULL}, 66 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 67 "motorcomm,rx-clk-drv-microamp", "3970"}, 68 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 69 "motorcomm,rx-data-drv-microamp", "2910"}, 70 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 71 "rx-internal-delay-ps", "1900"}, 72 {"/soc/ethernet@16030000/mdio/ethernet-phy@0", 73 "tx-internal-delay-ps", "1500"}, 74 75 {"/soc/ethernet@16040000/mdio/ethernet-phy@1", 76 "motorcomm,tx-clk-adj-enabled", NULL}, 77 { "/soc/ethernet@16040000/mdio/ethernet-phy@1", 78 "motorcomm,tx-clk-100-inverted", NULL}, 79 {"/soc/ethernet@16040000/mdio/ethernet-phy@1", 80 "motorcomm,rx-clk-drv-microamp", "3970"}, 81 {"/soc/ethernet@16040000/mdio/ethernet-phy@1", 82 "motorcomm,rx-data-drv-microamp", "2910"}, 83 {"/soc/ethernet@16040000/mdio/ethernet-phy@1", 84 "rx-internal-delay-ps", "0"}, 85 {"/soc/ethernet@16040000/mdio/ethernet-phy@1", 86 "tx-internal-delay-ps", "0"}, 87}; 88 89void spl_fdt_fixup_mars(void *fdt) 90{ 91 static const char compat[] = "milkv,mars\0starfive,jh7110"; 92 u32 phandle; 93 u8 i; 94 int offset; 95 int ret; 96 97 fdt_setprop(fdt, fdt_path_offset(fdt, "/"), "compatible", compat, sizeof(compat)); 98 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model", 99 "Milk-V Mars"); 100 101 /* gmac0 */ 102 offset = fdt_path_offset(fdt, "/soc/clock-controller@17000000"); 103 phandle = fdt_get_phandle(fdt, offset); 104 offset = fdt_path_offset(fdt, "/soc/ethernet@16030000"); 105 106 fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle); 107 fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_AONCLK_GMAC0_TX); 108 fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle); 109 fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", 110 JH7110_AONCLK_GMAC0_RMII_RTX); 111 112 /* gmac1 */ 113 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/soc/ethernet@16040000"), 114 "status", "disabled"); 115 116 for (i = 0; i < ARRAY_SIZE(milk_v_mars); i++) { 117 offset = fdt_path_offset(fdt, milk_v_mars[i].path); 118 119 if (milk_v_mars[i].value) 120 ret = fdt_setprop_u32(fdt, offset, milk_v_mars[i].name, 121 dectoul(milk_v_mars[i].value, NULL)); 122 else 123 ret = fdt_setprop_empty(fdt, offset, milk_v_mars[i].name); 124 125 if (ret) { 126 pr_err("%s set prop %s fail.\n", __func__, milk_v_mars[i].name); 127 break; 128 } 129 } 130} 131 132void spl_fdt_fixup_mars_cm(void *fdt) 133{ 134 const char *compat; 135 const char *model; 136 137 spl_fdt_fixup_mars(fdt); 138 139 if (!get_mmc_size_from_eeprom()) { 140 int offset; 141 142 model = "Milk-V Mars CM Lite"; 143 compat = "milkv,mars-cm-lite\0starfive,jh7110"; 144 145 offset = fdt_path_offset(fdt, "/soc/pinctrl/mmc0-pins/mmc0-pins-rest"); 146 /* GPIOMUX(22, GPOUT_SYS_SDIO0_RST, GPOEN_ENABLE, GPI_NONE) */ 147 fdt_setprop_u32(fdt, offset, "pinmux", 0xff130016); 148 } else { 149 model = "Milk-V Mars CM"; 150 compat = "milkv,mars-cm\0starfive,jh7110"; 151 } 152 fdt_setprop(fdt, fdt_path_offset(fdt, "/"), "compatible", compat, sizeof(compat)); 153 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model", model); 154} 155 156void spl_fdt_fixup_version_a(void *fdt) 157{ 158 static const char compat[] = "starfive,visionfive-2-v1.2a\0starfive,jh7110"; 159 u32 phandle; 160 u8 i; 161 int offset; 162 int ret; 163 164 fdt_setprop(fdt, fdt_path_offset(fdt, "/"), "compatible", compat, sizeof(compat)); 165 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model", 166 "StarFive VisionFive 2 v1.2A"); 167 168 offset = fdt_path_offset(fdt, "/soc/clock-controller@13020000"); 169 phandle = fdt_get_phandle(fdt, offset); 170 offset = fdt_path_offset(fdt, "/soc/ethernet@16040000"); 171 172 fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle); 173 fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_TX); 174 fdt_appendprop_u32(fdt, offset, "assigned-clocks", phandle); 175 fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_RX); 176 177 fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle); 178 fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", 179 JH7110_SYSCLK_GMAC1_RMII_RTX); 180 fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", phandle); 181 fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", 182 JH7110_SYSCLK_GMAC1_RMII_RTX); 183 184 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/soc/ethernet@16040000"), 185 "phy-mode", "rmii"); 186 187 for (i = 0; i < ARRAY_SIZE(starfive_vera); i++) { 188 offset = fdt_path_offset(fdt, starfive_vera[i].path); 189 190 if (starfive_vera[i].value) 191 ret = fdt_setprop_u32(fdt, offset, starfive_vera[i].name, 192 dectoul(starfive_vera[i].value, NULL)); 193 else 194 ret = fdt_setprop_empty(fdt, offset, starfive_vera[i].name); 195 196 if (ret) { 197 pr_err("%s set prop %s fail.\n", __func__, starfive_vera[i].name); 198 break; 199 } 200 } 201} 202 203void spl_fdt_fixup_version_b(void *fdt) 204{ 205 static const char compat[] = "starfive,visionfive-2-v1.3b\0starfive,jh7110"; 206 u32 phandle; 207 u8 i; 208 int offset; 209 int ret; 210 211 fdt_setprop(fdt, fdt_path_offset(fdt, "/"), "compatible", compat, sizeof(compat)); 212 fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model", 213 "StarFive VisionFive 2 v1.3B"); 214 215 /* gmac0 */ 216 offset = fdt_path_offset(fdt, "/soc/clock-controller@17000000"); 217 phandle = fdt_get_phandle(fdt, offset); 218 offset = fdt_path_offset(fdt, "/soc/ethernet@16030000"); 219 220 fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle); 221 fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_AONCLK_GMAC0_TX); 222 fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle); 223 fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", 224 JH7110_AONCLK_GMAC0_RMII_RTX); 225 226 /* gmac1 */ 227 offset = fdt_path_offset(fdt, "/soc/clock-controller@13020000"); 228 phandle = fdt_get_phandle(fdt, offset); 229 offset = fdt_path_offset(fdt, "/soc/ethernet@16040000"); 230 231 fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle); 232 fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_SYSCLK_GMAC1_TX); 233 fdt_setprop_u32(fdt, offset, "assigned-clock-parents", phandle); 234 fdt_appendprop_u32(fdt, offset, "assigned-clock-parents", 235 JH7110_SYSCLK_GMAC1_RMII_RTX); 236 237 for (i = 0; i < ARRAY_SIZE(starfive_verb); i++) { 238 offset = fdt_path_offset(fdt, starfive_verb[i].path); 239 240 if (starfive_verb[i].value) 241 ret = fdt_setprop_u32(fdt, offset, starfive_verb[i].name, 242 dectoul(starfive_verb[i].value, NULL)); 243 else 244 ret = fdt_setprop_empty(fdt, offset, starfive_verb[i].name); 245 246 if (ret) { 247 pr_err("%s set prop %s fail.\n", __func__, starfive_verb[i].name); 248 break; 249 } 250 } 251} 252 253void spl_perform_fixups(struct spl_image_info *spl_image) 254{ 255 u8 version; 256 const char *product_id; 257 258 product_id = get_product_id_from_eeprom(); 259 if (!product_id) { 260 pr_err("Can't read EEPROM\n"); 261 return; 262 } 263 if (!strncmp(product_id, "MARC", 4)) { 264 spl_fdt_fixup_mars_cm(spl_image->fdt_addr); 265 } else if (!strncmp(product_id, "MARS", 4)) { 266 spl_fdt_fixup_mars(spl_image->fdt_addr); 267 } else if (!strncmp(product_id, "VF7110", 6)) { 268 version = get_pcb_revision_from_eeprom(); 269 switch (version) { 270 case 'a': 271 case 'A': 272 spl_fdt_fixup_version_a(spl_image->fdt_addr); 273 break; 274 275 case 'b': 276 case 'B': 277 default: 278 spl_fdt_fixup_version_b(spl_image->fdt_addr); 279 break; 280 }; 281 } else { 282 pr_err("Unknown product %s\n", product_id); 283 }; 284 285 /* Update the memory size which read from eeprom or DT */ 286 fdt_fixup_memory(spl_image->fdt_addr, 0x40000000, gd->ram_size); 287} 288 289static void jh7110_jtag_init(void) 290{ 291 /* nTRST: GPIO36 */ 292 SYS_IOMUX_DOEN(36, HIGH); 293 SYS_IOMUX_DIN(36, 4); 294 /* TDI: GPIO61 */ 295 SYS_IOMUX_DOEN(61, HIGH); 296 SYS_IOMUX_DIN(61, 19); 297 /* TMS: GPIO63 */ 298 SYS_IOMUX_DOEN(63, HIGH); 299 SYS_IOMUX_DIN(63, 20); 300 /* TCK: GPIO60 */ 301 SYS_IOMUX_DOEN(60, HIGH); 302 SYS_IOMUX_DIN(60, 29); 303 /* TDO: GPIO44 */ 304 SYS_IOMUX_DOEN(44, 8); 305 SYS_IOMUX_DOUT(44, 22); 306} 307 308int spl_board_init_f(void) 309{ 310 int ret; 311 312 jh7110_jtag_init(); 313 314 ret = spl_dram_init(); 315 if (ret) { 316 debug("JH7110 DRAM init failed: %d\n", ret); 317 return ret; 318 } 319 320 return 0; 321} 322 323u32 spl_boot_device(void) 324{ 325 u32 mode; 326 327 mode = in_le32(JH7110_BOOT_MODE_SELECT_REG) 328 & JH7110_BOOT_MODE_SELECT_MASK; 329 switch (mode) { 330 case 0: 331 return BOOT_DEVICE_SPI; 332 333 case 1: 334 return BOOT_DEVICE_MMC2; 335 336 case 2: 337 return BOOT_DEVICE_MMC1; 338 339 case 3: 340 return BOOT_DEVICE_UART; 341 342 default: 343 debug("Unsupported boot device 0x%x.\n", mode); 344 return BOOT_DEVICE_NONE; 345 } 346} 347 348void board_init_f(ulong dummy) 349{ 350 int ret; 351 352 ret = spl_early_init(); 353 if (ret) 354 panic("spl_early_init() failed: %d\n", ret); 355 356 riscv_cpu_setup(); 357 preloader_console_init(); 358 359 /* Set the parent clock of cpu_root clock to pll0, 360 * it must be initialized here 361 */ 362 clrsetbits_le32(JH7110_SYS_CRG + JH7110_CLK_CPU_ROOT_OFFSET, 363 JH7110_CLK_CPU_ROOT_MASK, 364 BIT(JH7110_CLK_CPU_ROOT_SHIFT)); 365 366 ret = spl_board_init_f(); 367 if (ret) { 368 debug("spl_board_init_f init failed: %d\n", ret); 369 return; 370 } 371} 372 373#if CONFIG_IS_ENABLED(SPL_LOAD_FIT) 374int board_fit_config_name_match(const char *name) 375{ 376 /* boot using first FIT config */ 377 return 0; 378} 379#endif 380