// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 MediaTek Inc. */ #include /* needed by all modules */ #include /* needed by module macros */ #include /* needed by file_operations* */ #include /* needed by miscdevice* */ #include /* needed by device_* */ #include /* needed by kmalloc */ #include /* needed by copy_to_user */ #include /* needed by file_operations* */ #include /* needed by kmalloc */ #include /* needed by poll */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sspm_define.h" #include "sspm_common.h" #include "sspm_reservedmem.h" #ifdef CONFIG_OF_RESERVED_MEM #include #define SSPM_MEM_RESERVED_KEY "mediatek,reserve-memory-sspm_share" #endif static phys_addr_t sspm_mem_base_phys; static phys_addr_t sspm_mem_base_virt; static phys_addr_t sspm_mem_size; struct sspm_reserve_mblock *sspm_reserve_mblock; #if defined(MODULE) static void sspm_reserve_memory_ioremap(struct platform_device *pdev) { struct device_node *rmem_node; struct reserved_mem *rmem; /* Get reserved memory */ rmem_node = of_find_compatible_node(NULL, NULL, SSPM_MEM_RESERVED_KEY); if (!rmem_node) { pr_err("[SSPM] no node for reserved memory\n"); return; } rmem = of_reserved_mem_lookup(rmem_node); if (!rmem) { pr_err("[SSPM] cannot lookup reserved memory\n"); return; } sspm_mem_base_phys = (phys_addr_t) rmem->base; sspm_mem_size = (phys_addr_t) rmem->size; } #elif defined(CONFIG_OF_RESERVED_MEM) static int __init sspm_reserve_mem_of_init(struct reserved_mem *rmem) { sspm_mem_base_phys = rmem->base; sspm_mem_size = rmem->size; #ifdef DEBUG pr_debug("[SSPM] phys:0x%llx - 0x%llx (0x%llx)\n", (unsigned long long)rmem->base, (unsigned long long)(rmem->base + rmem->size), (unsigned long long)rmem->size); #endif return 0; } RESERVEDMEM_OF_DECLARE(sspm_reservedmem, SSPM_MEM_RESERVED_KEY, sspm_reserve_mem_of_init); #endif phys_addr_t sspm_reserve_mem_get_phys(unsigned int id) { if (id >= NUMS_MEM_ID) { pr_err("[SSPM] no reserve memory for 0x%x", id); return 0; } else return sspm_reserve_mblock[id].start_phys; } EXPORT_SYMBOL_GPL(sspm_reserve_mem_get_phys); phys_addr_t sspm_reserve_mem_get_virt(unsigned int id) { if (id >= NUMS_MEM_ID) { pr_err("[SSPM] no reserve memory for 0x%x", id); return 0; } else return sspm_reserve_mblock[id].start_virt; } EXPORT_SYMBOL_GPL(sspm_reserve_mem_get_virt); phys_addr_t sspm_reserve_mem_get_size(unsigned int id) { if (id >= NUMS_MEM_ID) { pr_err("[SSPM] no reserve memory for 0x%x", id); return 0; } else return sspm_reserve_mblock[id].size; } EXPORT_SYMBOL_GPL(sspm_reserve_mem_get_size); int sspm_reserve_memory_init(void) { unsigned int id; phys_addr_t accumlate_memory_size; if (NUMS_MEM_ID == 0) return 0; #if defined(MODULE) sspm_reserve_memory_ioremap(sspm_pdev); #endif if (!sspm_mem_base_phys) return -1; /* Phy memory */ accumlate_memory_size = 0; for (id = 0; id < NUMS_MEM_ID; id++) { sspm_reserve_mblock[id].start_phys = sspm_mem_base_phys + accumlate_memory_size; accumlate_memory_size += sspm_reserve_mblock[id].size; } /* Virt memory */ accumlate_memory_size = 0; sspm_mem_base_virt = (phys_addr_t)(uintptr_t) ioremap_wc(sspm_mem_base_phys, sspm_mem_size); #ifdef DEBUG pr_info("[SSPM]reserve mem: virt:0x%llx - 0x%p (0x%llx)\n", sspm_mem_base_virt, sspm_mem_base_virt + sspm_mem_size, sspm_mem_size); #endif for (id = 0; id < NUMS_MEM_ID; id++) { sspm_reserve_mblock[id].start_virt = sspm_mem_base_virt + accumlate_memory_size; accumlate_memory_size += sspm_reserve_mblock[id].size; } /* the reserved memory should be larger then expected memory * or sspm_reserve_mblock does not match dts */ BUG_ON(accumlate_memory_size > sspm_mem_size); #ifdef DEBUG for (id = 0; id < NUMS_MEM_ID; id++) { pr_info("[SSPM][mem_reserve-%d] ", id); pr_info("phys:0x%llx, virt:0x%llx,size:0x%llx\n", (unsigned long long)sspm_reserve_mem_get_phys(id), (unsigned long long)sspm_reserve_mem_get_virt(id), (unsigned long long)sspm_reserve_mem_get_size(id)); } #endif return 0; } void sspm_lock_emi_mpu(unsigned int region) { #ifdef CONFIG_MTK_EMI if (sspm_mem_size > 0) sspm_set_emi_mpu(region, sspm_mem_base_phys, sspm_mem_size); #endif } #ifdef SSPM_SHARE_BUFFER_SUPPORT void __iomem *sspm_base; phys_addr_t sspm_sbuf_get(unsigned int offset) { if (!is_sspm_ready()) { pr_notice("[SSPM] device resource is not ready\n"); return 0; } if (offset < SSPM_SHARE_REGION_BASE || offset > SSPM_SHARE_REGION_BASE + SSPM_SHARE_REGION_SIZE) { pr_notice("[SSPM] illegal sbuf request: 0x%x\n", offset); return 0; } else { return (phys_addr_t)(sspm_base + offset); } } EXPORT_SYMBOL_GPL(sspm_sbuf_get); int sspm_sbuf_init(void) { struct device *dev = &sspm_pdev->dev; struct resource *res; if (sspm_pdev) { res = platform_get_resource_byname(sspm_pdev, IORESOURCE_MEM, "sspm_base"); if (!res) return -1; sspm_base = devm_ioremap_resource(dev, res); if (IS_ERR((void const *) sspm_base)) return -1; } return 0; } #endif