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