18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-mmp/sram.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * based on mach-davinci/sram.c - DaVinci simple SRAM allocator 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2011 Marvell Semiconductors Inc. 88c2ecf20Sopenharmony_ci * All Rights Reserved 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Add for mmp sram support - Leo Yan <leoy@marvell.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/io.h> 188c2ecf20Sopenharmony_ci#include <linux/err.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/genalloc.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/platform_data/dma-mmp_tdma.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct sram_bank_info { 258c2ecf20Sopenharmony_ci char *pool_name; 268c2ecf20Sopenharmony_ci struct gen_pool *gpool; 278c2ecf20Sopenharmony_ci int granularity; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci phys_addr_t sram_phys; 308c2ecf20Sopenharmony_ci void __iomem *sram_virt; 318c2ecf20Sopenharmony_ci u32 sram_size; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci struct list_head node; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(sram_lock); 378c2ecf20Sopenharmony_cistatic LIST_HEAD(sram_bank_list); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct gen_pool *sram_get_gpool(char *pool_name) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct sram_bank_info *info = NULL; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (!pool_name) 448c2ecf20Sopenharmony_ci return NULL; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci mutex_lock(&sram_lock); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci list_for_each_entry(info, &sram_bank_list, node) 498c2ecf20Sopenharmony_ci if (!strcmp(pool_name, info->pool_name)) 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci mutex_unlock(&sram_lock); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (&info->node == &sram_bank_list) 558c2ecf20Sopenharmony_ci return NULL; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return info->gpool; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sram_get_gpool); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int sram_probe(struct platform_device *pdev) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct sram_platdata *pdata = pdev->dev.platform_data; 648c2ecf20Sopenharmony_ci struct sram_bank_info *info; 658c2ecf20Sopenharmony_ci struct resource *res; 668c2ecf20Sopenharmony_ci int ret = 0; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (!pdata || !pdata->pool_name) 698c2ecf20Sopenharmony_ci return -ENODEV; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 728c2ecf20Sopenharmony_ci if (!info) 738c2ecf20Sopenharmony_ci return -ENOMEM; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, info); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 788c2ecf20Sopenharmony_ci if (res == NULL) { 798c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no memory resource defined\n"); 808c2ecf20Sopenharmony_ci ret = -ENODEV; 818c2ecf20Sopenharmony_ci goto out; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (!resource_size(res)) 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci info->sram_phys = (phys_addr_t)res->start; 888c2ecf20Sopenharmony_ci info->sram_size = resource_size(res); 898c2ecf20Sopenharmony_ci info->sram_virt = ioremap(info->sram_phys, info->sram_size); 908c2ecf20Sopenharmony_ci info->pool_name = kstrdup(pdata->pool_name, GFP_KERNEL); 918c2ecf20Sopenharmony_ci info->granularity = pdata->granularity; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci info->gpool = gen_pool_create(ilog2(info->granularity), -1); 948c2ecf20Sopenharmony_ci if (!info->gpool) { 958c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "create pool failed\n"); 968c2ecf20Sopenharmony_ci ret = -ENOMEM; 978c2ecf20Sopenharmony_ci goto create_pool_err; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci ret = gen_pool_add_virt(info->gpool, (unsigned long)info->sram_virt, 1018c2ecf20Sopenharmony_ci info->sram_phys, info->sram_size, -1); 1028c2ecf20Sopenharmony_ci if (ret < 0) { 1038c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "add new chunk failed\n"); 1048c2ecf20Sopenharmony_ci ret = -ENOMEM; 1058c2ecf20Sopenharmony_ci goto add_chunk_err; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci mutex_lock(&sram_lock); 1098c2ecf20Sopenharmony_ci list_add(&info->node, &sram_bank_list); 1108c2ecf20Sopenharmony_ci mutex_unlock(&sram_lock); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "initialized\n"); 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciadd_chunk_err: 1168c2ecf20Sopenharmony_ci gen_pool_destroy(info->gpool); 1178c2ecf20Sopenharmony_cicreate_pool_err: 1188c2ecf20Sopenharmony_ci iounmap(info->sram_virt); 1198c2ecf20Sopenharmony_ci kfree(info->pool_name); 1208c2ecf20Sopenharmony_ciout: 1218c2ecf20Sopenharmony_ci kfree(info); 1228c2ecf20Sopenharmony_ci return ret; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int sram_remove(struct platform_device *pdev) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct sram_bank_info *info; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci info = platform_get_drvdata(pdev); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (info->sram_size) { 1328c2ecf20Sopenharmony_ci mutex_lock(&sram_lock); 1338c2ecf20Sopenharmony_ci list_del(&info->node); 1348c2ecf20Sopenharmony_ci mutex_unlock(&sram_lock); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci gen_pool_destroy(info->gpool); 1378c2ecf20Sopenharmony_ci iounmap(info->sram_virt); 1388c2ecf20Sopenharmony_ci kfree(info->pool_name); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci kfree(info); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic const struct platform_device_id sram_id_table[] = { 1478c2ecf20Sopenharmony_ci { "asram", MMP_ASRAM }, 1488c2ecf20Sopenharmony_ci { "isram", MMP_ISRAM }, 1498c2ecf20Sopenharmony_ci { } 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic struct platform_driver sram_driver = { 1538c2ecf20Sopenharmony_ci .probe = sram_probe, 1548c2ecf20Sopenharmony_ci .remove = sram_remove, 1558c2ecf20Sopenharmony_ci .driver = { 1568c2ecf20Sopenharmony_ci .name = "mmp-sram", 1578c2ecf20Sopenharmony_ci }, 1588c2ecf20Sopenharmony_ci .id_table = sram_id_table, 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int __init sram_init(void) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci return platform_driver_register(&sram_driver); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_cicore_initcall(sram_init); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 168