/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2025 Andes Technology Corporation */ #include #include #include #include #include #include #include #include #include #include static unsigned long andes_hart_data_offset; extern void _start_warm(void); void ae350_non_ret_save(struct sbi_scratch *scratch) { struct andes_hart_data *andes_hdata = sbi_scratch_offset_ptr(scratch, andes_hart_data_offset); andes_hdata->mcache_ctl = csr_read(CSR_MCACHE_CTL); andes_hdata->mmisc_ctl = csr_read(CSR_MMISC_CTL); andes_hdata->mpft_ctl = csr_read(CSR_MPFT_CTL); andes_hdata->mslideleg = csr_read(CSR_MSLIDELEG); andes_hdata->mxstatus = csr_read(CSR_MXSTATUS); andes_hdata->slie = csr_read(CSR_SLIE); andes_hdata->slip = csr_read(CSR_SLIP); andes_hdata->pmacfg0 = csr_read(CSR_PMACFG0); andes_hdata->pmacfg2 = csr_read_num(CSR_PMACFG0 + 2); for (int i = 0; i < 16; i++) andes_hdata->pmaaddrX[i] = csr_read_num(CSR_PMAADDR0 + i); } void ae350_non_ret_restore(struct sbi_scratch *scratch) { struct andes_hart_data *andes_hdata = sbi_scratch_offset_ptr(scratch, andes_hart_data_offset); csr_write(CSR_MCACHE_CTL, andes_hdata->mcache_ctl); csr_write(CSR_MMISC_CTL, andes_hdata->mmisc_ctl); csr_write(CSR_MPFT_CTL, andes_hdata->mpft_ctl); csr_write(CSR_MSLIDELEG, andes_hdata->mslideleg); csr_write(CSR_MXSTATUS, andes_hdata->mxstatus); csr_write(CSR_SLIE, andes_hdata->slie); csr_write(CSR_SLIP, andes_hdata->slip); csr_write(CSR_PMACFG0, andes_hdata->pmacfg0); csr_write_num(CSR_PMACFG0 + 2, andes_hdata->pmacfg2); for (int i = 0; i < 16; i++) csr_write_num(CSR_PMAADDR0 + i, andes_hdata->pmaaddrX[i]); } void ae350_enable_coherency_warmboot(void) { ae350_enable_coherency(); _start_warm(); } static int ae350_early_init(bool cold_boot) { u32 hartid = current_hartid(); u32 sleep_type = atcsmu_get_sleep_type(hartid); if (cold_boot) { andes_hart_data_offset = sbi_scratch_alloc_offset(sizeof(struct andes_hart_data)); if (!andes_hart_data_offset) return SBI_ENOMEM; } /* Don't restore Andes CSRs during boot or wake up from light sleep */ if (sbi_init_count(current_hartindex()) && sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND) ae350_non_ret_restore(sbi_scratch_thishart_ptr()); return generic_early_init(cold_boot); } static int ae350_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) { generic_platform_ops.early_init = ae350_early_init; generic_platform_ops.extensions_init = andes_pmu_extensions_init; generic_platform_ops.pmu_init = andes_pmu_init; generic_platform_ops.vendor_ext_provider = andes_sbi_vendor_ext_provider; return 0; } static const struct fdt_match andes_ae350_match[] = { { .compatible = "andestech,ae350" }, { }, }; const struct fdt_driver andes_ae350 = { .match_table = andes_ae350_match, .init = ae350_platform_init, };