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 CLKSEL (void *)(SYSCON_BASE + 0x24) 21 #define CLKSTAT (void *)(SYSCON_BASE + 0x28) 22 #define PLLCON (void *)(SYSCON_BASE + 0x2C) 23 #define APBCKSEL (void *)(SYSCON_BASE + 0x30) 24 #define AHBCKEN (void *)(SYSCON_BASE + 0x34) 25 #define USBPHY_PLL (void *)(SYSCON_BASE + 0x78) 26 #define USBCFG (void *)(SYSCON_BASE + 0x7c) 27 28 #define PLL_MASK_0 0xffcfffff 29 #define PLL_MASK_1 0xffcfff00 30 #define PLL_MASK_2 0xfbcfff00 31 32 #define CLKSEL_DEFAULT 0x5a690000 33 34 static int set_cpu_freq(unsigned int clk) 35 { 36 clk /= 1000000; 37 38 /* Set clk to ext Xtal (LSN value 0) */ 39 writel(CLKSEL_DEFAULT, CLKSEL); 40 41 switch (clk) { 42 case 16: 43 /* Bypass mode */ 44 return 0; 45 46 case 50: 47 writel(readl(PLLCON) & PLL_MASK_0, PLLCON); 48 /* pll_off=1, M=25, N=1, OD=3, PLL_OUT_CLK=50M */ 49 writel((readl(PLLCON) & PLL_MASK_1) | 0x300191, PLLCON); 50 /* pll_off=0, M=25, N=1, OD=3, PLL_OUT_CLK=50M */ 51 writel((readl(PLLCON) & PLL_MASK_2) | 0x300191, PLLCON); 52 break; 53 54 case 72: 55 writel(readl(PLLCON) & PLL_MASK_0, PLLCON); 56 /* pll_off=1, M=18, N=1, OD=2, PLL_OUT_CLK=72M */ 57 writel((readl(PLLCON) & PLL_MASK_1) | 0x200121, PLLCON); 58 /* pll_off=0, M=18, N=1, OD=2, PLL_OUT_CLK=72M */ 59 writel((readl(PLLCON) & PLL_MASK_2) | 0x200121, PLLCON); 60 break; 61 62 case 100: 63 writel(readl(PLLCON) & PLL_MASK_0, PLLCON); 64 /* pll_off=1,M=25, N=1, OD=2, PLL_OUT_CLK=100M */ 65 writel((readl(PLLCON) & PLL_MASK_1) | 0x200191, PLLCON); 66 /* pll_off=0,M=25, N=1, OD=2, PLL_OUT_CLK=100M */ 67 writel((readl(PLLCON) & PLL_MASK_2) | 0x200191, PLLCON); 68 break; 69 70 case 144: 71 writel(readl(PLLCON) & PLL_MASK_0, PLLCON); 72 /* pll_off=1, M=18, N=1, OD=1, PLL_OUT_CLK=144M */ 73 writel((readl(PLLCON) & PLL_MASK_1) | 0x100121, PLLCON); 74 /* pll_off=0, M=18, N=1, OD=1, PLL_OUT_CLK=144M */ 75 writel((readl(PLLCON) & PLL_MASK_2) | 0x100121, PLLCON); 76 break; 77 78 default: 79 return -EINVAL; 80 } 81 82 while (!(readl(CLKSTAT) & 0x4)) 83 ; 84 85 /* Set clk from PLL on bus (LSN = 1) */ 86 writel(CLKSEL_DEFAULT | BIT(0), CLKSEL); 87 88 return 0; 89 } 90 91 extern u8 __rom_end[]; 92 extern u8 __ram_start[]; 93 extern u8 __ram_end[]; 94 95 /* 96 * Use mach_cpu_init() for .data section copy as board_early_init_f() will be 97 * too late: initf_dm() will use a value of "av_" variable from not yet 98 * initialized (by copy) area. 99 */ 100 int mach_cpu_init(void) 101 { 102 int offset, freq; 103 104 /* Don't relocate U-Boot */ 105 gd->flags |= GD_FLG_SKIP_RELOC; 106 107 /* Copy data from ROM to RAM */ 108 u8 *src = __rom_end; 109 u8 *dst = __ram_start; 110 111 while (dst < __ram_end) 112 *dst++ = *src++; 113 114 /* Enable debug uart */ 115 #define DEBUG_UART_BASE 0x80014000 116 #define DEBUG_UART_DLF_OFFSET 0xc0 117 write_aux_reg(DEBUG_UART_BASE + DEBUG_UART_DLF_OFFSET, 1); 118 119 offset = fdt_path_offset(gd->fdt_blob, "/cpu_card/core_clk"); 120 if (offset < 0) 121 return offset; 122 123 freq = fdtdec_get_int(gd->fdt_blob, offset, "clock-frequency", 0); 124 if (!freq) 125 return -EINVAL; 126 127 /* If CPU freq > 100 MHz, divide eFLASH clock by 2 */ 128 if (freq > 100000000) { 129 u32 reg = readl(AHBCKDIV); 130 131 reg &= ~(0xF << 8); 132 reg |= 2 << 8; 133 writel(reg, AHBCKDIV); 134 } 135 136 return set_cpu_freq(freq); 137 } 138 139 #define ARC_PERIPHERAL_BASE 0xF0000000 140 #define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xB000) 141 142 int board_mmc_init(bd_t *bis) 143 { 144 struct dwmci_host *host = NULL; 145 146 host = malloc(sizeof(struct dwmci_host)); 147 if (!host) { 148 printf("dwmci_host malloc fail!\n"); 149 return -ENOMEM; 150 } 151 152 memset(host, 0, sizeof(struct dwmci_host)); 153 host->name = "Synopsys Mobile storage"; 154 host->ioaddr = (void *)SDIO_BASE; 155 host->buswidth = 4; 156 host->dev_index = 0; 157 host->bus_hz = 50000000; 158 159 add_dwmci(host, host->bus_hz / 2, 400000); 160 161 return 0; 162 } 163 164 int checkboard(void) 165 { 166 puts("Board: Synopsys IoT Development Kit\n"); 167 return 0; 168 }; 169