OpenCores
URL https://opencores.org/ocsvn/funbase_ip_library/funbase_ip_library/trunk

Subversion Repositories funbase_ip_library

[/] [funbase_ip_library/] [trunk/] [TUT/] [ip.swp.api/] [openmcapi/] [1.0/] [libmcapi/] [shm/] [linux/] [kmod/] [mpc85xx.c] - Rev 145

Compare with Previous | Blame | View Log

/*
 * Copyright (c) 2010, Mentor Graphics Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the <ORGANIZATION> nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
 
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of_platform.h>
 
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/fsl_msg.h>
 
#include "mcomm.h"
 
#define MESSAGE_VAL 1
 
struct notification {
	u32 core_id;
	u32 msg_num;
};
 
static struct mcomm_mpc85xx_data {
	struct fsl_msg_unit **notifications; /* Assumes contiguous PIRs. */
	int nr_notifications;
} mcomm_mpc85xx_data;
 
 
 
static pgprot_t mcomm_mpc85xx_mmap_pgprot(struct vm_area_struct *vma)
{
	return pgprot_cached(vma->vm_page_prot);
}
 
static void __iomem *mcomm_mpc85xx_ioremap(unsigned long phys_addr, size_t size)
{
	return ioremap_prot(phys_addr, size, _PAGE_COHERENT);
}
 
static void mcomm_mpc85xx_notify(u32 core_id)
{
	fsl_send_msg(mcomm_mpc85xx_data.notifications[core_id], MESSAGE_VAL);
}
 
static unsigned long mcomm_mpc85xx_cpuid(void)
{
	return mfspr(SPRN_PIR);
}
 
static void mcomm_mpc85xx_ack(void)
{
	fsl_clear_msg(mcomm_mpc85xx_data.notifications[mcomm_mpc85xx_cpuid()]);
}
 
static struct mcomm_platform_ops mcomm_mpc85xx_ops = {
	.mmap_pgprot = mcomm_mpc85xx_mmap_pgprot,
	.map = mcomm_mpc85xx_ioremap,
	.notify = mcomm_mpc85xx_notify,
	.ack = mcomm_mpc85xx_ack,
	.cpuid = mcomm_mpc85xx_cpuid,
};
 
static void mcomm_mpc85xx_hwuninit(void)
{
	int i;
 
	for (i = 0; i < mcomm_mpc85xx_data.nr_notifications; i++) {
		/* XXX leaves MER enabled? */
		fsl_release_msg_unit(mcomm_mpc85xx_data.notifications[i]);
	}
}
 
static int mcomm_mpc85xx_hwinit(const struct notification notifications[],
                                 int nr_notifications)
{
	struct mcomm_mpc85xx_data *data = &mcomm_mpc85xx_data;
	unsigned int cur_cpu = mcomm_mpc85xx_cpuid();
	struct fsl_msg_unit *self;
	int i;
 
	for (i = 0; i < nr_notifications; i++) {
		u32 core_id = notifications[i].core_id;
		u32 msg_num = notifications[i].msg_num;
		struct fsl_msg_unit *msgunit;
 
		msgunit = fsl_request_msg(msg_num);
		BUG_ON(IS_ERR(msgunit));
		data->notifications[core_id] = msgunit;
	}
 
	self = data->notifications[cur_cpu];
 
	/* Set our MIDR and enable ourselves in in MER. */
	fsl_set_msg_dest(self, cur_cpu);
	fsl_enable_msg(self);
 
	return self->irq;
}
 
static int mcomm_mpc85xx_remove(struct of_device *odev)
{
	struct mcomm_mpc85xx_data *data = &mcomm_mpc85xx_data;
 
	mcomm_remove_region(&odev->dev);
 
	mcomm_mpc85xx_hwuninit();
 
	kfree(data->notifications);
 
	return 0;
}
 
static int mcomm_mpc85xx_probe(struct of_device *odev,
                               const struct of_device_id *match)
{
	struct resource mem;
	struct resource irq;
	struct mcomm_mpc85xx_data *data = &mcomm_mpc85xx_data;
	const u32 *prop;
	int len;
	int rc;
	static int initialized;
 
	if (initialized++)
		return -EEXIST;
 
	rc = of_address_to_resource(odev->node, 0, &mem);
	if (rc < 0) {
		dev_err(&odev->dev, "invalid address\n");
		rc = -EINVAL;
		goto out1;
	}
 
	prop = of_get_property(odev->node, "notifications", &len);
	if (!prop) {
		dev_err(&odev->dev, "no message index\n");
		rc = -EINVAL;
		goto out1;
	}
	data->nr_notifications = len / sizeof(u32) / 2;
	data->notifications =
	            kmalloc(sizeof(data->notifications[0]) * data->nr_notifications,
	            GFP_KERNEL);
	if (!data->notifications) {
		rc = -ENOMEM;
		goto out1;
	}
 
	irq.start = mcomm_mpc85xx_hwinit((struct notification *)prop,
	                                  data->nr_notifications);
 
	rc = mcomm_new_region(&odev->dev, &mem, &irq);
	/* XXX check error path */
	if (rc)
		goto out2;
 
	return 0;
 
out2:
	mcomm_mpc85xx_remove(odev);
out1:
	return rc;
}
 
 
static const struct of_device_id mcomm_match_table[] = {
	{ .compatible	= "ment,mcomm", },
	{}
};
 
static struct of_platform_driver mcomm_of_driver = {
	.name = "mcomm",
	.match_table = mcomm_match_table,
 
	.probe = mcomm_mpc85xx_probe,
	.remove = mcomm_mpc85xx_remove,
};
 
/* Because our node isn't under the localbus or soc nodes, platform code won't
 * automatically create an of_device for it, so we have to do it ourselves. */
static void mcomm_mpc85xx_devices_find(void)
{
	struct device_node *node = NULL;
	int i = 0;
 
	for (node = NULL;
		 (node = of_find_compatible_node(node, NULL, "ment,mcomm")) != NULL;) {
		char bus_id[32];
		sprintf(bus_id, "%s.%d", node->name, i++);
		of_platform_device_create(node, bus_id, NULL);
	}
}
 
static void mcomm_mpc85xx_devices_remove(void)
{
	struct device_node *node = NULL;
 
	for (node = NULL;
		 (node = of_find_compatible_node(node, NULL, "ment,mcomm")) != NULL;) {
		struct of_device *odev = of_find_device_by_node(node);
 
		if (odev)
			of_device_unregister(odev);
	}
}
 
static int __init mcomm_mpc85xx_modinit(void)
{
	int rc;
 
	rc = mcomm_init(&mcomm_mpc85xx_ops, THIS_MODULE);
	if (rc) {
		printk(KERN_ERR "%s: mcomm_init failed\n", __func__);
		goto out1;
	}
 
	rc = of_register_platform_driver(&mcomm_of_driver);
	if (rc) {
		printk(KERN_ERR "%s: failed to register platform driver\n", __func__);
		goto out2;
	}
 
	mcomm_mpc85xx_devices_find();
 
	return 0;
 
out2:
	mcomm_exit();
out1:
	return rc;
}
module_init(mcomm_mpc85xx_modinit);
 
static void mcomm_mpc85xx_modexit(void)
{
	mcomm_mpc85xx_devices_remove();
	mcomm_exit();
	return of_unregister_platform_driver(&mcomm_of_driver);
}
module_exit(mcomm_mpc85xx_modexit);
 
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Hollis Blanchard <hollis_blanchard@mentor.com>");
MODULE_DESCRIPTION("Shared memory platform support for multi-core e500 processors using MPIC");
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.