18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2009-2010 Freescale Semiconductor, Inc. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Vivek Mahajan <vivek.mahajan@freescale.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is derived from the original work done 108c2ecf20Sopenharmony_ci * by Sylvain Munaut for the Bestcomm SRAM allocator. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/export.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 188c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 198c2ecf20Sopenharmony_ci#include <asm/fsl_85xx_cache_sram.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "fsl_85xx_cache_ctlr.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct mpc85xx_cache_sram *cache_sram; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_civoid *mpc85xx_cache_sram_alloc(unsigned int size, 268c2ecf20Sopenharmony_ci phys_addr_t *phys, unsigned int align) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci unsigned long offset; 298c2ecf20Sopenharmony_ci unsigned long flags; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (unlikely(cache_sram == NULL)) 328c2ecf20Sopenharmony_ci return NULL; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (!size || (size > cache_sram->size) || (align > cache_sram->size)) { 358c2ecf20Sopenharmony_ci pr_err("%s(): size(=%x) or align(=%x) zero or too big\n", 368c2ecf20Sopenharmony_ci __func__, size, align); 378c2ecf20Sopenharmony_ci return NULL; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if ((align & (align - 1)) || align <= 1) { 418c2ecf20Sopenharmony_ci pr_err("%s(): align(=%x) must be power of two and >1\n", 428c2ecf20Sopenharmony_ci __func__, align); 438c2ecf20Sopenharmony_ci return NULL; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci spin_lock_irqsave(&cache_sram->lock, flags); 478c2ecf20Sopenharmony_ci offset = rh_alloc_align(cache_sram->rh, size, align, NULL); 488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cache_sram->lock, flags); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (IS_ERR_VALUE(offset)) 518c2ecf20Sopenharmony_ci return NULL; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci *phys = cache_sram->base_phys + offset; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return (unsigned char *)cache_sram->base_virt + offset; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpc85xx_cache_sram_alloc); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_civoid mpc85xx_cache_sram_free(void *ptr) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci unsigned long flags; 628c2ecf20Sopenharmony_ci BUG_ON(!ptr); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci spin_lock_irqsave(&cache_sram->lock, flags); 658c2ecf20Sopenharmony_ci rh_free(cache_sram->rh, ptr - cache_sram->base_virt); 668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cache_sram->lock, flags); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpc85xx_cache_sram_free); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ciint __init instantiate_cache_sram(struct platform_device *dev, 718c2ecf20Sopenharmony_ci struct sram_parameters sram_params) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci int ret = 0; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (cache_sram) { 768c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Already initialized cache-sram\n"); 778c2ecf20Sopenharmony_ci return -EBUSY; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL); 818c2ecf20Sopenharmony_ci if (!cache_sram) { 828c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Out of memory for cache_sram structure\n"); 838c2ecf20Sopenharmony_ci return -ENOMEM; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci cache_sram->base_phys = sram_params.sram_offset; 878c2ecf20Sopenharmony_ci cache_sram->size = sram_params.sram_size; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (!request_mem_region(cache_sram->base_phys, cache_sram->size, 908c2ecf20Sopenharmony_ci "fsl_85xx_cache_sram")) { 918c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: request memory failed\n", 928c2ecf20Sopenharmony_ci dev->dev.of_node); 938c2ecf20Sopenharmony_ci ret = -ENXIO; 948c2ecf20Sopenharmony_ci goto out_free; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci cache_sram->base_virt = ioremap_coherent(cache_sram->base_phys, 988c2ecf20Sopenharmony_ci cache_sram->size); 998c2ecf20Sopenharmony_ci if (!cache_sram->base_virt) { 1008c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: ioremap_coherent failed\n", 1018c2ecf20Sopenharmony_ci dev->dev.of_node); 1028c2ecf20Sopenharmony_ci ret = -ENOMEM; 1038c2ecf20Sopenharmony_ci goto out_release; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci cache_sram->rh = rh_create(sizeof(unsigned int)); 1078c2ecf20Sopenharmony_ci if (IS_ERR(cache_sram->rh)) { 1088c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to create remote heap\n", 1098c2ecf20Sopenharmony_ci dev->dev.of_node); 1108c2ecf20Sopenharmony_ci ret = PTR_ERR(cache_sram->rh); 1118c2ecf20Sopenharmony_ci goto out_unmap; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci rh_attach_region(cache_sram->rh, 0, cache_sram->size); 1158c2ecf20Sopenharmony_ci spin_lock_init(&cache_sram->lock); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n", 1188c2ecf20Sopenharmony_ci (unsigned long long)cache_sram->base_phys, cache_sram->size); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ciout_unmap: 1238c2ecf20Sopenharmony_ci iounmap(cache_sram->base_virt); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciout_release: 1268c2ecf20Sopenharmony_ci release_mem_region(cache_sram->base_phys, cache_sram->size); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ciout_free: 1298c2ecf20Sopenharmony_ci kfree(cache_sram); 1308c2ecf20Sopenharmony_ci return ret; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_civoid remove_cache_sram(struct platform_device *dev) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci BUG_ON(!cache_sram); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci rh_detach_region(cache_sram->rh, 0, cache_sram->size); 1388c2ecf20Sopenharmony_ci rh_destroy(cache_sram->rh); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci iounmap(cache_sram->base_virt); 1418c2ecf20Sopenharmony_ci release_mem_region(cache_sram->base_phys, cache_sram->size); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci kfree(cache_sram); 1448c2ecf20Sopenharmony_ci cache_sram = NULL; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n"); 1478c2ecf20Sopenharmony_ci} 148