18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Simple memory allocator for on-board SRAM 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Maintainer : Sylvain Munaut <tnt@246tNt.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License 108c2ecf20Sopenharmony_ci * version 2. This program is licensed "as is" without any warranty of any 118c2ecf20Sopenharmony_ci * kind, whether express or implied. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/export.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 198c2ecf20Sopenharmony_ci#include <linux/string.h> 208c2ecf20Sopenharmony_ci#include <linux/ioport.h> 218c2ecf20Sopenharmony_ci#include <linux/of.h> 228c2ecf20Sopenharmony_ci#include <linux/of_address.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/io.h> 258c2ecf20Sopenharmony_ci#include <asm/mmu.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <linux/fsl/bestcomm/sram.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Struct keeping our 'state' */ 318c2ecf20Sopenharmony_cistruct bcom_sram *bcom_sram = NULL; 328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram); /* needed for inline functions */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* ======================================================================== */ 368c2ecf20Sopenharmony_ci/* Public API */ 378c2ecf20Sopenharmony_ci/* ======================================================================== */ 388c2ecf20Sopenharmony_ci/* DO NOT USE in interrupts, if needed in irq handler, we should use the 398c2ecf20Sopenharmony_ci _irqsave version of the spin_locks */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciint bcom_sram_init(struct device_node *sram_node, char *owner) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int rv; 448c2ecf20Sopenharmony_ci const u32 *regaddr_p; 458c2ecf20Sopenharmony_ci u64 regaddr64, size64; 468c2ecf20Sopenharmony_ci unsigned int psize; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* Create our state struct */ 498c2ecf20Sopenharmony_ci if (bcom_sram) { 508c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 518c2ecf20Sopenharmony_ci "Already initialized !\n", owner); 528c2ecf20Sopenharmony_ci return -EBUSY; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL); 568c2ecf20Sopenharmony_ci if (!bcom_sram) { 578c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 588c2ecf20Sopenharmony_ci "Couldn't allocate internal state !\n", owner); 598c2ecf20Sopenharmony_ci return -ENOMEM; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* Get address and size of the sram */ 638c2ecf20Sopenharmony_ci regaddr_p = of_get_address(sram_node, 0, &size64, NULL); 648c2ecf20Sopenharmony_ci if (!regaddr_p) { 658c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 668c2ecf20Sopenharmony_ci "Invalid device node !\n", owner); 678c2ecf20Sopenharmony_ci rv = -EINVAL; 688c2ecf20Sopenharmony_ci goto error_free; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci regaddr64 = of_translate_address(sram_node, regaddr_p); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci bcom_sram->base_phys = (phys_addr_t) regaddr64; 748c2ecf20Sopenharmony_ci bcom_sram->size = (unsigned int) size64; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* Request region */ 778c2ecf20Sopenharmony_ci if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) { 788c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 798c2ecf20Sopenharmony_ci "Couldn't request region !\n", owner); 808c2ecf20Sopenharmony_ci rv = -EBUSY; 818c2ecf20Sopenharmony_ci goto error_free; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* Map SRAM */ 858c2ecf20Sopenharmony_ci /* sram is not really __iomem */ 868c2ecf20Sopenharmony_ci bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (!bcom_sram->base_virt) { 898c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: bcom_sram_init: " 908c2ecf20Sopenharmony_ci "Map error SRAM zone 0x%08lx (0x%0x)!\n", 918c2ecf20Sopenharmony_ci owner, (long)bcom_sram->base_phys, bcom_sram->size ); 928c2ecf20Sopenharmony_ci rv = -ENOMEM; 938c2ecf20Sopenharmony_ci goto error_release; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* Create an rheap (defaults to 32 bits word alignment) */ 978c2ecf20Sopenharmony_ci bcom_sram->rh = rh_create(4); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* Attach the free zones */ 1008c2ecf20Sopenharmony_ci#if 0 1018c2ecf20Sopenharmony_ci /* Currently disabled ... for future use only */ 1028c2ecf20Sopenharmony_ci reg_addr_p = of_get_property(sram_node, "available", &psize); 1038c2ecf20Sopenharmony_ci#else 1048c2ecf20Sopenharmony_ci regaddr_p = NULL; 1058c2ecf20Sopenharmony_ci psize = 0; 1068c2ecf20Sopenharmony_ci#endif 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (!regaddr_p || !psize) { 1098c2ecf20Sopenharmony_ci /* Attach the whole zone */ 1108c2ecf20Sopenharmony_ci rh_attach_region(bcom_sram->rh, 0, bcom_sram->size); 1118c2ecf20Sopenharmony_ci } else { 1128c2ecf20Sopenharmony_ci /* Attach each zone independently */ 1138c2ecf20Sopenharmony_ci while (psize >= 2 * sizeof(u32)) { 1148c2ecf20Sopenharmony_ci phys_addr_t zbase = of_translate_address(sram_node, regaddr_p); 1158c2ecf20Sopenharmony_ci rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]); 1168c2ecf20Sopenharmony_ci regaddr_p += 2; 1178c2ecf20Sopenharmony_ci psize -= 2 * sizeof(u32); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Init our spinlock */ 1228c2ecf20Sopenharmony_ci spin_lock_init(&bcom_sram->lock); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cierror_release: 1278c2ecf20Sopenharmony_ci release_mem_region(bcom_sram->base_phys, bcom_sram->size); 1288c2ecf20Sopenharmony_cierror_free: 1298c2ecf20Sopenharmony_ci kfree(bcom_sram); 1308c2ecf20Sopenharmony_ci bcom_sram = NULL; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return rv; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram_init); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_civoid bcom_sram_cleanup(void) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci /* Free resources */ 1398c2ecf20Sopenharmony_ci if (bcom_sram) { 1408c2ecf20Sopenharmony_ci rh_destroy(bcom_sram->rh); 1418c2ecf20Sopenharmony_ci iounmap((void __iomem *)bcom_sram->base_virt); 1428c2ecf20Sopenharmony_ci release_mem_region(bcom_sram->base_phys, bcom_sram->size); 1438c2ecf20Sopenharmony_ci kfree(bcom_sram); 1448c2ecf20Sopenharmony_ci bcom_sram = NULL; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram_cleanup); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_civoid* bcom_sram_alloc(int size, int align, phys_addr_t *phys) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci unsigned long offset; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci spin_lock(&bcom_sram->lock); 1548c2ecf20Sopenharmony_ci offset = rh_alloc_align(bcom_sram->rh, size, align, NULL); 1558c2ecf20Sopenharmony_ci spin_unlock(&bcom_sram->lock); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (IS_ERR_VALUE(offset)) 1588c2ecf20Sopenharmony_ci return NULL; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci *phys = bcom_sram->base_phys + offset; 1618c2ecf20Sopenharmony_ci return bcom_sram->base_virt + offset; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram_alloc); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_civoid bcom_sram_free(void *ptr) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci unsigned long offset; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (!ptr) 1708c2ecf20Sopenharmony_ci return; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci offset = ptr - bcom_sram->base_virt; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci spin_lock(&bcom_sram->lock); 1758c2ecf20Sopenharmony_ci rh_free(bcom_sram->rh, offset); 1768c2ecf20Sopenharmony_ci spin_unlock(&bcom_sram->lock); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_sram_free); 1798c2ecf20Sopenharmony_ci 180