18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include <linux/highmem.h>
48c2ecf20Sopenharmony_ci#include <linux/genalloc.h>
58c2ecf20Sopenharmony_ci#include <asm/tlbflush.h>
68c2ecf20Sopenharmony_ci#include <asm/fixmap.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#if (CONFIG_ITCM_RAM_BASE == 0xffffffff)
98c2ecf20Sopenharmony_ci#error "You should define ITCM_RAM_BASE"
108c2ecf20Sopenharmony_ci#endif
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_DTCM
138c2ecf20Sopenharmony_ci#if (CONFIG_DTCM_RAM_BASE == 0xffffffff)
148c2ecf20Sopenharmony_ci#error "You should define DTCM_RAM_BASE"
158c2ecf20Sopenharmony_ci#endif
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#if (CONFIG_DTCM_RAM_BASE == CONFIG_ITCM_RAM_BASE)
188c2ecf20Sopenharmony_ci#error "You should define correct DTCM_RAM_BASE"
198c2ecf20Sopenharmony_ci#endif
208c2ecf20Sopenharmony_ci#endif
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciextern char __tcm_start, __tcm_end, __dtcm_start;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic struct gen_pool *tcm_pool;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic void __init tcm_mapping_init(void)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	pte_t *tcm_pte;
298c2ecf20Sopenharmony_ci	unsigned long vaddr, paddr;
308c2ecf20Sopenharmony_ci	int i;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	paddr = CONFIG_ITCM_RAM_BASE;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (pfn_valid(PFN_DOWN(CONFIG_ITCM_RAM_BASE)))
358c2ecf20Sopenharmony_ci		goto panic;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#ifndef CONFIG_HAVE_DTCM
388c2ecf20Sopenharmony_ci	for (i = 0; i < TCM_NR_PAGES; i++) {
398c2ecf20Sopenharmony_ci#else
408c2ecf20Sopenharmony_ci	for (i = 0; i < CONFIG_ITCM_NR_PAGES; i++) {
418c2ecf20Sopenharmony_ci#endif
428c2ecf20Sopenharmony_ci		vaddr = __fix_to_virt(FIX_TCM - i);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci		tcm_pte =
458c2ecf20Sopenharmony_ci			pte_offset_kernel((pmd_t *)pgd_offset_k(vaddr), vaddr);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci		set_pte(tcm_pte, pfn_pte(__phys_to_pfn(paddr), PAGE_KERNEL));
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci		flush_tlb_one(vaddr);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci		paddr = paddr + PAGE_SIZE;
528c2ecf20Sopenharmony_ci	}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_DTCM
558c2ecf20Sopenharmony_ci	if (pfn_valid(PFN_DOWN(CONFIG_DTCM_RAM_BASE)))
568c2ecf20Sopenharmony_ci		goto panic;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	paddr = CONFIG_DTCM_RAM_BASE;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	for (i = 0; i < CONFIG_DTCM_NR_PAGES; i++) {
618c2ecf20Sopenharmony_ci		vaddr = __fix_to_virt(FIX_TCM - CONFIG_ITCM_NR_PAGES - i);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		tcm_pte =
648c2ecf20Sopenharmony_ci			pte_offset_kernel((pmd_t *) pgd_offset_k(vaddr), vaddr);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci		set_pte(tcm_pte, pfn_pte(__phys_to_pfn(paddr), PAGE_KERNEL));
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci		flush_tlb_one(vaddr);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		paddr = paddr + PAGE_SIZE;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci#endif
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#ifndef CONFIG_HAVE_DTCM
758c2ecf20Sopenharmony_ci	memcpy((void *)__fix_to_virt(FIX_TCM),
768c2ecf20Sopenharmony_ci				&__tcm_start, &__tcm_end - &__tcm_start);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	pr_info("%s: mapping tcm va:0x%08lx to pa:0x%08x\n",
798c2ecf20Sopenharmony_ci			__func__, __fix_to_virt(FIX_TCM), CONFIG_ITCM_RAM_BASE);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	pr_info("%s: __tcm_start va:0x%08lx size:%d\n",
828c2ecf20Sopenharmony_ci			__func__, (unsigned long)&__tcm_start, &__tcm_end - &__tcm_start);
838c2ecf20Sopenharmony_ci#else
848c2ecf20Sopenharmony_ci	memcpy((void *)__fix_to_virt(FIX_TCM),
858c2ecf20Sopenharmony_ci				&__tcm_start, &__dtcm_start - &__tcm_start);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	pr_info("%s: mapping itcm va:0x%08lx to pa:0x%08x\n",
888c2ecf20Sopenharmony_ci			__func__, __fix_to_virt(FIX_TCM), CONFIG_ITCM_RAM_BASE);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	pr_info("%s: __itcm_start va:0x%08lx size:%d\n",
918c2ecf20Sopenharmony_ci			__func__, (unsigned long)&__tcm_start, &__dtcm_start - &__tcm_start);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	memcpy((void *)__fix_to_virt(FIX_TCM - CONFIG_ITCM_NR_PAGES),
948c2ecf20Sopenharmony_ci				&__dtcm_start, &__tcm_end - &__dtcm_start);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	pr_info("%s: mapping dtcm va:0x%08lx to pa:0x%08x\n",
978c2ecf20Sopenharmony_ci			__func__, __fix_to_virt(FIX_TCM - CONFIG_ITCM_NR_PAGES),
988c2ecf20Sopenharmony_ci						CONFIG_DTCM_RAM_BASE);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	pr_info("%s: __dtcm_start va:0x%08lx size:%d\n",
1018c2ecf20Sopenharmony_ci			__func__, (unsigned long)&__dtcm_start, &__tcm_end - &__dtcm_start);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#endif
1048c2ecf20Sopenharmony_ci	return;
1058c2ecf20Sopenharmony_cipanic:
1068c2ecf20Sopenharmony_ci	panic("TCM init error");
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_civoid *tcm_alloc(size_t len)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	unsigned long vaddr;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (!tcm_pool)
1148c2ecf20Sopenharmony_ci		return NULL;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	vaddr = gen_pool_alloc(tcm_pool, len);
1178c2ecf20Sopenharmony_ci	if (!vaddr)
1188c2ecf20Sopenharmony_ci		return NULL;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return (void *) vaddr;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcm_alloc);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_civoid tcm_free(void *addr, size_t len)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	gen_pool_free(tcm_pool, (unsigned long) addr, len);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcm_free);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int __init tcm_setup_pool(void)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci#ifndef CONFIG_HAVE_DTCM
1338c2ecf20Sopenharmony_ci	u32 pool_size = (u32) (TCM_NR_PAGES * PAGE_SIZE)
1348c2ecf20Sopenharmony_ci				- (u32) (&__tcm_end - &__tcm_start);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	u32 tcm_pool_start = __fix_to_virt(FIX_TCM)
1378c2ecf20Sopenharmony_ci				+ (u32) (&__tcm_end - &__tcm_start);
1388c2ecf20Sopenharmony_ci#else
1398c2ecf20Sopenharmony_ci	u32 pool_size = (u32) (CONFIG_DTCM_NR_PAGES * PAGE_SIZE)
1408c2ecf20Sopenharmony_ci				- (u32) (&__tcm_end - &__dtcm_start);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	u32 tcm_pool_start = __fix_to_virt(FIX_TCM - CONFIG_ITCM_NR_PAGES)
1438c2ecf20Sopenharmony_ci				+ (u32) (&__tcm_end - &__dtcm_start);
1448c2ecf20Sopenharmony_ci#endif
1458c2ecf20Sopenharmony_ci	int ret;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	tcm_pool = gen_pool_create(2, -1);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	ret = gen_pool_add(tcm_pool, tcm_pool_start, pool_size, -1);
1508c2ecf20Sopenharmony_ci	if (ret) {
1518c2ecf20Sopenharmony_ci		pr_err("%s: gen_pool add failed!\n", __func__);
1528c2ecf20Sopenharmony_ci		return ret;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	pr_info("%s: Added %d bytes @ 0x%08x to memory pool\n",
1568c2ecf20Sopenharmony_ci		__func__, pool_size, tcm_pool_start);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return 0;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic int __init tcm_init(void)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	tcm_mapping_init();
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	tcm_setup_pool();
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	return 0;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ciarch_initcall(tcm_init);
170