/* * (C) Copyright 2009 * Marvell Semiconductor * Written-by: Prafulla Wadaskar * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include void reset_cpu(unsigned long ignored) { struct kwcpu_registers *cpureg = (struct kwcpu_registers *)KW_CPU_REG_BASE; writel(readl(&cpureg->rstoutn_mask) | (1 << 2), &cpureg->rstoutn_mask); writel(readl(&cpureg->sys_soft_rst) | 1, &cpureg->sys_soft_rst); while (1) ; } /* * Window Size * Used with the Base register to set the address window size and location. * Must be programmed from LSB to MSB as sequence of ones followed by * sequence of zeros. The number of ones specifies the size of the window in * 64 KByte granularity (e.g., a value of 0x00FF specifies 256 = 16 MByte). * NOTE: A value of 0x0 specifies 64-KByte size. */ unsigned int kw_winctrl_calcsize(unsigned int sizeval) { int i; unsigned int j = 0; u32 val = sizeval >> 1; for (i = 0; val >= 0x10000; i++) { j |= (1 << i); val = val >> 1; } return (0x0000ffff & j); } /* * kw_config_adr_windows - Configure address Windows * * There are 8 address windows supported by Kirkwood Soc to addess different * devices. Each window can be configured for size, BAR and remap addr * Below configuration is standard for most of the cases * * If remap function not used, remap_lo must be set as base * * Reference Documentation: * Mbus-L to Mbus Bridge Registers Configuration. * (Sec 25.1 and 25.3 of Datasheet) */ int kw_config_adr_windows(void) { struct kwwin_registers *winregs = (struct kwwin_registers *)KW_CPU_WIN_BASE; /* Window 0: PCIE MEM address space */ writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 256, KWCPU_TARGET_PCIE, KWCPU_ATTR_PCIE_MEM, KWCPU_WIN_ENABLE), &winregs[0].ctrl); writel(KW_DEFADR_PCI_MEM, &winregs[0].base); writel(KW_DEFADR_PCI_MEM, &winregs[0].remap_lo); writel(0x0, &winregs[0].remap_hi); /* Window 1: PCIE IO address space */ writel(KWCPU_WIN_CTRL_DATA(1024 * 64, KWCPU_TARGET_PCIE, KWCPU_ATTR_PCIE_IO, KWCPU_WIN_ENABLE), &winregs[1].ctrl); writel(KW_DEFADR_PCI_IO, &winregs[1].base); writel(KW_DEFADR_PCI_IO_REMAP, &winregs[1].remap_lo); writel(0x0, &winregs[1].remap_hi); /* Window 2: NAND Flash address space */ writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY, KWCPU_ATTR_NANDFLASH, KWCPU_WIN_ENABLE), &winregs[2].ctrl); writel(KW_DEFADR_NANDF, &winregs[2].base); writel(KW_DEFADR_NANDF, &winregs[2].remap_lo); writel(0x0, &winregs[2].remap_hi); /* Window 3: SPI Flash address space */ writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY, KWCPU_ATTR_SPIFLASH, KWCPU_WIN_ENABLE), &winregs[3].ctrl); writel(KW_DEFADR_SPIF, &winregs[3].base); writel(KW_DEFADR_SPIF, &winregs[3].remap_lo); writel(0x0, &winregs[3].remap_hi); /* Window 4: BOOT Memory address space */ writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY, KWCPU_ATTR_BOOTROM, KWCPU_WIN_ENABLE), &winregs[4].ctrl); writel(KW_DEFADR_BOOTROM, &winregs[4].base); /* Window 5: Security SRAM address space */ writel(KWCPU_WIN_CTRL_DATA(1024 * 64, KWCPU_TARGET_SASRAM, KWCPU_ATTR_SASRAM, KWCPU_WIN_ENABLE), &winregs[5].ctrl); writel(KW_DEFADR_SASRAM, &winregs[5].base); /* Window 6-7: Disabled */ writel(KWCPU_WIN_DISABLE, &winregs[6].ctrl); writel(KWCPU_WIN_DISABLE, &winregs[7].ctrl); return 0; } /* * SYSRSTn Duration Counter Support * * Kirkwood SoC implements a hardware-based SYSRSTn duration counter. * When SYSRSTn is asserted low, a SYSRSTn duration counter is running. * The SYSRSTn duration counter is useful for implementing a manufacturer * or factory reset. Upon a long reset assertion that is greater than a * pre-configured environment variable value for sysrstdelay, * The counter value is stored in the SYSRSTn Length Counter Register * The counter is based on the 25-MHz reference clock (40ns) * It is a 29-bit counter, yielding a maximum counting duration of * 2^29/25 MHz (21.4 seconds). When the counter reach its maximum value, * it remains at this value until counter reset is triggered by setting * bit 31 of KW_REG_SYSRST_CNT */ static void kw_sysrst_action(void) { int ret; char *s = getenv("sysrstcmd"); if (!s) { debug("Error.. %s failed, check sysrstcmd\n", __FUNCTION__); return; } debug("Starting %s process...\n", __FUNCTION__); ret = run_command(s, 0); if (ret != 0) debug("Error.. %s failed\n", __FUNCTION__); else debug("%s process finished\n", __FUNCTION__); } static void kw_sysrst_check(void) { u32 sysrst_cnt, sysrst_dly; char *s; /* * no action if sysrstdelay environment variable is not defined */ s = getenv("sysrstdelay"); if (s == NULL) return; /* read sysrstdelay value */ sysrst_dly = (u32) simple_strtoul(s, NULL, 10); /* read SysRst Length counter register (bits 28:0) */ sysrst_cnt = (0x1fffffff & readl(KW_REG_SYSRST_CNT)); debug("H/w Rst hold time: %d.%d secs\n", sysrst_cnt / SYSRST_CNT_1SEC_VAL, sysrst_cnt % SYSRST_CNT_1SEC_VAL); /* clear the counter for next valid read*/ writel(1 << 31, KW_REG_SYSRST_CNT); /* * sysrst_action: * if H/w Reset key is pressed and hold for time * more than sysrst_dly in seconds */ if (sysrst_cnt >= SYSRST_CNT_1SEC_VAL * sysrst_dly) kw_sysrst_action(); } #if defined(CONFIG_DISPLAY_CPUINFO) int print_cpuinfo(void) { char *rev = "??"; u16 devid = (readl(KW_REG_PCIE_DEVID) >> 16) & 0xffff; u8 revid = readl(KW_REG_PCIE_REVID) & 0xff; if ((readl(KW_REG_DEVICE_ID) & 0x03) > 2) { printf("Error.. %s:Unsupported Kirkwood SoC 88F%04x\n", __FUNCTION__, devid); return -1; } switch (revid) { case 0: if (devid == 0x6281) rev = "Z0"; else if (devid == 0x6282) rev = "A0"; break; case 1: rev = "A1"; break; case 2: rev = "A0"; break; case 3: rev = "A1"; break; default: break; } printf("SoC: Kirkwood 88F%04x_%s\n", devid, rev); return 0; } #endif /* CONFIG_DISPLAY_CPUINFO */ #ifdef CONFIG_ARCH_CPU_INIT int arch_cpu_init(void) { u32 reg; struct kwcpu_registers *cpureg = (struct kwcpu_registers *)KW_CPU_REG_BASE; /* Linux expects` the internal registers to be at 0xf1000000 */ writel(KW_REGS_PHY_BASE, KW_OFFSET_REG); /* Enable and invalidate L2 cache in write through mode */ writel(readl(&cpureg->l2_cfg) | 0x18, &cpureg->l2_cfg); invalidate_l2_cache(); kw_config_adr_windows(); #ifdef CONFIG_KIRKWOOD_RGMII_PAD_1V8 /* * Configures the I/O voltage of the pads connected to Egigabit * Ethernet interface to 1.8V * By default it is set to 3.3V */ reg = readl(KW_REG_MPP_OUT_DRV_REG); reg |= (1 << 7); writel(reg, KW_REG_MPP_OUT_DRV_REG); #endif #ifdef CONFIG_KIRKWOOD_EGIGA_INIT /* * Set egiga port0/1 in normal functional mode * This is required becasue on kirkwood by default ports are in reset mode * OS egiga driver may not have provision to set them in normal mode * and if u-boot is build without network support, network may fail at OS level */ reg = readl(KWGBE_PORT_SERIAL_CONTROL1_REG(0)); reg &= ~(1 << 4); /* Clear PortReset Bit */ writel(reg, (KWGBE_PORT_SERIAL_CONTROL1_REG(0))); reg = readl(KWGBE_PORT_SERIAL_CONTROL1_REG(1)); reg &= ~(1 << 4); /* Clear PortReset Bit */ writel(reg, (KWGBE_PORT_SERIAL_CONTROL1_REG(1))); #endif #ifdef CONFIG_KIRKWOOD_PCIE_INIT /* * Enable PCI Express Port0 */ reg = readl(&cpureg->ctrl_stat); reg |= (1 << 0); /* Set PEX0En Bit */ writel(reg, &cpureg->ctrl_stat); #endif return 0; } #endif /* CONFIG_ARCH_CPU_INIT */ /* * SOC specific misc init */ #if defined(CONFIG_ARCH_MISC_INIT) int arch_misc_init(void) { volatile u32 temp; /*CPU streaming & write allocate */ temp = readfr_extra_feature_reg(); temp &= ~(1 << 28); /* disable wr alloc */ writefr_extra_feature_reg(temp); temp = readfr_extra_feature_reg(); temp &= ~(1 << 29); /* streaming disabled */ writefr_extra_feature_reg(temp); /* L2Cache settings */ temp = readfr_extra_feature_reg(); /* Disable L2C pre fetch - Set bit 24 */ temp |= (1 << 24); /* enable L2C - Set bit 22 */ temp |= (1 << 22); writefr_extra_feature_reg(temp); icache_enable(); /* Change reset vector to address 0x0 */ temp = get_cr(); set_cr(temp & ~CR_V); /* checks and execute resset to factory event */ kw_sysrst_check(); return 0; } #endif /* CONFIG_ARCH_MISC_INIT */ #ifdef CONFIG_MVGBE int cpu_eth_init(bd_t *bis) { mvgbe_initialize(bis); return 0; } #endif #ifdef CONFIG_MVEBU_MMC int board_mmc_init(bd_t *bis) { mvebu_mmc_init(bis); return 0; } #endif /* CONFIG_MVEBU_MMC */