16db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai/*
26db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * Copyright 2009-2010 Freescale Semiconductor, Inc.
36db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai *
46db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM
56db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai *
66db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
76db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai *
86db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * This file is derived from the original work done
96db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * by Sylvain Munaut for the Bestcomm SRAM allocator.
106db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai *
116db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * This program is free software; you can redistribute  it and/or modify it
126db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * under  the terms of  the GNU General  Public License as published by the
136db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * Free Software Foundation;  either version 2 of the  License, or (at your
146db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * option) any later version.
156db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai *
166db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * This program is distributed in the hope that it will be useful,
176db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * but WITHOUT ANY WARRANTY; without even the implied warranty of
186db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
196db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * GNU General Public License for more details.
206db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai *
216db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * You should have received a copy of the GNU General Public License
226db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * along with this program; if not, write to the Free Software
236db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
246db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai */
256db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
266db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai#include <linux/kernel.h>
27e4399461bdf4d230129c99f785ebe6814269427bClaudiu Manoil#include <linux/export.h>
286db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai#include <linux/slab.h>
296db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai#include <linux/err.h>
306db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai#include <linux/of_platform.h>
316db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai#include <asm/pgtable.h>
326db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai#include <asm/fsl_85xx_cache_sram.h>
336db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
346db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai#include "fsl_85xx_cache_ctlr.h"
356db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
366db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Raistruct mpc85xx_cache_sram *cache_sram;
376db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
386db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Raivoid *mpc85xx_cache_sram_alloc(unsigned int size,
396db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai				phys_addr_t *phys, unsigned int align)
406db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai{
416db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	unsigned long offset;
426db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	unsigned long flags;
436db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
446db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	if (unlikely(cache_sram == NULL))
456db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		return NULL;
466db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
476db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	if (!size || (size > cache_sram->size) || (align > cache_sram->size)) {
486db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		pr_err("%s(): size(=%x) or align(=%x) zero or too big\n",
496db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai			__func__, size, align);
506db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		return NULL;
516db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	}
526db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
536db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	if ((align & (align - 1)) || align <= 1) {
546db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		pr_err("%s(): align(=%x) must be power of two and >1\n",
556db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai			__func__, align);
566db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		return NULL;
576db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	}
586db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
596db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	spin_lock_irqsave(&cache_sram->lock, flags);
606db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	offset = rh_alloc_align(cache_sram->rh, size, align, NULL);
616db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	spin_unlock_irqrestore(&cache_sram->lock, flags);
626db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
636db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	if (IS_ERR_VALUE(offset))
646db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		return NULL;
656db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
666db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	*phys = cache_sram->base_phys + offset;
676db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
686db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	return (unsigned char *)cache_sram->base_virt + offset;
696db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai}
706db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder RaiEXPORT_SYMBOL(mpc85xx_cache_sram_alloc);
716db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
726db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Raivoid mpc85xx_cache_sram_free(void *ptr)
736db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai{
746db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	unsigned long flags;
756db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	BUG_ON(!ptr);
766db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
776db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	spin_lock_irqsave(&cache_sram->lock, flags);
786db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	rh_free(cache_sram->rh, ptr - cache_sram->base_virt);
796db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	spin_unlock_irqrestore(&cache_sram->lock, flags);
806db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai}
816db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder RaiEXPORT_SYMBOL(mpc85xx_cache_sram_free);
826db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
836db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Raiint __init instantiate_cache_sram(struct platform_device *dev,
846db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		struct sram_parameters sram_params)
856db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai{
866db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	int ret = 0;
876db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
886db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	if (cache_sram) {
896db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		dev_err(&dev->dev, "Already initialized cache-sram\n");
906db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		return -EBUSY;
916db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	}
926db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
936db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL);
946db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	if (!cache_sram) {
956db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		dev_err(&dev->dev, "Out of memory for cache_sram structure\n");
966db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		return -ENOMEM;
976db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	}
986db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
996db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	cache_sram->base_phys = sram_params.sram_offset;
1006db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	cache_sram->size = sram_params.sram_size;
1016db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1026db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
1036db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai						"fsl_85xx_cache_sram")) {
1046db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		dev_err(&dev->dev, "%s: request memory failed\n",
1056db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai				dev->dev.of_node->full_name);
1066db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		ret = -ENXIO;
1076db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		goto out_free;
1086db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	}
1096db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
11040f1ce7fb7e8b5d4d0821c0f3dc866cb1d47d99cAnton Blanchard	cache_sram->base_virt = ioremap_prot(cache_sram->base_phys,
1116db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai				cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL);
1126db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	if (!cache_sram->base_virt) {
11340f1ce7fb7e8b5d4d0821c0f3dc866cb1d47d99cAnton Blanchard		dev_err(&dev->dev, "%s: ioremap_prot failed\n",
1146db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai				dev->dev.of_node->full_name);
1156db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		ret = -ENOMEM;
1166db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		goto out_release;
1176db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	}
1186db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1196db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	cache_sram->rh = rh_create(sizeof(unsigned int));
1206db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	if (IS_ERR(cache_sram->rh)) {
1216db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		dev_err(&dev->dev, "%s: Unable to create remote heap\n",
1226db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai				dev->dev.of_node->full_name);
1236db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		ret = PTR_ERR(cache_sram->rh);
1246db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		goto out_unmap;
1256db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	}
1266db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1276db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	rh_attach_region(cache_sram->rh, 0, cache_sram->size);
1286db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	spin_lock_init(&cache_sram->lock);
1296db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1306db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n",
1316db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai		(unsigned long long)cache_sram->base_phys, cache_sram->size);
1326db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1336db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	return 0;
1346db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1356db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Raiout_unmap:
1366db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	iounmap(cache_sram->base_virt);
1376db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1386db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Raiout_release:
1396db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	release_mem_region(cache_sram->base_phys, cache_sram->size);
1406db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1416db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Raiout_free:
1426db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	kfree(cache_sram);
1436db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	return ret;
1446db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai}
1456db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1466db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Raivoid remove_cache_sram(struct platform_device *dev)
1476db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai{
1486db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	BUG_ON(!cache_sram);
1496db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1506db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	rh_detach_region(cache_sram->rh, 0, cache_sram->size);
1516db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	rh_destroy(cache_sram->rh);
1526db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1536db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	iounmap(cache_sram->base_virt);
1546db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	release_mem_region(cache_sram->base_phys, cache_sram->size);
1556db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1566db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	kfree(cache_sram);
1576db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	cache_sram = NULL;
1586db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai
1596db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai	dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n");
1606db92cc9d07db9f713da8554b4bcdfc8e54ad386Harninder Rai}
161