1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2018 Synopsys, Inc. All rights reserved. 4 */ 5 6 #include <common.h> 7 #include <malloc.h> 8 #include <dwmmc.h> 9 #include <linux/libfdt.h> 10 #include <fdtdec.h> 11 12 #include <asm/arcregs.h> 13 14 DECLARE_GLOBAL_DATA_PTR; 15 16 #define SYSCON_BASE 0xf000a000 17 #define AHBCKDIV (void *)(SYSCON_BASE + 0x04) 18 #define APBCKDIV (void *)(SYSCON_BASE + 0x08) 19 #define APBCKEN (void *)(SYSCON_BASE + 0x0C) 20 #define RESET_REG (void *)(SYSCON_BASE + 0x18) 21 #define CLKSEL (void *)(SYSCON_BASE + 0x24) 22 #define CLKSTAT (void *)(SYSCON_BASE + 0x28) 23 #define PLLCON (void *)(SYSCON_BASE + 0x2C) 24 #define APBCKSEL (void *)(SYSCON_BASE + 0x30) 25 #define AHBCKEN (void *)(SYSCON_BASE + 0x34) 26 #define USBPHY_PLL (void *)(SYSCON_BASE + 0x78) 27 #define USBCFG (void *)(SYSCON_BASE + 0x7c) 28 29 #define PLL_MASK_0 0xffcfffff 30 #define PLL_MASK_1 0xffcfff00 31 #define PLL_MASK_2 0xfbcfff00 32 33 #define CLKSEL_DEFAULT 0x5a690000 34 35 static int set_cpu_freq(unsigned int clk) 36 { 37 clk /= 1000000; 38 39 /* Set clk to ext Xtal (LSN value 0) */ 40 writel(CLKSEL_DEFAULT, CLKSEL); 41 42 switch (clk) { 43 case 16: 44 /* Bypass mode */ 45 return 0; 46 47 case 50: 48 writel(readl(PLLCON) & PLL_MASK_0, PLLCON); 49 /* pll_off=1, M=25, N=1, OD=3, PLL_OUT_CLK=50M */ 50 writel((readl(PLLCON) & PLL_MASK_1) | 0x300191, PLLCON); 51 /* pll_off=0, M=25, N=1, OD=3, PLL_OUT_CLK=50M */ 52 writel((readl(PLLCON) & PLL_MASK_2) | 0x300191, PLLCON); 53 break; 54 55 case 72: 56 writel(readl(PLLCON) & PLL_MASK_0, PLLCON); 57 /* pll_off=1, M=18, N=1, OD=2, PLL_OUT_CLK=72M */ 58 writel((readl(PLLCON) & PLL_MASK_1) | 0x200121, PLLCON); 59 /* pll_off=0, M=18, N=1, OD=2, PLL_OUT_CLK=72M */ 60 writel((readl(PLLCON) & PLL_MASK_2) | 0x200121, PLLCON); 61 break; 62 63 case 100: 64 writel(readl(PLLCON) & PLL_MASK_0, PLLCON); 65 /* pll_off=1,M=25, N=1, OD=2, PLL_OUT_CLK=100M */ 66 writel((readl(PLLCON) & PLL_MASK_1) | 0x200191, PLLCON); 67 /* pll_off=0,M=25, N=1, OD=2, PLL_OUT_CLK=100M */ 68 writel((readl(PLLCON) & PLL_MASK_2) | 0x200191, PLLCON); 69 break; 70 71 case 136: 72 writel(readl(PLLCON) & PLL_MASK_0, PLLCON); 73 /* pll_off=1, M=17, N=1, OD=1, PLL_OUT_CLK=136M */ 74 writel((readl(PLLCON) & PLL_MASK_1) | 0x100111, PLLCON); 75 /* pll_off=0, M=17, N=1, OD=1, PLL_OUT_CLK=136M */ 76 writel((readl(PLLCON) & PLL_MASK_2) | 0x100111, PLLCON); 77 break; 78 79 case 144: 80 writel(readl(PLLCON) & PLL_MASK_0, PLLCON); 81 /* pll_off=1, M=18, N=1, OD=1, PLL_OUT_CLK=144M */ 82 writel((readl(PLLCON) & PLL_MASK_1) | 0x100121, PLLCON); 83 /* pll_off=0, M=18, N=1, OD=1, PLL_OUT_CLK=144M */ 84 writel((readl(PLLCON) & PLL_MASK_2) | 0x100121, PLLCON); 85 break; 86 87 default: 88 return -EINVAL; 89 } 90 91 while (!(readl(CLKSTAT) & 0x4)) 92 ; 93 94 /* Set clk from PLL on bus (LSN = 1) */ 95 writel(CLKSEL_DEFAULT | BIT(0), CLKSEL); 96 97 return 0; 98 } 99 100 extern u8 __rom_end[]; 101 extern u8 __ram_start[]; 102 extern u8 __ram_end[]; 103 104 /* 105 * Use mach_cpu_init() for .data section copy as board_early_init_f() will be 106 * too late: initf_dm() will use a value of "av_" variable from not yet 107 * initialized (by copy) area. 108 */ 109 int mach_cpu_init(void) 110 { 111 int offset; 112 113 /* Don't relocate U-Boot */ 114 gd->flags |= GD_FLG_SKIP_RELOC; 115 116 /* Copy data from ROM to RAM */ 117 u8 *src = __rom_end; 118 u8 *dst = __ram_start; 119 120 while (dst < __ram_end) 121 *dst++ = *src++; 122 123 /* Enable debug uart */ 124 #define DEBUG_UART_BASE 0x80014000 125 #define DEBUG_UART_DLF_OFFSET 0xc0 126 write_aux_reg(DEBUG_UART_BASE + DEBUG_UART_DLF_OFFSET, 1); 127 128 offset = fdt_path_offset(gd->fdt_blob, "/cpu_card/core_clk"); 129 if (offset < 0) 130 return offset; 131 132 gd->cpu_clk = fdtdec_get_int(gd->fdt_blob, offset, "clock-frequency", 0); 133 if (!gd->cpu_clk) 134 return -EINVAL; 135 136 /* If CPU freq > 100 MHz, divide eFLASH clock by 2 */ 137 if (gd->cpu_clk > 100000000) { 138 u32 reg = readl(AHBCKDIV); 139 140 reg &= ~(0xF << 8); 141 reg |= 2 << 8; 142 writel(reg, AHBCKDIV); 143 } 144 145 return set_cpu_freq(gd->cpu_clk); 146 } 147 148 #define ARC_PERIPHERAL_BASE 0xF0000000 149 #define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xB000) 150 151 int board_mmc_init(bd_t *bis) 152 { 153 struct dwmci_host *host = NULL; 154 155 host = malloc(sizeof(struct dwmci_host)); 156 if (!host) { 157 printf("dwmci_host malloc fail!\n"); 158 return -ENOMEM; 159 } 160 161 memset(host, 0, sizeof(struct dwmci_host)); 162 host->name = "Synopsys Mobile storage"; 163 host->ioaddr = (void *)SDIO_BASE; 164 host->buswidth = 4; 165 host->dev_index = 0; 166 host->bus_hz = 50000000; 167 168 add_dwmci(host, host->bus_hz / 2, 400000); 169 170 return 0; 171 } 172 173 int board_mmc_getcd(struct mmc *mmc) 174 { 175 struct dwmci_host *host = mmc->priv; 176 177 return !(dwmci_readl(host, DWMCI_CDETECT) & 1); 178 } 179 180 #define IOTDK_RESET_SEQ 0x55AA6699 181 182 void reset_cpu(ulong addr) 183 { 184 writel(IOTDK_RESET_SEQ, RESET_REG); 185 } 186 187 int checkboard(void) 188 { 189 puts("Board: Synopsys IoT Development Kit\n"); 190 return 0; 191 }; 192 193 #ifdef CONFIG_DISPLAY_CPUINFO 194 int print_cpuinfo(void) 195 { 196 char mhz[8]; 197 198 printf("CPU: ARC EM9D at %s MHz\n", strmhz(mhz, gd->cpu_clk)); 199 return 0; 200 } 201 #endif /* CONFIG_DISPLAY_CPUINFO */ 202