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        struct resource *res;
 345        int (*init_func)(void);
 346
 347        sram = devm_kzalloc(&pdev->dev, sizeof(*sram), GFP_KERNEL);
 348        if (!sram)
 349                return -ENOMEM;
 350
 351        sram->dev = &pdev->dev;
 352
 353        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 354        if (of_property_read_bool(pdev->dev.of_node, "no-memory-wc"))
 355                sram->virt_base = devm_ioremap_resource(&pdev->dev, res);
 356        else
 357                sram->virt_base = devm_ioremap_resource_wc(&pdev->dev, res);
 358        if (IS_ERR(sram->virt_base)) {
 359                dev_err(&pdev->dev, "could not map SRAM registers\n");
 360                return PTR_ERR(sram->virt_base);
 361        }
 362
 363        sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY),
 364                                          NUMA_NO_NODE, NULL);
 365        if (IS_ERR(sram->pool))
 366                return PTR_ERR(sram->pool);
 367
 368        sram->clk = devm_clk_get(sram->dev, NULL);
 369        if (IS_ERR(sram->clk))
 370                sram->clk = NULL;
 371        else
 372                clk_prepare_enable(sram->clk);
 373
 374        ret = sram_reserve_regions(sram,
 375                        platform_get_resource(pdev, IORESOURCE_MEM, 0));
 376        if (ret)
 377                goto err_disable_clk;
 378
 379        platform_set_drvdata(pdev, sram);
 380
 381        init_func = of_device_get_match_data(&pdev->dev);
 382        if (init_func) {
 383                ret = init_func();
 384                if (ret)
 385                        goto err_free_partitions;
 386        }
 387
 388        dev_dbg(sram->dev, "SRAM pool: %zu KiB @ 0x%p\n",
 389                gen_pool_size(sram->pool) / 1024, sram->virt_base);
 390
 391        return 0;
 392
 393err_free_partitions:
 394        sram_free_partitions(sram);
 395err_disable_clk:
 396        if (sram->clk)
 397                clk_disable_unprepare(sram->clk);
 398
 399        return ret;
 400}
 401
 402static int sram_remove(struct platform_device *pdev)
 403{
 404        struct sram_dev *sram = platform_get_drvdata(pdev);
 405
 406        sram_free_partitions(sram);
 407
 408        if (gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
 409                dev_err(sram->dev, "removed while SRAM allocated\n");
 410
 411        if (sram->clk)
 412                clk_disable_unprepare(sram->clk);
 413
 414        return 0;
 415}
 416
 417static struct platform_driver sram_driver = {
 418        .driver = {
 419                .name = "sram",
 420                .of_match_table = sram_dt_ids,
 421        },
 422        .probe = sram_probe,
 423        .remove = sram_remove,
 424};
 425
 426static int __init sram_init(void)
 427{
 428        return platform_driver_register(&sram_driver);
 429}
 430
 431postcore_initcall(sram_init);
 432