Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Simple memory allocator for on-board SRAM
0004  *
0005  * Maintainer : Sylvain Munaut <tnt@246tNt.com>
0006  *
0007  * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
0008  */
0009 
0010 #include <linux/err.h>
0011 #include <linux/kernel.h>
0012 #include <linux/export.h>
0013 #include <linux/slab.h>
0014 #include <linux/spinlock.h>
0015 #include <linux/string.h>
0016 #include <linux/ioport.h>
0017 #include <linux/of.h>
0018 #include <linux/of_address.h>
0019 
0020 #include <asm/io.h>
0021 #include <asm/mmu.h>
0022 
0023 #include <linux/fsl/bestcomm/sram.h>
0024 
0025 
0026 /* Struct keeping our 'state' */
0027 struct bcom_sram *bcom_sram = NULL;
0028 EXPORT_SYMBOL_GPL(bcom_sram);   /* needed for inline functions */
0029 
0030 
0031 /* ======================================================================== */
0032 /* Public API                                                               */
0033 /* ======================================================================== */
0034 /* DO NOT USE in interrupts, if needed in irq handler, we should use the
0035    _irqsave version of the spin_locks */
0036 
0037 int bcom_sram_init(struct device_node *sram_node, char *owner)
0038 {
0039     int rv;
0040     const u32 *regaddr_p;
0041     u64 regaddr64, size64;
0042     unsigned int psize;
0043 
0044     /* Create our state struct */
0045     if (bcom_sram) {
0046         printk(KERN_ERR "%s: bcom_sram_init: "
0047             "Already initialized !\n", owner);
0048         return -EBUSY;
0049     }
0050 
0051     bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL);
0052     if (!bcom_sram) {
0053         printk(KERN_ERR "%s: bcom_sram_init: "
0054             "Couldn't allocate internal state !\n", owner);
0055         return -ENOMEM;
0056     }
0057 
0058     /* Get address and size of the sram */
0059     regaddr_p = of_get_address(sram_node, 0, &size64, NULL);
0060     if (!regaddr_p) {
0061         printk(KERN_ERR "%s: bcom_sram_init: "
0062             "Invalid device node !\n", owner);
0063         rv = -EINVAL;
0064         goto error_free;
0065     }
0066 
0067     regaddr64 = of_translate_address(sram_node, regaddr_p);
0068 
0069     bcom_sram->base_phys = (phys_addr_t) regaddr64;
0070     bcom_sram->size = (unsigned int) size64;
0071 
0072     /* Request region */
0073     if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) {
0074         printk(KERN_ERR "%s: bcom_sram_init: "
0075             "Couldn't request region !\n", owner);
0076         rv = -EBUSY;
0077         goto error_free;
0078     }
0079 
0080     /* Map SRAM */
0081         /* sram is not really __iomem */
0082     bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size);
0083 
0084     if (!bcom_sram->base_virt) {
0085         printk(KERN_ERR "%s: bcom_sram_init: "
0086             "Map error SRAM zone 0x%08lx (0x%0x)!\n",
0087             owner, (long)bcom_sram->base_phys, bcom_sram->size );
0088         rv = -ENOMEM;
0089         goto error_release;
0090     }
0091 
0092     /* Create an rheap (defaults to 32 bits word alignment) */
0093     bcom_sram->rh = rh_create(4);
0094 
0095     /* Attach the free zones */
0096 #if 0
0097     /* Currently disabled ... for future use only */
0098     reg_addr_p = of_get_property(sram_node, "available", &psize);
0099 #else
0100     regaddr_p = NULL;
0101     psize = 0;
0102 #endif
0103 
0104     if (!regaddr_p || !psize) {
0105         /* Attach the whole zone */
0106         rh_attach_region(bcom_sram->rh, 0, bcom_sram->size);
0107     } else {
0108         /* Attach each zone independently */
0109         while (psize >= 2 * sizeof(u32)) {
0110             phys_addr_t zbase = of_translate_address(sram_node, regaddr_p);
0111             rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]);
0112             regaddr_p += 2;
0113             psize -= 2 * sizeof(u32);
0114         }
0115     }
0116 
0117     /* Init our spinlock */
0118     spin_lock_init(&bcom_sram->lock);
0119 
0120     return 0;
0121 
0122 error_release:
0123     release_mem_region(bcom_sram->base_phys, bcom_sram->size);
0124 error_free:
0125     kfree(bcom_sram);
0126     bcom_sram = NULL;
0127 
0128     return rv;
0129 }
0130 EXPORT_SYMBOL_GPL(bcom_sram_init);
0131 
0132 void bcom_sram_cleanup(void)
0133 {
0134     /* Free resources */
0135     if (bcom_sram) {
0136         rh_destroy(bcom_sram->rh);
0137         iounmap((void __iomem *)bcom_sram->base_virt);
0138         release_mem_region(bcom_sram->base_phys, bcom_sram->size);
0139         kfree(bcom_sram);
0140         bcom_sram = NULL;
0141     }
0142 }
0143 EXPORT_SYMBOL_GPL(bcom_sram_cleanup);
0144 
0145 void* bcom_sram_alloc(int size, int align, phys_addr_t *phys)
0146 {
0147     unsigned long offset;
0148 
0149     spin_lock(&bcom_sram->lock);
0150     offset = rh_alloc_align(bcom_sram->rh, size, align, NULL);
0151     spin_unlock(&bcom_sram->lock);
0152 
0153     if (IS_ERR_VALUE(offset))
0154         return NULL;
0155 
0156     *phys = bcom_sram->base_phys + offset;
0157     return bcom_sram->base_virt + offset;
0158 }
0159 EXPORT_SYMBOL_GPL(bcom_sram_alloc);
0160 
0161 void bcom_sram_free(void *ptr)
0162 {
0163     unsigned long offset;
0164 
0165     if (!ptr)
0166         return;
0167 
0168     offset = ptr - bcom_sram->base_virt;
0169 
0170     spin_lock(&bcom_sram->lock);
0171     rh_free(bcom_sram->rh, offset);
0172     spin_unlock(&bcom_sram->lock);
0173 }
0174 EXPORT_SYMBOL_GPL(bcom_sram_free);