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