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