/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2025 SpacemiT * Authors: * Xianbin Zhu * Troy Mitchell */ #include #include #include #include /* only use 0-1 cluster in SpacemiT K1 */ static const int cci_map[] = { PLAT_CCI_CLUSTER0_IFACE_IX, PLAT_CCI_CLUSTER1_IFACE_IX, }; static void cci_enable_snoop_dvm_reqs(unsigned int master_id) { int slave_if_id = cci_map[master_id]; /* * Enable Snoops and DVM messages, no need for Read/Modify/Write as * rest of bits are write ignore */ writel(CCI_550_SNOOP_CTRL_ENABLE_DVMS | CCI_550_SNOOP_CTRL_ENABLE_SNOOPS, (void *)(u64)CCI_550_PLATFORM_CCI_ADDR + CCI_550_SLAVE_IFACE_OFFSET(slave_if_id) + CCI_550_SNOOP_CTRL); /* * Wait for the completion of the write to the Snoop Control Register * before testing the change_pending bit */ mb(); /* Wait for the dust to settle down */ while ((readl((void *)(u64)CCI_550_PLATFORM_CCI_ADDR + CCI_550_STATUS) & CCI_550_STATUS_CHANGE_PENDING)) ; } static void spacemit_k1_pre_init(void) { unsigned int clusterid, cluster_enabled = 0; struct sbi_scratch *scratch; int i; scratch = sbi_scratch_thishart_ptr(); writel(scratch->warmboot_addr, (unsigned int *)C0_RVBADDR_LO_ADDR); writel(scratch->warmboot_addr >> 32, (unsigned int *)C0_RVBADDR_HI_ADDR); writel(scratch->warmboot_addr, (unsigned int *)C1_RVBADDR_LO_ADDR); writel(scratch->warmboot_addr >> 32, (unsigned int *)C1_RVBADDR_HI_ADDR); for (i = 0; i < PLATFORM_MAX_CPUS; i++) { clusterid = CPU_TO_CLUSTER(i); if (!(cluster_enabled & (1 << clusterid))) { cluster_enabled |= 1 << clusterid; cci_enable_snoop_dvm_reqs(clusterid); } } } /* * Platform early initialization. */ static int spacemit_k1_early_init(bool cold_boot) { int rc; rc = generic_early_init(cold_boot); if (rc) return rc; csr_set(CSR_MSETUP, MSETUP_DE | MSETUP_IE | MSETUP_BPE | MSETUP_PFE | MSETUP_MME | MSETUP_ECCE); if (cold_boot) spacemit_k1_pre_init(); return 0; } static bool spacemit_cold_boot_allowed(u32 hartid) { csr_set(CSR_ML2SETUP, 1 << (hartid % PLATFORM_MAX_CPUS_PER_CLUSTER)); return !hartid; } static int spacemit_k1_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) { generic_platform_ops.early_init = spacemit_k1_early_init; generic_platform_ops.cold_boot_allowed = spacemit_cold_boot_allowed; return 0; } static const struct fdt_match spacemit_k1_match[] = { { .compatible = "spacemit,k1" }, { /* sentinel */ } }; const struct fdt_driver spacemit_k1 = { .match_table = spacemit_k1_match, .init = spacemit_k1_platform_init, };