18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2008-2015 Freescale Semiconductor Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
58c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
68c2ecf20Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
78c2ecf20Sopenharmony_ci *       notice, this list of conditions and the following disclaimer.
88c2ecf20Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
98c2ecf20Sopenharmony_ci *       notice, this list of conditions and the following disclaimer in the
108c2ecf20Sopenharmony_ci *       documentation and/or other materials provided with the distribution.
118c2ecf20Sopenharmony_ci *     * Neither the name of Freescale Semiconductor nor the
128c2ecf20Sopenharmony_ci *       names of its contributors may be used to endorse or promote products
138c2ecf20Sopenharmony_ci *       derived from this software without specific prior written permission.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the
178c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software
188c2ecf20Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any
198c2ecf20Sopenharmony_ci * later version.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
228c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
238c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
248c2ecf20Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
258c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
268c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
278c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
288c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
298c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
308c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include "fman_muram.h"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/io.h>
368c2ecf20Sopenharmony_ci#include <linux/slab.h>
378c2ecf20Sopenharmony_ci#include <linux/genalloc.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistruct muram_info {
408c2ecf20Sopenharmony_ci	struct gen_pool *pool;
418c2ecf20Sopenharmony_ci	void __iomem *vbase;
428c2ecf20Sopenharmony_ci	size_t size;
438c2ecf20Sopenharmony_ci	phys_addr_t pbase;
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic unsigned long fman_muram_vbase_to_offset(struct muram_info *muram,
478c2ecf20Sopenharmony_ci						unsigned long vaddr)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	return vaddr - (unsigned long)muram->vbase;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/**
538c2ecf20Sopenharmony_ci * fman_muram_init
548c2ecf20Sopenharmony_ci * @base:	Pointer to base of memory mapped FM-MURAM.
558c2ecf20Sopenharmony_ci * @size:	Size of the FM-MURAM partition.
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * Creates partition in the MURAM.
588c2ecf20Sopenharmony_ci * The routine returns a pointer to the MURAM partition.
598c2ecf20Sopenharmony_ci * This pointer must be passed as to all other FM-MURAM function calls.
608c2ecf20Sopenharmony_ci * No actual initialization or configuration of FM_MURAM hardware is done by
618c2ecf20Sopenharmony_ci * this routine.
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * Return: pointer to FM-MURAM object, or NULL for Failure.
648c2ecf20Sopenharmony_ci */
658c2ecf20Sopenharmony_cistruct muram_info *fman_muram_init(phys_addr_t base, size_t size)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	struct muram_info *muram;
688c2ecf20Sopenharmony_ci	void __iomem *vaddr;
698c2ecf20Sopenharmony_ci	int ret;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	muram = kzalloc(sizeof(*muram), GFP_KERNEL);
728c2ecf20Sopenharmony_ci	if (!muram)
738c2ecf20Sopenharmony_ci		return NULL;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	muram->pool = gen_pool_create(ilog2(64), -1);
768c2ecf20Sopenharmony_ci	if (!muram->pool) {
778c2ecf20Sopenharmony_ci		pr_err("%s(): MURAM pool create failed\n", __func__);
788c2ecf20Sopenharmony_ci		goto  muram_free;
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	vaddr = ioremap(base, size);
828c2ecf20Sopenharmony_ci	if (!vaddr) {
838c2ecf20Sopenharmony_ci		pr_err("%s(): MURAM ioremap failed\n", __func__);
848c2ecf20Sopenharmony_ci		goto pool_destroy;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	ret = gen_pool_add_virt(muram->pool, (unsigned long)vaddr,
888c2ecf20Sopenharmony_ci				base, size, -1);
898c2ecf20Sopenharmony_ci	if (ret < 0) {
908c2ecf20Sopenharmony_ci		pr_err("%s(): MURAM pool add failed\n", __func__);
918c2ecf20Sopenharmony_ci		iounmap(vaddr);
928c2ecf20Sopenharmony_ci		goto pool_destroy;
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	memset_io(vaddr, 0, (int)size);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	muram->vbase = vaddr;
988c2ecf20Sopenharmony_ci	muram->pbase = base;
998c2ecf20Sopenharmony_ci	return muram;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cipool_destroy:
1028c2ecf20Sopenharmony_ci	gen_pool_destroy(muram->pool);
1038c2ecf20Sopenharmony_cimuram_free:
1048c2ecf20Sopenharmony_ci	kfree(muram);
1058c2ecf20Sopenharmony_ci	return NULL;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/**
1098c2ecf20Sopenharmony_ci * fman_muram_offset_to_vbase
1108c2ecf20Sopenharmony_ci * @muram:	FM-MURAM module pointer.
1118c2ecf20Sopenharmony_ci * @offset:	the offset of the memory block
1128c2ecf20Sopenharmony_ci *
1138c2ecf20Sopenharmony_ci * Gives the address of the memory region from specific offset
1148c2ecf20Sopenharmony_ci *
1158c2ecf20Sopenharmony_ci * Return: The address of the memory block
1168c2ecf20Sopenharmony_ci */
1178c2ecf20Sopenharmony_ciunsigned long fman_muram_offset_to_vbase(struct muram_info *muram,
1188c2ecf20Sopenharmony_ci					 unsigned long offset)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	return offset + (unsigned long)muram->vbase;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/**
1248c2ecf20Sopenharmony_ci * fman_muram_alloc
1258c2ecf20Sopenharmony_ci * @muram:	FM-MURAM module pointer.
1268c2ecf20Sopenharmony_ci * @size:	Size of the memory to be allocated.
1278c2ecf20Sopenharmony_ci *
1288c2ecf20Sopenharmony_ci * Allocate some memory from FM-MURAM partition.
1298c2ecf20Sopenharmony_ci *
1308c2ecf20Sopenharmony_ci * Return: address of the allocated memory; NULL otherwise.
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_ciunsigned long fman_muram_alloc(struct muram_info *muram, size_t size)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	unsigned long vaddr;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	vaddr = gen_pool_alloc(muram->pool, size);
1378c2ecf20Sopenharmony_ci	if (!vaddr)
1388c2ecf20Sopenharmony_ci		return -ENOMEM;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	memset_io((void __iomem *)vaddr, 0, size);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	return fman_muram_vbase_to_offset(muram, vaddr);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/**
1468c2ecf20Sopenharmony_ci * fman_muram_free_mem
1478c2ecf20Sopenharmony_ci * @muram:	FM-MURAM module pointer.
1488c2ecf20Sopenharmony_ci * @offset:	offset of the memory region to be freed.
1498c2ecf20Sopenharmony_ci * @size:	size of the memory to be freed.
1508c2ecf20Sopenharmony_ci *
1518c2ecf20Sopenharmony_ci * Free an allocated memory from FM-MURAM partition.
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_civoid fman_muram_free_mem(struct muram_info *muram, unsigned long offset,
1548c2ecf20Sopenharmony_ci			 size_t size)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	unsigned long addr = fman_muram_offset_to_vbase(muram, offset);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	gen_pool_free(muram->pool, addr, size);
1598c2ecf20Sopenharmony_ci}
160