linux/drivers/misc/sram.c
<<
>>
Prefs
   1/*
   2 * Generic on-chip SRAM allocation driver
   3 *
   4 * Copyright (C) 2012 Philipp Zabel, Pengutronix
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version 2
   9 * of the License, or (at your option) any later version.
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  18 * MA 02110-1301, USA.
  19 */
  20
  21#include <linux/clk.h>
  22#include <linux/delay.h>
  23#include <linux/genalloc.h>
  24#include <linux/io.h>
  25#include <linux/list_sort.h>
  26#include <linux/of_address.h>
  27#include <linux/of_device.h>
  28#include <linux/platform_device.h>
  29#include <linux/regmap.h>
  30#include <linux/slab.h>
  31#include <linux/mfd/syscon.h>
  32#include <soc/at91/atmel-secumod.h>
  33
  34#include "sram.h"
  35
  36#define SRAM_GRANULARITY        32
  37
  38static ssize_t sram_read(struct file *filp, struct kobject *kobj,
  39                         struct bin_attribute *attr,
  40                         char *buf, loff_t pos, size_t count)
  41{
  42        struct sram_partition *part;
  43
  44        part = container_of(attr, struct sram_partition, battr);
  45
  46        mutex_lock(&part->lock);
  47        memcpy_fromio(buf, part->base + pos, count);
  48        mutex_unlock(&part->lock);
  49
  50        return count;
  51}
  52
  53static ssize_t sram_write(struct file *filp, struct kobject *kobj,
  54                          struct bin_attribute *attr,
  55                          char *buf, loff_t pos, size_t count)
  56{
  57        struct sram_partition *part;
  58
  59        part = container_of(attr, struct sram_partition, battr);
  60
  61        mutex_lock(&part->lock);
  62        memcpy_toio(part->base + pos, buf, count);
  63        mutex_unlock(&part->lock);
  64
  65        return count;
  66}
  67
  68static int sram_add_pool(struct sram_dev *sram, struct sram_reserve *block,
  69                         phys_addr_t start, struct sram_partition *part)
  70{
  71        int ret;
  72
  73        part->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY),
  74                                          NUMA_NO_NODE, block->label);
  75        if (IS_ERR(part->pool))
  76                return PTR_ERR(part->pool);
  77
  78        ret = gen_pool_add_virt(part->pool, (unsigned long)part->base, start,
  79                                block->size, NUMA_NO_NODE);
  80        if (ret < 0) {
  81                dev_err(sram->dev, "failed to register subpool: %d\n", ret);
  82                return ret;
  83        }
  84
  85        return 0;
  86}
  87
  88static int sram_add_export(struct sram_dev *sram, struct sram_reserve *block,
  89                           phys_addr_t start, struct sram_partition *part)
  90{
  91        sysfs_bin_attr_init(&part->battr);
  92        part->battr.attr.name = devm_kasprintf(sram->dev, GFP_KERNEL,
  93                                               "%llx.sram",
  94                                               (unsigned long long)start);
  95        if (!part->battr.attr.name)
  96                return -ENOMEM;
  97
  98        part->battr.attr.mode = S_IRUSR | S_IWUSR;
  99        part->battr.read = sram_read;
 100        part->battr.write = sram_write;
 101        part->battr.size = block->size;
 102
 103        return device_create_bin_file(sram->dev, &part->battr);
 104}
 105
 106static int sram_add_partition(struct sram_dev *sram, struct sram_reserve *block,
 107                              phys_addr_t start)
 108{
 109        int ret;
 110        struct sram_partition *part = &sram->partition[sram->partitions];
 111
 112        mutex_init(&part->lock);
 113        part->base = sram->virt_base + block->start;
 114
 115        if (block->pool) {
 116                ret = sram_add_pool(sram, block, start, part);
 117                if (ret)
 118                        return ret;
 119        }
 120        if (block->export) {
 121                ret = sram_add_export(sram, block, start, part);
 122                if (ret)
 123                        return ret;
 124        }
 125        if (block->protect_exec) {
 126                ret = sram_check_protect_exec(sram, block, part);
 127                if (ret)
 128                        return ret;
 129
 130                ret = sram_add_pool(sram, block, start, part);
 131                if (ret)
 132                        return ret;
 133
 134                sram_add_protect_exec(part);
 135        }
 136
 137        sram->partitions++;
 138
 139        return 0;
 140}
 141
 142static void sram_free_partitions(struct sram_dev *sram)
 143{
 144        struct sram_partition *part;
 145
 146        if (!sram->partitions)
 147                return;
 148
 149        part = &sram->partition[sram->partitions - 1];
 150        for (; sram->partitions; sram->partitions--, part--) {
 151                if (part->battr.size)
 152                        device_remove_bin_file(sram->dev, &part->battr);
 153
 154                if (part->pool &&
 155                    gen_pool_avail(part->pool) < gen_pool_size(part->pool))
 156                        dev_err(sram->dev, "removed pool while SRAM allocated\n");
 157        }
 158}
 159
 160static int sram_reserve_cmp(void *priv, struct list_head *a,
 161                                        struct list_head *b)
 162{
 163        struct sram_reserve *ra = list_entry(a, struct sram_reserve, list);
 164        struct sram_reserve *rb = list_entry(b, struct sram_reserve, list);
 165
 166        return ra->start - rb->start;
 167}
 168
 169static int sram_reserve_regions(struct sram_dev *sram, struct resource *res)
 170{
 171        struct device_node *np = sram->dev->of_node, *child;
 172        unsigned long size, cur_start, cur_size;
 173        struct sram_reserve *rblocks, *block;
 174        struct list_head reserve_list;
 175        unsigned int nblocks, exports = 0;
 176        const char *label;
 177        int ret = 0;
 178
 179        INIT_LIST_HEAD(&reserve_list);
 180
 181        size = resource_size(res);
 182
 183        /*
 184         * We need an additional block to mark the end of the memory region
 185         * after the reserved blocks from the dt are processed.
 186         */
 187        nblocks = (np) ? of_get_available_child_count(np) + 1 : 1;
 188        rblocks = kcalloc(nblocks, sizeof(*rblocks), GFP_KERNEL);
 189        if (!rblocks)
 190                return -ENOMEM;
 191
 192        block = &rblocks[0];
 193        for_each_available_child_of_node(np, child) {
 194                struct resource child_res;
 195
 196                ret = of_address_to_resource(child, 0, &child_res);
 197                if (ret < 0) {
 198                        dev_err(sram->dev,
 199                                "could not get address for node %pOF\n",
 200                                child);
 201                        goto err_chunks;
 202                }
 203
 204                if (child_res.start < res->start || child_res.end > res->end) {
 205                        dev_err(sram->dev,
 206                                "reserved block %pOF outside the sram area\n",
 207                                child);
 208                        ret = -EINVAL;
 209                        goto err_chunks;
 210                }
 211
 212                block->start = child_res.start - res->start;
 213                block->size = resource_size(&child_res);
 214                list_add_tail(&block->list, &reserve_list);
 215
 216                if (of_find_property(child, "export", NULL))
 217                        block->export = true;
 218
 219                if (of_find_property(child, "pool", NULL))
 220                        block->pool = true;
 221
 222                if (of_find_property(child, "protect-exec", NULL))
 223                        block->protect_exec = true;
 224
 225                if ((block->export || block->pool || block->protect_exec) &&
 226                    block->size) {
 227                        exports++;
 228
 229                        label = NULL;
 230                        ret = of_property_read_string(child, "label", &label);
 231                        if (ret && ret != -EINVAL) {
 232                                dev_err(sram->dev,
 233                                        "%pOF has invalid label name\n",
 234                                        child);
 235                                goto err_chunks;
 236                        }
 237                        if (!label)
 238                                label = child->name;
 239
 240                        block->label = devm_kstrdup(sram->dev,
 241                                                    label, GFP_KERNEL);
 242                        if (!block->label) {
 243                                ret = -ENOMEM;
 244                                goto err_chunks;
 245                        }
 246
 247                        dev_dbg(sram->dev, "found %sblock '%s' 0x%x-0x%x\n",
 248                                block->export ? "exported " : "", block->label,
 249                                block->start, block->start + block->size);
 250                } else {
 251                        dev_dbg(sram->dev, "found reserved block 0x%x-0x%x\n",
 252                                block->start, block->start + block->size);
 253                }
 254
 255                block++;
 256        }
 257        child = NULL;
 258
 259        /* the last chunk marks the end of the region */
 260        rblocks[nblocks - 1].start = size;
 261        rblocks[nblocks - 1].size = 0;
 262        list_add_tail(&rblocks[nblocks - 1].list, &reserve_list);
 263
 264        list_sort(NULL, &reserve_list, sram_reserve_cmp);
 265
 266        if (exports) {
 267                sram->partition = devm_kcalloc(sram->dev,
 268                                       exports, sizeof(*sram->partition),
 269                                       GFP_KERNEL);
 270                if (!sram->partition) {
 271                        ret = -ENOMEM;
 272                        goto err_chunks;
 273                }
 274        }
 275
 276        cur_start = 0;
 277        list_for_each_entry(block, &reserve_list, list) {
 278                /* can only happen if sections overlap */
 279                if (block->start < cur_start) {
 280                        dev_err(sram->dev,
 281                                "block at 0x%x starts after current offset 0x%lx\n",
 282                                block->start, cur_start);
 283                        ret = -EINVAL;
 284                        sram_free_partitions(sram);
 285                        goto err_chunks;
 286                }
 287
 288                if ((block->export || block->pool || block->protect_exec) &&
 289                    block->size) {
 290                        ret = sram_add_partition(sram, block,
 291                                                 res->start + block->start);
 292                        if (ret) {
 293                                sram_free_partitions(sram);
 294                                goto err_chunks;
 295                        }
 296                }
 297
 298                /* current start is in a reserved block, so continue after it */
 299                if (block->start == cur_start) {
 300                        cur_start = block->start + block->size;
 301                        continue;
 302                }
 303
 304                /*
 305                 * allocate the space between the current starting
 306                 * address and the following reserved block, or the
 307                 * end of the region.
 308                 */
 309                cur_size = block->start - cur_start;
 310
 311                dev_dbg(sram->dev, "adding chunk 0x%lx-0x%lx\n",
 312                        cur_start, cur_start + cur_size);
 313
 314                ret = gen_pool_add_virt(sram->pool,
 315                                (unsigned long)sram->virt_base + cur_start,
 316                                res->start + cur_start, cur_size, -1);
 317                if (ret < 0) {
 318                        sram_free_partitions(sram);
 319                        goto err_chunks;
 320                }
 321
 322                /* next allocation after this reserved block */
 323                cur_start = block->start + block->size;
 324        }
 325
 326 err_chunks:
 327        if (child)
 328                of_node_put(child);
 329
 330        kfree(rblocks);
 331
 332        return ret;
 333}
 334
 335static int atmel_securam_wait(void)
 336{
 337        struct regmap *regmap;
 338        u32 val;
 339
 340        regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-secumod");
 341        if (IS_ERR(regmap))
 342                return -ENODEV;
 343
 344        return regmap_read_poll_timeout(regmap, AT91_SECUMOD_RAMRDY, val,
 345                                        val & AT91_SECUMOD_RAMRDY_READY,
 346                                        10000, 500000);
 347}
 348
 349static const struct of_device_id sram_dt_ids[] = {
 350        { .compatible = "mmio-sram" },
 351        { .compatible = "atmel,sama5d2-securam", .data = atmel_securam_wait },
 352        {}
 353};
 354
 355static int sram_probe(struct platform_device *pdev)
 356{
 357        struct sram_dev *sram;
 358        struct resource *res;
 359        size_t size;
 360        int ret;
 361        int (*init_func)(void);
 362
 363        sram = devm_kzalloc(&pdev->dev, sizeof(*sram), GFP_KERNEL);
 364        if (!sram)
 365                return -ENOMEM;
 366
 367        sram->dev = &pdev->dev;
 368
 369        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 370        if (!res) {
 371                dev_err(sram->dev, "found no memory resource\n");
 372                return -EINVAL;
 373        }
 374
 375        size = resource_size(res);
 376
 377        if (!devm_request_mem_region(sram->dev, res->start, size, pdev->name)) {
 378                dev_err(sram->dev, "could not request region for resource\n");
 379                return -EBUSY;
 380        }
 381
 382        if (of_property_read_bool(pdev->dev.of_node, "no-memory-wc"))
 383                sram->virt_base = devm_ioremap(sram->dev, res->start, size);
 384        else
 385                sram->virt_base = devm_ioremap_wc(sram->dev, res->start, size);
 386        if (!sram->virt_base)
 387                return -ENOMEM;
 388
 389        sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY),
 390                                          NUMA_NO_NODE, NULL);
 391        if (IS_ERR(sram->pool))
 392                return PTR_ERR(sram->pool);
 393
 394        ret = sram_reserve_regions(sram, res);
 395        if (ret)
 396                return ret;
 397
 398        sram->clk = devm_clk_get(sram->dev, NULL);
 399        if (IS_ERR(sram->clk))
 400                sram->clk = NULL;
 401        else
 402                clk_prepare_enable(sram->clk);
 403
 404        platform_set_drvdata(pdev, sram);
 405
 406        init_func = of_device_get_match_data(&pdev->dev);
 407        if (init_func) {
 408                ret = init_func();
 409                if (ret)
 410                        return ret;
 411        }
 412
 413        dev_dbg(sram->dev, "SRAM pool: %zu KiB @ 0x%p\n",
 414                gen_pool_size(sram->pool) / 1024, sram->virt_base);
 415
 416        return 0;
 417}
 418
 419static int sram_remove(struct platform_device *pdev)
 420{
 421        struct sram_dev *sram = platform_get_drvdata(pdev);
 422
 423        sram_free_partitions(sram);
 424
 425        if (gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
 426                dev_err(sram->dev, "removed while SRAM allocated\n");
 427
 428        if (sram->clk)
 429                clk_disable_unprepare(sram->clk);
 430
 431        return 0;
 432}
 433
 434static struct platform_driver sram_driver = {
 435        .driver = {
 436                .name = "sram",
 437                .of_match_table = sram_dt_ids,
 438        },
 439        .probe = sram_probe,
 440        .remove = sram_remove,
 441};
 442
 443static int __init sram_init(void)
 444{
 445        return platform_driver_register(&sram_driver);
 446}
 447
 448postcore_initcall(sram_init);
 449