linux/drivers/dma/bestcomm/sram.c
<<
>>
Prefs
   1/*
   2 * Simple memory allocator for on-board SRAM
   3 *
   4 *
   5 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
   6 *
   7 * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
   8 *
   9 * This file is licensed under the terms of the GNU General Public License
  10 * version 2. This program is licensed "as is" without any warranty of any
  11 * kind, whether express or implied.
  12 */
  13
  14#include <linux/err.h>
  15#include <linux/kernel.h>
  16#include <linux/export.h>
  17#include <linux/slab.h>
  18#include <linux/spinlock.h>
  19#include <linux/string.h>
  20#include <linux/ioport.h>
  21#include <linux/of.h>
  22#include <linux/of_address.h>
  23
  24#include <asm/io.h>
  25#include <asm/mmu.h>
  26
  27#include <linux/fsl/bestcomm/sram.h>
  28
  29
  30/* Struct keeping our 'state' */
  31struct bcom_sram *bcom_sram = NULL;
  32EXPORT_SYMBOL_GPL(bcom_sram);   /* needed for inline functions */
  33
  34
  35/* ======================================================================== */
  36/* Public API                                                               */
  37/* ======================================================================== */
  38/* DO NOT USE in interrupts, if needed in irq handler, we should use the
  39   _irqsave version of the spin_locks */
  40
  41int bcom_sram_init(struct device_node *sram_node, char *owner)
  42{
  43        int rv;
  44        const u32 *regaddr_p;
  45        u64 regaddr64, size64;
  46        unsigned int psize;
  47
  48        /* Create our state struct */
  49        if (bcom_sram) {
  50                printk(KERN_ERR "%s: bcom_sram_init: "
  51                        "Already initialized !\n", owner);
  52                return -EBUSY;
  53        }
  54
  55        bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL);
  56        if (!bcom_sram) {
  57                printk(KERN_ERR "%s: bcom_sram_init: "
  58                        "Couldn't allocate internal state !\n", owner);
  59                return -ENOMEM;
  60        }
  61
  62        /* Get address and size of the sram */
  63        regaddr_p = of_get_address(sram_node, 0, &size64, NULL);
  64        if (!regaddr_p) {
  65                printk(KERN_ERR "%s: bcom_sram_init: "
  66                        "Invalid device node !\n", owner);
  67                rv = -EINVAL;
  68                goto error_free;
  69        }
  70
  71        regaddr64 = of_translate_address(sram_node, regaddr_p);
  72
  73        bcom_sram->base_phys = (phys_addr_t) regaddr64;
  74        bcom_sram->size = (unsigned int) size64;
  75
  76        /* Request region */
  77        if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) {
  78                printk(KERN_ERR "%s: bcom_sram_init: "
  79                        "Couldn't request region !\n", owner);
  80                rv = -EBUSY;
  81                goto error_free;
  82        }
  83
  84        /* Map SRAM */
  85                /* sram is not really __iomem */
  86        bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size);
  87
  88        if (!bcom_sram->base_virt) {
  89                printk(KERN_ERR "%s: bcom_sram_init: "
  90                        "Map error SRAM zone 0x%08lx (0x%0x)!\n",
  91                        owner, (long)bcom_sram->base_phys, bcom_sram->size );
  92                rv = -ENOMEM;
  93                goto error_release;
  94        }
  95
  96        /* Create an rheap (defaults to 32 bits word alignment) */
  97        bcom_sram->rh = rh_create(4);
  98
  99        /* Attach the free zones */
 100#if 0
 101        /* Currently disabled ... for future use only */
 102        reg_addr_p = of_get_property(sram_node, "available", &psize);
 103#else
 104        regaddr_p = NULL;
 105        psize = 0;
 106#endif
 107
 108        if (!regaddr_p || !psize) {
 109                /* Attach the whole zone */
 110                rh_attach_region(bcom_sram->rh, 0, bcom_sram->size);
 111        } else {
 112                /* Attach each zone independently */
 113                while (psize >= 2 * sizeof(u32)) {
 114                        phys_addr_t zbase = of_translate_address(sram_node, regaddr_p);
 115                        rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]);
 116                        regaddr_p += 2;
 117                        psize -= 2 * sizeof(u32);
 118                }
 119        }
 120
 121        /* Init our spinlock */
 122        spin_lock_init(&bcom_sram->lock);
 123
 124        return 0;
 125
 126error_release:
 127        release_mem_region(bcom_sram->base_phys, bcom_sram->size);
 128error_free:
 129        kfree(bcom_sram);
 130        bcom_sram = NULL;
 131
 132        return rv;
 133}
 134EXPORT_SYMBOL_GPL(bcom_sram_init);
 135
 136void bcom_sram_cleanup(void)
 137{
 138        /* Free resources */
 139        if (bcom_sram) {
 140                rh_destroy(bcom_sram->rh);
 141                iounmap((void __iomem *)bcom_sram->base_virt);
 142                release_mem_region(bcom_sram->base_phys, bcom_sram->size);
 143                kfree(bcom_sram);
 144                bcom_sram = NULL;
 145        }
 146}
 147EXPORT_SYMBOL_GPL(bcom_sram_cleanup);
 148
 149void* bcom_sram_alloc(int size, int align, phys_addr_t *phys)
 150{
 151        unsigned long offset;
 152
 153        spin_lock(&bcom_sram->lock);
 154        offset = rh_alloc_align(bcom_sram->rh, size, align, NULL);
 155        spin_unlock(&bcom_sram->lock);
 156
 157        if (IS_ERR_VALUE(offset))
 158                return NULL;
 159
 160        *phys = bcom_sram->base_phys + offset;
 161        return bcom_sram->base_virt + offset;
 162}
 163EXPORT_SYMBOL_GPL(bcom_sram_alloc);
 164
 165void bcom_sram_free(void *ptr)
 166{
 167        unsigned long offset;
 168
 169        if (!ptr)
 170                return;
 171
 172        offset = ptr - bcom_sram->base_virt;
 173
 174        spin_lock(&bcom_sram->lock);
 175        rh_free(bcom_sram->rh, offset);
 176        spin_unlock(&bcom_sram->lock);
 177}
 178EXPORT_SYMBOL_GPL(bcom_sram_free);
 179
 180