18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2009-2010 Freescale Semiconductor, Inc.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This file is derived from the original work done
108c2ecf20Sopenharmony_ci * by Sylvain Munaut for the Bestcomm SRAM allocator.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/export.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/err.h>
178c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
188c2ecf20Sopenharmony_ci#include <linux/pgtable.h>
198c2ecf20Sopenharmony_ci#include <asm/fsl_85xx_cache_sram.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "fsl_85xx_cache_ctlr.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistruct mpc85xx_cache_sram *cache_sram;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_civoid *mpc85xx_cache_sram_alloc(unsigned int size,
268c2ecf20Sopenharmony_ci				phys_addr_t *phys, unsigned int align)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	unsigned long offset;
298c2ecf20Sopenharmony_ci	unsigned long flags;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	if (unlikely(cache_sram == NULL))
328c2ecf20Sopenharmony_ci		return NULL;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (!size || (size > cache_sram->size) || (align > cache_sram->size)) {
358c2ecf20Sopenharmony_ci		pr_err("%s(): size(=%x) or align(=%x) zero or too big\n",
368c2ecf20Sopenharmony_ci			__func__, size, align);
378c2ecf20Sopenharmony_ci		return NULL;
388c2ecf20Sopenharmony_ci	}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if ((align & (align - 1)) || align <= 1) {
418c2ecf20Sopenharmony_ci		pr_err("%s(): align(=%x) must be power of two and >1\n",
428c2ecf20Sopenharmony_ci			__func__, align);
438c2ecf20Sopenharmony_ci		return NULL;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	spin_lock_irqsave(&cache_sram->lock, flags);
478c2ecf20Sopenharmony_ci	offset = rh_alloc_align(cache_sram->rh, size, align, NULL);
488c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&cache_sram->lock, flags);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (IS_ERR_VALUE(offset))
518c2ecf20Sopenharmony_ci		return NULL;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	*phys = cache_sram->base_phys + offset;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return (unsigned char *)cache_sram->base_virt + offset;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpc85xx_cache_sram_alloc);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_civoid mpc85xx_cache_sram_free(void *ptr)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	unsigned long flags;
628c2ecf20Sopenharmony_ci	BUG_ON(!ptr);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	spin_lock_irqsave(&cache_sram->lock, flags);
658c2ecf20Sopenharmony_ci	rh_free(cache_sram->rh, ptr - cache_sram->base_virt);
668c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&cache_sram->lock, flags);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpc85xx_cache_sram_free);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciint __init instantiate_cache_sram(struct platform_device *dev,
718c2ecf20Sopenharmony_ci		struct sram_parameters sram_params)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	int ret = 0;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (cache_sram) {
768c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Already initialized cache-sram\n");
778c2ecf20Sopenharmony_ci		return -EBUSY;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL);
818c2ecf20Sopenharmony_ci	if (!cache_sram) {
828c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Out of memory for cache_sram structure\n");
838c2ecf20Sopenharmony_ci		return -ENOMEM;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	cache_sram->base_phys = sram_params.sram_offset;
878c2ecf20Sopenharmony_ci	cache_sram->size = sram_params.sram_size;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
908c2ecf20Sopenharmony_ci						"fsl_85xx_cache_sram")) {
918c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "%pOF: request memory failed\n",
928c2ecf20Sopenharmony_ci				dev->dev.of_node);
938c2ecf20Sopenharmony_ci		ret = -ENXIO;
948c2ecf20Sopenharmony_ci		goto out_free;
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	cache_sram->base_virt = ioremap_coherent(cache_sram->base_phys,
988c2ecf20Sopenharmony_ci						 cache_sram->size);
998c2ecf20Sopenharmony_ci	if (!cache_sram->base_virt) {
1008c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "%pOF: ioremap_coherent failed\n",
1018c2ecf20Sopenharmony_ci			dev->dev.of_node);
1028c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1038c2ecf20Sopenharmony_ci		goto out_release;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	cache_sram->rh = rh_create(sizeof(unsigned int));
1078c2ecf20Sopenharmony_ci	if (IS_ERR(cache_sram->rh)) {
1088c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "%pOF: Unable to create remote heap\n",
1098c2ecf20Sopenharmony_ci				dev->dev.of_node);
1108c2ecf20Sopenharmony_ci		ret = PTR_ERR(cache_sram->rh);
1118c2ecf20Sopenharmony_ci		goto out_unmap;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	rh_attach_region(cache_sram->rh, 0, cache_sram->size);
1158c2ecf20Sopenharmony_ci	spin_lock_init(&cache_sram->lock);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n",
1188c2ecf20Sopenharmony_ci		(unsigned long long)cache_sram->base_phys, cache_sram->size);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return 0;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ciout_unmap:
1238c2ecf20Sopenharmony_ci	iounmap(cache_sram->base_virt);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciout_release:
1268c2ecf20Sopenharmony_ci	release_mem_region(cache_sram->base_phys, cache_sram->size);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ciout_free:
1298c2ecf20Sopenharmony_ci	kfree(cache_sram);
1308c2ecf20Sopenharmony_ci	return ret;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_civoid remove_cache_sram(struct platform_device *dev)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	BUG_ON(!cache_sram);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	rh_detach_region(cache_sram->rh, 0, cache_sram->size);
1388c2ecf20Sopenharmony_ci	rh_destroy(cache_sram->rh);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	iounmap(cache_sram->base_virt);
1418c2ecf20Sopenharmony_ci	release_mem_region(cache_sram->base_phys, cache_sram->size);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	kfree(cache_sram);
1448c2ecf20Sopenharmony_ci	cache_sram = NULL;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n");
1478c2ecf20Sopenharmony_ci}
148