162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Simple memory allocator for on-board SRAM 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Maintainer : Sylvain Munaut <tnt@246tNt.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/export.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/spinlock.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/ioport.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/of_address.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <asm/io.h> 2162306a36Sopenharmony_ci#include <asm/mmu.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/fsl/bestcomm/sram.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Struct keeping our 'state' */ 2762306a36Sopenharmony_cistruct bcom_sram *bcom_sram = NULL; 2862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram); /* needed for inline functions */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* ======================================================================== */ 3262306a36Sopenharmony_ci/* Public API */ 3362306a36Sopenharmony_ci/* ======================================================================== */ 3462306a36Sopenharmony_ci/* DO NOT USE in interrupts, if needed in irq handler, we should use the 3562306a36Sopenharmony_ci _irqsave version of the spin_locks */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciint bcom_sram_init(struct device_node *sram_node, char *owner) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci int rv; 4062306a36Sopenharmony_ci const u32 *regaddr_p; 4162306a36Sopenharmony_ci struct resource res; 4262306a36Sopenharmony_ci unsigned int psize; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* Create our state struct */ 4562306a36Sopenharmony_ci if (bcom_sram) { 4662306a36Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 4762306a36Sopenharmony_ci "Already initialized !\n", owner); 4862306a36Sopenharmony_ci return -EBUSY; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL); 5262306a36Sopenharmony_ci if (!bcom_sram) { 5362306a36Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 5462306a36Sopenharmony_ci "Couldn't allocate internal state !\n", owner); 5562306a36Sopenharmony_ci return -ENOMEM; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* Get address and size of the sram */ 5962306a36Sopenharmony_ci rv = of_address_to_resource(sram_node, 0, &res); 6062306a36Sopenharmony_ci if (rv) { 6162306a36Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 6262306a36Sopenharmony_ci "Invalid device node !\n", owner); 6362306a36Sopenharmony_ci goto error_free; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci bcom_sram->base_phys = res.start; 6762306a36Sopenharmony_ci bcom_sram->size = resource_size(&res); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* Request region */ 7062306a36Sopenharmony_ci if (!request_mem_region(res.start, resource_size(&res), owner)) { 7162306a36Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 7262306a36Sopenharmony_ci "Couldn't request region !\n", owner); 7362306a36Sopenharmony_ci rv = -EBUSY; 7462306a36Sopenharmony_ci goto error_free; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Map SRAM */ 7862306a36Sopenharmony_ci /* sram is not really __iomem */ 7962306a36Sopenharmony_ci bcom_sram->base_virt = (void *)ioremap(res.start, resource_size(&res)); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (!bcom_sram->base_virt) { 8262306a36Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 8362306a36Sopenharmony_ci "Map error SRAM zone 0x%08lx (0x%0x)!\n", 8462306a36Sopenharmony_ci owner, (long)bcom_sram->base_phys, bcom_sram->size ); 8562306a36Sopenharmony_ci rv = -ENOMEM; 8662306a36Sopenharmony_ci goto error_release; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* Create an rheap (defaults to 32 bits word alignment) */ 9062306a36Sopenharmony_ci bcom_sram->rh = rh_create(4); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Attach the free zones */ 9362306a36Sopenharmony_ci#if 0 9462306a36Sopenharmony_ci /* Currently disabled ... for future use only */ 9562306a36Sopenharmony_ci reg_addr_p = of_get_property(sram_node, "available", &psize); 9662306a36Sopenharmony_ci#else 9762306a36Sopenharmony_ci regaddr_p = NULL; 9862306a36Sopenharmony_ci psize = 0; 9962306a36Sopenharmony_ci#endif 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (!regaddr_p || !psize) { 10262306a36Sopenharmony_ci /* Attach the whole zone */ 10362306a36Sopenharmony_ci rh_attach_region(bcom_sram->rh, 0, bcom_sram->size); 10462306a36Sopenharmony_ci } else { 10562306a36Sopenharmony_ci /* Attach each zone independently */ 10662306a36Sopenharmony_ci while (psize >= 2 * sizeof(u32)) { 10762306a36Sopenharmony_ci phys_addr_t zbase = of_translate_address(sram_node, regaddr_p); 10862306a36Sopenharmony_ci rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]); 10962306a36Sopenharmony_ci regaddr_p += 2; 11062306a36Sopenharmony_ci psize -= 2 * sizeof(u32); 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* Init our spinlock */ 11562306a36Sopenharmony_ci spin_lock_init(&bcom_sram->lock); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cierror_release: 12062306a36Sopenharmony_ci release_mem_region(res.start, resource_size(&res)); 12162306a36Sopenharmony_cierror_free: 12262306a36Sopenharmony_ci kfree(bcom_sram); 12362306a36Sopenharmony_ci bcom_sram = NULL; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return rv; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram_init); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_civoid bcom_sram_cleanup(void) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci /* Free resources */ 13262306a36Sopenharmony_ci if (bcom_sram) { 13362306a36Sopenharmony_ci rh_destroy(bcom_sram->rh); 13462306a36Sopenharmony_ci iounmap((void __iomem *)bcom_sram->base_virt); 13562306a36Sopenharmony_ci release_mem_region(bcom_sram->base_phys, bcom_sram->size); 13662306a36Sopenharmony_ci kfree(bcom_sram); 13762306a36Sopenharmony_ci bcom_sram = NULL; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram_cleanup); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_civoid* bcom_sram_alloc(int size, int align, phys_addr_t *phys) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci unsigned long offset; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci spin_lock(&bcom_sram->lock); 14762306a36Sopenharmony_ci offset = rh_alloc_align(bcom_sram->rh, size, align, NULL); 14862306a36Sopenharmony_ci spin_unlock(&bcom_sram->lock); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (IS_ERR_VALUE(offset)) 15162306a36Sopenharmony_ci return NULL; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci *phys = bcom_sram->base_phys + offset; 15462306a36Sopenharmony_ci return bcom_sram->base_virt + offset; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram_alloc); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_civoid bcom_sram_free(void *ptr) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci unsigned long offset; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (!ptr) 16362306a36Sopenharmony_ci return; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci offset = ptr - bcom_sram->base_virt; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci spin_lock(&bcom_sram->lock); 16862306a36Sopenharmony_ci rh_free(bcom_sram->rh, offset); 16962306a36Sopenharmony_ci spin_unlock(&bcom_sram->lock); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram_free); 172