+static void smp_kick_cpu_x(u32 cpu_id)
+{
+ int cmd = readl((void __iomem *)CREG_CPU_START);
+
+ if (cpu_id > NR_CPUS)
+ return;
+
+ cmd &= ~CREG_CPU_START_MASK;
+ cmd |= (1 << cpu_id);
+ writel(cmd, (void __iomem *)CREG_CPU_START);
+}
+
+static u32 prepare_cpu_ctart_reg(void)
+{
+ int cmd = readl((void __iomem *)CREG_CPU_START);
+
+ cmd &= ~CREG_CPU_START_MASK;
+
+ return cmd | env_common.core_mask.val;
+}
+
+/* slave CPU entry for configuration */
+__attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void)
+{
+ __asm__ __volatile__(
+ "ld.di r8, [%0]\n"
+ "mov %%sp, r8\n"
+ "mov %%fp, %%sp\n"
+ : /* no output */
+ : "r" (&cross_cpu_data.stack_ptr));
+
+ invalidate_icache_all();
+
+ arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_1);
+ init_slave_cpu_func(CPU_ID_GET());
+
+ arc_write_uncached_32(&cross_cpu_data.ready_flag, SLAVE_CPU_READY);
+ arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_2);
+
+ /* Halt the processor until the master kick us again */
+ halt_this_cpu();
+
+ /*
+ * 3 NOPs after FLAG 1 instruction are no longer required for ARCv2
+ * cores but we leave them for gebug purposes.
+ */
+ __builtin_arc_nop();
+ __builtin_arc_nop();
+ __builtin_arc_nop();
+
+ arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_3);
+
+ /* get the updated entry - invalidate i$ */
+ invalidate_icache_all();
+
+ arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_4);
+
+ /* Run our program */
+ ((void (*)(void))(arc_read_uncached_32(&cross_cpu_data.entry[CPU_ID_GET()])))();
+
+ /* This bootstage is unreachable as we don't return from app we launch */
+ arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_5);
+
+ /* Something went terribly wrong */
+ while (true)
+ halt_this_cpu();
+}
+
+static void clear_cross_cpu_data(void)
+{
+ arc_write_uncached_32(&cross_cpu_data.ready_flag, 0);
+ arc_write_uncached_32(&cross_cpu_data.stack_ptr, 0);
+
+ for (u32 i = 0; i < NR_CPUS; i++)
+ arc_write_uncached_32(&cross_cpu_data.status[i], 0);
+}
+
+static noinline void do_init_slave_cpu(u32 cpu_id)
+{
+ /* attempts number for check clave CPU ready_flag */
+ u32 attempts = 100;
+ u32 stack_ptr = (u32)(slave_stack + (64 * cpu_id));
+
+ if (cpu_id >= NR_CPUS)
+ return;
+
+ arc_write_uncached_32(&cross_cpu_data.ready_flag, 0);
+
+ /* Use global unique place for each slave cpu stack */
+ arc_write_uncached_32(&cross_cpu_data.stack_ptr, stack_ptr);
+
+ debug("CPU %u: stack pool base: %p\n", cpu_id, slave_stack);
+ debug("CPU %u: current slave stack base: %x\n", cpu_id, stack_ptr);
+ slave_cpu_set_boot_addr((u32)hsdk_core_init_f);
+
+ smp_kick_cpu_x(cpu_id);
+
+ debug("CPU %u: cross-cpu flag: %x [before timeout]\n", cpu_id,
+ arc_read_uncached_32(&cross_cpu_data.ready_flag));
+
+ while (!arc_read_uncached_32(&cross_cpu_data.ready_flag) && attempts--)
+ mdelay(10);
+
+ /* Just to be sure that slave cpu is halted after it set ready_flag */
+ mdelay(20);
+
+ /*
+ * Only print error here if we reach timeout as there is no option to
+ * halt slave cpu (or check that slave cpu is halted)
+ */
+ if (!attempts)
+ pr_err("CPU %u is not responding after init!\n", cpu_id);
+
+ /* Check current stage of slave cpu */
+ if (arc_read_uncached_32(&cross_cpu_data.status[cpu_id]) != BOOTSTAGE_2)
+ pr_err("CPU %u status is unexpected: %d\n", cpu_id,
+ arc_read_uncached_32(&cross_cpu_data.status[cpu_id]));
+
+ debug("CPU %u: cross-cpu flag: %x [after timeout]\n", cpu_id,
+ arc_read_uncached_32(&cross_cpu_data.ready_flag));
+ debug("CPU %u: status: %d [after timeout]\n", cpu_id,
+ arc_read_uncached_32(&cross_cpu_data.status[cpu_id]));
+}
+
+static void do_init_slave_cpus(void)
+{
+ clear_cross_cpu_data();
+ sync_cross_cpu_data();
+
+ debug("cross_cpu_data location: %#x\n", (u32)&cross_cpu_data);
+
+ for (u32 i = MASTER_CPU_ID + 1; i < NR_CPUS; i++)
+ if (is_cpu_used(i))
+ do_init_slave_cpu(i);
+}
+
+static void do_init_master_cpu(void)
+{
+ /*
+ * Setup master caches even if master isn't used as we want to use
+ * same cache configuration on all running CPUs
+ */
+ init_master_icache();
+ init_master_dcache();
+}
+
+enum hsdk_axi_masters {
+ M_HS_CORE = 0,
+ M_HS_RTT,
+ M_AXI_TUN,
+ M_HDMI_VIDEO,
+ M_HDMI_AUDIO,
+ M_USB_HOST,
+ M_ETHERNET,
+ M_SDIO,
+ M_GPU,
+ M_DMAC_0,
+ M_DMAC_1,
+ M_DVFS
+};
+
+#define UPDATE_VAL 1
+
+/*
+ * m master AXI_M_m_SLV0 AXI_M_m_SLV1 AXI_M_m_OFFSET0 AXI_M_m_OFFSET1
+ * 0 HS (CBU) 0x11111111 0x63111111 0xFEDCBA98 0x0E543210
+ * 1 HS (RTT) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 2 AXI Tunnel 0x88888888 0x88888888 0xFEDCBA98 0x76543210
+ * 3 HDMI-VIDEO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 4 HDMI-ADUIO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 5 USB-HOST 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
+ * 6 ETHERNET 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
+ * 7 SDIO 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
+ * 8 GPU 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 9 DMAC (port #1) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 10 DMAC (port #2) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
+ * 11 DVFS 0x00000000 0x60000000 0x00000000 0x00000000
+ *
+ * Please read ARC HS Development IC Specification, section 17.2 for more
+ * information about apertures configuration.
+ * NOTE: we intentionally modify default settings in U-boot. Default settings
+ * are specified in "Table 111 CREG Address Decoder register reset values".
+ */
+
+#define CREG_AXI_M_SLV0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m)))
+#define CREG_AXI_M_SLV1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x004))
+#define CREG_AXI_M_OFT0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x008))
+#define CREG_AXI_M_OFT1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x00C))
+#define CREG_AXI_M_UPDT(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x014))
+
+#define CREG_AXI_M_HS_CORE_BOOT ((void __iomem *)(CREG_BASE + 0x010))
+
+#define CREG_PAE ((void __iomem *)(CREG_BASE + 0x180))
+#define CREG_PAE_UPDT ((void __iomem *)(CREG_BASE + 0x194))
+
+void init_memory_bridge(void)
+{
+ u32 reg;
+
+ /*
+ * M_HS_CORE has one unic register - BOOT.
+ * We need to clean boot mirror (BOOT[1:0]) bits in them.
+ */
+ reg = readl(CREG_AXI_M_HS_CORE_BOOT) & (~0x3);
+ writel(reg, CREG_AXI_M_HS_CORE_BOOT);
+ writel(0x11111111, CREG_AXI_M_SLV0(M_HS_CORE));
+ writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_CORE));
+ writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_HS_RTT));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_HS_RTT));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_RTT));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_HS_RTT));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_RTT));
+
+ writel(0x88888888, CREG_AXI_M_SLV0(M_AXI_TUN));
+ writel(0x88888888, CREG_AXI_M_SLV1(M_AXI_TUN));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_AXI_TUN));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_AXI_TUN));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_AXI_TUN));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_VIDEO));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_VIDEO));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_VIDEO));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_VIDEO));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_VIDEO));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_AUDIO));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_AUDIO));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_AUDIO));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_AUDIO));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_AUDIO));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_USB_HOST));
+ writel(0x77999999, CREG_AXI_M_SLV1(M_USB_HOST));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_USB_HOST));
+ writel(0x76DCBA98, CREG_AXI_M_OFT1(M_USB_HOST));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_ETHERNET));
+ writel(0x77999999, CREG_AXI_M_SLV1(M_ETHERNET));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_ETHERNET));
+ writel(0x76DCBA98, CREG_AXI_M_OFT1(M_ETHERNET));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_SDIO));
+ writel(0x77999999, CREG_AXI_M_SLV1(M_SDIO));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_SDIO));
+ writel(0x76DCBA98, CREG_AXI_M_OFT1(M_SDIO));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_GPU));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_GPU));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_GPU));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_GPU));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
+
+ writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
+ writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1));
+ writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
+ writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
+
+ writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS));
+ writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS));
+ writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS));
+ writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS));
+ writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS));
+
+ writel(0x00000000, CREG_PAE);
+ writel(UPDATE_VAL, CREG_PAE_UPDT);
+}
+
+static void setup_clocks(void)
+{
+ ulong rate;
+
+ /* Setup CPU clock */
+ if (env_common.cpu_freq.set) {
+ rate = env_common.cpu_freq.val;
+ soc_clk_ctl("cpu-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ);