15396e8b1SAlexey Brodkin // SPDX-License-Identifier: GPL-2.0+
25396e8b1SAlexey Brodkin /*
35396e8b1SAlexey Brodkin  * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
45396e8b1SAlexey Brodkin  */
55396e8b1SAlexey Brodkin 
65396e8b1SAlexey Brodkin #include <common.h>
75396e8b1SAlexey Brodkin #include <malloc.h>
85396e8b1SAlexey Brodkin #include <dwmmc.h>
95396e8b1SAlexey Brodkin #include <linux/libfdt.h>
105396e8b1SAlexey Brodkin #include <fdtdec.h>
115396e8b1SAlexey Brodkin 
125396e8b1SAlexey Brodkin #include <asm/arcregs.h>
135396e8b1SAlexey Brodkin 
145396e8b1SAlexey Brodkin DECLARE_GLOBAL_DATA_PTR;
155396e8b1SAlexey Brodkin 
165396e8b1SAlexey Brodkin #define SYSCON_BASE	0xf000a000
175396e8b1SAlexey Brodkin #define AHBCKDIV	(void *)(SYSCON_BASE + 0x04)
185396e8b1SAlexey Brodkin #define APBCKDIV	(void *)(SYSCON_BASE + 0x08)
195396e8b1SAlexey Brodkin #define APBCKEN		(void *)(SYSCON_BASE + 0x0C)
207d388addSAlexey Brodkin #define RESET_REG	(void *)(SYSCON_BASE + 0x18)
215396e8b1SAlexey Brodkin #define CLKSEL		(void *)(SYSCON_BASE + 0x24)
225396e8b1SAlexey Brodkin #define CLKSTAT		(void *)(SYSCON_BASE + 0x28)
235396e8b1SAlexey Brodkin #define PLLCON		(void *)(SYSCON_BASE + 0x2C)
245396e8b1SAlexey Brodkin #define APBCKSEL	(void *)(SYSCON_BASE + 0x30)
255396e8b1SAlexey Brodkin #define AHBCKEN		(void *)(SYSCON_BASE + 0x34)
265396e8b1SAlexey Brodkin #define USBPHY_PLL	(void *)(SYSCON_BASE + 0x78)
275396e8b1SAlexey Brodkin #define USBCFG		(void *)(SYSCON_BASE + 0x7c)
285396e8b1SAlexey Brodkin 
295396e8b1SAlexey Brodkin #define PLL_MASK_0	0xffcfffff
305396e8b1SAlexey Brodkin #define PLL_MASK_1	0xffcfff00
315396e8b1SAlexey Brodkin #define PLL_MASK_2	0xfbcfff00
325396e8b1SAlexey Brodkin 
335396e8b1SAlexey Brodkin #define CLKSEL_DEFAULT	0x5a690000
345396e8b1SAlexey Brodkin 
set_cpu_freq(unsigned int clk)355396e8b1SAlexey Brodkin static int set_cpu_freq(unsigned int clk)
365396e8b1SAlexey Brodkin {
375396e8b1SAlexey Brodkin 	clk /= 1000000;
385396e8b1SAlexey Brodkin 
395396e8b1SAlexey Brodkin 	/* Set clk to ext Xtal (LSN value 0) */
405396e8b1SAlexey Brodkin 	writel(CLKSEL_DEFAULT, CLKSEL);
415396e8b1SAlexey Brodkin 
425396e8b1SAlexey Brodkin 	switch (clk) {
435396e8b1SAlexey Brodkin 	case 16:
445396e8b1SAlexey Brodkin 		/* Bypass mode */
455396e8b1SAlexey Brodkin 		return 0;
465396e8b1SAlexey Brodkin 
475396e8b1SAlexey Brodkin 	case 50:
485396e8b1SAlexey Brodkin 		writel(readl(PLLCON) & PLL_MASK_0, PLLCON);
495396e8b1SAlexey Brodkin 		/* pll_off=1, M=25, N=1, OD=3, PLL_OUT_CLK=50M */
505396e8b1SAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_1) | 0x300191, PLLCON);
515396e8b1SAlexey Brodkin 		/* pll_off=0, M=25, N=1, OD=3, PLL_OUT_CLK=50M */
525396e8b1SAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_2) | 0x300191, PLLCON);
535396e8b1SAlexey Brodkin 		break;
545396e8b1SAlexey Brodkin 
555396e8b1SAlexey Brodkin 	case 72:
565396e8b1SAlexey Brodkin 		writel(readl(PLLCON) & PLL_MASK_0, PLLCON);
575396e8b1SAlexey Brodkin 		/* pll_off=1, M=18, N=1, OD=2, PLL_OUT_CLK=72M */
585396e8b1SAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_1) | 0x200121, PLLCON);
595396e8b1SAlexey Brodkin 		/* pll_off=0, M=18, N=1, OD=2, PLL_OUT_CLK=72M */
605396e8b1SAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_2) | 0x200121, PLLCON);
615396e8b1SAlexey Brodkin 		break;
625396e8b1SAlexey Brodkin 
635396e8b1SAlexey Brodkin 	case 100:
645396e8b1SAlexey Brodkin 		writel(readl(PLLCON) & PLL_MASK_0, PLLCON);
655396e8b1SAlexey Brodkin 		/* pll_off=1,M=25, N=1, OD=2, PLL_OUT_CLK=100M */
665396e8b1SAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_1) | 0x200191, PLLCON);
675396e8b1SAlexey Brodkin 		/* pll_off=0,M=25, N=1, OD=2, PLL_OUT_CLK=100M */
685396e8b1SAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_2) | 0x200191, PLLCON);
695396e8b1SAlexey Brodkin 		break;
705396e8b1SAlexey Brodkin 
71031154feSAlexey Brodkin 	case 136:
72031154feSAlexey Brodkin 		writel(readl(PLLCON) & PLL_MASK_0, PLLCON);
73031154feSAlexey Brodkin 		/* pll_off=1, M=17, N=1, OD=1, PLL_OUT_CLK=136M */
74031154feSAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_1) | 0x100111, PLLCON);
75031154feSAlexey Brodkin 		/* pll_off=0, M=17, N=1, OD=1, PLL_OUT_CLK=136M */
76031154feSAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_2) | 0x100111, PLLCON);
77031154feSAlexey Brodkin 		break;
78031154feSAlexey Brodkin 
795396e8b1SAlexey Brodkin 	case 144:
805396e8b1SAlexey Brodkin 		writel(readl(PLLCON) & PLL_MASK_0, PLLCON);
815396e8b1SAlexey Brodkin 		/* pll_off=1, M=18, N=1, OD=1, PLL_OUT_CLK=144M */
825396e8b1SAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_1) | 0x100121, PLLCON);
835396e8b1SAlexey Brodkin 		/* pll_off=0, M=18, N=1, OD=1, PLL_OUT_CLK=144M */
845396e8b1SAlexey Brodkin 		writel((readl(PLLCON) & PLL_MASK_2) | 0x100121, PLLCON);
855396e8b1SAlexey Brodkin 		break;
865396e8b1SAlexey Brodkin 
875396e8b1SAlexey Brodkin 	default:
885396e8b1SAlexey Brodkin 		return -EINVAL;
895396e8b1SAlexey Brodkin 	}
905396e8b1SAlexey Brodkin 
915396e8b1SAlexey Brodkin 	while (!(readl(CLKSTAT) & 0x4))
925396e8b1SAlexey Brodkin 		;
935396e8b1SAlexey Brodkin 
945396e8b1SAlexey Brodkin 	/* Set clk from PLL on bus (LSN = 1) */
955396e8b1SAlexey Brodkin 	writel(CLKSEL_DEFAULT | BIT(0), CLKSEL);
965396e8b1SAlexey Brodkin 
975396e8b1SAlexey Brodkin 	return 0;
985396e8b1SAlexey Brodkin }
995396e8b1SAlexey Brodkin 
1005396e8b1SAlexey Brodkin extern u8 __rom_end[];
1015396e8b1SAlexey Brodkin extern u8 __ram_start[];
1025396e8b1SAlexey Brodkin extern u8 __ram_end[];
1035396e8b1SAlexey Brodkin 
1045396e8b1SAlexey Brodkin /*
1055396e8b1SAlexey Brodkin  * Use mach_cpu_init() for .data section copy as board_early_init_f() will be
1065396e8b1SAlexey Brodkin  * too late: initf_dm() will use a value of "av_" variable from not yet
1075396e8b1SAlexey Brodkin  * initialized (by copy) area.
1085396e8b1SAlexey Brodkin  */
mach_cpu_init(void)1095396e8b1SAlexey Brodkin int mach_cpu_init(void)
1105396e8b1SAlexey Brodkin {
1118a8f32d8SAlexey Brodkin 	int offset;
1125396e8b1SAlexey Brodkin 
1135396e8b1SAlexey Brodkin 	/* Don't relocate U-Boot */
1145396e8b1SAlexey Brodkin 	gd->flags |= GD_FLG_SKIP_RELOC;
1155396e8b1SAlexey Brodkin 
1165396e8b1SAlexey Brodkin 	/* Copy data from ROM to RAM */
1175396e8b1SAlexey Brodkin 	u8 *src = __rom_end;
1185396e8b1SAlexey Brodkin 	u8 *dst = __ram_start;
1195396e8b1SAlexey Brodkin 
1205396e8b1SAlexey Brodkin 	while (dst < __ram_end)
1215396e8b1SAlexey Brodkin 		*dst++ = *src++;
1225396e8b1SAlexey Brodkin 
1235396e8b1SAlexey Brodkin 	/* Enable debug uart */
1245396e8b1SAlexey Brodkin #define DEBUG_UART_BASE		0x80014000
1255396e8b1SAlexey Brodkin #define DEBUG_UART_DLF_OFFSET	0xc0
1265396e8b1SAlexey Brodkin 	write_aux_reg(DEBUG_UART_BASE + DEBUG_UART_DLF_OFFSET, 1);
1275396e8b1SAlexey Brodkin 
1285396e8b1SAlexey Brodkin 	offset = fdt_path_offset(gd->fdt_blob, "/cpu_card/core_clk");
1295396e8b1SAlexey Brodkin 	if (offset < 0)
1305396e8b1SAlexey Brodkin 		return offset;
1315396e8b1SAlexey Brodkin 
1328a8f32d8SAlexey Brodkin 	gd->cpu_clk = fdtdec_get_int(gd->fdt_blob, offset, "clock-frequency", 0);
1338a8f32d8SAlexey Brodkin 	if (!gd->cpu_clk)
1345396e8b1SAlexey Brodkin 		return -EINVAL;
1355396e8b1SAlexey Brodkin 
1365396e8b1SAlexey Brodkin 	/* If CPU freq > 100 MHz, divide eFLASH clock by 2 */
1378a8f32d8SAlexey Brodkin 	if (gd->cpu_clk > 100000000) {
1385396e8b1SAlexey Brodkin 		u32 reg = readl(AHBCKDIV);
1395396e8b1SAlexey Brodkin 
1405396e8b1SAlexey Brodkin 		reg &= ~(0xF << 8);
1415396e8b1SAlexey Brodkin 		reg |= 2 << 8;
1425396e8b1SAlexey Brodkin 		writel(reg, AHBCKDIV);
1435396e8b1SAlexey Brodkin 	}
1445396e8b1SAlexey Brodkin 
1458a8f32d8SAlexey Brodkin 	return set_cpu_freq(gd->cpu_clk);
1465396e8b1SAlexey Brodkin }
1475396e8b1SAlexey Brodkin 
1485396e8b1SAlexey Brodkin #define ARC_PERIPHERAL_BASE	0xF0000000
1495396e8b1SAlexey Brodkin #define SDIO_BASE		(ARC_PERIPHERAL_BASE + 0xB000)
1505396e8b1SAlexey Brodkin 
board_mmc_init(bd_t * bis)1515396e8b1SAlexey Brodkin int board_mmc_init(bd_t *bis)
1525396e8b1SAlexey Brodkin {
1535396e8b1SAlexey Brodkin 	struct dwmci_host *host = NULL;
1545396e8b1SAlexey Brodkin 
1555396e8b1SAlexey Brodkin 	host = malloc(sizeof(struct dwmci_host));
1565396e8b1SAlexey Brodkin 	if (!host) {
1575396e8b1SAlexey Brodkin 		printf("dwmci_host malloc fail!\n");
1585396e8b1SAlexey Brodkin 		return -ENOMEM;
1595396e8b1SAlexey Brodkin 	}
1605396e8b1SAlexey Brodkin 
1615396e8b1SAlexey Brodkin 	memset(host, 0, sizeof(struct dwmci_host));
1625396e8b1SAlexey Brodkin 	host->name = "Synopsys Mobile storage";
1635396e8b1SAlexey Brodkin 	host->ioaddr = (void *)SDIO_BASE;
1645396e8b1SAlexey Brodkin 	host->buswidth = 4;
1655396e8b1SAlexey Brodkin 	host->dev_index = 0;
1665396e8b1SAlexey Brodkin 	host->bus_hz = 50000000;
1675396e8b1SAlexey Brodkin 
1685396e8b1SAlexey Brodkin 	add_dwmci(host, host->bus_hz / 2, 400000);
1695396e8b1SAlexey Brodkin 
1705396e8b1SAlexey Brodkin 	return 0;
1715396e8b1SAlexey Brodkin }
1725396e8b1SAlexey Brodkin 
board_mmc_getcd(struct mmc * mmc)173*9f87d470SAlexey Brodkin int board_mmc_getcd(struct mmc *mmc)
174*9f87d470SAlexey Brodkin {
175*9f87d470SAlexey Brodkin 	struct dwmci_host *host = mmc->priv;
176*9f87d470SAlexey Brodkin 
177*9f87d470SAlexey Brodkin 	return !(dwmci_readl(host, DWMCI_CDETECT) & 1);
178*9f87d470SAlexey Brodkin }
179*9f87d470SAlexey Brodkin 
1807d388addSAlexey Brodkin #define IOTDK_RESET_SEQ		0x55AA6699
1817d388addSAlexey Brodkin 
reset_cpu(ulong addr)1827d388addSAlexey Brodkin void reset_cpu(ulong addr)
1837d388addSAlexey Brodkin {
1847d388addSAlexey Brodkin 	writel(IOTDK_RESET_SEQ, RESET_REG);
1857d388addSAlexey Brodkin }
1867d388addSAlexey Brodkin 
checkboard(void)1875396e8b1SAlexey Brodkin int checkboard(void)
1885396e8b1SAlexey Brodkin {
1895396e8b1SAlexey Brodkin 	puts("Board: Synopsys IoT Development Kit\n");
1905396e8b1SAlexey Brodkin 	return 0;
1915396e8b1SAlexey Brodkin };
192