LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* RE: PCIE Hotplug on P2010(mpc85xx) ?
From: Joakim Tjernlund @ 2012-07-20  9:57 UTC (permalink / raw)
  To: Zang Roy-R61911; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <3E027F8168735B46AC006B1D0C7BB002079C3332@039-SN2MPN1-013.039d.mgd.msft.net>

Zang Roy-R61911 <r61911@freescale.com> wrote on 2012/07/20 11:31:31:
>
>
> > -----Original Message-----
> > From: Joakim Tjernlund [mailto:joakim.tjernlund@transmode.se]
> > Sent: Friday, July 20, 2012 16:36 PM
> > To: Zang Roy-R61911
> > Cc: linuxppc-dev@ozlabs.org
> > Subject: RE: PCIE Hotplug on P2010(mpc85xx) ?
> >
> > Zang Roy-R61911 <r61911@freescale.com> wrote on 2012/07/20 10:15:46:
> > >
> > > I do not think P2010 has a functional pciehp module in the pcie
> > controller.
> > > Roy
> >
> > Maybe there is, see my latest mail to the list (today) titled:
> > mpc8xxx PCIe hotplug needs fixing, some clues
> No. if you check the hotplug register in configuration space in
> P2010, which missrd some important bit define for hotplug, for example,
> "Data Link Layer State Changed" in slot status register.

Too bad, but one might be able to use something else, just guessing though.
However, performing a manual rescan should do the trick.

Perhaps you could comment on the "mpc8xxx PCIe hotplug needs fixing, some clues" mail too?

> And more, hotplug needs extra hardware pin in the silicon, which is missing for P2010.

Ohh, what is the name of this pin?

 Jocke

^ permalink raw reply

* [PATCH][upstream] TDM Framework
From: sandeep @ 2012-07-20 12:35 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Sandeep Singh, Poonam Aggrwal

From: Sandeep Singh <Sandeep@freescale.com>

TDM Framework is an attempt to provide a platform independent layer which can
offer a standard interface  for TDM access to different client modules.
Beneath, the framework layer can house different types of TDM drivers to handle
various TDM devices, the hardware intricacies of the devices being completely
taken care by TDM drivers.
This framework layer will allow any type of TDM device to hook with it.
For example Freescale controller as on MPC8315, UCC based TDM controller, etc

The main functions of this Framework are:
 - provides interface to TDM clients to access TDM functionalities.
 - provides standard interface for TDM drivers to hook with the framework.
 - handles various data handling stuff and buffer management.

In future this Framework will be extended to provide Interface for Line control devices also. For example SLIC, E1/T1 Framers etc.

Presently the framework supports only Single Port channelised mode.
Also the configurability options are limited which will be extended later on.
Only kernel mode TDM clients are supported currently. Support for User mode clients will be added later.

Signed-off-by: Sandeep Singh <Sandeep@freescale.com>
Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
---

Based on: git://git.am.freescale.net/gitolite/mirrors/galak-powerpc.git
Branch: master
Checkpatch: passed

First patch version was RFC.

Changes since RFC:
	- Since all read/write operations are in TDM are channel based, polling
	on TDM channel for data instead of TDM port before going for read/write.
	- Also corrected a faulty error leg
	- Removed unused function tdm_port_get_wait_queue.

	Incorporated Scott's comments:
	- Removed TDM_CORE_DEBUG.
	- Added sysfs knob to change use_latest_tdm_data at runtime.
	- Works more silently now (lesser prints).
	- Cosmetic errors rectified.
	- Removed unused function tdm_init.
	- Removed unused variables.
	- Removed unnecessary typecast and NULL check.
	- Removed #include "device/tdm_fsl.h".

	Incorporated Timur's comments:
	- Handled errors.
	- Used dev_err instead of pr_err
	- Removed extern from function declaration.



 drivers/Kconfig                 |    1 +
 drivers/Makefile                |    1 +
 drivers/tdm/Kconfig             |   18 +
 drivers/tdm/Makefile            |    5 +
 drivers/tdm/tdm-core.c          | 1082 +++++++++++++++++++++++++++++++++++++++
 include/linux/mod_devicetable.h |   11 +
 include/linux/tdm.h             |  338 ++++++++++++
 7 files changed, 1456 insertions(+), 0 deletions(-)
 create mode 100644 drivers/tdm/Kconfig
 create mode 100644 drivers/tdm/Makefile
 create mode 100644 drivers/tdm/tdm-core.c
 create mode 100644 include/linux/tdm.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 5afe5d1..abd6c83 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -136,4 +136,5 @@ source "drivers/virt/Kconfig"
 
 source "drivers/devfreq/Kconfig"
 
+source "drivers/tdm/Kconfig"
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 1b31421..7cb88e3 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -104,6 +104,7 @@ obj-$(CONFIG_INFINIBAND)	+= infiniband/
 obj-$(CONFIG_SGI_SN)		+= sn/
 obj-y				+= firmware/
 obj-$(CONFIG_CRYPTO)		+= crypto/
+obj-$(CONFIG_TDM)		+= tdm/
 obj-$(CONFIG_SUPERH)		+= sh/
 obj-$(CONFIG_ARCH_SHMOBILE)	+= sh/
 ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
diff --git a/drivers/tdm/Kconfig b/drivers/tdm/Kconfig
new file mode 100644
index 0000000..0b0fda8
--- /dev/null
+++ b/drivers/tdm/Kconfig
@@ -0,0 +1,18 @@
+#
+# TDM subsystem configuration
+#
+
+menuconfig TDM
+	tristate "TDM support"
+	---help---
+	  More information is contained in the directory <file:Documentation/tdm/>,
+	  especially in the file called "summary" there.
+	  If you want TDM support, you should say Y here and also to the
+	  specific driver for your bus adapter(s) below.
+
+	  This TDM support can also be built as a module.  If so, the module
+	  will be called tdm-core.
+
+if TDM
+
+endif # TDM
diff --git a/drivers/tdm/Makefile b/drivers/tdm/Makefile
new file mode 100644
index 0000000..84e2cb9
--- /dev/null
+++ b/drivers/tdm/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the TDM core.
+#
+
+obj-$(CONFIG_TDM)		+= tdm-core.o
diff --git a/drivers/tdm/tdm-core.c b/drivers/tdm/tdm-core.c
new file mode 100644
index 0000000..9973b6b
--- /dev/null
+++ b/drivers/tdm/tdm-core.c
@@ -0,0 +1,1082 @@
+/* driver/tdm/tdm-core.c
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc, All rights reserved.
+ *
+ * TDM core is the interface between TDM clients and TDM devices.
+ * It is also intended to serve as an interface for line controlled
+ * devices later on.
+ *
+ * Author:Hemant Agrawal <hemant@freescale.com>
+ *	Rajesh Gumasta <rajesh.gumasta@freescale.com>
+ *
+ * Modified by Sandeep Kr Singh <sandeep@freescale.com>
+ *		Poonam Aggarwal <poonam.aggarwal@freescale.com>
+ * 1. Added framework based initialization of device.
+ * 2. All the init/run time configuration is now done by framework.
+ * 3. Added channel level operations.
+ * 4. Added sysfs knob to configure use_latest_tdm_data at runtime.
+ *
+ * Note that some parts of this code may have been derived from i2c subsystem.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/tdm.h>
+#include <linux/init.h>
+#include <linux/idr.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/hardirq.h>
+#include <linux/irqflags.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+
+static DEFINE_MUTEX(tdm_core_lock);
+static DEFINE_IDR(tdm_adapter_idr);
+/* List of TDM adapters registered with TDM framework */
+LIST_HEAD(adapter_list);
+
+/* List of TDM clients registered with TDM framework */
+LIST_HEAD(driver_list);
+
+/* In case the previous data is not fetched by the client driver, the
+ * de-interleaving function will  discard the old data and rewrite the
+ * new data */
+static int use_latest_tdm_data = 1;
+
+/* Data structures required for sysfs */
+static struct tdm_sysfs attr = {
+	.attr.name = "use_latest_data",
+	.attr.mode = 0664,
+	.cmd_type = TDM_LATEST_DATA,
+};
+
+static struct attribute *tdm_attr[] = {
+	&attr.attr,
+	NULL
+};
+
+const struct sysfs_ops tdm_ops = {
+	.show = tdm_show_sysfs,
+	.store = tdm_store_sysfs,
+};
+
+static struct kobj_type tdm_type = {
+	.sysfs_ops = &tdm_ops,
+	.default_attrs = tdm_attr,
+};
+
+/* tries to match client driver with the adapter */
+static int tdm_device_match(struct tdm_driver *driver, struct tdm_adapter *adap)
+{
+	/* match on an id table if there is one */
+	if (driver->id_table && driver->id_table->name[0]) {
+		if (!(strcmp(driver->id_table->name, adap->name)))
+			return (int)driver->id_table;
+	}
+	return TDM_E_OK;
+}
+
+static int tdm_attach_driver_adap(struct tdm_driver *driver,
+		struct tdm_adapter *adap)
+{
+	int ret = TDM_E_OK;
+	/* if driver is already attached to any other adapter, return*/
+	if (driver->adapter && (driver->adapter != adap))
+		return ret;
+
+	driver->adapter = adap;
+
+	if (driver->attach_adapter) {
+		ret = driver->attach_adapter(adap);
+		if (ret < 0) {
+			pr_err("attach_adapter failed for driver [%s] err:%d\n"
+					, driver->name, ret);
+			return ret;
+		}
+	}
+	adap->drv_count++;
+
+	if (!adap->tasklet_conf) {
+		tdm_sysfs_init();
+		tasklet_init(&adap->tdm_data_tasklet, tdm_data_tasklet_fn,
+				(unsigned long)adap);
+		adap->tasklet_conf = 1;
+	}
+
+	return ret;
+}
+
+/* Detach client driver and adapter */
+static int tdm_detach_driver_adap(struct tdm_driver *driver,
+		struct tdm_adapter *adap)
+{
+	int res = TDM_E_OK;
+
+	if (!driver->adapter || (driver->adapter != adap))
+		return TDM_E_OK;
+
+	adap->drv_count--;
+
+	/* If no more driver is registed with the adapter*/
+	if (!adap->drv_count && adap->tasklet_conf) {
+		tasklet_disable(&adap->tdm_data_tasklet);
+		tasklet_kill(&adap->tdm_data_tasklet);
+		adap->tasklet_conf = 0;
+	}
+
+	if (driver->detach_adapter) {
+		if (driver->detach_adapter(adap))
+			pr_err("detach_adapter failed for driver [%s]\n",
+					driver->name);
+	}
+
+	driver->adapter = NULL;
+	return res;
+}
+
+/* TDM adapter Registration/De-registration with TDM framework */
+
+static int tdm_register_adapter(struct tdm_adapter *adap)
+{
+	int res = TDM_E_OK;
+	struct tdm_driver *driver, *next;
+
+	mutex_init(&adap->adap_lock);
+	INIT_LIST_HEAD(&adap->myports);
+	spin_lock_init(&adap->portlist_lock);
+
+	adap->drv_count = 0;
+	adap->tasklet_conf = 0;
+
+	list_add_tail(&adap->list, &adapter_list);
+
+	/* initialization of driver by framework in default configuration */
+	init_config_adapter(adap);
+
+	/* Notify drivers */
+	pr_info("adapter [%s] registered\n", adap->name);
+	mutex_lock(&tdm_core_lock);
+	list_for_each_entry_safe(driver, next, &driver_list, list) {
+		if (tdm_device_match(driver, adap)) {
+			res = tdm_attach_driver_adap(driver, adap);
+			if (res == TDM_E_OK) {
+				pr_info("Driver(ID=%d) is "
+						"attached with Adapter %s(ID"
+						" = %d)\n", driver->id,
+						adap->name, adap->id);
+			} else {
+				pr_err("Driver(ID=%d) is unable "
+						"to attach with Adapter %s(ID = %d)\n",
+						driver->id, adap->name,
+						adap->id);
+			}
+		}
+	}
+	mutex_unlock(&tdm_core_lock);
+
+	return res;
+}
+
+/*
+ * tdm_add_adapter - declare tdm adapter, use dynamic device number
+ * @adapter: the adapter to add
+ * Context: can sleep
+ *
+ * This routine is used to declare a TDM adapter
+ * When this returns zero, a new device number will be allocated and stored
+ * in adap->id, and the specified adapter became available for the clients.
+ * Otherwise, a negative errno value is returned.
+ */
+int tdm_add_adapter(struct tdm_adapter *adapter)
+{
+	int id, res = TDM_E_OK;
+
+retry:
+	if (idr_pre_get(&tdm_adapter_idr, GFP_KERNEL) == 0)
+		return -ENOMEM;
+
+	mutex_lock(&tdm_core_lock);
+	res = idr_get_new(&tdm_adapter_idr, adapter, &id);
+	mutex_unlock(&tdm_core_lock);
+
+	if (res < 0) {
+		if (res == -EAGAIN)
+			goto retry;
+		return res;
+	}
+
+	adapter->id = id;
+	return tdm_register_adapter(adapter);
+}
+EXPORT_SYMBOL(tdm_add_adapter);
+
+
+/**
+ * tdm_del_adapter - unregister TDM adapter
+ * @adap: the adapter being unregistered
+ *
+ * This unregisters an TDM adapter which was previously registered
+ * by @tdm_add_adapter.
+ */
+int tdm_del_adapter(struct tdm_adapter *adap)
+{
+	int res = TDM_E_OK;
+	struct tdm_adapter *found;
+	struct tdm_driver *driver, *next;
+
+	/* First make sure that this adapter was ever added */
+	mutex_lock(&tdm_core_lock);
+	found = idr_find(&tdm_adapter_idr, adap->id);
+	mutex_unlock(&tdm_core_lock);
+	if (found != adap) {
+		pr_err("tdm-core: attempting to delete unregistered "
+				"adapter [%s]\n", adap->name);
+		return -EINVAL;
+	}
+
+	/*disable and kill the data processing tasklet */
+	if (adap->tasklet_conf) {
+		tasklet_disable(&adap->tdm_data_tasklet);
+		tasklet_kill(&adap->tdm_data_tasklet);
+		adap->tasklet_conf = 0;
+	}
+
+	/* Detach any active ports. This can't fail, thus we do not
+	   checking the returned value. */
+	mutex_lock(&tdm_core_lock);
+	list_for_each_entry_safe(driver, next, &driver_list, list) {
+		if (tdm_device_match(driver, adap)) {
+			tdm_detach_driver_adap(driver, adap);
+			pr_info(
+					"Driver(ID=%d) is detached from Adapter %s(ID = %d)\n",
+					driver->id, adap->name, adap->id);
+		}
+	}
+	idr_remove(&tdm_adapter_idr, adap->id);
+	mutex_unlock(&tdm_core_lock);
+
+	pr_debug("adapter [%s] unregistered\n", adap->name);
+
+	list_del(&adap->list);
+	/* Clear the device structure in case this adapter is ever going to be
+	   added again */
+	adap->parent = NULL;
+
+	return res;
+}
+EXPORT_SYMBOL(tdm_del_adapter);
+
+/* TDM Client Drivers Registration/De-registration Functions */
+int tdm_register_driver(struct tdm_driver *driver)
+{
+	int res = TDM_E_OK;
+	struct tdm_adapter *adap, *next;
+
+	list_add_tail(&driver->list, &driver_list);
+
+	mutex_lock(&tdm_core_lock);
+	/* Walk the adapters that are already present */
+	list_for_each_entry_safe(adap, next, &adapter_list, list) {
+		if (tdm_device_match(driver, adap)) {
+			res = tdm_attach_driver_adap(driver, adap);
+			if (res == TDM_E_OK) {
+				pr_info("TDM Driver(ID=%d)is attached with "
+						"Adapter%s(ID = %d) drv_count=%d",
+						driver->id, adap->name,
+						adap->id, adap->drv_count);
+			} else {
+				pr_err("TDM Driver(ID=%d) unable to attach "
+						"to Adapter%s(ID = %d) drv_count=%d",
+						driver->id, adap->name,
+						adap->id, adap->drv_count);
+			}
+			break;
+		}
+	}
+	mutex_unlock(&tdm_core_lock);
+
+	return res;
+}
+EXPORT_SYMBOL(tdm_register_driver);
+
+/*
+ * tdm_unregister_driver - unregister TDM client driver from TDM framework
+ * @driver: the driver being unregistered
+ */
+void tdm_unregister_driver(struct tdm_driver *driver)
+{
+	/* A driver can register to only one adapter,
+	 * so no need to browse the list */
+	mutex_lock(&tdm_core_lock);
+	tdm_detach_driver_adap(driver, driver->adapter);
+	mutex_unlock(&tdm_core_lock);
+
+	list_del(&driver->list);
+
+	pr_debug("tdm-core: driver [%s] unregistered\n", driver->name);
+}
+EXPORT_SYMBOL(tdm_unregister_driver);
+
+/* Interface to the tdm device/adapter */
+
+/* tdm_adap_send - issue a TDM write
+ * @adap: Handle to TDM device
+ * @buf: Data that will be written to the TDM device
+ * @count: How many bytes to write
+ *
+ * Returns negative errno, or else the number of bytes written.
+ */
+int tdm_adap_send(struct tdm_adapter *adap, void **buf, int count)
+{
+	int res;
+
+	if (adap->algo->tdm_write)
+		res = adap->algo->tdm_write(adap, buf, count);
+	else {
+		pr_err("TDM level write not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	/* If everything went ok (i.e. frame transmitted), return #bytes
+	   transmitted, else error code. */
+	return (res == 1) ? count : res;
+}
+EXPORT_SYMBOL(tdm_adap_send);
+
+/**
+ * tdm_adap_recv - issue a TDM read
+ * @adap: Handle to TDM device
+ * @buf: Where to store data read from TDM device
+ *
+ * Returns negative errno, or else the number of bytes read.
+ */
+int tdm_adap_recv(struct tdm_adapter *adap, void **buf)
+{
+	int res;
+
+	if (adap->algo->tdm_read)
+		res = adap->algo->tdm_read(adap, (u16 **)buf);
+	else {
+		pr_err("TDM level read not supported\n");
+		return -EOPNOTSUPP;
+	}
+	/* If everything went ok (i.e. frame received), return #bytes
+	   transmitted, else error code. */
+	return res;
+}
+
+/**
+ * tdm_adap_get_write_buf - get next write TDM device buffer
+ * @adap: Handle to TDM device
+ * @buf: pointer to TDM device buffer
+ *
+ * Returns negative errno, or else size of the write buffer.
+ */
+int tdm_adap_get_write_buf(struct tdm_adapter *adap, void **buf)
+{
+	int res;
+
+	if (adap->algo->tdm_get_write_buf) {
+		res = adap->algo->tdm_get_write_buf(adap, (u16 **)buf);
+	} else {
+		pr_err("TDM level write buf get not supported\n");
+		return -EOPNOTSUPP;
+	}
+	/* If everything went ok (i.e. 1 msg received), return #bytes
+	   transmitted, else error code. */
+	return res;
+}
+EXPORT_SYMBOL(tdm_adap_get_write_buf);
+
+int tdm_adap_enable(struct tdm_driver *drv)
+{
+	int res;
+	struct tdm_adapter *adap;
+	adap = drv->adapter;
+
+	if (adap->algo->tdm_enable) {
+		res = adap->algo->tdm_enable(adap);
+	} else {
+		pr_err("TDM level enable not supported\n");
+		return -EOPNOTSUPP;
+	}
+	return res;
+}
+EXPORT_SYMBOL(tdm_adap_enable);
+
+int tdm_adap_disable(struct tdm_driver *drv)
+{
+	int res;
+	struct tdm_adapter *adap;
+	adap = drv->adapter;
+
+	if (adap->algo->tdm_disable) {
+		res = adap->algo->tdm_disable(adap);
+	} else {
+		pr_err("TDM level enable not supported\n");
+		return -EOPNOTSUPP;
+	}
+	return res;
+}
+EXPORT_SYMBOL(tdm_adap_disable);
+
+struct tdm_adapter *tdm_get_adapter(int id)
+{
+	struct tdm_adapter *adapter;
+
+	mutex_lock(&tdm_core_lock);
+	adapter = idr_find(&tdm_adapter_idr, id);
+	if (adapter && !try_module_get(adapter->owner))
+		adapter = NULL;
+
+	mutex_unlock(&tdm_core_lock);
+
+	return adapter;
+}
+EXPORT_SYMBOL(tdm_get_adapter);
+
+void tdm_put_adapter(struct tdm_adapter *adap)
+{
+	module_put(adap->owner);
+}
+EXPORT_SYMBOL(tdm_put_adapter);
+
+
+/* Port Level APIs of TDM Framework */
+int tdm_port_open(struct tdm_driver *driver, struct tdm_port **h_port)
+{
+	struct tdm_port *port;
+	struct tdm_adapter *adap;
+	unsigned long		flags;
+	int res = TDM_E_OK;
+
+	adap = tdm_get_adapter(driver->adapter->id);
+	if (!adap)
+		return -ENODEV;
+
+	/* This creates an anonymous tdm_port, which may later be
+	 * pointed to some slot.
+	 *
+	 */
+	port = kzalloc(sizeof(*port), GFP_KERNEL);
+	if (!port) {
+		res = -ENOMEM;
+		goto out;
+	}
+
+	port->rx_max_frames = NUM_SAMPLES_PER_FRAME;
+	port->port_cfg.port_mode = TDM_PORT_CHANNELIZED;
+
+	snprintf(driver->name, TDM_NAME_SIZE, "tdm-dev");
+	port->driver = driver;
+	port->adapter = adap;
+
+	spin_lock_irqsave(&adap->portlist_lock, flags);
+	list_add_tail(&port->list, &adap->myports);
+	spin_unlock_irqrestore(&adap->portlist_lock, flags);
+
+	INIT_LIST_HEAD(&port->mychannels);
+
+	*h_port = port;
+
+out:
+	return res;
+}
+EXPORT_SYMBOL(tdm_port_open);
+
+int tdm_port_close(struct tdm_port *h_port)
+{
+	struct tdm_adapter *adap;
+	struct tdm_driver *driver;
+	struct tdm_port *port;
+	struct tdm_channel *temp, *channel;
+	unsigned long flags;
+	int res = TDM_E_OK;
+	port = h_port;
+
+	driver =  port->driver;
+
+	list_for_each_entry_safe(channel, temp, &port->mychannels, list) {
+		if (channel)
+			if (channel->in_use) {
+				pr_err("%s:Cannot close port. Channel in use\n",
+						__func__);
+				res = -ENXIO;
+				goto out;
+			}
+	}
+	adap = driver->adapter;
+
+	spin_lock_irqsave(&adap->portlist_lock, flags);
+	list_del(&port->list);
+	spin_unlock_irqrestore(&adap->portlist_lock, flags);
+
+	if (port->p_port_data != NULL) {
+		int i;
+		struct tdm_bd *ch_bd;
+
+		/* If the tdm is in channelised mode,
+		   de-allocate the channelised buffer */
+		ch_bd = &(port->p_port_data->rx_data_fifo[0]);
+		for (i = 0; ch_bd && i < TDM_CH_RX_BD_RING_SIZE; i++) {
+			ch_bd->flag = 0;
+			ch_bd++;
+		}
+		ch_bd = &(port->p_port_data->tx_data_fifo[0]);
+		for (i = 0; ch_bd && i < TDM_CH_TX_BD_RING_SIZE; i++) {
+			ch_bd->flag = 0;
+			ch_bd++;
+		}
+		kfree(port->p_port_data);
+	}
+	kfree(port);
+	return res;
+out:
+	if (port)
+		kfree(port->p_port_data);
+	kfree(port);
+	return res;
+}
+EXPORT_SYMBOL(tdm_port_close);
+
+int tdm_channel_read(struct tdm_port *h_port, struct tdm_channel *h_channel,
+		void *p_data, u16 *size)
+{
+	struct tdm_channel *channel;
+	struct tdm_bd *rx_bd;
+	unsigned long flags;
+	int i, res = TDM_E_OK;
+	unsigned short *buf, *buf1;
+	channel = h_channel;
+
+	if (!channel->p_ch_data || !channel->in_use)
+		return -EIO;
+
+	spin_lock_irqsave(&channel->p_ch_data->rx_channel_lock, flags);
+	rx_bd = channel->p_ch_data->rx_out_data;
+
+	if (rx_bd->flag) {
+		*size = rx_bd->length;
+		buf = (u16 *) p_data;
+		buf1 = (u16 *)rx_bd->p_data;
+		for (i = 0; i < NUM_SAMPLES_PER_FRAME; i++)
+			buf[i] = buf1[i];
+		rx_bd->flag = 0;
+		rx_bd->offset = 0;
+		channel->p_ch_data->rx_out_data = (rx_bd->wrap) ?
+			channel->p_ch_data->rx_data_fifo : rx_bd + 1;
+
+	} else {
+		spin_unlock_irqrestore(&channel->p_ch_data->rx_channel_lock,
+				flags);
+		pr_debug("No Data Available");
+		return -EAGAIN;
+	}
+	spin_unlock_irqrestore(&channel->p_ch_data->rx_channel_lock, flags);
+
+	return res;
+}
+EXPORT_SYMBOL(tdm_channel_read);
+
+
+int tdm_channel_write(struct tdm_port *h_port, struct tdm_channel *h_channel,
+		void *p_data, u16 size)
+{
+	struct tdm_port *port;
+	struct tdm_channel *channel;
+	struct tdm_bd *tx_bd;
+	unsigned long flags;
+	int err = TDM_E_OK;
+	port = h_port;
+	channel = h_channel;
+#ifdef DEBUG
+	bool data_flag = 0;
+#endif
+
+	if (p_data == NULL) { /* invalid data*/
+		pr_err("Invalid Data");
+		return -EFAULT;
+	}
+
+	if (!channel->p_ch_data || !channel->in_use)
+		return -EIO;
+
+	spin_lock_irqsave(&channel->p_ch_data->tx_channel_lock, flags);
+	tx_bd = channel->p_ch_data->tx_in_data;
+
+	if (!tx_bd->flag) {
+		tx_bd->length = size;
+		memcpy(tx_bd->p_data, p_data,
+				size * port->adapter->adapt_cfg.slot_width);
+		tx_bd->flag = 1;
+		tx_bd->offset = 0;
+		channel->p_ch_data->tx_in_data = (tx_bd->wrap) ?
+			channel->p_ch_data->tx_data_fifo : tx_bd+1;
+		port->port_stat.tx_pkt_count++;
+#ifdef DEBUG
+		data_flag = 1;
+#endif
+	} else {
+		spin_unlock_irqrestore(&channel->p_ch_data->tx_channel_lock,
+				flags);
+		port->port_stat.tx_pkt_drop_count++;
+		pr_err("E_NO_MEMORY -Failed Transmit");
+		return -ENOMEM;
+	}
+	spin_unlock_irqrestore(&channel->p_ch_data->tx_channel_lock, flags);
+
+#ifdef	DEBUG
+	if (data_flag) {
+		int k;
+		pr_info("\nTX port:%d - Write - Port TX-%d\n",
+				port->port_id, size);
+		for (k = 0; k < size; k++)
+			pr_info("%x", p_data[k]);
+		pr_info("\n");
+	}
+#endif
+	return err;
+}
+EXPORT_SYMBOL(tdm_channel_write);
+
+/* Driver Function for select and poll. Based on Channel, it sleeps on
+ * waitqueue */
+int tdm_ch_poll(struct tdm_channel *h_channel, unsigned int wait_time)
+{
+	struct tdm_channel *channel;
+	unsigned long timeout = msecs_to_jiffies(wait_time);
+	channel = h_channel;
+
+	if (!channel->p_ch_data || !channel->in_use)
+		return -EIO;
+
+	if (channel->p_ch_data->rx_out_data->flag) {
+		pr_debug("Data Available");
+		return TDM_E_OK;
+	}
+	if (timeout) {
+		wait_event_interruptible_timeout(channel->ch_wait_queue,
+				channel->p_ch_data->rx_out_data->flag,
+				timeout);
+
+		if (channel->p_ch_data->rx_out_data->flag) {
+			pr_debug("Data Available");
+			return TDM_E_OK;
+		}
+	}
+	return -EAGAIN;
+}
+EXPORT_SYMBOL(tdm_ch_poll);
+
+unsigned int tdm_port_get_stats(struct tdm_port *h_port,
+		struct tdm_port_stats *portStat)
+{
+	struct tdm_port *port;
+	int port_num;
+	port = h_port;
+
+	if (port == NULL || portStat == NULL) { /* invalid handle*/
+		pr_err("Invalid Handle");
+		return -ENXIO;
+	}
+	port_num =  port->port_id;
+
+	memcpy(portStat, &port->port_stat, sizeof(struct tdm_port_stats));
+
+	pr_info("TDM Port %d Get Stats", port_num);
+
+	return TDM_E_OK;
+}
+EXPORT_SYMBOL(tdm_port_get_stats);
+
+/* Data handling functions */
+
+static int tdm_data_rx_deinterleave(struct tdm_adapter *adap)
+{
+	struct tdm_port *port, *next;
+	struct tdm_channel *channel, *temp;
+	struct tdm_bd	*ch_bd;
+
+	int i, buf_size, ch_data_len;
+	u16 *input_tdm_buffer;
+	u16 *pcm_buffer;
+	int slot_width;
+	int frame_ch_data_size;
+	bool ch_data;
+	int bytes_in_fifo_per_frame;
+	int bytes_slot_offset;
+
+	ch_data_len = NUM_SAMPLES_PER_FRAME;
+	frame_ch_data_size = NUM_SAMPLES_PER_FRAME;
+	ch_data = 0;
+
+	slot_width = adap->adapt_cfg.slot_width;
+	buf_size = tdm_adap_recv(adap, (void **)&input_tdm_buffer);
+	if (buf_size <= 0 || !input_tdm_buffer)
+		return -EINVAL;
+
+	bytes_in_fifo_per_frame = buf_size/frame_ch_data_size;
+	bytes_slot_offset = bytes_in_fifo_per_frame/slot_width;
+
+	/* de-interleaving for all ports*/
+	list_for_each_entry_safe(port, next, &adap->myports, list) {
+
+		list_for_each_entry_safe(channel, temp, &port->mychannels,
+				list) {
+			/* if the channel is not open */
+			if (!channel->in_use || !channel->p_ch_data)
+				continue;
+			ch_bd = channel->p_ch_data->rx_in_data;
+			spin_lock(&channel->p_ch_data->rx_channel_lock);
+			/*if old data is to be discarded */
+			if (use_latest_tdm_data && ch_bd->flag) {
+				ch_bd->flag = 0;
+				ch_bd->offset = 0;
+				if (ch_bd == channel->p_ch_data->rx_out_data)
+					channel->p_ch_data->rx_out_data =
+						ch_bd->wrap ?
+						channel->p_ch_data->rx_data_fifo
+						: ch_bd+1;
+				port->port_stat.rx_pkt_drop_count++;
+			}
+			/* if the bd is empty */
+			if (!ch_bd->flag) {
+				if (ch_bd->offset == 0)
+					ch_bd->length = port->rx_max_frames;
+
+				pcm_buffer = ch_bd->p_data + ch_bd->offset;
+				/* De-interleaving the data */
+				for (i = 0; i < ch_data_len; i++) {
+					pcm_buffer[i]
+						= input_tdm_buffer[i*
+						bytes_slot_offset +
+						channel->ch_id];
+				}
+				ch_bd->offset += ch_data_len * slot_width;
+
+				if (ch_bd->offset >=
+						(ch_bd->length -
+						frame_ch_data_size)*
+						(adap->adapt_cfg.slot_width)) {
+					ch_bd->flag = 1;
+					ch_bd->offset = 0;
+					channel->p_ch_data->rx_in_data =
+						ch_bd->wrap ?
+						channel->p_ch_data->rx_data_fifo
+						: ch_bd+1;
+					ch_data = 1;
+					wake_up_interruptible
+						(&channel->ch_wait_queue);
+				}
+			} else {
+				port->port_stat.rx_pkt_drop_count++;
+			}
+			spin_unlock(&channel->p_ch_data->rx_channel_lock);
+		}
+
+		if (ch_data) {
+			/*	Wake up the Port Data Poll event */
+#ifdef	DEBUG
+			pr_info("Port RX-%d-%d\n", channel->ch_id, ch_data_len);
+			for (i = 0; i < ch_data_len; i++)
+				pr_info("%x", pcm_buffer[i]);
+			pr_info("\n");
+#endif
+			port->port_stat.rx_pkt_count++;
+			ch_data = 0;
+		}
+	}
+	return TDM_E_OK;
+}
+
+static int tdm_data_tx_interleave(struct tdm_adapter *adap)
+{
+	struct tdm_port *port, *next;
+	struct tdm_channel *channel, *temp;
+	struct tdm_bd	*ch_bd;
+	int i, buf_size, ch_data_len = NUM_SAMPLES_PER_FRAME;
+	bool last_data = 0;
+	u16 *output_tdm_buffer;
+	u16 *pcm_buffer;
+	int frame_ch_data_size = NUM_SAMPLES_PER_FRAME;
+	int bytes_in_fifo_per_frame;
+	int bytes_slot_offset;
+
+#ifdef DEBUG
+	u8	data_flag = 0;
+#endif
+
+	buf_size = tdm_adap_get_write_buf(adap, (void **)&output_tdm_buffer);
+	if (buf_size <= 0 || !output_tdm_buffer)
+		return -EINVAL;
+
+	bytes_in_fifo_per_frame = buf_size/frame_ch_data_size;
+	bytes_slot_offset = bytes_in_fifo_per_frame/adap->adapt_cfg.slot_width;
+
+
+	memset(output_tdm_buffer, 0, sizeof(buf_size));
+
+	list_for_each_entry_safe(port, next, &adap->myports, list) {
+
+		list_for_each_entry_safe(channel, temp, &port->mychannels,
+				list) {
+			pr_debug("TX-Tdm %d (slots-)", channel->ch_id);
+
+
+			/* if the channel is open */
+			if (!channel->in_use || !channel->p_ch_data)
+				continue;
+
+			spin_lock(&channel->p_ch_data->tx_channel_lock);
+			if (!channel->in_use || !channel->p_ch_data)
+				continue;
+			ch_bd = channel->p_ch_data->tx_out_data;
+			if (ch_bd->flag) {
+				pcm_buffer = (u16 *)((uint8_t *)ch_bd->p_data +
+						ch_bd->offset);
+				/*if the buffer has less frames than required */
+				if (frame_ch_data_size >=
+						(ch_bd->length - ch_bd->offset/
+						 adap->adapt_cfg.slot_width)) {
+					ch_data_len =
+						ch_bd->length - ch_bd->offset/
+						adap->adapt_cfg.slot_width;
+					last_data = 1;
+				} else {
+					ch_data_len = frame_ch_data_size;
+				}
+				/* Interleaving the data */
+				for (i = 0; i < ch_data_len; i++) {
+					/* TODO- need to be genric for any size
+					   assignment*/
+					output_tdm_buffer[channel->ch_id +
+						bytes_slot_offset * i] =
+						pcm_buffer[i];
+				}
+				/* If all the data of this buffer is
+				   transmitted */
+				if (last_data) {
+					ch_bd->flag = 0;
+					ch_bd->offset = 0;
+					channel->p_ch_data->tx_out_data =
+						ch_bd->wrap ?
+						channel->p_ch_data->tx_data_fifo
+						: ch_bd+1;
+					port->port_stat.tx_pkt_conf_count++;
+				} else {
+					ch_bd->offset += ch_data_len *
+						(adap->adapt_cfg.slot_width);
+				}
+#ifdef	DEBUG
+				data_flag = 1;
+#endif
+			}
+			spin_unlock(&channel->p_ch_data->tx_channel_lock);
+		}
+	}
+
+#ifdef	DEBUG
+	if (data_flag) {
+		pr_info("TX-TDM Interleaved Data-\n");
+		for (i = 0; i < 64; i++)
+			pr_info("%x", output_tdm_buffer[i]);
+		pr_info("\n");
+	}
+#endif
+	return TDM_E_OK;
+}
+
+/* Channel Level APIs of TDM Framework */
+int tdm_channel_open(u16 chanid, u16 ch_width, struct tdm_port *port,
+		struct tdm_channel **h_channel)
+{
+	struct tdm_channel *channel, *temp;
+	unsigned long		flags;
+	struct tdm_ch_data	*p_ch_data;
+	int res = TDM_E_OK;
+
+	if (ch_width != 1) {
+		pr_err("%s: Mode not supported\n", __func__);
+		return -EINVAL;
+	}
+
+	list_for_each_entry_safe(channel, temp, &port->mychannels, list) {
+		if (channel->ch_id == chanid) {
+			pr_err("%s: Channel %d already open\n",
+					__func__, chanid);
+			return -EINVAL;
+		}
+	}
+
+	channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+	if (!channel) {
+		res = -ENOMEM;
+		goto out;
+	}
+
+	init_waitqueue_head(&channel->ch_wait_queue);
+	p_ch_data = kzalloc(sizeof(struct tdm_ch_data), GFP_KERNEL);
+	if (!p_ch_data) {
+		res = -ENOMEM;
+		goto outdata;
+	}
+
+	p_ch_data->rx_data_fifo[TDM_CH_RX_BD_RING_SIZE-1].wrap = 1;
+	p_ch_data->tx_data_fifo[TDM_CH_TX_BD_RING_SIZE-1].wrap = 1;
+
+	p_ch_data->rx_in_data = p_ch_data->rx_data_fifo;
+	p_ch_data->rx_out_data = p_ch_data->rx_data_fifo;
+	p_ch_data->tx_in_data = p_ch_data->tx_data_fifo;
+	p_ch_data->tx_out_data = p_ch_data->tx_data_fifo;
+	spin_lock_init(&p_ch_data->rx_channel_lock);
+	spin_lock_init(&p_ch_data->tx_channel_lock);
+
+	channel->p_ch_data = p_ch_data;
+
+	channel->ch_id = chanid;
+	channel->ch_cfg.first_slot = chanid;
+	channel->ch_cfg.num_slots = 1;	/* This is 1 for channelized mode and
+					   configurable for other modes */
+	channel->port = port;
+	channel->in_use = 1;
+
+	spin_lock_irqsave(&port->ch_list_lock, flags);
+	list_add_tail(&channel->list, &port->mychannels);
+	spin_unlock_irqrestore(&port->ch_list_lock, flags);
+
+	*h_channel = channel;
+
+	return res;
+
+outdata:
+	kfree(channel);
+out:
+	return res;
+}
+EXPORT_SYMBOL(tdm_channel_open);
+
+int tdm_sysfs_init(void)
+{
+	struct kobject *tdm_kobj;
+	int err = 1;
+	tdm_kobj = kzalloc(sizeof(*tdm_kobj), GFP_KERNEL);
+	if (tdm_kobj) {
+		kobject_init(tdm_kobj, &tdm_type);
+		if (kobject_add(tdm_kobj, NULL, "%s", "tdm")) {
+			pr_err("Sysfs creation failed\n");
+			kobject_put(tdm_kobj);
+			err = -EINVAL;
+			goto out;
+		}
+	} else {
+		pr_err("Unable to allocate tdm_kobj\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+out:
+	return err;
+}
+
+int tdm_channel_close(u16 chanid, u16 ch_width, struct tdm_port *port,
+		struct tdm_channel *h_channel)
+{
+	struct tdm_channel *channel;
+	unsigned long		flags;
+	int res = TDM_E_OK;
+	channel = h_channel;
+
+	spin_lock_irqsave(&port->ch_list_lock, flags);
+	list_del(&channel->list);
+	spin_unlock_irqrestore(&port->ch_list_lock, flags);
+
+	if (channel)
+		kfree(channel->p_ch_data);
+	kfree(channel);
+	return res;
+}
+EXPORT_SYMBOL(tdm_channel_close);
+
+ssize_t tdm_show_sysfs(struct kobject *kobj,
+		struct attribute *attr, char *buf)
+{
+	int retval = 0;
+	struct tdm_sysfs *a = container_of(attr,
+			struct tdm_sysfs, attr);
+	switch (a->cmd_type) {
+	case TDM_LATEST_DATA:
+		pr_info("use_latest_tdm_data: %d\n", use_latest_tdm_data);
+		break;
+	default:
+		pr_info("Invalid cmd_type value\n");
+		return -EINVAL;
+	}
+	return retval;
+}
+
+ssize_t tdm_store_sysfs(struct kobject *kobj,
+		struct attribute *attr, const char *buf, size_t len)
+{
+	struct tdm_sysfs *a = container_of(attr,
+			struct tdm_sysfs, attr);
+
+	sscanf(buf, "%d", &a->data);
+	use_latest_tdm_data = a->data;
+	return strlen(buf);
+}
+
+void init_config_adapter(struct tdm_adapter *adap)
+{
+	struct fsl_tdm_adapt_cfg default_adapt_cfg = {
+		.loopback = TDM_PROCESS_NORMAL,
+		.num_ch = NUM_CHANNELS,
+		.ch_size_type = CHANNEL_16BIT_LIN,
+		.frame_len = NUM_SAMPLES_PER_FRAME,
+		.num_frames = NUM_SAMPLES_PER_FRAME,
+		.adap_mode = TDM_ADAPTER_MODE_NONE
+	};
+
+	default_adapt_cfg.slot_width = default_adapt_cfg.ch_size_type/3 + 1;
+
+	memcpy(&adap->adapt_cfg, &default_adapt_cfg,
+			sizeof(struct fsl_tdm_adapt_cfg));
+
+	return;
+}
+EXPORT_SYMBOL(init_config_adapter);
+
+void tdm_data_tasklet_fn(unsigned long data)
+{
+	struct tdm_adapter *adapter;
+	adapter = (struct tdm_adapter *)data;
+	if (adapter != NULL) {
+		tdm_data_tx_interleave(adapter);
+		tdm_data_rx_deinterleave(adapter);
+	}
+}
+
+
+MODULE_AUTHOR("Hemant Agrawal <hemant@freescale.com> and "
+	"Rajesh Gumasta <rajesh.gumasta@freescale.com>");
+MODULE_DESCRIPTION("TDM Driver Framework Core");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 83ac071..573ac40 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -425,6 +425,17 @@ struct i2c_device_id {
 			__attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+/* tdm */
+
+#define TDM_NAME_SIZE   20
+#define TDM_MODULE_PREFIX "tdm:"
+
+struct tdm_device_id {
+	char name[TDM_NAME_SIZE];
+	kernel_ulong_t driver_data      /* Data private to the driver */
+			__attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+
 /* spi */
 
 #define SPI_NAME_SIZE	32
diff --git a/include/linux/tdm.h b/include/linux/tdm.h
new file mode 100644
index 0000000..a2f9628
--- /dev/null
+++ b/include/linux/tdm.h
@@ -0,0 +1,338 @@
+/* include/linux/tdm.h
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc, All rights reserved.
+ *
+ * tdm.h - definitions for the tdm-device framework interface
+ *
+ * Author:Hemant Agrawal <hemant@freescale.com>
+ *	Rajesh Gumasta <rajesh.gumasta@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef _LINUX_TDM_H
+#define _LINUX_TDM_H
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/device.h>	/* for struct device */
+#include <linux/sched.h>	/* for completion */
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+
+#define TDM_LATEST_DATA		1
+#define CHANNEL_8BIT_LIN	0	/* 8 bit linear */
+#define CHANNEL_8BIT_ULAW	1	/* 8 bit Mu-law */
+#define CHANNEL_8BIT_ALAW	2	/* 8 bit A-law */
+#define CHANNEL_16BIT_LIN	3	/* 16 bit Linear */
+
+/*
+ * Default adapter configuration. All the TDM adapters registered with
+ * framework will be configured with following default configuration.
+ */
+#define NUM_CHANNELS	16
+
+/* Default configuration for typical voice data sample. These parameters
+ * will generally not be required to be changed for voice type applications.
+ */
+#define NUM_SAMPLES_PER_MS	8	/* 8 samples per milli sec per
+					 channel. Req for voice data */
+#define NUM_MS			10
+#define NUM_SAMPLES_PER_FRAME	(NUM_MS * NUM_SAMPLES_PER_MS) /* Number of
+						samples for 1 client buffer */
+#define NUM_OF_TDM_BUF		3
+
+/* General options */
+
+struct tdm_adapt_algorithm;
+struct tdm_adapter;
+struct tdm_port;
+struct tdm_driver;
+
+
+/**
+ * struct tdm_driver - represent an TDM device driver
+ * @class: What kind of tdm device we instantiate (for detect)
+ * @id:Driver id
+ * @name: Name of the driver
+ * @attach_adapter: Callback for device addition (for legacy drivers)
+ * @detach_adapter: Callback for device removal (for legacy drivers)
+ * @probe: Callback for device binding
+ * @remove: Callback for device unbinding
+ * @shutdown: Callback for device shutdown
+ * @suspend: Callback for device suspend
+ * @resume: Callback for device resume
+ * @command: Callback for sending commands to device
+ * @id_table: List of TDM devices supported by this driver
+ * @list: List of drivers created (for tdm-core use only)
+ */
+struct tdm_driver {
+	unsigned int class;
+	unsigned int id;
+	char name[TDM_NAME_SIZE];
+
+	int (*attach_adapter)(struct tdm_adapter *);
+	int (*detach_adapter)(struct tdm_adapter *);
+
+	/* Standard driver model interfaces */
+	int (*probe)(const struct tdm_device_id *);
+	int (*remove)(void);
+
+	/* driver model interfaces that don't relate to enumeration */
+	void (*shutdown)(void);
+	int (*suspend)(pm_message_t mesg);
+	int (*resume)(void);
+
+	const struct tdm_device_id *id_table;
+
+	/* The associated adapter for this driver */
+	struct tdm_adapter *adapter;
+	struct list_head list;
+};
+
+/* tdm per port statistics structure, used for providing and storing tdm port
+ * statistics.
+ */
+struct tdm_port_stats {
+	unsigned int rx_pkt_count;	/* Rx frame count per channel */
+	unsigned int rx_pkt_drop_count;	/* Rx drop count per channel to
+					 clean space for new buffer */
+	unsigned int tx_pkt_count;	/* Tx frame count per channel */
+	unsigned int tx_pkt_conf_count;	/* Tx frame confirmation count per
+					 channel */
+	unsigned int tx_pkt_drop_count;	/* Tx drop count per channel due to
+					 queue full */
+};
+
+
+/* tdm Buffer Descriptor, used for Creating Interleaved and De-interleaved
+ * FIFOs
+ */
+struct tdm_bd {
+	unsigned char flag;		/* BD is full or empty */
+	unsigned char wrap;		/* BD is last in the queue */
+	unsigned short length;	/* Length of Data in BD */
+	/*TODO: use dyanmic memory */
+	unsigned short p_data[NUM_SAMPLES_PER_FRAME];	/* Data Pointer */
+	unsigned long offset;	/* Offset of the Data Pointer to be used */
+};
+
+#define TDM_CH_RX_BD_RING_SIZE	3
+#define TDM_CH_TX_BD_RING_SIZE	3
+
+/* tdm RX-TX Channelised Data */
+struct tdm_port_data {
+	struct tdm_bd rx_data_fifo[TDM_CH_RX_BD_RING_SIZE]; /* Rx Channel Data
+								BD Ring */
+	struct tdm_bd *rx_in_data;	/* Current Channel Rx BD to be filled by
+						de-interleave function */
+	struct tdm_bd *rx_out_data;	/* Current Channel Rx BD to be
+							read by App */
+	struct tdm_bd tx_data_fifo[TDM_CH_TX_BD_RING_SIZE]; /* Tx Channel Data
+								BD Ring */
+	struct tdm_bd *tx_in_data;	/* Current Channel Tx BD to be
+						 filled by App */
+	struct tdm_bd *tx_out_data;	/* Current Channel Tx BD to be read by
+						interleave function */
+	spinlock_t rx_channel_lock;	/* Spin Lock for Rx Channel */
+	spinlock_t tx_channel_lock;	/* Spin Lock for Tx Channel */
+};
+
+/* structure tdm_port_cfg - contains configuration params for a port */
+struct tdm_port_cfg {
+	unsigned short port_mode;
+};
+
+/* struct tdm_port - represent an TDM ports for a device */
+struct tdm_port {
+	unsigned short port_id;
+	unsigned short in_use;		/* Port is enabled? */
+	uint16_t rx_max_frames;		/* Received Port frames
+					 before allowing Read Operation in
+					 Port Mode */
+
+	struct tdm_port_stats port_stat;/* A structure parameters defining
+					 TDM port statistics. */
+	struct tdm_port_data *p_port_data;	/* a structure parameters
+						defining tdm channelised data */
+
+	struct tdm_driver *driver;	/* driver for this port */
+	struct tdm_adapter *adapter;	/* adapter for this port */
+	struct list_head list;		/* list of ports */
+	struct list_head mychannels;	/* list of channels, created on this
+					 port*/
+	spinlock_t ch_list_lock;	/* Spin Lock for channel_list */
+	struct tdm_port_cfg port_cfg;/* A structure parameters defining
+					 TDM port configuration. */
+};
+
+/* tdm RX-TX Channelised Data */
+struct tdm_ch_data {
+	struct tdm_bd rx_data_fifo[TDM_CH_RX_BD_RING_SIZE]; /* Rx Port Data BD
+								Ring */
+	struct tdm_bd *rx_in_data;	/* Current Port Rx BD to be filled by
+						de-interleave function */
+	struct tdm_bd *rx_out_data; /* Current Port Rx BD to be read by App */
+	struct tdm_bd tx_data_fifo[TDM_CH_TX_BD_RING_SIZE]; /* Tx Port Data BD
+								Ring */
+	struct tdm_bd *tx_in_data;	/* Current Port Tx BD to be filled by
+						App */
+	struct tdm_bd *tx_out_data;	/* Current Port Tx BD to be read by
+						interleave function */
+	spinlock_t rx_channel_lock;	/* Spin Lock for Rx Port */
+	spinlock_t tx_channel_lock;	/* Spin Lock for Tx Port */
+};
+
+/* Channel config params */
+struct tdm_ch_cfg {
+	unsigned short num_slots;
+	unsigned short first_slot;
+};
+
+/* struct tdm_channel- represent a TDM channel for a port */
+struct tdm_channel {
+	u16 ch_id;			/* logical channel number */
+	struct list_head list;		/* list of channels in a port*/
+	struct tdm_port *port;		/* port for this channel */
+	u8 in_use;			/* channel is enabled? */
+	struct tdm_ch_cfg ch_cfg;	/* channel configuration */
+	struct tdm_ch_data *p_ch_data;	/* data storage space for channel */
+	wait_queue_head_t ch_wait_queue;/* waitQueue for RX Channel Data */
+};
+
+/* tdm_adapt_algorithm is for accessing the routines of device */
+struct tdm_adapt_algorithm {
+	u32 (*tdm_read)(struct tdm_adapter *, u16 **);
+	u32 (*tdm_get_write_buf)(struct tdm_adapter *, u16 **);
+	u32 (*tdm_write)(struct tdm_adapter *, void *, unsigned int len);
+	int (*tdm_enable)(struct tdm_adapter *);
+	int (*tdm_disable)(struct tdm_adapter *);
+};
+
+/* tdm_adapter_mode is to define in mode of the device */
+enum tdm_adapter_mode {
+	TDM_ADAPTER_MODE_NONE = 0x00,
+	TDM_ADAPTER_MODE_T1 = 0x01,
+	TDM_ADAPTER_MODE_E1 = 0x02,
+	TDM_ADAPTER_MODE_T1_RAW = 0x10,
+	TDM_ADAPTER_MODE_E1_RAW = 0x20,
+};
+
+/* tdm_port_mode defines the mode in which the port is configured to operate
+ * It can be channelized/full/fractional.
+ */
+enum tdm_port_mode {
+	TDM_PORT_CHANNELIZED = 0,	/* Channelized mode */
+	TDM_PORT_FULL = 1,		/* Full mode */
+	TDM_PORT_FRACTIONAL = 2		/* Fractional mode */
+};
+
+/* tdm_process_mode used for testing the tdm device in normal mode or internal
+ * loopback or external loopback
+ */
+enum tdm_process_mode {
+	TDM_PROCESS_NORMAL = 0,		/* Normal mode */
+	TDM_PROCESS_INT_LPB = 1,	/* Internal loop mode */
+	TDM_PROCESS_EXT_LPB = 2		/* External Loopback mode */
+};
+
+/* TDM configuration parameters */
+struct fsl_tdm_adapt_cfg {
+	u8 num_ch;		/* Number of channels in this adpater */
+	u8 ch_size_type;		/* reciever/transmit channel
+						size for all channels */
+	u8 slot_width;		/* 1 or 2 Is defined by channel type */
+	u8 frame_len;		/* Length of frame in samples */
+	u32 num_frames;
+	u8 loopback;			/* loopback or normal */
+	u8 adap_mode;			/* 0=None, 1= T1, 2= T1-FULL, 3=E1,
+						4 = E1-FULL */
+	int max_timeslots;		/* Max Number of timeslots that are
+					supported on this adapter */
+};
+
+/*
+ * tdm_adapter is the structure used to identify a physical tdm device along
+ * with the access algorithms necessary to access it.
+ */
+struct tdm_adapter {
+	struct module *owner;	/* owner of the adapter module */
+	unsigned int id;	/* Adapter Id */
+	unsigned int drv_count;	/* Number of drivers associated with the
+				 adapter */
+
+	const struct tdm_adapt_algorithm *algo;	/* the algorithm to access the
+						 adapter*/
+
+	char name[TDM_NAME_SIZE];	/* Name of Adapter */
+	struct mutex adap_lock;
+	struct device *parent;
+
+	struct tasklet_struct tdm_data_tasklet;	/* tasklet handle to perform
+						 data processing*/
+	int tasklet_conf;	/* flag for tasklet configuration */
+	int tdm_rx_flag;
+
+	struct list_head myports;	/* list of ports, created on this
+					 adapter */
+	struct list_head list;
+	spinlock_t portlist_lock;
+	void *data;
+	struct fsl_tdm_adapt_cfg adapt_cfg;
+};
+
+struct tdm_sysfs {
+	struct attribute attr;
+	int data;
+	u32 cmd_type;
+};
+
+/* functions exported by tdm.o */
+
+int tdm_add_adapter(struct tdm_adapter *adpater);
+int tdm_del_adapter(struct tdm_adapter *adapter);
+int tdm_register_driver(struct tdm_driver *driver);
+void tdm_unregister_driver(struct tdm_driver *driver);
+void init_config_adapter(struct tdm_adapter *adapter);
+
+int tdm_port_open(struct tdm_driver *driver, struct tdm_port **h_port);
+int tdm_port_close(struct tdm_port *h_port);
+int tdm_channel_read(struct tdm_port *h_port, struct tdm_channel *h_channel,
+		void *p_data, u16 *size);
+int tdm_channel_write(struct tdm_port *h_port, struct tdm_channel *h_channel,
+		void *p_data, u16 size);
+int tdm_ch_poll(struct tdm_channel *h_channel, unsigned int wait_time);
+
+int tdm_channel_open(u16 chanid, u16 ch_width, struct tdm_port *port,
+		struct tdm_channel **h_channel);
+int tdm_channel_close(u16 chanid, u16 ch_width, struct tdm_port *port,
+		struct tdm_channel *h_channel);
+/* this tasklet is created for each adapter instance */
+void tdm_data_tasklet_fn(unsigned long);
+int tdm_sysfs_init(void);
+ssize_t tdm_show_sysfs(struct kobject *kobj,
+		struct attribute *attr, char *buf);
+ssize_t tdm_store_sysfs(struct kobject *kobj,
+		struct attribute *attr, const char *buf, size_t len);
+
+struct tdm_adapter *tdm_get_adapter(int id);
+void tdm_put_adapter(struct tdm_adapter *adap);
+
+#endif /* __KERNEL__ */
+
+#define TDM_E_OK 0
-- 
1.5.6.5

^ permalink raw reply related

* [PATCH][upstream]Added TDM device support and Freescale Starlite driver
From: sandeep @ 2012-07-20 12:35 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Sandeep Singh, Poonam Aggrwal
In-Reply-To: <1342787714-8415-1-git-send-email-sandeep@freescale.com>

From: Sandeep Singh <Sandeep@freescale.com>

Freescale TDM controller consists of a TDM module supporting 128 channels
running at up to 50 Mbps with 8-bit and 16-bit word size. The TDM bus connects
gluelessly to most T1/E1 frames as well as to common buses such as the H.110,
SCAS, and MVIP. TDM also supports an I2S mode. The TDM module operates in
independent or shared mode when receiving or transmitting data.

This controller is available on MPC8315, P1010, P1020, P1022 and P1024 Freescale SOCs.

The driver registers itself with the TDM Framework & provides TDM functionality to the client modules.

In its present form this driver supports only channelised mode.

Signed-off-by: Sandeep Singh <Sandeep@freescale.com>
Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
---

Based on: git://git.am.freescale.net/gitolite/mirrors/galak-powerpc.git
Branch: master
Checkpatch: passed

First patch version was RFC

Changes from RFC:
	- Enabling Tx FIFO for TDM
	- Removed unused variables.
	- PMUXCR has been removed as it is taken care by u-boot

	Incorporated Timur's comments:
	- Improved Copyright statement.
	- Removed unused function.
	- Introduced read after each write to register
	- Used spin_event_timeout for polling
	- Removed unused spinlock
	- Moved all macros and structures from header file to tdm_fsl.c
	- Rectified cosmetic problems.

 drivers/tdm/Kconfig          |    3 -
 drivers/tdm/Makefile         |    2 +-
 drivers/tdm/device/Kconfig   |   15 +
 drivers/tdm/device/Makefile  |    9 +
 drivers/tdm/device/tdm_fsl.c | 1186 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1211 insertions(+), 4 deletions(-)
 create mode 100644 drivers/tdm/device/Kconfig
 create mode 100644 drivers/tdm/device/Makefile
 create mode 100644 drivers/tdm/device/tdm_fsl.c

diff --git a/drivers/tdm/Kconfig b/drivers/tdm/Kconfig
index 0b0fda8..69b8987 100644
--- a/drivers/tdm/Kconfig
+++ b/drivers/tdm/Kconfig
@@ -13,6 +13,3 @@ menuconfig TDM
 	  This TDM support can also be built as a module.  If so, the module
 	  will be called tdm-core.
 
-if TDM
-
-endif # TDM
diff --git a/drivers/tdm/Makefile b/drivers/tdm/Makefile
index 84e2cb9..a605b3d 100644
--- a/drivers/tdm/Makefile
+++ b/drivers/tdm/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the TDM core.
 #
 
-obj-$(CONFIG_TDM)		+= tdm-core.o
+obj-$(CONFIG_TDM)		+= tdm-core.o device/
diff --git a/drivers/tdm/device/Kconfig b/drivers/tdm/device/Kconfig
new file mode 100644
index 0000000..9fd1b06
--- /dev/null
+++ b/drivers/tdm/device/Kconfig
@@ -0,0 +1,15 @@
+#
+# TDM device configuration
+#
+
+menu "TDM Device support"
+
+config TDM_FSL
+        tristate "Driver for Freescale TDM controller"
+        depends on FSL_SOC
+        ---help---
+          This is a driver for Freescale TDM controller. The controller
+          is found in various Freescale SOCs viz MPC8315, P1020. The TDM driver
+          basically multiplexes and demultiplexes data from different channels.
+          The TDM can interface SLIC kind of devices.
+endmenu
diff --git a/drivers/tdm/device/Makefile b/drivers/tdm/device/Makefile
new file mode 100644
index 0000000..4156d7f
--- /dev/null
+++ b/drivers/tdm/device/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the TDM device drivers.
+#
+
+obj-y	+= tdm_fsl.o
+
+#ifeq ($(CONFIG_TDM_DEBUG_BUS),y)
+#EXTRA_CFLAGS += -DDEBUG
+#endif
diff --git a/drivers/tdm/device/tdm_fsl.c b/drivers/tdm/device/tdm_fsl.c
new file mode 100644
index 0000000..732bcb8
--- /dev/null
+++ b/drivers/tdm/device/tdm_fsl.c
@@ -0,0 +1,1186 @@
+/*
+ * Copyright 2007-2012 Freescale Semiconductor, Inc, All rights reserved.
+ *
+ * TDM driver for Freescale TDM controller.
+ * This driver can interface with SLIC device to run VOIP kind of
+ * applications.
+ *
+ * Author: P. V. Suresh <pala@freescale.com>
+ *	Hemant Agrawal <hemant@freescale.com>
+ *	Rajesh Gumasta <rajesh.gumasta@freescale.com>
+ *
+ * Modifier: Sandeep Kr. Singh <sandeep@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Note that this is a complete rewrite of P.V. Suresh's driver code.
+ * But we have used so much of his original code and ideas that it seems
+ * only fair to recognize him as co-author -- Rajesh & Hemant
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/tdm.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <sysdev/fsl_soc.h>
+
+#define DRV_DESC "Freescale TDM Driver Adapter"
+#define DRV_NAME "fsl_tdm"
+
+/* TDM data register offset */
+#define TDM_TDR_OFFSET 0x108
+#define TDM_RDR_OFFSET 0x100
+#define TDM_DATAREG_OFFSET 0x100
+#define TDM_CLKREG_OFFSET 0x180
+
+/* TCD params */
+#define SOFF_VAL	0x08
+#define DOFF_VAL	0x08
+#define NBYTES		0x08 /*Minor Bytes transfer count*/
+#define SLAST		0x00 /* last source addr adjustment*/
+#define SLAST_SGA	0x00
+#define DLAST_SGA	0x00
+
+/* RIR Params*/
+#define RIR_RFSD_VAL	0x01
+#define RIR_RFWM_VAL	0x00
+
+/* TIR Params*/
+#define TIR_RFSD_VAL	0x01
+#define TIR_RFWM_VAL	0x00
+
+/* TDMTCEN */
+#define NUM_TDMTCEN_REG		0x04
+#define TDMTCEN_REG_LEN		32
+
+
+#define DMAC_TX_INT 1
+#define DMAC_RX_INT 2
+
+/* DMA GPOR */
+#define DMAGPOR_SNOOP	0x00000040	/* Enable Snooping */
+
+/* DMA Control Register (DMACR) */
+#define DMACR_EMLM	0x00000080	/* Enable Minor loop Mapping */
+#define DMACR_CLM	0x00000040	/* Continuous link mode */
+#define DMACR_HALT	0x00000020	/* Halt DMA */
+#define DMACR_HOE	0x00000010	/* Halt on Error */
+#define DMACR_ERGA	0x00000008	/* Round robin among the groups */
+#define DMACR_ERCA	0x00000004	/* Round robin Port Arbitration */
+#define DMACR_EDBG	0x00000002	/* Debug */
+#define DMACR_EBW	0x00000001	/* Enable Buffer */
+
+/* DMA Error Status DMAES */
+#define DMAES_VLD	0x80000000	/* Logical OR of all DMA errors. */
+#define DMAES_ECX	0x00010000	/* Transfer cancelled */
+#define DMAES_GPE	0x00008000	/* Group priority error */
+#define DMAES_CPE	0x00004000	/* Channel priority error */
+/* errored/cancelled channel */
+#define DMAES_ERRCHN(errch)	(((errch) & 0x1F00) >> 8)
+#define DMAES_SAE	0x00000080	/* Source address error */
+#define DMAES_SOE	0x00000040	/* Source offset error */
+#define DMAES_DAE	0x00000020	/* Destination address error */
+#define DMAES_DOE	0x00000010	/* Destination offset error */
+#define DMAES_NCE	0x00000008	/* Nbytes citer error */
+#define DMAES_SGE	0x00000004	/* Scatter gather error */
+#define DMAES_SBE	0x00000002	/* Source bus error */
+#define DMAES_DBE	0x00000001	/* Destination bus error */
+
+/* DMA Enable Request (DMAERQH, DMAERQL) Enable/disable device
+	request for the channel */
+#define DMA_SET_ENABLE_REQUEST(regs, ch)	out_8(((regs)->dmasreq), ch)
+#define DMA_CLEAR_ENABLE_REQUEST(regs, ch)	out_8(((regs)->dmacerq), ch)
+
+/* DMA Enable Error Interrupt (DMAEEIH, DMAEEIL) Enable/disable
+	error interrupt for the channel */
+#define DMA_SET_ENABLE_ERROR_INT(regs, ch)	out_8(((regs)->dmaseei), ch)
+#define DMA_CLEAR_ENABLE_ERROR_INT(regs, ch)	out_8(((regs)->dmaceei), ch)
+
+/*   Clear interrupt/error for the channel */
+#define DMA_CLEAR_INTT_REQUEST(regs, ch)	out_8(((regs)->dmacint), ch)
+#define DMA_CLEAR_ERROR(regs, ch)	out_8(((regs)->dmacerr), ch)
+
+/* Clear done bit for the channel */
+#define DMA_CLEAR_DONE_BIT(regs, ch)	out_8(((regs)->dmacdne), ch)
+/* Set start bit for the channel */
+#define DMA_SET_START_BIT(regs, ch)	out_8(((regs)->dmassrt), ch)
+
+#define TDMTX_DMA_CH	0	/* TDM Tx uses DMA channel 0 HardWired */
+#define TDMRX_DMA_CH	1	/* TDM Rx uses DMA channel 1 Hardwired */
+#define TCD_SIZE 64	/* 64 byte buffer for TCD */
+
+/* Source address modulo */
+#define DMA_TCD1_SMOD(smod)   (((smod) & 0x1F) << 27)
+/* Source data transfer size */
+#define DMA_TCD1_SSIZE(ssize) (((ssize) & 0x7) << 24)
+
+/* Destination address modulo */
+#define DMA_TCD1_DMOD(dmod)   (((dmod) & 0x1F) << 19)
+/* data transfer size  */
+#define DMA_TCD1_DSIZE(dsize) (((dsize) & 0x7) << 16)
+
+/* Source address signed offset */
+#define DMA_TCD1_SOFF(soff)   ((soff) & 0xFFFF)
+
+/* Enable link to another channel on minor iteration completion. */
+#define DMA_TCD5_E_MINOR_LINK 0x80000000
+/* Link to this channel. */
+#define DMA_TCD5_LINK_CH(ch) (((ch) & 0x3F) << 25)
+/* Current iteration count when linking disnabled */
+#define DMA_TCD5_CITER_DISABLE_LINK(citer) (((citer) & 0x7FFF) << 16)
+/* Current iteration count when linking enabled */
+#define DMA_TCD5_CITER_ENABLE_LINK(citer) (((citer) & 0x00FF) << 16)
+/*  Destination address signed offset */
+#define DMA_TCD5_DOFF(doff) ((doff) & 0xFFFF)
+
+/* Beginning iteration count when linking disabled */
+#define DMA_TCD7_BITER_DISABLE_LINK(citer) (((citer) & 0x7FFF) << 16)
+/* Beginning iteration count when linking enabled */
+#define DMA_TCD7_BITER_ENABLE_LINK(citer) (((citer) & 0x00FF) << 16)
+#define DMA_TCD7_BWC(bw) (((bw)&0x3)<<14)	/* BandWidth Control. */
+/* Link channel number */
+#define DMA_TCD7_LINKCH(ch)   (((ch) & 0x1F) << 8)
+#define DMA_TCD7_DONE		0x00000080	/* Channel done  */
+#define DMA_TCD7_ACTIVE		0x00000040	/* Channel active */
+#define DMA_TCD7_E_MAJOR_LINK	0x00000020	/* channel to channel linking */
+#define DMA_TCD7_E_SG		0x00000010	/* Enable scatter gather */
+#define DMA_TCD7_D_REQ		0x00000008	/* Disable request */
+/* interrupt on half major counter */
+#define DMA_TCD7_INT_HALF	0x00000004
+#define DMA_TCD7_INT_MAJ	0x00000002	/* interrupt on major counter */
+#define DMA_TCD7_START		0x00000001	/* Channel start */
+
+/* Source data transfer size */
+#define SSIZE_08BITS		0x00
+#define SSIZE_16BITS		0x01
+#define SSIZE_32BITS		0x02
+#define SSIZE_64BITS		0x03
+
+/* max number of TDM-DMA channels */
+#define DMA_MAX_CHANNELS 4
+
+/* each DMA-ch contains 8 Transfer Control Discriptors  */
+#define MAX_TCD_WORD 8
+
+/* TDMGIR  General Interface Register */
+#define GIR_LPBK	0x00000004	/* loopback mode */
+#define GIR_CTS		0x00000002	/* Common TDM signals */
+#define GIR_RTS		0x00000001	/* Rx & Tx sharing */
+
+/* TDMRIR Recieve Interface Rgister */
+#define RIR_RFWM_MASK	0x00000003	/* Recieve FIFO Watermark */
+#define RIR_RFWM_SHIFT	16
+#define RIR_RFWM(x)     ((x & RIR_RFWM_MASK) << RIR_RFWM_SHIFT)
+#define RIR_RFEN	0x00008000	/* Recieve FIFO Enable */
+#define RIR_RWEN	0x00004000	/* Recieve Wide FIFO Enable */
+#define RIR_RDMA	0x00000040	/* Recieve DMA Enable */
+#define RIR_RFSD_SHIFT	0x00000004	/* Recieve Frame Sync Delay */
+#define RIR_RFSD_MASK	0x00000003
+#define RIR_RFSD(x)	((x & RIR_RFSD_MASK) << RIR_RFSD_SHIFT)
+#define RIR_RSO		0x00002000	/* Recieve sync Out */
+#define RIR_RSL		0x00000800	/* Recieve sync Out Length */
+#define RIR_RSOE	0x00000400	/* Recieve sync Out Edge */
+#define RIR_RCOE	0x00000200	/* Recieve Clock Output Enable */
+#define RIR_RSA		0x00000008	/* Recieve Sync Active */
+#define RIR_RDE		0x00000004	/* Recieve Data Edge */
+#define RIR_RFSE	0x00000002	/* Recieve Frame Sync Edge */
+#define RIR_RRDO	0x00000001	/* Revieve Reversed Data Order */
+
+/* TDMTIR  Transmit Interface Rgister */
+#define TIR_TFWM_MASK	0x00000003	/* Transmit FIFO Watermark */
+#define TIR_TFWM_SHIFT	16
+#define TIR_TFWM(x)	((x & TIR_TFWM_MASK) << TIR_TFWM_SHIFT)
+#define TIR_TFEN	0x00008000	/* Transmit FIFO Enable */
+#define TIR_TWEN	0x00004000	/* Transmit Wide FIFO Enable */
+#define TIR_TDMA	0x00000040	/* Transmit DMA Enable */
+#define TIR_TFSD_SHIFT	0x00000004	/* Transmit Frame Sync Delay */
+#define TIR_TFSD_MASK	0x00000003
+#define TIR_TFSD(x)	((x & TIR_TFSD_MASK) << TIR_TFSD_SHIFT)
+#define TIR_TSO		0x00002000	/* Transmit Sync Output */
+#define TIR_TSL		0x00000800	/* Transmit sync Out Length */
+#define TIR_TSOE	0x00000400	/* Transmit sync Out Edge */
+#define TIR_TCOE	0x00000200	/* Transmit Clock Output Enable */
+#define TIR_TSA		0x00000008	/* Transmit Sync Active */
+#define TIR_TDE		0x00000004	/* Transmit Data Edge */
+#define TIR_TFSE	0x00000002	/* Transmit Frame Sync Edge */
+#define TIR_TRDO	0x00000001	/* Transmit Reversed Data Order */
+
+/*TDMRFP  Revieve Frame Parameters */
+#define RFP_RNCF_SHIFT	0x00000010	/* Number of Channels in TDM Frame */
+#define RFP_RNCF_MASK	0x000000FF
+#define RFP_RNCF(x)	(((x - 1) & RFP_RNCF_MASK) << RFP_RNCF_SHIFT)
+#define RFP_RCS_SHIFT	0x00000004	/* Recieve Channel Size */
+#define RFP_RCS_MASK	0x00000003
+#define RFP_RCS(x)	((x & RFP_RCS_MASK) << RFP_RCS_SHIFT)
+#define RFP_RT1		0x00000002	/* Recieve T1 Frame */
+
+/*TDMTFP Transmit Frame Parameters */
+#define TFP_TNCF_SHIFT	0x00000010	/* Number of Channels in TDM Frame */
+#define TFP_TNCF_MASK	0x000000FF
+#define TFP_TNCF(x)	(((x - 1) & TFP_TNCF_MASK) << TFP_TNCF_SHIFT)
+#define TFP_TCS_SHIFT	0x00000004	/* Transmit Channel Size */
+#define TFP_TCS_MASK	0x00000003
+#define TFP_TCS(x)	((x & RFP_RCS_MASK) << RFP_RCS_SHIFT)
+#define TFP_TT1		0x00000002	/* Transmit T1 Frame */
+
+
+/* TDMRCR  Recieve Control Register */
+#define RCR_REN		0x00000001	/* Recieve Enable */
+/* TDMTCR  Transmit Control Register */
+#define TCR_TEN		0x00000001	/* Transmit Enable */
+
+/* TDMRIER receive interrupt enable register */
+#define RIER_RCEUE	0x00000100	/* Channel Enable Update Enable */
+#define RIER_RLCEE	0x00000080	/* Recieve Last Channel Event Enable */
+#define RIER_RFSEE	0x00000040	/* Recieve Frame Sync Event Enable */
+#define RIER_RFFEE	0x00000020	/* Recieve FIFO Full Event Enable */
+#define RIER_RDREE	0x00000010	/* Recieve Data Ready Event Enable */
+#define RIER_RSEEE	0x00000008	/* Recieve Sync Error Event Enable */
+#define RIER_ROEE	0x00000004	/* Recieve Overrun Event Enable */
+
+/* TDMTIER  transmit interrupt enable register */
+#define TIER_TCEUE	0x00000100	/* Channel Enable Update Enable */
+#define TIER_TLCEE	0x00000080	/* Transmit Last Channel Event */
+#define TIER_TFSEE	0x00000040	/* Transmit Frame Sync Event Enable */
+#define TIER_TFFEE	0x00000020	/* Transmit FIFO Full Event Enable */
+#define TIER_TDREE	0x00000010	/* Transmit Data Ready Event Enable */
+#define TIER_TSEEE	0x00000008	/* Transmit Sync Error Event Enable */
+#define TIER_TUEE	0x00000004	/* Transmit Overrun Event Enable */
+
+/* TDMRER  Recieve Event Register */
+#define RER_RCEU	0x00000100	/* Recieve Channel Enable Update */
+#define RER_RLCE	0x00000080	/* Recieve Last Channel Event */
+#define RER_RFSE	0x00000040	/* Recieve Frame Sync Event */
+#define RER_RFFE	0x00000020	/* Recieve FIFO Full Event */
+#define RER_RDRE	0x00000010	/* Recieve Data Ready Event */
+#define RER_RSEE	0x00000008	/* Recieve Sync Error Event */
+#define RER_ROE		0x00000004	/* Recieve Overrun Event */
+
+/* TDMTER  Transmit Event Register */
+#define TER_TCEU	0x00000100	/* Transmit Channel Enable Update */
+#define TER_TLCE	0x00000080	/* Transmit Last Channel Event */
+#define TER_TFSE	0x00000040	/* Transmit Frame Sync Event */
+#define TER_TFEE	0x00000020	/* Transmit FIFO Full Event */
+#define TER_TDRE	0x00000010	/* Transmit Data Ready Event */
+#define TER_TSEE	0x00000008	/* Transmit Sync Error Event */
+#define TER_TUE		0x00000004	/* Transmit Overrun Event */
+
+/* TDMRSR  Recieve Status Register */
+#define RSR_RFCNT	0x00000038	/* Recieve FIFO counter */
+#define RSSS_MASK	0x00000003	/* Recieve SYNC Status */
+#define RSR_RSSS_SHIFT  1
+#define RSR_RSSS(sss)	(((sss) >> (RSR_RSSS_SHIFT)) & (RSR_RSSS_MASK))
+#define RSR_RENS	0x00000001	/* Recieve Enable Status */
+
+/* TDMTSR  Transmit Status Register */
+#define TSR_TFCNT	0x00000038	/* Transmit FIFO counter */
+#define TSR_TSSS_MASK	0x00000003	/* Transmit SYNC Status */
+#define TSR_TSSS_SHIFT	1
+#define TSR_TSSS(sss)	(((sss) >> (TSR_TSSS_SHIFT)) & TSR_TSSS_MASK)
+#define TSR_TENS	0x00000001	/* Transmit Enable Status */
+
+
+/* channel parameters   */
+#define TDM_ENABLE_TIMEOUT	1000	/* time out for TDM rx, tx enable */
+#define NUM_OF_TDM_BUF		3	/* Number of tdm buffers for startlite
+					   DMA */
+#define ALIGNED_2_BYTES		0x02	/* 2-bytes alignment */
+#define ALIGNED_4_BYTES		0x04	/* 4-bytes alignment */
+#define ALIGNED_8_BYTES		0x08	/* 8-bytes alignment */
+#define ALIGNED_16_BYTES	0x10	/* 16-bytes alignment */
+#define ALIGNED_32_BYTES	0x20	/* 32-bytes alignment */
+#define ALIGNED_64_BYTES	0x40	/* 64-bytes alignment */
+
+static int tdmen = 1;
+
+module_param(tdmen, int, S_IRUSR);
+MODULE_PARM_DESC(tdmen, "Enable TDM: Enable=1, Disable=0(default)");
+
+/* DMAC TCD structure */
+struct tcd {
+	u32 tcd[MAX_TCD_WORD];
+};
+
+/* DMA Controllor */
+struct dmac_regs {
+	u32 dmacr;		/* DMA Control Register			*/
+	u32 dmaes;		/* DMA Error Status Register		*/
+	u32 dmaerqh;		/* DMA Enable Request			*/
+	u32 dmaerql;		/* DMA Enable Request			*/
+	u32 dmaeeih;		/* DMA Enable Error Interrupt		*/
+	u32 dmaeeil;		/* DMA Enable Error Interrupt		*/
+
+	u8 dmaserq;		/* DMA Set Enable Request		*/
+	u8 dmacerq;		/* DMA Clear Enable Request		*/
+	u8 dmaseei;		/* DMA Set Enable Error Interrupt	*/
+	u8 dmaceei;		/* DMA Clear Enable Error Interrupt	*/
+
+	u8 dmacint;		/* DMA Clear Interrupt Request		*/
+	u8 dmacerr;		/* DMA Clear Error			*/
+	u8 dmassrt;		/* DMA Set Start Bit			*/
+	u8 dmacdne;		/* DMA Clear Done Bit			*/
+
+	u32 dmainth;		/* DMA Interrupt Request High		*/
+	u32 dmaintl;		/* DMA Interrupt Request		*/
+	u32 dmaerrh;		/* DMA Error				*/
+	u32 dmaerrl;		/* DMA Error				*/
+	u32 dmahrsh;		/* DMA Hardware Request status		*/
+	u32 dmahrsl;		/* DMA HardWired Request status		*/
+	u32 dmagpor;		/* DMA General Purpose Register		*/
+	u8 reserved0[0xC4];
+	u8 dchpri[DMA_MAX_CHANNELS];	/* DMA Port Priority		*/
+	u8 reserved1[0xEFC];
+	struct tcd tcd[DMA_MAX_CHANNELS];	/*Transfer Control Descriptor */
+};
+
+/* TDM  Control Registers. */
+struct tdm_regs {
+	u32 gir;		/*  General Interface Register  */
+	u32 rir;		/*  Receive Interface Register  */
+	u32 tir;		/*  Transmit Interface Register */
+	u32 rfp;		/*  Receive Frame Parameters    */
+	u32 tfp;		/*  Transmit Frame Parameters   */
+	u8 reserved0[0xC];
+	u32 rcen[4];		/*  Recieve Channel Enabled     */
+	u8 reserved1[0x10];
+	u32 tcen[4];		/*  Transmit Channel Enabled    */
+	u8 reservedd2[0x10];
+	u32 tcma[4];		/*  Transmit Channel Mask       */
+	u8 reservederved3[0x10];
+	u32 rcr;		/*  Receiver Control Register           */
+	u32 tcr;		/*  Transmitter Control Register        */
+	u32 rier;		/*  Receive Interrupt Enable Register   */
+	u32 tier;		/*  Transmit Interrupt Enable Register  */
+	u8 reserved4[0x10];
+	u32 rer;		/*  Receive Event Register              */
+	u32 ter;		/*  Transmit Event Register             */
+	u32 rsr;		/*  Receive Status Register             */
+	u32 tsr;		/*  Transmit Status Register            */
+};
+
+struct tdm_data {
+	u64 rdr;		/* Receive Data Register */
+	u64 tdr;		/* Transmit Dataa Register */
+};
+
+struct tdm_clock {
+	u32 rx;			/* Transmit Dataa Register */
+	u32 tx;			/* Receive Data Register */
+};
+
+
+struct tdm_priv {
+	struct tdm_regs __iomem *tdm_regs;
+	struct tdm_data __iomem *data_regs;
+	struct dmac_regs __iomem *dmac_regs;
+	struct tdm_clock __iomem *clk_regs;
+	u32 ptdm_base;
+	u8 *tdm_input_data;
+	u8 *tdm_output_data;
+	dma_addr_t dma_input_paddr;	/* dma mapped buffer for TDM Rx */
+	dma_addr_t dma_output_paddr;	/* dma mapped buffer for TDM Tx */
+	void *dma_input_vaddr;
+	void *dma_output_vaddr;
+	u32 phase_rx;
+	u32 phase_tx;
+	struct tcd *dma_rx_tcd[NUM_OF_TDM_BUF];
+	struct tcd *dma_tx_tcd[NUM_OF_TDM_BUF];
+	dma_addr_t dma_rx_tcd_paddr;
+	dma_addr_t dma_tx_tcd_paddr;
+	void *dma_rx_tcd_vaddr;
+	void *dma_tx_tcd_vaddr;
+	u32 tdm_buffer_size;
+	u32 tdm_err_intr;
+	u32 dmac_err_intr;
+	u32 dmac_done_intr;
+	int tdm_active;
+	struct device *device;
+	spinlock_t tdmlock;
+	struct tdm_adapter *adap;
+};
+
+/* Extend a given size to make it alignable */
+static inline int ALIGNABLE_SIZE(u32 size, u32 alignment)
+{
+	return size + alignment - 1;
+}
+
+/* Align a given address */
+static inline void *ALIGN_ADDRESS(void *address, u32 alignment)
+{
+	return (void *)(((unsigned long) address + alignment - 1) &
+			(~(alignment - 1)));
+}
+
+/* Size of the buffer */
+static inline int TDM_1BUF_SIZE(u32 num_ch, u32 channel_size, u32 frame_size)
+{
+	return frame_size *
+		ALIGN(channel_size * num_ch, ALIGNED_8_BYTES);
+}
+
+/* Alignable size of the 3 buffers */
+static inline int TDM_3BUF_SIZE(u32 num_ch, u32 channel_size, u32 frame_size)
+{
+	return
+	    ALIGNABLE_SIZE((TDM_1BUF_SIZE(num_ch, channel_size, frame_size) *
+			    NUM_OF_TDM_BUF), ALIGNED_8_BYTES);
+}
+
+
+
+/* Initialize the Tx Transmit Control Descriptor parameters*/
+static void tx_tcd_init(struct tdm_priv *priv)
+{
+	int i;
+	u32 iter;
+	u32 offset;
+	dma_addr_t physaddr;
+	struct tdm_adapter *adap;
+	int bytes_in_fifo_per_frame;
+	adap = priv->adap;
+
+	if (!adap) {
+		dev_err(priv->device, "%s:Invalid handle\n", __func__);
+		return;
+	}
+	bytes_in_fifo_per_frame =
+		ALIGN(adap->adapt_cfg.num_ch * adap->adapt_cfg.slot_width, 8);
+
+	iter = (bytes_in_fifo_per_frame / NBYTES) * adap->adapt_cfg.num_frames;
+
+	for (i = 0; i < NUM_OF_TDM_BUF; i++) {
+		offset = i * adap->adapt_cfg.num_frames *
+			bytes_in_fifo_per_frame;
+		/* TCD word 0: source addr */
+		priv->dma_tx_tcd[i]->tcd[0] = (u32)priv->dma_output_paddr
+			+ offset;
+
+		/* TCD word 1: ssize=dsize=64bit, soff=8, smod=dmod=0 */
+		priv->dma_tx_tcd[i]->tcd[1] =
+			DMA_TCD1_SOFF(SOFF_VAL) | DMA_TCD1_SSIZE(SSIZE_64BITS) |
+			DMA_TCD1_DSIZE(SSIZE_64BITS);
+
+		/*
+		 * TCD word 2: number of bytes for minor loop, wide fifo
+		 *  8 bytes for dma
+		 */
+		priv->dma_tx_tcd[i]->tcd[2] = NBYTES;
+
+		/* TCD word 3: last source addr adjustment = 0 */
+		priv->dma_tx_tcd[i]->tcd[3] = SLAST;
+
+		/* TCD word 4: destination addr */
+		priv->dma_tx_tcd[i]->tcd[4] = TDM_TDR_OFFSET + priv->ptdm_base;
+
+		/*
+		 * channel to channel linking is disabled ,
+		 * destination offset is inc destination adr by 8,
+		 * current iteration(citer) = number of transfers for frame
+		 */
+		/* TCD word 5: citer count, dest addr offset */
+		priv->dma_tx_tcd[i]->tcd[5] = DMA_TCD5_CITER_DISABLE_LINK(iter);
+
+		/* TCD word 6: enable scater gather, interrupt on 1 Frame, */
+		priv->dma_tx_tcd[i]->tcd[6] = SLAST_SGA;
+
+		/*
+		 * TCD word 7: begining major iteration count(biter),
+		 * channel control/status
+		 */
+		priv->dma_tx_tcd[i]->tcd[7] =
+			DMA_TCD7_BITER_DISABLE_LINK(iter) | DMA_TCD7_E_SG;
+	}
+
+	/* Linking the TCDs togather for SG operation */
+	physaddr = priv->dma_tx_tcd_paddr;
+	priv->dma_tx_tcd[2]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+	physaddr += TCD_SIZE;
+	priv->dma_tx_tcd[0]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+	physaddr += TCD_SIZE;
+	priv->dma_tx_tcd[1]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+}
+
+/* Initialize the Rx Transmit Control Discriptor parameters */
+static void rx_tcd_init(struct tdm_priv *priv)
+{
+	int i;
+	u32 iter;
+	u32 offset;
+	dma_addr_t physaddr;
+	struct tdm_adapter *adap;
+	int bytes_in_fifo_per_frame;
+	adap = priv->adap;
+	bytes_in_fifo_per_frame =
+		ALIGN(adap->adapt_cfg.num_ch * adap->adapt_cfg.slot_width, 8);
+
+	iter = (bytes_in_fifo_per_frame / NBYTES) * adap->adapt_cfg.num_frames;
+
+	for (i = 0; i < NUM_OF_TDM_BUF; i++) {
+		/* TCD word 0: source addr */
+		priv->dma_rx_tcd[i]->tcd[0] = TDM_RDR_OFFSET + priv->ptdm_base;
+
+		/* TCD word 1: ssize=dsize=64bit, soff=smod=dmod=0 */
+		priv->dma_rx_tcd[i]->tcd[1] =
+			DMA_TCD1_SSIZE(SSIZE_64BITS) |
+			DMA_TCD1_DSIZE(SSIZE_64BITS);
+
+		/*
+		 * TCD word 2: number of bytes for minor loop,
+		 * wide fifo 8 bytes for dma
+		 */
+		priv->dma_rx_tcd[i]->tcd[2] = NBYTES;
+
+		/* TCD word 3: last source addr adjustment = 0 */
+		priv->dma_rx_tcd[i]->tcd[3] = SLAST;
+
+		offset = i * adap->adapt_cfg.num_frames *
+			bytes_in_fifo_per_frame;
+
+		/* TCD word 4: destination addr */
+		priv->dma_rx_tcd[i]->tcd[4] = (u32)priv->dma_input_paddr
+			+ offset;
+
+		/*
+		 * channel to channel linking is disabled ,
+		 * destination offset is inc destination adr by 8,
+		 * current iteration(citer) = number of transfers for frame
+		 */
+		/* TCD word 5: citer count, dest addr offset */
+		priv->dma_rx_tcd[i]->tcd[5] =
+			DMA_TCD5_DOFF(DOFF_VAL) |
+			DMA_TCD5_CITER_DISABLE_LINK(iter);
+
+		/* TCD word 6: enable scater gather, interrupt on 1 Frame, */
+		priv->dma_rx_tcd[i]->tcd[6] = DLAST_SGA;
+
+		/*
+		 * TCD word 7: begining major iteration count(biter),
+		 * channel control/status
+		 */
+		priv->dma_rx_tcd[i]->tcd[7] =
+			DMA_TCD7_BITER_DISABLE_LINK(iter) | DMA_TCD7_E_SG |
+			DMA_TCD7_INT_MAJ;
+	}
+
+	/* Next TCD for SG operation */
+	physaddr = priv->dma_rx_tcd_paddr;
+	priv->dma_rx_tcd[2]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+	physaddr += TCD_SIZE;
+	priv->dma_rx_tcd[0]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+	physaddr += TCD_SIZE;
+	priv->dma_rx_tcd[1]->tcd[6] = ALIGN(physaddr, ALIGNED_32_BYTES);
+}
+
+static irqreturn_t dmac_done_isr(int irq, void *p)
+{
+	u32 ch;
+	int ret = IRQ_NONE;
+	struct tdm_priv *priv;
+
+	priv = p;
+
+	ch = in_be32(&priv->dmac_regs->dmaintl);
+
+	/* clear interrupt */
+	if (ch & DMAC_RX_INT) {
+		out_8(&priv->dmac_regs->dmacint, TDMRX_DMA_CH);
+		ret = IRQ_HANDLED;
+		/* track phases for Rx/Tx */
+		priv->phase_rx += 1;
+		if (priv->phase_rx == NUM_OF_TDM_BUF)
+			priv->phase_rx = 0;
+	}
+	if (ch & DMAC_TX_INT) {
+		out_8(&priv->dmac_regs->dmacint, TDMTX_DMA_CH);
+		ret = IRQ_HANDLED;
+	}
+
+	if (ret == IRQ_HANDLED) {
+		/* set the flag and wake up the thread */
+		priv->adap->tdm_rx_flag = 1;
+
+		/* schedule the tasklet */
+		if (priv->adap->tasklet_conf)
+			tasklet_schedule(&priv->adap->tdm_data_tasklet);
+	}
+	return ret;
+}
+
+static int init_tdm(struct tdm_priv *priv)
+{
+	u8 *buf;
+	int i;
+	int buf_size;
+	dma_addr_t physaddr = 0;
+	int ret = 0;
+	struct tdm_adapter *adap;
+
+
+	adap = priv->adap;
+
+	/*
+	 * Allocate memory for Rx/Tx buffer according to active time slots
+	 * BufferSize = NUM_OF_TDM_BUF * NUM_SAMPLES_PER_FRAME * slot_width *
+	 * num_ch
+	 */
+	/*Allocating Rx Buffer*/
+	buf_size = TDM_3BUF_SIZE(adap->adapt_cfg.num_ch,
+			adap->adapt_cfg.slot_width,
+			adap->adapt_cfg.num_frames);
+	buf = dma_alloc_coherent(priv->device, buf_size, &physaddr, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_alloc_ip;
+	}
+	priv->dma_input_paddr = physaddr;
+	priv->dma_input_vaddr = buf;
+	priv->tdm_input_data = ALIGN_ADDRESS(buf, ALIGNED_8_BYTES);
+
+	buf = dma_alloc_coherent(priv->device, buf_size, &physaddr, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_alloc_op;
+	}
+	priv->dma_output_paddr = physaddr;
+	priv->dma_output_vaddr = buf;
+	priv->tdm_output_data = ALIGN_ADDRESS(buf, ALIGNED_8_BYTES);
+
+	/* allocate memory for TCD buffer descriptors */
+	buf = dma_alloc_coherent(priv->device, NUM_OF_TDM_BUF * TCD_SIZE,
+			&physaddr, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_alloc_rx;
+	}
+
+	memset(buf, 0, NUM_OF_TDM_BUF * TCD_SIZE);
+	priv->dma_rx_tcd_paddr = physaddr;
+	priv->dma_rx_tcd_vaddr = buf;
+	for (i = 0; i < NUM_OF_TDM_BUF; i++) {
+		priv->dma_rx_tcd[i] = ALIGN_ADDRESS(buf, ALIGNED_32_BYTES);
+		buf += TCD_SIZE;
+	}
+
+	buf = dma_alloc_coherent(priv->device, 3 * TCD_SIZE, &physaddr,
+			GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_alloc_tx;
+	}
+	memset(buf, 0, NUM_OF_TDM_BUF * TCD_SIZE);
+	priv->dma_tx_tcd_paddr = physaddr;
+	priv->dma_tx_tcd_vaddr = buf;
+	for (i = 0; i < NUM_OF_TDM_BUF; i++) {
+		priv->dma_tx_tcd[i] = ALIGN_ADDRESS(buf, ALIGNED_32_BYTES);
+		buf += TCD_SIZE;
+	}
+
+	priv->phase_rx = 0;
+	priv->phase_tx = 0;
+	return 0;
+
+err_alloc_tx:
+	dma_free_coherent(priv->device, NUM_OF_TDM_BUF * TCD_SIZE,
+			priv->dma_rx_tcd_vaddr, priv->dma_rx_tcd_paddr);
+err_alloc_rx:
+	dma_free_coherent(priv->device, buf_size, priv->dma_output_vaddr,
+			priv->dma_output_paddr);
+err_alloc_op:
+	dma_free_coherent(priv->device, buf_size, priv->dma_input_vaddr,
+			priv->dma_input_paddr);
+err_alloc_ip:
+	return ret;
+}
+
+/* TDM register programming */
+static int tdm_fsl_reg_init(struct tdm_priv *priv)
+{
+	int i;
+	int ch_size_type;
+	struct tdm_adapter *adap;
+
+	if (!priv) {
+		pr_err("%s: Invalid handle\n", __func__);
+		return -EINVAL;
+	}
+	adap = priv->adap;
+
+	/* channel/group round robin */
+	out_be32(&priv->dmac_regs->dmacr, DMACR_ERGA | DMACR_ERCA);
+	/* Enable error Interrupts for TDM Rx &Tx */
+	out_8(&priv->dmac_regs->dmaseei, TDMTX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaseei);
+	out_8(&priv->dmac_regs->dmaseei, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaseei);
+	out_be32(&priv->dmac_regs->dmagpor, DMAGPOR_SNOOP);
+
+	tx_tcd_init(priv);
+	rx_tcd_init(priv);
+
+	/* TDM RD->TD loopback, Share T/R Fsync,Clock */
+	if (adap->adapt_cfg.loopback)
+		out_be32(&priv->tdm_regs->gir, GIR_LPBK | GIR_RTS);
+	else
+		out_be32(&priv->tdm_regs->gir, GIR_RTS);
+
+	/*
+	 *  Rx Water mark 0,  FIFO enable,  Wide fifo, DMA enable for RX,
+	 *  Receive Sync out, syncwidth = ch width, Rx clk out,zero sync,
+	 *  falling edge , data order
+	 */
+
+	out_be32(&priv->tdm_regs->rir,
+			RIR_RFWM(RIR_RFWM_VAL) | RIR_RFEN | RIR_RWEN |
+			RIR_RDMA | RIR_RSL | RIR_RSO | RIR_RCOE | RIR_RRDO |
+			RIR_RFSD(RIR_RFSD_VAL));
+	out_be32(&priv->tdm_regs->tir,
+			TIR_TFWM(TIR_RFWM_VAL) | TIR_TFEN | TIR_TWEN |
+			TIR_TDMA | TIR_TSL | TIR_TSO | TIR_TRDO |
+			TIR_TFSD(TIR_RFSD_VAL));
+
+	/* no of channels ,Channel size-coading */
+	switch (adap->adapt_cfg.ch_size_type) {
+	case CHANNEL_8BIT_LIN:
+		ch_size_type = CHANNEL_8BIT_LIN;
+		break;
+	case CHANNEL_8BIT_ULAW:
+		ch_size_type = CHANNEL_8BIT_ULAW;
+		break;
+	case CHANNEL_8BIT_ALAW:
+		ch_size_type = CHANNEL_8BIT_ALAW;
+		break;
+	case CHANNEL_16BIT_LIN:
+		ch_size_type = CHANNEL_16BIT_LIN;
+		break;
+	default:
+		dev_err(priv->device, "%s:Invalid channel size_type\n"
+				"Setting channel to default size: 16 bits",
+				__func__);
+		ch_size_type = CHANNEL_16BIT_LIN;
+	}
+	out_be32(&priv->tdm_regs->rfp,
+			RFP_RNCF(adap->adapt_cfg.num_ch) |
+			RFP_RCS(ch_size_type));
+	out_be32(&priv->tdm_regs->tfp,
+			TFP_TNCF(adap->adapt_cfg.num_ch) |
+			TFP_TCS(ch_size_type));
+
+	out_be32(&priv->tdm_regs->rier, 0);
+	out_be32(&priv->tdm_regs->tier, 0);
+
+	/* clear all receive and transmit chs */
+	for (i = 0; i < 4; i++) {
+		out_be32(&priv->tdm_regs->tcma[i], 0);
+		out_be32(&priv->tdm_regs->tcen[i], 0);
+		out_be32(&priv->tdm_regs->rcen[i], 0);
+	}
+
+	return 0;
+
+}
+
+static void tdm_fsl_stop(struct tdm_priv *priv)
+{
+	/* stop the Tx & Rx */
+	out_be32(&priv->tdm_regs->tcr, 0);
+	out_be32(&priv->tdm_regs->rcr, 0);
+
+	/* Clear DMA error Enable Request DMAEEIH/L */
+	out_8(&priv->dmac_regs->dmaceei, TDMTX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaceei);
+	out_8(&priv->dmac_regs->dmaceei, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaceei);
+	out_8(&priv->dmac_regs->dmacint, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmacint);
+	out_8(&priv->dmac_regs->dmacint, TDMTX_DMA_CH);
+	in_8(&priv->dmac_regs->dmacint);
+
+	/* disable the dma request */
+	out_8(&priv->dmac_regs->dmacerq, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmacerq);
+	out_8(&priv->dmac_regs->dmacerq, TDMTX_DMA_CH);
+}
+
+static int tdm_fsl_disable(struct tdm_adapter *adap)
+{
+	struct tdm_priv *priv;
+
+	priv = adap->data;
+	if (priv->tdm_active == 0) {
+		dev_warn(priv->device, "already Disabled");
+		return 0;
+	}
+
+	spin_lock(&priv->tdmlock);
+	priv->tdm_active = 0;
+	spin_unlock(&priv->tdmlock);
+
+	return 0;
+}
+
+static int tdm_fsl_enable(struct tdm_adapter *adap)
+{
+	int i;
+	u32 ch_enab[NUM_TDMTCEN_REG] = {0};
+	unsigned long timeout;
+	struct tdm_priv *priv;
+	u32 ph;
+
+	priv = adap->data;
+	ph = priv->phase_tx;
+
+	if (priv->tdm_active == 1) {
+		dev_warn(priv->device, "already Enabled");
+		return 0;
+	}
+
+	/* enable the Channels required 0 to number of ch -1 */
+	for (i = 0; i < adap->adapt_cfg.num_ch; i++)
+		ch_enab[i / TDMTCEN_REG_LEN] |= (1 << (i & 0x1F));
+
+	for (i = 0; i < NUM_TDMTCEN_REG; i++) {
+		out_be32(&priv->tdm_regs->rcen[i], ch_enab[i]);
+		out_be32(&priv->tdm_regs->tcen[i], ch_enab[i]);
+	}
+
+	/* Clear the DONE bit */
+	out_8(&priv->dmac_regs->dmacdne, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmacdne);
+	out_8(&priv->dmac_regs->dmacdne, TDMTX_DMA_CH);
+
+	/* Load the Tx  transfer control descriptors */
+	for (i = 0; i < MAX_TCD_WORD; i++)
+		out_be32(&priv->dmac_regs->tcd[TDMTX_DMA_CH].tcd[i],
+				priv->dma_tx_tcd[ph]->tcd[i]);
+
+	/* Load the Rx  transfer control descriptors */
+	for (i = 0; i < MAX_TCD_WORD; i++)
+		out_be32(&priv->dmac_regs->tcd[TDMRX_DMA_CH].tcd[i],
+				priv->dma_rx_tcd[ph]->tcd[i]);
+
+	/* enable the dma request */
+	out_8(&priv->dmac_regs->dmaserq, TDMRX_DMA_CH);
+	in_8(&priv->dmac_regs->dmaserq);
+	out_8(&priv->dmac_regs->dmaserq, TDMTX_DMA_CH);
+
+	/* Enable Receiver, transmitter */
+	timeout = jiffies + TDM_ENABLE_TIMEOUT;
+	out_be32(&priv->tdm_regs->tcr, TCR_TEN);
+	spin_event_timeout(!(in_be32(&priv->tdm_regs->tsr) & TSR_TENS),
+			timeout, 0);
+
+	timeout = jiffies + TDM_ENABLE_TIMEOUT;
+	out_be32(&priv->tdm_regs->rcr, RCR_REN);
+	spin_event_timeout(!(in_be32(&priv->tdm_regs->rsr) & RSR_RENS),
+			timeout, 0);
+
+	spin_lock(&priv->tdmlock);
+	priv->tdm_active = 1;
+	spin_unlock(&priv->tdmlock);
+
+	return 1;
+}
+
+static u32 tdm_fsl_read(struct tdm_adapter *adap,
+		u16 **input_tdm_buffer)
+{
+	struct tdm_priv *priv;
+	u32 phase_rx;
+	u32 buf_addr, buf_size;
+	int bytes_in_fifo_per_frame;
+
+	/* point to where to start for the current phase data processing */
+	bytes_in_fifo_per_frame =
+		ALIGN(adap->adapt_cfg.num_ch * adap->adapt_cfg.slot_width, 8);
+
+	priv = adap->data;
+	if (!priv) {
+		pr_err("%s: Invalid handle\n", __func__);
+		return -EINVAL;
+	}
+
+	if (priv->tdm_active == 0) {
+		dev_warn(priv->device, "TDM is not ready");
+		return 0;
+	}
+
+	if (priv->phase_rx == 0)
+		phase_rx = NUM_OF_TDM_BUF - 1;
+	else
+		phase_rx = priv->phase_rx - 1;
+
+	buf_size = bytes_in_fifo_per_frame * adap->adapt_cfg.num_frames;
+	buf_addr = buf_size * phase_rx;
+	*input_tdm_buffer = (u16 *)(priv->tdm_input_data + buf_addr);
+
+	return buf_size;
+}
+
+static u32 tdm_fsl_get_write_buf(struct tdm_adapter *adap,
+		u16 **output_tdm_buffer)
+{
+	struct tdm_priv *priv;
+	u32 tmp;
+	u32 phase_tx;
+	u32 buf_addr, buf_size;
+	int bytes_in_fifo_per_frame;
+
+	/* point to where to start for the current phase data processing */
+	bytes_in_fifo_per_frame =
+		ALIGN(adap->adapt_cfg.num_ch * adap->adapt_cfg.slot_width, 8);
+
+	priv = adap->data;
+	if (!priv) {
+		pr_err("%s: Invalid handle\n", __func__);
+		return -EINVAL;
+	}
+
+	if (priv->tdm_active == 0) {
+		dev_warn(priv->device, "TDM is not ready");
+		return 0;
+	}
+
+	tmp = in_be32(&priv->dmac_regs->tcd[TDMTX_DMA_CH].tcd[0]);
+
+	tmp -= priv->dma_tx_tcd[0]->tcd[0];
+
+	priv->phase_tx = tmp/(bytes_in_fifo_per_frame *
+			adap->adapt_cfg.num_frames);
+
+	if (priv->phase_tx == 0)
+		phase_tx = NUM_OF_TDM_BUF - 1;
+	else
+		phase_tx = priv->phase_tx - 1;
+
+	buf_size = bytes_in_fifo_per_frame * adap->adapt_cfg.num_frames;
+	buf_addr = buf_size * phase_tx;
+	*output_tdm_buffer = (u16 *)(priv->tdm_output_data + buf_addr);
+
+	return buf_size;
+}
+
+static const struct tdm_adapt_algorithm tdm_algo = {
+	.tdm_read = tdm_fsl_read,
+	.tdm_get_write_buf = tdm_fsl_get_write_buf,
+	.tdm_enable = tdm_fsl_enable,
+	.tdm_disable = tdm_fsl_disable,
+};
+
+static struct tdm_adapter tdm_fsl_ops = {
+	.owner = THIS_MODULE,
+	.name = "fsl_tdm",
+	.algo = &tdm_algo,
+};
+
+static int __devinit tdm_fsl_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct tdm_priv *priv;
+	struct resource res;
+
+	priv = kzalloc(sizeof(struct tdm_priv), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	dev_set_drvdata(&pdev->dev, priv);
+	priv->device = &pdev->dev;
+	ret = of_address_to_resource(pdev->dev.of_node, 0, &res);
+	if (ret) {
+		ret = -EINVAL;
+		goto err_resource;
+	}
+
+	priv->ptdm_base = (u32)res.start;
+	priv->tdm_regs = of_iomap(pdev->dev.of_node, 0);
+	if (!priv->tdm_regs) {
+		ret = -ENOMEM;
+		goto err_tdmregs;
+	}
+
+	priv->dmac_regs = of_iomap(pdev->dev.of_node, 1);
+	if (!priv->dmac_regs) {
+		ret = -ENOMEM;
+		goto err_dmacreg;
+	}
+
+	priv->dmac_done_intr = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (priv->dmac_done_intr ==  NO_IRQ) {
+		ret = -EINVAL;
+		goto err_dmacdone_irqmap;
+	}
+	ret = request_irq(priv->dmac_done_intr, dmac_done_isr, 0,
+			"dmac_done_isr", priv);
+	if (ret)
+		goto err_dmacdoneisr;
+
+	priv->adap = &tdm_fsl_ops;
+
+	/* Wait q initilization */
+	priv->adap->tdm_rx_flag = 0;
+	/* TODO - these should be configured by dts or init time */
+	priv->adap->data = priv;
+	priv->adap->parent = &pdev->dev;
+
+	ret = tdm_add_adapter(priv->adap);
+	if (ret < 0) {
+		dev_err(priv->device, "failed to add adapter\n");
+		goto fail_adapter;
+	}
+
+	/* Device does not supports 36 bit mode */
+	dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+	ret = init_tdm(priv);
+	if (ret)
+		goto err_tdminit;
+
+	tdm_fsl_reg_init(priv);
+
+	spin_lock_init(&priv->tdmlock);
+	priv->tdm_active = 0;
+
+	if (tdmen) {
+		ret = tdm_fsl_enable(priv->adap);
+		if (!ret)
+			goto err_tdminit;
+	}
+
+	return 0;
+
+err_tdminit:
+fail_adapter:
+	free_irq(priv->dmac_done_intr, priv);
+err_dmacdoneisr:
+	free_irq(priv->tdm_err_intr, priv);
+err_dmacdone_irqmap:
+	irq_dispose_mapping(priv->dmac_done_intr);
+err_dmacreg:
+	iounmap(priv->dmac_regs);
+err_tdmregs:
+err_resource:
+	dev_set_drvdata(&pdev->dev, NULL);
+	kfree(priv);
+err_alloc:
+	return ret;
+}
+
+static int __devexit tdm_fsl_remove(struct platform_device *pdev)
+{
+	struct tdm_priv *priv;
+	int buf_size;
+	struct tdm_adapter *adap;
+
+	if (!pdev) {
+		pr_err("%s: Invalid handle\n", __func__);
+		return -EINVAL;
+	}
+
+	priv = dev_get_drvdata(&pdev->dev);
+	adap = priv->adap;
+
+	tdm_fsl_disable(priv->adap);
+
+	tdm_fsl_stop(priv);
+
+	tdm_del_adapter(priv->adap);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	/* free the irqs and dispose their mapping */
+	free_irq(priv->tdm_err_intr, priv);
+	free_irq(priv->dmac_done_intr, priv);
+	irq_dispose_mapping(priv->tdm_err_intr);
+	irq_dispose_mapping(priv->dmac_done_intr);
+	iounmap(priv->tdm_regs);
+	iounmap(priv->dmac_regs);
+
+	/* free the buffers */
+	buf_size =
+		TDM_3BUF_SIZE(adap->adapt_cfg.num_ch,
+				adap->adapt_cfg.slot_width,
+				adap->adapt_cfg.num_frames);
+	dma_free_coherent(priv->device, buf_size, priv->dma_input_vaddr,
+			priv->dma_input_paddr);
+	dma_free_coherent(priv->device, buf_size, priv->dma_output_vaddr,
+			priv->dma_output_paddr);
+
+	/* free the TCDs */
+	dma_free_coherent(priv->device, NUM_OF_TDM_BUF * TCD_SIZE,
+			priv->dma_rx_tcd_vaddr,  priv->dma_rx_tcd_paddr);
+	dma_free_coherent(priv->device, NUM_OF_TDM_BUF * TCD_SIZE,
+			priv->dma_tx_tcd_vaddr,  priv->dma_tx_tcd_paddr);
+	dev_set_drvdata(&pdev->dev, NULL);
+	kfree(priv);
+	return 0;
+}
+
+static const struct of_device_id fsl_tdm_match[] = {
+	{
+		.compatible = "fsl,tdm1.0",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, fsl_tdm_match);
+
+static struct platform_driver tdm_fsl_driver = {
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= DRV_NAME,
+		.of_match_table	= fsl_tdm_match,
+
+	},
+	.probe		= tdm_fsl_probe,
+	.remove		= __devexit_p(tdm_fsl_remove),
+};
+
+static int __init tdm_fsl_init(void)
+{
+	int ret;
+	pr_info(DRV_NAME ": " DRV_DESC ":Init\n");
+	ret = platform_driver_register(&tdm_fsl_driver);
+	if (ret)
+		pr_err(DRV_NAME  "of_register_platform_driver failed (%i)\n",
+				ret);
+	return ret;
+}
+
+static void __exit tdm_fsl_exit(void)
+{
+	pr_info(DRV_NAME ": " DRV_DESC ":Exit\n");
+	platform_driver_unregister(&tdm_fsl_driver);
+}
+
+module_init(tdm_fsl_init);
+module_exit(tdm_fsl_exit);
+/*
+   module_platform_driver(tdm_fsl_driver);
+ */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("P.V.Suresh, Freescale Semiconductor");
+MODULE_DESCRIPTION("Driver For Freescale TDM controller");
-- 
1.5.6.5

^ permalink raw reply related

* [PATCH v8 0/7] power management patch set
From: Zhao Chenhui @ 2012-07-20 12:42 UTC (permalink / raw)
  To: linuxppc-dev, scottwood, galak; +Cc: linux-kernel

Changes for v8:
* Separated the cpu hotplug patch into three patches, as follows
  [PATCH v8 1/7] powerpc/smp: use a struct epapr_spin_table to replace macros
  [PATCH v8 2/7] powerpc/smp: add generic_set_cpu_up() to set cpu_state as CPU_UP_PREPARE
  [PATCH v8 4/7] powerpc/85xx: add HOTPLUG_CPU support

* Replaced magic numbers with macros in "[PATCH 5/7] powerpc/85xx: add sleep and deep sleep support"

* no change to the rest of the patch set

^ permalink raw reply

* [PATCH v8 1/7] powerpc/smp: use a struct epapr_spin_table to replace macros
From: Zhao Chenhui @ 2012-07-20 12:42 UTC (permalink / raw)
  To: linuxppc-dev, scottwood, galak; +Cc: linux-kernel
In-Reply-To: <1342788159-27529-1-git-send-email-chenhui.zhao@freescale.com>

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
 arch/powerpc/platforms/85xx/smp.c |   46 ++++++++++++++++++------------------
 1 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index ff42490..4827709 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -2,7 +2,7 @@
  * Author: Andy Fleming <afleming@freescale.com>
  * 	   Kumar Gala <galak@kernel.crashing.org>
  *
- * Copyright 2006-2008, 2011 Freescale Semiconductor Inc.
+ * Copyright 2006-2008, 2011-2012 Freescale Semiconductor Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/kexec.h>
 #include <linux/highmem.h>
+#include <linux/cpu.h>
 
 #include <asm/machdep.h>
 #include <asm/pgtable.h>
@@ -31,23 +32,21 @@
 
 extern void __early_start(void);
 
-#define BOOT_ENTRY_ADDR_UPPER	0
-#define BOOT_ENTRY_ADDR_LOWER	1
-#define BOOT_ENTRY_R3_UPPER	2
-#define BOOT_ENTRY_R3_LOWER	3
-#define BOOT_ENTRY_RESV		4
-#define BOOT_ENTRY_PIR		5
-#define BOOT_ENTRY_R6_UPPER	6
-#define BOOT_ENTRY_R6_LOWER	7
-#define NUM_BOOT_ENTRY		8
-#define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32))
+struct epapr_spin_table {
+	u32	addr_h;
+	u32	addr_l;
+	u32	r3_h;
+	u32	r3_l;
+	u32	reserved;
+	u32	pir;
+};
 
 static int __init
 smp_85xx_kick_cpu(int nr)
 {
 	unsigned long flags;
 	const u64 *cpu_rel_addr;
-	__iomem u32 *bptr_vaddr;
+	__iomem struct epapr_spin_table *spin_table;
 	struct device_node *np;
 	int n = 0, hw_cpu = get_hard_smp_processor_id(nr);
 	int ioremappable;
@@ -75,19 +74,20 @@ smp_85xx_kick_cpu(int nr)
 
 	/* Map the spin table */
 	if (ioremappable)
-		bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
+		spin_table = ioremap(*cpu_rel_addr,
+				sizeof(struct epapr_spin_table));
 	else
-		bptr_vaddr = phys_to_virt(*cpu_rel_addr);
+		spin_table = phys_to_virt(*cpu_rel_addr);
 
 	local_irq_save(flags);
 
-	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, hw_cpu);
+	out_be32(&spin_table->pir, hw_cpu);
 #ifdef CONFIG_PPC32
-	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
+	out_be32(&spin_table->addr_l, __pa(__early_start));
 
 	if (!ioremappable)
-		flush_dcache_range((ulong)bptr_vaddr,
-				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+		flush_dcache_range((ulong)spin_table,
+			(ulong)spin_table + sizeof(struct epapr_spin_table));
 
 	/* Wait a bit for the CPU to ack. */
 	while ((__secondary_hold_acknowledge != hw_cpu) && (++n < 1000))
@@ -95,18 +95,18 @@ smp_85xx_kick_cpu(int nr)
 #else
 	smp_generic_kick_cpu(nr);
 
-	out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
-		__pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
+	out_be64((u64 *)(&spin_table->addr_h),
+	  __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
 
 	if (!ioremappable)
-		flush_dcache_range((ulong)bptr_vaddr,
-				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+		flush_dcache_range((ulong)spin_table,
+			(ulong)spin_table + sizeof(struct epapr_spin_table));
 #endif
 
 	local_irq_restore(flags);
 
 	if (ioremappable)
-		iounmap(bptr_vaddr);
+		iounmap(spin_table);
 
 	pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
 
-- 
1.6.4.1

^ permalink raw reply related

* [PATCH v8 3/7] powerpc/85xx: implement hardware timebase sync
From: Zhao Chenhui @ 2012-07-20 12:42 UTC (permalink / raw)
  To: linuxppc-dev, scottwood, galak; +Cc: linux-kernel
In-Reply-To: <1342788159-27529-1-git-send-email-chenhui.zhao@freescale.com>

Do hardware timebase sync. Firstly, stop all timebases, and transfer
the timebase value of the boot core to the other core. Finally,
start all timebases.

Only apply to dual-core chips, such as MPC8572, P2020, etc.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
 arch/powerpc/include/asm/fsl_guts.h |    2 +
 arch/powerpc/platforms/85xx/smp.c   |   82 +++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index aa4c488..dd5ba2c 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -48,6 +48,8 @@ struct ccsr_guts {
         __be32  dmuxcr;		/* 0x.0068 - DMA Mux Control Register */
         u8	res06c[0x70 - 0x6c];
 	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
+#define CCSR_GUTS_DEVDISR_TB1	0x00001000
+#define CCSR_GUTS_DEVDISR_TB0	0x00004000
 	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
 	u8	res078[0x7c - 0x78];
 	__be32  pmjcr;		/* 0x.007c - 4 Power Management Jog Control Register */
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 4827709..7ed52a6 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -25,6 +25,7 @@
 #include <asm/mpic.h>
 #include <asm/cacheflush.h>
 #include <asm/dbell.h>
+#include <asm/fsl_guts.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/mpic.h>
@@ -41,6 +42,64 @@ struct epapr_spin_table {
 	u32	pir;
 };
 
+static struct ccsr_guts __iomem *guts;
+static u64 timebase;
+static int tb_req;
+static int tb_valid;
+
+static void mpc85xx_timebase_freeze(int freeze)
+{
+	uint32_t mask;
+
+	mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
+	if (freeze)
+		setbits32(&guts->devdisr, mask);
+	else
+		clrbits32(&guts->devdisr, mask);
+
+	in_be32(&guts->devdisr);
+}
+
+static void mpc85xx_give_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	while (!tb_req)
+		barrier();
+	tb_req = 0;
+
+	mpc85xx_timebase_freeze(1);
+	timebase = get_tb();
+	mb();
+	tb_valid = 1;
+
+	while (tb_valid)
+		barrier();
+
+	mpc85xx_timebase_freeze(0);
+
+	local_irq_restore(flags);
+}
+
+static void mpc85xx_take_timebase(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	tb_req = 1;
+	while (!tb_valid)
+		barrier();
+
+	set_tb(timebase >> 32, timebase & 0xffffffff);
+	isync();
+	tb_valid = 0;
+
+	local_irq_restore(flags);
+}
+
 static int __init
 smp_85xx_kick_cpu(int nr)
 {
@@ -228,6 +287,16 @@ smp_85xx_setup_cpu(int cpu_nr)
 		doorbell_setup_this_cpu();
 }
 
+static const struct of_device_id mpc85xx_smp_guts_ids[] = {
+	{ .compatible = "fsl,mpc8572-guts", },
+	{ .compatible = "fsl,p1020-guts", },
+	{ .compatible = "fsl,p1021-guts", },
+	{ .compatible = "fsl,p1022-guts", },
+	{ .compatible = "fsl,p1023-guts", },
+	{ .compatible = "fsl,p2020-guts", },
+	{},
+};
+
 void __init mpc85xx_smp_init(void)
 {
 	struct device_node *np;
@@ -249,6 +318,19 @@ void __init mpc85xx_smp_init(void)
 		smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
 	}
 
+	np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
+	if (np) {
+		guts = of_iomap(np, 0);
+		of_node_put(np);
+		if (!guts) {
+			pr_err("%s: Could not map guts node address\n",
+								__func__);
+			return;
+		}
+		smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
+		smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
+	}
+
 	smp_ops = &smp_85xx_ops;
 
 #ifdef CONFIG_KEXEC
-- 
1.6.4.1

^ permalink raw reply related

* [PATCH v8 2/7] powerpc/smp: add generic_set_cpu_up() to set cpu_state as CPU_UP_PREPARE
From: Zhao Chenhui @ 2012-07-20 12:42 UTC (permalink / raw)
  To: linuxppc-dev, scottwood, galak; +Cc: linux-kernel
In-Reply-To: <1342788159-27529-1-git-send-email-chenhui.zhao@freescale.com>

In the case of cpu hotplug, the cpu_state should be set to CPU_UP_PREPARE when kicking cpu.
Otherwise, the cpu_state is always CPU_DEAD after calling generic_set_cpu_dead(), which
makes the delay in generic_cpu_die() not happen.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
 arch/powerpc/include/asm/smp.h |    1 +
 arch/powerpc/kernel/smp.c      |   12 +++++++++++-
 2 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index ebc24dc..ce8e2bd 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -65,6 +65,7 @@ int generic_cpu_disable(void);
 void generic_cpu_die(unsigned int cpu);
 void generic_mach_cpu_die(void);
 void generic_set_cpu_dead(unsigned int cpu);
+void generic_set_cpu_up(unsigned int cpu);
 int generic_check_cpu_restart(unsigned int cpu);
 #endif
 
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 0321007..fecb038 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -102,7 +102,7 @@ int __devinit smp_generic_kick_cpu(int nr)
 	 * Ok it's not there, so it might be soft-unplugged, let's
 	 * try to bring it back
 	 */
-	per_cpu(cpu_state, nr) = CPU_UP_PREPARE;
+	generic_set_cpu_up(nr);
 	smp_wmb();
 	smp_send_reschedule(nr);
 #endif /* CONFIG_HOTPLUG_CPU */
@@ -406,6 +406,16 @@ void generic_set_cpu_dead(unsigned int cpu)
 	per_cpu(cpu_state, cpu) = CPU_DEAD;
 }
 
+/*
+ * The cpu_state should be set to CPU_UP_PREPARE in kick_cpu(), otherwise
+ * the cpu_state is always CPU_DEAD after calling generic_set_cpu_dead(),
+ * which makes the delay in generic_cpu_die() not happen.
+ */
+void generic_set_cpu_up(unsigned int cpu)
+{
+	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+}
+
 int generic_check_cpu_restart(unsigned int cpu)
 {
 	return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE;
-- 
1.6.4.1

^ permalink raw reply related

* [PATCH v8 4/7] powerpc/85xx: add HOTPLUG_CPU support
From: Zhao Chenhui @ 2012-07-20 12:42 UTC (permalink / raw)
  To: linuxppc-dev, scottwood, galak; +Cc: linux-kernel
In-Reply-To: <1342788159-27529-1-git-send-email-chenhui.zhao@freescale.com>

Add support to disable and re-enable individual cores at runtime
on MPC85xx/QorIQ SMP machines. Currently support e500v1/e500v2 core.

MPC85xx machines use ePAPR spin-table in boot page for CPU kick-off.
This patch uses the boot page from bootloader to boot core at runtime.
It supports 32-bit and 36-bit physical address.

Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
 arch/powerpc/Kconfig                  |    6 ++-
 arch/powerpc/include/asm/cacheflush.h |    2 +
 arch/powerpc/include/asm/smp.h        |    1 +
 arch/powerpc/kernel/head_fsl_booke.S  |   28 ++++++++++
 arch/powerpc/platforms/85xx/smp.c     |   90 ++++++++++++++++++++++++++++-----
 5 files changed, 112 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 9a5d3cd..a7c6914 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -213,7 +213,8 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
 	def_bool y
 	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
-		   (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x
+		   (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
+		   || 44x || 40x
 
 config PPC_DCR_NATIVE
 	bool
@@ -323,7 +324,8 @@ config SWIOTLB
 
 config HOTPLUG_CPU
 	bool "Support for enabling/disabling CPUs"
-	depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV)
+	depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || \
+	PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
 	---help---
 	  Say Y here to be able to disable and re-enable individual
 	  CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index ab9e402..b843e35 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -30,6 +30,8 @@ extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
 
+extern void __flush_disable_L1(void);
+
 extern void __flush_icache_range(unsigned long, unsigned long);
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index ce8e2bd..e807e9d 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -191,6 +191,7 @@ extern unsigned long __secondary_hold_spinloop;
 extern unsigned long __secondary_hold_acknowledge;
 extern char __secondary_hold;
 
+extern void __early_start(void);
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 0f59863..b221541 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -1043,6 +1043,34 @@ _GLOBAL(flush_dcache_L1)
 
 	blr
 
+/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
+_GLOBAL(__flush_disable_L1)
+	mflr	r10
+	bl	flush_dcache_L1	/* Flush L1 d-cache */
+	mtlr	r10
+
+	mfspr	r4, SPRN_L1CSR0	/* Invalidate and disable d-cache */
+	li	r5, 2
+	rlwimi	r4, r5, 0, 3
+
+	msync
+	isync
+	mtspr	SPRN_L1CSR0, r4
+	isync
+
+1:	mfspr	r4, SPRN_L1CSR0	/* Wait for the invalidate to finish */
+	andi.	r4, r4, 2
+	bne	1b
+
+	mfspr	r4, SPRN_L1CSR1	/* Invalidate and disable i-cache */
+	li	r5, 2
+	rlwimi	r4, r5, 0, 3
+
+	mtspr	SPRN_L1CSR1, r4
+	isync
+
+	blr
+
 #ifdef CONFIG_SMP
 /* When we get here, r24 needs to hold the CPU # */
 	.globl __secondary_start
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 7ed52a6..6fcfa12 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -31,8 +31,6 @@
 #include <sysdev/mpic.h>
 #include "smp.h"
 
-extern void __early_start(void);
-
 struct epapr_spin_table {
 	u32	addr_h;
 	u32	addr_l;
@@ -100,15 +98,45 @@ static void mpc85xx_take_timebase(void)
 	local_irq_restore(flags);
 }
 
-static int __init
-smp_85xx_kick_cpu(int nr)
+#ifdef CONFIG_HOTPLUG_CPU
+static void __cpuinit smp_85xx_mach_cpu_die(void)
+{
+	unsigned int cpu = smp_processor_id();
+	u32 tmp;
+
+	local_irq_disable();
+	idle_task_exit();
+	generic_set_cpu_dead(cpu);
+	mb();
+
+	mtspr(SPRN_TCR, 0);
+
+	__flush_disable_L1();
+	tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP;
+	mtspr(SPRN_HID0, tmp);
+	isync();
+
+	/* Enter NAP mode. */
+	tmp = mfmsr();
+	tmp |= MSR_WE;
+	mb();
+	mtmsr(tmp);
+	isync();
+
+	while (1)
+		;
+}
+#endif
+
+static int __cpuinit smp_85xx_kick_cpu(int nr)
 {
 	unsigned long flags;
 	const u64 *cpu_rel_addr;
 	__iomem struct epapr_spin_table *spin_table;
 	struct device_node *np;
-	int n = 0, hw_cpu = get_hard_smp_processor_id(nr);
+	int hw_cpu = get_hard_smp_processor_id(nr);
 	int ioremappable;
+	int ret = 0;
 
 	WARN_ON(nr < 0 || nr >= NR_CPUS);
 	WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS);
@@ -139,9 +167,34 @@ smp_85xx_kick_cpu(int nr)
 		spin_table = phys_to_virt(*cpu_rel_addr);
 
 	local_irq_save(flags);
+#ifdef CONFIG_PPC32
+#ifdef CONFIG_HOTPLUG_CPU
+	/* Corresponding to generic_set_cpu_dead() */
+	generic_set_cpu_up(nr);
+
+	if (system_state == SYSTEM_RUNNING) {
+		out_be32(&spin_table->addr_l, 0);
 
+		/*
+		 * We don't set the BPTR register here since it already points
+		 * to the boot page properly.
+		 */
+		mpic_reset_core(hw_cpu);
+
+		/* wait until core is ready... */
+		if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1,
+						10000, 100)) {
+			pr_err("%s: timeout waiting for core %d to reset\n",
+							__func__, hw_cpu);
+			ret = -ENOENT;
+			goto out;
+		}
+
+		/*  clear the acknowledge status */
+		__secondary_hold_acknowledge = -1;
+	}
+#endif
 	out_be32(&spin_table->pir, hw_cpu);
-#ifdef CONFIG_PPC32
 	out_be32(&spin_table->addr_l, __pa(__early_start));
 
 	if (!ioremappable)
@@ -149,11 +202,18 @@ smp_85xx_kick_cpu(int nr)
 			(ulong)spin_table + sizeof(struct epapr_spin_table));
 
 	/* Wait a bit for the CPU to ack. */
-	while ((__secondary_hold_acknowledge != hw_cpu) && (++n < 1000))
-		mdelay(1);
+	if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
+					10000, 100)) {
+		pr_err("%s: timeout waiting for core %d to ack\n",
+						__func__, hw_cpu);
+		ret = -ENOENT;
+		goto out;
+	}
+out:
 #else
 	smp_generic_kick_cpu(nr);
 
+	out_be32(&spin_table->pir, hw_cpu);
 	out_be64((u64 *)(&spin_table->addr_h),
 	  __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
 
@@ -167,13 +227,15 @@ smp_85xx_kick_cpu(int nr)
 	if (ioremappable)
 		iounmap(spin_table);
 
-	pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
-
-	return 0;
+	return ret;
 }
 
 struct smp_ops_t smp_85xx_ops = {
 	.kick_cpu = smp_85xx_kick_cpu,
+#ifdef CONFIG_HOTPLUG_CPU
+	.cpu_disable	= generic_cpu_disable,
+	.cpu_die	= generic_cpu_die,
+#endif
 #ifdef CONFIG_KEXEC
 	.give_timebase	= smp_generic_give_timebase,
 	.take_timebase	= smp_generic_take_timebase,
@@ -277,8 +339,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
 }
 #endif /* CONFIG_KEXEC */
 
-static void __init
-smp_85xx_setup_cpu(int cpu_nr)
+static void __cpuinit smp_85xx_setup_cpu(int cpu_nr)
 {
 	if (smp_85xx_ops.probe == smp_mpic_probe)
 		mpic_setup_this_cpu();
@@ -329,6 +390,9 @@ void __init mpc85xx_smp_init(void)
 		}
 		smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
 		smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
+#ifdef CONFIG_HOTPLUG_CPU
+		ppc_md.cpu_die = smp_85xx_mach_cpu_die;
+#endif
 	}
 
 	smp_ops = &smp_85xx_ops;
-- 
1.6.4.1

^ permalink raw reply related

* [PATCH v8 5/7] powerpc/85xx: add sleep and deep sleep support
From: Zhao Chenhui @ 2012-07-20 12:42 UTC (permalink / raw)
  To: linuxppc-dev, scottwood, galak; +Cc: linux-kernel
In-Reply-To: <1342788159-27529-1-git-send-email-chenhui.zhao@freescale.com>

In sleep PM mode, the clocks of e500 core and unused IP blocks is
turned off. IP blocks which are allowed to wake up the processor
are still running.

Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode
in addtion to the sleep PM mode.

While in deep sleep PM mode, additionally, the power supply is
removed from e500 core and most IP blocks. Only the blocks needed
to wake up the chip out of deep sleep are ON.

This patch supports 32-bit and 36-bit address space.

The sleep mode is equal to the Standby state in Linux. The deep sleep
mode is equal to the Suspend-to-RAM state of Linux Power Management.

Command to enter sleep mode.
  echo standby > /sys/power/state
Command to enter deep sleep mode.
  echo mem > /sys/power/state

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
Cc: Scott Wood <scottwood@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
 arch/powerpc/Kconfig                  |    2 +-
 arch/powerpc/include/asm/cacheflush.h |    2 +
 arch/powerpc/kernel/Makefile          |    3 +
 arch/powerpc/kernel/l2cache_85xx.S    |   56 +++
 arch/powerpc/platforms/85xx/Makefile  |    2 +-
 arch/powerpc/platforms/85xx/sleep.S   |  621 +++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_pmc.c         |   98 +++++-
 arch/powerpc/sysdev/fsl_soc.h         |    5 +
 8 files changed, 769 insertions(+), 20 deletions(-)
 create mode 100644 arch/powerpc/kernel/l2cache_85xx.S
 create mode 100644 arch/powerpc/platforms/85xx/sleep.S

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a7c6914..9d6de82 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -665,7 +665,7 @@ config FSL_PCI
 config FSL_PMC
 	bool
 	default y
-	depends on SUSPEND && (PPC_85xx || PPC_86xx)
+	depends on SUSPEND && (PPC_85xx || PPC_86xx) && !PPC_E500MC
 	help
 	  Freescale MPC85xx/MPC86xx power management controller support
 	  (suspend/resume). For MPC83xx see platforms/83xx/suspend.c
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index b843e35..6c5f1c2 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -58,6 +58,8 @@ extern void flush_inval_dcache_range(unsigned long start, unsigned long stop);
 extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
 #endif
 
+extern void flush_dcache_L1(void);
+
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
 	do { \
 		memcpy(dst, src, len); \
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 83afacd..0ddef24 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -64,6 +64,9 @@ obj-$(CONFIG_FA_DUMP)		+= fadump.o
 ifeq ($(CONFIG_PPC32),y)
 obj-$(CONFIG_E500)		+= idle_e500.o
 endif
+ifneq ($(CONFIG_PPC_E500MC),y)
+obj-$(CONFIG_PPC_85xx)		+= l2cache_85xx.o
+endif
 obj-$(CONFIG_6xx)		+= idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
 obj-$(CONFIG_TAU)		+= tau_6xx.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o suspend.o
diff --git a/arch/powerpc/kernel/l2cache_85xx.S b/arch/powerpc/kernel/l2cache_85xx.S
new file mode 100644
index 0000000..e920d69
--- /dev/null
+++ b/arch/powerpc/kernel/l2cache_85xx.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009-2012 Freescale Semiconductor, Inc. All rights reserved.
+ *	Scott Wood <scottwood@freescale.com>
+ *	Dave Liu <daveliu@freescale.com>
+ * implement the L2 cache operations of e500 based L2 controller
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/reg.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+#define L2CTL_L2E	0x80000000
+#define L2CTL_L2I	0x40000000
+
+	.section .text
+
+	/* r3 = virtual address of L2 controller, WIMG = 01xx */
+_GLOBAL(flush_disable_L2)
+	/* It's a write-through cache, so only invalidation is needed. */
+	mbar
+	isync
+	lwz	r4, 0(r3)
+	li	r5, 1
+	rlwimi	r4, r5, 30, L2CTL_L2E | L2CTL_L2I
+	stw	r4, 0(r3)
+
+	/* Wait for the invalidate to finish */
+1:	lwz	r4, 0(r3)
+	andis.	r4, r4, L2CTL_L2I@h
+	bne	1b
+	mbar
+
+	blr
+
+	/* r3 = virtual address of L2 controller, WIMG = 01xx */
+_GLOBAL(invalidate_enable_L2)
+	mbar
+	isync
+	lwz	r4, 0(r3)
+	li	r5, 3
+	rlwimi	r4, r5, 30, L2CTL_L2E | L2CTL_L2I
+	stw	r4, 0(r3)
+
+	/* Wait for the invalidate to finish */
+1:	lwz	r4, 0(r3)
+	andis.	r4, r4, L2CTL_L2I@h
+	bne	1b
+	mbar
+
+	blr
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 3dfe811..405ab79 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,7 +3,7 @@
 #
 obj-$(CONFIG_SMP) += smp.o
 
-obj-y += common.o
+obj-y += common.o sleep.o
 
 obj-$(CONFIG_BSC9131_RDB) += bsc913x_rdb.o
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
diff --git a/arch/powerpc/platforms/85xx/sleep.S b/arch/powerpc/platforms/85xx/sleep.S
new file mode 100644
index 0000000..e6dfede
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sleep.S
@@ -0,0 +1,621 @@
+/*
+ * Enter and leave deep sleep/sleep state on MPC85xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (C) 2006-2012 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+#include <asm/mmu.h>
+
+#define CCSR_ADDR		0xf0000000
+
+#define L2C_OFFSET		0x20000	/* L2 Cache Controller offset */
+
+#define BPTR_OFFSET		0x20 /* Boot Page Translation Register */
+#define BPTR_EN			0x80000000
+
+#define PMRCCR_OFFSET		0xe0084
+#define PMRCCR_VRCNT_PRE_MASK	0x1f000000
+#define PMRCCR_VRCNT_MASK	0x00ff0000
+
+#define POWMGTSCR_OFFSET	0xe0080
+#define POWMGTSCR_DPSLP		0x00100000 /* deep sleep mode */
+
+#define SS_TB		0x00
+#define SS_HID		0x08 /* 2 HIDs */
+#define SS_IAC		0x10 /* 2 IACs */
+#define SS_DAC		0x18 /* 2 DACs */
+#define SS_DBCR		0x20 /* 3 DBCRs */
+#define SS_PID		0x2c /* 3 PIDs */
+#define SS_SPRG		0x38 /* 8 SPRGs */
+#define SS_IVOR		0x58 /* 20 interrupt vectors */
+#define SS_TCR		0xa8
+#define SS_BUCSR	0xac
+#define SS_L1CSR	0xb0 /* 2 L1CSRs */
+#define SS_MSR		0xb8
+#define SS_USPRG	0xbc
+#define SS_GPREG	0xc0 /* r12-r31 */
+#define SS_LR		0x110
+#define SS_CR		0x114
+#define SS_SP		0x118
+#define SS_CURRENT	0x11c
+#define SS_IVPR		0x120
+#define SS_BPTR		0x124
+
+#define STATE_SAVE_SIZE 0x128
+
+	.section .data
+	.align	5
+mpc85xx_sleep_save_area:
+	.space	STATE_SAVE_SIZE
+ccsrbase_low:
+	.long	0
+ccsrbase_high:
+	.long	0
+powmgtreq:
+	.long	0
+
+	.section .text
+	.align	12
+
+	/*
+	 * r3 = high word of physical address of CCSR
+	 * r4 = low word of physical address of CCSR
+	 * r5 = JOG or deep sleep request
+	 *      JOG-0x00200000, deep sleep-0x00100000
+	 */
+_GLOBAL(mpc85xx_enter_deep_sleep)
+	lis	r6, ccsrbase_low@ha
+	stw	r4, ccsrbase_low@l(r6)
+	lis	r6, ccsrbase_high@ha
+	stw	r3, ccsrbase_high@l(r6)
+
+	lis	r6, powmgtreq@ha
+	stw	r5, powmgtreq@l(r6)
+
+	lis	r10, mpc85xx_sleep_save_area@h
+	ori	r10, r10, mpc85xx_sleep_save_area@l
+
+	mfspr	r5, SPRN_HID0
+	mfspr	r6, SPRN_HID1
+
+	stw	r5, SS_HID+0(r10)
+	stw	r6, SS_HID+4(r10)
+
+	mfspr	r4, SPRN_IAC1
+	mfspr	r5, SPRN_IAC2
+	mfspr	r6, SPRN_DAC1
+	mfspr	r7, SPRN_DAC2
+
+	stw	r4, SS_IAC+0(r10)
+	stw	r5, SS_IAC+4(r10)
+	stw	r6, SS_DAC+0(r10)
+	stw	r7, SS_DAC+4(r10)
+
+	mfspr	r4, SPRN_DBCR0
+	mfspr	r5, SPRN_DBCR1
+	mfspr	r6, SPRN_DBCR2
+
+	stw	r4, SS_DBCR+0(r10)
+	stw	r5, SS_DBCR+4(r10)
+	stw	r6, SS_DBCR+8(r10)
+
+	mfspr	r4, SPRN_PID0
+	mfspr	r5, SPRN_PID1
+	mfspr	r6, SPRN_PID2
+
+	stw	r4, SS_PID+0(r10)
+	stw	r5, SS_PID+4(r10)
+	stw	r6, SS_PID+8(r10)
+
+	mfspr	r4, SPRN_SPRG0
+	mfspr	r5, SPRN_SPRG1
+	mfspr	r6, SPRN_SPRG2
+	mfspr	r7, SPRN_SPRG3
+
+	stw	r4, SS_SPRG+0x00(r10)
+	stw	r5, SS_SPRG+0x04(r10)
+	stw	r6, SS_SPRG+0x08(r10)
+	stw	r7, SS_SPRG+0x0c(r10)
+
+	mfspr	r4, SPRN_SPRG4
+	mfspr	r5, SPRN_SPRG5
+	mfspr	r6, SPRN_SPRG6
+	mfspr	r7, SPRN_SPRG7
+
+	stw	r4, SS_SPRG+0x10(r10)
+	stw	r5, SS_SPRG+0x14(r10)
+	stw	r6, SS_SPRG+0x18(r10)
+	stw	r7, SS_SPRG+0x1c(r10)
+
+	mfspr	r4, SPRN_IVPR
+	stw	r4, SS_IVPR(r10)
+
+	mfspr	r4, SPRN_IVOR0
+	mfspr	r5, SPRN_IVOR1
+	mfspr	r6, SPRN_IVOR2
+	mfspr	r7, SPRN_IVOR3
+
+	stw	r4, SS_IVOR+0x00(r10)
+	stw	r5, SS_IVOR+0x04(r10)
+	stw	r6, SS_IVOR+0x08(r10)
+	stw	r7, SS_IVOR+0x0c(r10)
+
+	mfspr	r4, SPRN_IVOR4
+	mfspr	r5, SPRN_IVOR5
+	mfspr	r6, SPRN_IVOR6
+	mfspr	r7, SPRN_IVOR7
+
+	stw	r4, SS_IVOR+0x10(r10)
+	stw	r5, SS_IVOR+0x14(r10)
+	stw	r6, SS_IVOR+0x18(r10)
+	stw	r7, SS_IVOR+0x1c(r10)
+
+	mfspr	r4, SPRN_IVOR8
+	mfspr	r5, SPRN_IVOR9
+	mfspr	r6, SPRN_IVOR10
+	mfspr	r7, SPRN_IVOR11
+
+	stw	r4, SS_IVOR+0x20(r10)
+	stw	r5, SS_IVOR+0x24(r10)
+	stw	r6, SS_IVOR+0x28(r10)
+	stw	r7, SS_IVOR+0x2c(r10)
+
+	mfspr	r4, SPRN_IVOR12
+	mfspr	r5, SPRN_IVOR13
+	mfspr	r6, SPRN_IVOR14
+	mfspr	r7, SPRN_IVOR15
+
+	stw	r4, SS_IVOR+0x30(r10)
+	stw	r5, SS_IVOR+0x34(r10)
+	stw	r6, SS_IVOR+0x38(r10)
+	stw	r7, SS_IVOR+0x3c(r10)
+
+	mfspr	r4, SPRN_IVOR32
+	mfspr	r5, SPRN_IVOR33
+	mfspr	r6, SPRN_IVOR34
+	mfspr	r7, SPRN_IVOR35
+
+	stw	r4, SS_IVOR+0x40(r10)
+	stw	r5, SS_IVOR+0x44(r10)
+	stw	r6, SS_IVOR+0x48(r10)
+	stw	r7, SS_IVOR+0x4c(r10)
+
+	mfspr	r4, SPRN_TCR
+	mfspr	r5, SPRN_BUCSR
+	mfspr	r6, SPRN_L1CSR0
+	mfspr	r7, SPRN_L1CSR1
+	mfspr	r8, SPRN_USPRG0
+
+	stw	r4, SS_TCR(r10)
+	stw	r5, SS_BUCSR(r10)
+	stw	r6, SS_L1CSR+0(r10)
+	stw	r7, SS_L1CSR+4(r10)
+	stw	r8, SS_USPRG+0(r10)
+
+	stmw	r12, SS_GPREG(r10)
+
+	mfmsr	r4
+	mflr	r5
+	mfcr	r6
+
+	stw	r4, SS_MSR(r10)
+	stw	r5, SS_LR(r10)
+	stw	r6, SS_CR(r10)
+	stw	r1, SS_SP(r10)
+	stw	r2, SS_CURRENT(r10)
+
+1:	mftbu	r4
+	mftb	r5
+	mftbu	r6
+	cmpw	r4, r6
+	bne	1b
+
+	stw	r4, SS_TB+0(r10)
+	stw	r5, SS_TB+4(r10)
+
+	lis	r5, ccsrbase_low@ha
+	lwz	r4, ccsrbase_low@l(r5)
+	lis	r5, ccsrbase_high@ha
+	lwz	r3, ccsrbase_high@l(r5)
+
+	/* Disable machine checks and critical exceptions */
+	mfmsr	r5
+	rlwinm	r5, r5, 0, ~MSR_CE
+	rlwinm	r5, r5, 0, ~MSR_ME
+	mtmsr	r5
+	isync
+
+	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
+	LOAD_REG_IMMEDIATE(r5, MAS0_TLBSEL(1) | MAS0_ESEL(15))
+	mtspr	SPRN_MAS0, r5
+	LOAD_REG_IMMEDIATE(r5,
+		MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(BOOK3E_PAGESZ_1M))
+	mtspr	SPRN_MAS1, r5
+	LOAD_REG_IMMEDIATE(r5, CCSR_ADDR | MAS2_I | MAS2_M)
+	mtspr	SPRN_MAS2, r5
+	rlwinm	r5, r4, 0, MAS3_RPN
+	ori	r5, r5, (MAS3_SW | MAS3_SR)
+	mtspr	SPRN_MAS3, r5
+	mtspr	SPRN_MAS7, r3
+	isync
+	tlbwe
+	isync
+
+	LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + BPTR_OFFSET)
+	lwz	r4, 0(r3)
+	stw	r4, SS_BPTR(r10)
+
+	LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + L2C_OFFSET)
+	bl	flush_disable_L2
+	bl	__flush_disable_L1
+
+	/* Enable I-cache, so as not to upset the bus
+	 * with our loop.
+	 */
+	mfspr	r4, SPRN_L1CSR1
+	ori	r4, r4, L1CSR1_ICE
+	mtspr	SPRN_L1CSR1, r4
+	isync
+
+	/* Set boot page translation */
+	LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + BPTR_OFFSET)
+	lis	r4, (mpc85xx_deep_resume - PAGE_OFFSET)@h
+	ori	r4, r4, (mpc85xx_deep_resume - PAGE_OFFSET)@l
+	rlwinm	r4, r4, 20, 12, 31
+	oris	r4, r4, BPTR_EN@h
+	stw	r4, 0(r3)
+	lwz	r4, 0(r3) /* read-back to flush write */
+	twi	0, r4, 0
+	isync
+
+	/* Disable the decrementer */
+	mfspr	r4, SPRN_TCR
+	rlwinm	r4, r4, 0, ~TCR_DIE
+	mtspr	SPRN_TCR, r4
+
+	mfspr	r4, SPRN_TSR
+	oris	r4, r4, TSR_DIS@h
+	mtspr	SPRN_TSR, r4
+
+	/* set PMRCCR[VRCNT] to wait power stable for 40ms */
+	LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + PMRCCR_OFFSET)
+	lwz	r4, 0(r3)
+	li	r5, 0x12
+	rlwimi	r4, r5, 0, PMRCCR_VRCNT_PRE_MASK
+	li	r5, 0xa3
+	rlwimi	r4, r5, 0, PMRCCR_VRCNT_MASK
+	stw	r4, 0(r3)
+	lwz	r4, 0(r3)
+
+	/* set deep sleep bit in POWMGTSCR */
+	lis	r3, powmgtreq@ha
+	lwz	r8, powmgtreq@l(r3)
+	LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + POWMGTSCR_OFFSET)
+	lwz	r4, 0(r3)
+	or	r4, r4, r8
+	stw	r4, 0(r3)
+	lwz	r4, 0(r3)		/* read-back to flush write */
+	twi	0, r4, 0
+	isync
+
+	mftb	r5
+1:	/* spin until either we enter deep sleep, or the sleep process is
+	 * aborted due to a pending wakeup event.  Wait some time between
+	 * accesses, so we don't flood the bus and prevent the pmc from
+	 * detecting an idle system.
+	 */
+
+	mftb	r4
+	subf	r7, r5, r4
+	cmpwi	r7, 1000
+	blt	1b
+	mr	r5, r4
+
+	lwz	r6, 0(r3)
+	andis.	r6, r6, POWMGTSCR_DPSLP@h
+	bne	1b
+	b	2f
+
+2:	mfspr	r4, SPRN_PIR
+	andi.	r4, r4, 1
+99:	bne	99b
+
+	/* Establish a temporary 64MB 0->0 mapping in TLB1[1]. */
+	LOAD_REG_IMMEDIATE(r4, MAS0_TLBSEL(1) | MAS0_ESEL(1))
+	mtspr	SPRN_MAS0, r4
+	LOAD_REG_IMMEDIATE(r4,
+		MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(BOOK3E_PAGESZ_64M))
+	mtspr	SPRN_MAS1, r4
+	li	r4, 0
+	mtspr	SPRN_MAS2, r4
+	li	r4, (MAS3_SX | MAS3_SW | MAS3_SR)
+	mtspr	SPRN_MAS3, r4
+	li	r4, 0
+	mtspr	SPRN_MAS7, r4
+	isync
+	tlbwe
+	isync
+
+	lis	r3, (3f - PAGE_OFFSET)@h
+	ori	r3, r3, (3f - PAGE_OFFSET)@l
+	mtctr	r3
+	bctr
+
+	/* Locate the resume vector in the last word of the current page. */
+	. = mpc85xx_enter_deep_sleep + 0xffc
+mpc85xx_deep_resume:
+	b	2b
+
+3:
+	/* Restore the contents of TLB1[0].  It is assumed that it covers
+	 * the currently executing code and the sleep save area, and that
+	 * it does not alias our temporary mapping (which is at virtual zero).
+	 */
+	lis	r3, (TLBCAM - PAGE_OFFSET)@h
+	ori	r3, r3, (TLBCAM - PAGE_OFFSET)@l
+
+	lwz	r4, 0(r3)
+	lwz	r5, 4(r3)
+	lwz	r6, 8(r3)
+	lwz	r7, 12(r3)
+	lwz	r8, 16(r3)
+
+	mtspr	SPRN_MAS0, r4
+	mtspr	SPRN_MAS1, r5
+	mtspr	SPRN_MAS2, r6
+	mtspr	SPRN_MAS3, r7
+	mtspr	SPRN_MAS7, r8
+
+	isync
+	tlbwe
+	isync
+
+	/* Access the ccsrbase address with TLB1[0] */
+	lis	r5, ccsrbase_low@ha
+	lwz	r4, ccsrbase_low@l(r5)
+	lis	r5, ccsrbase_high@ha
+	lwz	r3, ccsrbase_high@l(r5)
+
+	/* Use TLB1[15] to map the CCSR at 0xf0000000 */
+	LOAD_REG_IMMEDIATE(r5, MAS0_TLBSEL(1) | MAS0_ESEL(15))
+	mtspr	SPRN_MAS0, r5
+	LOAD_REG_IMMEDIATE(r5,
+		MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(BOOK3E_PAGESZ_1M))
+	mtspr	SPRN_MAS1, r5
+	LOAD_REG_IMMEDIATE(r5, CCSR_ADDR | MAS2_I | MAS2_M)
+	mtspr	SPRN_MAS2, r5
+	rlwinm	r5, r4, 0, MAS3_RPN
+	ori	r5, r5, (MAS3_SW | MAS3_SR)
+	mtspr	SPRN_MAS3, r5
+	mtspr	SPRN_MAS7, r3
+	isync
+	tlbwe
+	isync
+
+	LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + L2C_OFFSET)
+	bl	invalidate_enable_L2
+
+	/* Access the MEM(r10) with TLB1[0] */
+	lis	r10, mpc85xx_sleep_save_area@h
+	ori	r10, r10, mpc85xx_sleep_save_area@l
+
+	LOAD_REG_IMMEDIATE(r3, CCSR_ADDR + BPTR_OFFSET)
+	lwz	r4, SS_BPTR(r10)
+	stw	r4, 0(r3)		/* restore BPTR */
+
+	/* Program shift running space to PAGE_OFFSET */
+	mfmsr	r3
+	lis	r4, 1f@h
+	ori	r4, r4, 1f@l
+
+	mtsrr1	r3
+	mtsrr0	r4
+	rfi
+
+1:	/* Restore the rest of TLB1, in ascending order so that
+	 * the TLB1[1] gets invalidated first.
+	 *
+	 * XXX: It's better to invalidate the temporary mapping
+	 * TLB1[15] for CCSR before restore any TLB1 entry include 0.
+	 */
+	LOAD_REG_IMMEDIATE(r4, MAS0_TLBSEL(1) | MAS0_ESEL(15))
+	mtspr	SPRN_MAS0, r4
+	lis	r4, 0
+	mtspr	SPRN_MAS1, r4
+	isync
+	tlbwe
+	isync
+
+	lis	r3, (TLBCAM + 5*4 - 4)@h
+	ori	r3, r3, (TLBCAM + 5*4 - 4)@l
+	li	r4, 15
+	mtctr	r4
+
+2:
+	lwz	r5, 4(r3)
+	lwz	r6, 8(r3)
+	lwz	r7, 12(r3)
+	lwz	r8, 16(r3)
+	lwzu	r9, 20(r3)
+
+	mtspr	SPRN_MAS0, r5
+	mtspr	SPRN_MAS1, r6
+	mtspr	SPRN_MAS2, r7
+	mtspr	SPRN_MAS3, r8
+	mtspr	SPRN_MAS7, r9
+
+	isync
+	tlbwe
+	isync
+	bdnz	2b
+
+	lis	r10, mpc85xx_sleep_save_area@h
+	ori	r10, r10, mpc85xx_sleep_save_area@l
+
+	lwz	r5, SS_HID+0(r10)
+	lwz	r6, SS_HID+4(r10)
+
+	isync
+	mtspr	SPRN_HID0, r5
+	isync
+
+	msync
+	mtspr	SPRN_HID1, r6
+	isync
+
+	lwz	r4, SS_IAC+0(r10)
+	lwz	r5, SS_IAC+4(r10)
+	lwz	r6, SS_DAC+0(r10)
+	lwz	r7, SS_DAC+4(r10)
+
+	mtspr	SPRN_IAC1, r4
+	mtspr	SPRN_IAC2, r5
+	mtspr	SPRN_DAC1, r6
+	mtspr	SPRN_DAC2, r7
+
+	lwz	r4, SS_DBCR+0(r10)
+	lwz	r5, SS_DBCR+4(r10)
+	lwz	r6, SS_DBCR+8(r10)
+
+	mtspr	SPRN_DBCR0, r4
+	mtspr	SPRN_DBCR1, r5
+	mtspr	SPRN_DBCR2, r6
+
+	lwz	r4, SS_PID+0(r10)
+	lwz	r5, SS_PID+4(r10)
+	lwz	r6, SS_PID+8(r10)
+
+	mtspr	SPRN_PID0, r4
+	mtspr	SPRN_PID1, r5
+	mtspr	SPRN_PID2, r6
+
+	lwz	r4, SS_SPRG+0x00(r10)
+	lwz	r5, SS_SPRG+0x04(r10)
+	lwz	r6, SS_SPRG+0x08(r10)
+	lwz	r7, SS_SPRG+0x0c(r10)
+
+	mtspr	SPRN_SPRG0, r4
+	mtspr	SPRN_SPRG1, r5
+	mtspr	SPRN_SPRG2, r6
+	mtspr	SPRN_SPRG3, r7
+
+	lwz	r4, SS_SPRG+0x10(r10)
+	lwz	r5, SS_SPRG+0x14(r10)
+	lwz	r6, SS_SPRG+0x18(r10)
+	lwz	r7, SS_SPRG+0x1c(r10)
+
+	mtspr	SPRN_SPRG4, r4
+	mtspr	SPRN_SPRG5, r5
+	mtspr	SPRN_SPRG6, r6
+	mtspr	SPRN_SPRG7, r7
+
+	lwz	r4, SS_IVPR(r10)
+	mtspr	SPRN_IVPR, r4
+
+	lwz	r4, SS_IVOR+0x00(r10)
+	lwz	r5, SS_IVOR+0x04(r10)
+	lwz	r6, SS_IVOR+0x08(r10)
+	lwz	r7, SS_IVOR+0x0c(r10)
+
+	mtspr	SPRN_IVOR0, r4
+	mtspr	SPRN_IVOR1, r5
+	mtspr	SPRN_IVOR2, r6
+	mtspr	SPRN_IVOR3, r7
+
+	lwz	r4, SS_IVOR+0x10(r10)
+	lwz	r5, SS_IVOR+0x14(r10)
+	lwz	r6, SS_IVOR+0x18(r10)
+	lwz	r7, SS_IVOR+0x1c(r10)
+
+	mtspr	SPRN_IVOR4, r4
+	mtspr	SPRN_IVOR5, r5
+	mtspr	SPRN_IVOR6, r6
+	mtspr	SPRN_IVOR7, r7
+
+	lwz	r4, SS_IVOR+0x20(r10)
+	lwz	r5, SS_IVOR+0x24(r10)
+	lwz	r6, SS_IVOR+0x28(r10)
+	lwz	r7, SS_IVOR+0x2c(r10)
+
+	mtspr	SPRN_IVOR8, r4
+	mtspr	SPRN_IVOR9, r5
+	mtspr	SPRN_IVOR10, r6
+	mtspr	SPRN_IVOR11, r7
+
+	lwz	r4, SS_IVOR+0x30(r10)
+	lwz	r5, SS_IVOR+0x34(r10)
+	lwz	r6, SS_IVOR+0x38(r10)
+	lwz	r7, SS_IVOR+0x3c(r10)
+
+	mtspr	SPRN_IVOR12, r4
+	mtspr	SPRN_IVOR13, r5
+	mtspr	SPRN_IVOR14, r6
+	mtspr	SPRN_IVOR15, r7
+
+	lwz	r4, SS_IVOR+0x40(r10)
+	lwz	r5, SS_IVOR+0x44(r10)
+	lwz	r6, SS_IVOR+0x48(r10)
+	lwz	r7, SS_IVOR+0x4c(r10)
+
+	mtspr	SPRN_IVOR32, r4
+	mtspr	SPRN_IVOR33, r5
+	mtspr	SPRN_IVOR34, r6
+	mtspr	SPRN_IVOR35, r7
+
+	lwz	r4, SS_TCR(r10)
+	lwz	r5, SS_BUCSR(r10)
+	lwz	r6, SS_L1CSR+0(r10)
+	lwz	r7, SS_L1CSR+4(r10)
+	lwz	r8, SS_USPRG+0(r10)
+
+	mtspr	SPRN_TCR, r4
+	mtspr	SPRN_BUCSR, r5
+
+	msync
+	isync
+	mtspr	SPRN_L1CSR0, r6
+	isync
+
+	mtspr	SPRN_L1CSR1, r7
+	isync
+
+	mtspr	SPRN_USPRG0, r8
+
+	lmw	r12, SS_GPREG(r10)
+
+	lwz	r1, SS_SP(r10)
+	lwz	r2, SS_CURRENT(r10)
+	lwz	r4, SS_MSR(r10)
+	lwz	r5, SS_LR(r10)
+	lwz	r6, SS_CR(r10)
+
+	msync
+	mtmsr	r4
+	isync
+
+	mtlr	r5
+	mtcr	r6
+
+	li	r4, 0
+	mtspr	SPRN_TBWL, r4
+
+	lwz	r4, SS_TB+0(r10)
+	lwz	r5, SS_TB+4(r10)
+
+	mtspr	SPRN_TBWU, r4
+	mtspr	SPRN_TBWL, r5
+
+	lis	r3, 1
+	mtdec	r3
+
+	blr
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 592a0f8..45718c5 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -2,6 +2,7 @@
  * Suspend/resume support
  *
  * Copyright 2009  MontaVista Software, Inc.
+ * Copyright 2010-2012 Freescale Semiconductor Inc.
  *
  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
  *
@@ -19,39 +20,89 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/of_platform.h>
+#include <linux/pm.h>
+#include <asm/cacheflush.h>
+#include <asm/switch_to.h>
+
+#include <sysdev/fsl_soc.h>
 
 struct pmc_regs {
+	/* 0xe0070: Device disable control register */
 	__be32 devdisr;
+	/* 0xe0074: 2nd Device disable control register */
 	__be32 devdisr2;
-	__be32 :32;
-	__be32 :32;
-	__be32 pmcsr;
-#define PMCSR_SLP	(1 << 17)
+	__be32 res1;
+	/* 0xe007c: Power Management Jog Control Register */
+	__be32 pmjcr;
+	/* 0xe0080: Power management control and status register */
+	__be32 powmgtcsr;
+#define POWMGTCSR_SLP		0x00020000
+#define POWMGTCSR_DPSLP		0x00100000
+	__be32 res3[2];
+	/* 0xe008c: Power management clock disable register */
+	__be32 pmcdr;
 };
 
-static struct device *pmc_dev;
 static struct pmc_regs __iomem *pmc_regs;
+static unsigned int pmc_flag;
+
+#define PMC_SLEEP	0x1
+#define PMC_DEEP_SLEEP	0x2
 
 static int pmc_suspend_enter(suspend_state_t state)
 {
-	int ret;
+	int ret = 0;
+
+	switch (state) {
+#ifdef CONFIG_PPC_85xx
+	case PM_SUSPEND_MEM:
+#ifdef CONFIG_SPE
+		enable_kernel_spe();
+#endif
+		enable_kernel_fp();
+
+		pr_debug("%s: Entering deep sleep\n", __func__);
+
+		local_irq_disable();
+		mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_DPSLP);
+
+		pr_debug("%s: Resumed from deep sleep\n", __func__);
+		break;
+#endif
 
-	setbits32(&pmc_regs->pmcsr, PMCSR_SLP);
-	/* At this point, the CPU is asleep. */
+	case PM_SUSPEND_STANDBY:
+		local_irq_disable();
+#ifdef CONFIG_PPC_85xx
+		flush_dcache_L1();
+#endif
+		setbits32(&pmc_regs->powmgtcsr, POWMGTCSR_SLP);
+		/* At this point, the CPU is asleep. */
 
-	/* Upon resume, wait for SLP bit to be clear. */
-	ret = spin_event_timeout((in_be32(&pmc_regs->pmcsr) & PMCSR_SLP) == 0,
-				 10000, 10) ? 0 : -ETIMEDOUT;
-	if (ret)
-		dev_err(pmc_dev, "tired waiting for SLP bit to clear\n");
+		/* Upon resume, wait for SLP bit to be clear. */
+		ret = spin_event_timeout(
+			(in_be32(&pmc_regs->powmgtcsr) & POWMGTCSR_SLP) == 0,
+			10000, 10);
+		if (!ret) {
+			pr_err("%s: timeout waiting for SLP bit "
+				"to be cleared\n", __func__);
+			ret = -EINVAL;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+
+	}
 	return ret;
 }
 
 static int pmc_suspend_valid(suspend_state_t state)
 {
-	if (state != PM_SUSPEND_STANDBY)
+	if (((pmc_flag & PMC_SLEEP) && (state == PM_SUSPEND_STANDBY)) ||
+	    ((pmc_flag & PMC_DEEP_SLEEP) && (state == PM_SUSPEND_MEM)))
+		return 1;
+	else
 		return 0;
-	return 1;
 }
 
 static const struct platform_suspend_ops pmc_suspend_ops = {
@@ -59,14 +110,25 @@ static const struct platform_suspend_ops pmc_suspend_ops = {
 	.enter = pmc_suspend_enter,
 };
 
-static int pmc_probe(struct platform_device *ofdev)
+static int pmc_probe(struct platform_device *pdev)
 {
-	pmc_regs = of_iomap(ofdev->dev.of_node, 0);
+	struct device_node *np = pdev->dev.of_node;
+
+	pmc_regs = of_iomap(np, 0);
 	if (!pmc_regs)
 		return -ENOMEM;
 
-	pmc_dev = &ofdev->dev;
+	pmc_flag = PMC_SLEEP;
+	if (of_device_is_compatible(np, "fsl,mpc8536-pmc"))
+		pmc_flag |= PMC_DEEP_SLEEP;
+
+	if (of_device_is_compatible(np, "fsl,p1022-pmc"))
+		pmc_flag |= PMC_DEEP_SLEEP;
+
 	suspend_set_ops(&pmc_suspend_ops);
+
+	pr_info("Freescale PMC driver: sleep(standby)%s\n",
+		(pmc_flag & PMC_DEEP_SLEEP) ? ", deep sleep(mem)" : "");
 	return 0;
 }
 
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index c6d0073..11d9f94 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -48,5 +48,10 @@ extern struct platform_diu_data_ops diu_ops;
 void fsl_hv_restart(char *cmd);
 void fsl_hv_halt(void);
 
+/*
+ * ccsrbar is u64 rather than phys_addr_t so that the assembly
+ * code can be compatible with both 32-bit & 36-bit.
+ */
+extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq);
 #endif
 #endif
-- 
1.6.4.1

^ permalink raw reply related

* [PATCH v8 6/7] fsl_pmc: Add API to enable device as wakeup event source
From: Zhao Chenhui @ 2012-07-20 12:42 UTC (permalink / raw)
  To: linuxppc-dev, scottwood, galak; +Cc: linux-kernel
In-Reply-To: <1342788159-27529-1-git-send-email-chenhui.zhao@freescale.com>

Add APIs for setting wakeup source and lossless Ethernet in low power modes.
These APIs can be used by wake-on-packet feature.

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
 arch/powerpc/sysdev/fsl_pmc.c |   77 ++++++++++++++++++++++++++++++++++++++++-
 arch/powerpc/sysdev/fsl_soc.h |   12 ++++++
 2 files changed, 88 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index 45718c5..b6c8c8f 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -38,6 +38,7 @@ struct pmc_regs {
 	__be32 powmgtcsr;
 #define POWMGTCSR_SLP		0x00020000
 #define POWMGTCSR_DPSLP		0x00100000
+#define POWMGTCSR_LOSSLESS	0x00400000
 	__be32 res3[2];
 	/* 0xe008c: Power management clock disable register */
 	__be32 pmcdr;
@@ -48,6 +49,77 @@ static unsigned int pmc_flag;
 
 #define PMC_SLEEP	0x1
 #define PMC_DEEP_SLEEP	0x2
+#define PMC_LOSSLESS	0x4
+
+#define PMCDR_MASK_INIT		0x00e008e0
+
+/**
+ * mpc85xx_pmc_set_wake - enable devices as wakeup event source
+ * @dev: a device affected
+ * @enable: True to enable event generation; false to disable
+ *
+ * This enables the device as a wakeup event source, or disables it.
+ *
+ * RETURN VALUE:
+ * 0 is returned on success.
+ * -EINVAL is returned if device is not supposed to wake up the system.
+ * -ENODEV is returned if PMC is unavailable.
+ * Error code depending on the platform is returned if both the platform and
+ * the native mechanism fail to enable the generation of wake-up events
+ */
+int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+	int ret = 0;
+	struct device_node *clk_np;
+	const u32 *prop;
+	u32 pmcdr_mask;
+
+	if (!pmc_regs) {
+		pr_err("%s: PMC is unavailable\n", __func__);
+		return -ENODEV;
+	}
+
+	if (enable && !device_may_wakeup(dev))
+		return -EINVAL;
+
+	clk_np = of_parse_phandle(dev->of_node, "fsl,pmc-handle", 0);
+	if (!clk_np)
+		return -EINVAL;
+
+	prop = of_get_property(clk_np, "fsl,pmcdr-mask", NULL);
+	if (!prop) {
+		ret = -EINVAL;
+		goto out;
+	}
+	pmcdr_mask = be32_to_cpup(prop);
+
+	if (enable)
+		/* clear to enable clock in low power mode */
+		clrbits32(&pmc_regs->pmcdr, pmcdr_mask);
+	else
+		setbits32(&pmc_regs->pmcdr, pmcdr_mask);
+
+out:
+	of_node_put(clk_np);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_wake);
+
+/**
+ * mpc85xx_pmc_set_lossless_ethernet - enable lossless ethernet
+ * in (deep) sleep mode
+ * @enable: True to enable event generation; false to disable
+ */
+void mpc85xx_pmc_set_lossless_ethernet(int enable)
+{
+	if (pmc_flag & PMC_LOSSLESS) {
+		if (enable)
+			setbits32(&pmc_regs->powmgtcsr,	POWMGTCSR_LOSSLESS);
+		else
+			clrbits32(&pmc_regs->powmgtcsr, POWMGTCSR_LOSSLESS);
+	}
+}
+EXPORT_SYMBOL_GPL(mpc85xx_pmc_set_lossless_ethernet);
 
 static int pmc_suspend_enter(suspend_state_t state)
 {
@@ -123,7 +195,10 @@ static int pmc_probe(struct platform_device *pdev)
 		pmc_flag |= PMC_DEEP_SLEEP;
 
 	if (of_device_is_compatible(np, "fsl,p1022-pmc"))
-		pmc_flag |= PMC_DEEP_SLEEP;
+		pmc_flag |= PMC_DEEP_SLEEP | PMC_LOSSLESS;
+
+	/* Init the Power Management Clock Disable Register. */
+	setbits32(&pmc_regs->pmcdr, PMCDR_MASK_INIT);
 
 	suspend_set_ops(&pmc_suspend_ops);
 
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 11d9f94..b1510ef 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -3,6 +3,7 @@
 #ifdef __KERNEL__
 
 #include <asm/mmu.h>
+#include <linux/platform_device.h>
 
 struct spi_device;
 
@@ -21,6 +22,17 @@ struct device_node;
 
 extern void fsl_rstcr_restart(char *cmd);
 
+#ifdef CONFIG_FSL_PMC
+extern int mpc85xx_pmc_set_wake(struct device *dev, bool enable);
+extern void mpc85xx_pmc_set_lossless_ethernet(int enable);
+#else
+static inline int mpc85xx_pmc_set_wake(struct device *dev, bool enable)
+{
+	return -ENODEV;
+}
+#define mpc85xx_pmc_set_lossless_ethernet(enable)	do { } while (0)
+#endif
+
 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
 
 /* The different ports that the DIU can be connected to */
-- 
1.6.4.1

^ permalink raw reply related

* [PATCH v8 7/7] powerpc/85xx: add support to JOG feature using cpufreq interface
From: Zhao Chenhui @ 2012-07-20 12:42 UTC (permalink / raw)
  To: linuxppc-dev, scottwood, galak; +Cc: linux-kernel
In-Reply-To: <1342788159-27529-1-git-send-email-chenhui.zhao@freescale.com>

Some 85xx silicons like MPC8536 and P1022 have a JOG feature, which provides
a dynamic mechanism to lower or raise the CPU core clock at runtime.

This patch adds the support to change CPU frequency using the standard
cpufreq interface. The ratio CORE to CCB can be 1:1(except MPC8536), 3:2,
2:1, 5:2, 3:1, 7:2 and 4:1.

Two CPU cores on P1022 must not in the low power state during the frequency
transition. The driver uses a atomic counter to meet the requirement.

The jog mode frequency transition process on the MPC8536 is similar to
the deep sleep process. The driver need save the CPU state and restore
it after CPU warm reset.

Note:
 * The I/O peripherals such as PCIe and eTSEC may lose packets during
   the jog mode frequency transition.
 * The driver doesn't support MPC8536 Rev 1.0 due to a JOG erratum.
   Subsequent revisions of MPC8536 have corrected the erratum.

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
CC: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/platforms/85xx/Makefile      |    1 +
 arch/powerpc/platforms/85xx/cpufreq-jog.c |  388 +++++++++++++++++++++++++++++
 arch/powerpc/platforms/Kconfig            |   11 +
 arch/powerpc/sysdev/fsl_pmc.c             |    3 +
 arch/powerpc/sysdev/fsl_soc.h             |    2 +
 include/linux/cpu.h                       |    4 +
 6 files changed, 409 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/cpufreq-jog.c

diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 405ab79..901cdd5 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -4,6 +4,7 @@
 obj-$(CONFIG_SMP) += smp.o
 
 obj-y += common.o sleep.o
+obj-$(CONFIG_MPC85xx_CPUFREQ) += cpufreq-jog.o
 
 obj-$(CONFIG_BSC9131_RDB) += bsc913x_rdb.o
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
diff --git a/arch/powerpc/platforms/85xx/cpufreq-jog.c b/arch/powerpc/platforms/85xx/cpufreq-jog.c
new file mode 100644
index 0000000..ccc0c33
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/cpufreq-jog.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
+ * Author: Dave Liu <daveliu@freescale.com>
+ * Modifier: Chenhui Zhao <chenhui.zhao@freescale.com>
+ *
+ * The cpufreq driver is for Freescale 85xx processor,
+ * based on arch/powerpc/platforms/cell/cbe_cpufreq.c
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *	Christian Krafft <krafft@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <linux/of_platform.h>
+#include <linux/suspend.h>
+#include <linux/cpu.h>
+
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/reg.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/smp.h>
+
+#include <sysdev/fsl_soc.h>
+
+static DEFINE_MUTEX(mpc85xx_switch_mutex);
+static void __iomem *guts;
+
+static u32 sysfreq;
+static unsigned int max_pll[2];
+static atomic_t in_jog_process;
+static struct cpufreq_frequency_table *mpc85xx_freqs;
+static int (*set_pll)(unsigned int cpu, unsigned int pll);
+
+static struct cpufreq_frequency_table mpc8536_freqs_table[] = {
+	{3,	0},
+	{4,	0},
+	{5,	0},
+	{6,	0},
+	{7,	0},
+	{8,	0},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_frequency_table p1022_freqs_table[] = {
+	{2,	0},
+	{3,	0},
+	{4,	0},
+	{5,	0},
+	{6,	0},
+	{7,	0},
+	{8,	0},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+#define FREQ_500MHz	500000000
+#define FREQ_800MHz	800000000
+
+#define CORE_RATIO_STRIDE	8
+#define CORE_RATIO_MASK		0x3f
+#define CORE_RATIO_SHIFT	16
+
+#define PORPLLSR	0x0	/* Power-On Reset PLL ratio status register */
+
+#define PMJCR		0x7c	/* Power Management Jog Control Register */
+#define PMJCR_CORE0_SPD	0x00001000
+#define PMJCR_CORE_SPD	0x00002000
+
+#define POWMGTCSR	0x80 /* Power management control and status register */
+#define POWMGTCSR_JOG		0x00200000
+#define POWMGTCSR_INT_MASK	0x00000f00
+
+static void spin_while_jogging(void *dummy)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	atomic_inc(&in_jog_process);
+
+	while (atomic_read(&in_jog_process) != 0)
+		barrier();
+
+	local_irq_restore(flags);
+}
+
+static int get_pll(int hw_cpu)
+{
+	int shift;
+	u32 val = in_be32(guts + PORPLLSR);
+
+	shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+
+	return (val >> shift) & CORE_RATIO_MASK;
+}
+
+static int mpc8536_set_pll(unsigned int cpu, unsigned int pll)
+{
+	u32 corefreq, val, mask;
+	unsigned int cur_pll = get_pll(0);
+	unsigned long flags;
+
+	if (pll == cur_pll)
+		return 0;
+
+	val = (pll & CORE_RATIO_MASK) << CORE_RATIO_SHIFT;
+
+	corefreq = sysfreq * pll / 2;
+	/*
+	 * Set the COREx_SPD bit if the requested core frequency
+	 * is larger than the threshold frequency.
+	 */
+	if (corefreq > FREQ_800MHz)
+			val |= PMJCR_CORE_SPD;
+
+	mask = (CORE_RATIO_MASK << CORE_RATIO_SHIFT) | PMJCR_CORE_SPD;
+	clrsetbits_be32(guts + PMJCR, mask, val);
+
+	/* readback to sync write */
+	in_be32(guts + PMJCR);
+
+	local_irq_save(flags);
+	mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_JOG);
+	local_irq_restore(flags);
+
+	/* verify */
+	cur_pll =  get_pll(0);
+	if (cur_pll != pll) {
+		pr_err("%s: error. The current PLL is %d instead of %d.\n",
+				__func__, cur_pll, pll);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int p1022_set_pll(unsigned int cpu, unsigned int pll)
+{
+	int index, hw_cpu = get_hard_smp_processor_id(cpu);
+	int shift;
+	u32 corefreq, val, mask = 0;
+	unsigned int cur_pll = get_pll(hw_cpu);
+	unsigned long flags;
+	int ret = 0;
+
+	if (pll == cur_pll)
+		return 0;
+
+	shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+	val = (pll & CORE_RATIO_MASK) << shift;
+
+	corefreq = sysfreq * pll / 2;
+	/*
+	 * Set the COREx_SPD bit if the requested core frequency
+	 * is larger than the threshold frequency.
+	 */
+	if (corefreq > FREQ_500MHz)
+		val |= PMJCR_CORE0_SPD << hw_cpu;
+
+	mask = (CORE_RATIO_MASK << shift) | (PMJCR_CORE0_SPD << hw_cpu);
+	clrsetbits_be32(guts + PMJCR, mask, val);
+
+	/* readback to sync write */
+	in_be32(guts + PMJCR);
+
+	cpu_hotplug_disable_before_freeze();
+	/*
+	 * A Jog request can not be asserted when any core is in a low
+	 * power state on P1022. Before executing a jog request, any
+	 * core which is in a low power state must be waked by a
+	 * interrupt, and keep waking up until the sequence is
+	 * finished.
+	 */
+	for_each_present_cpu(index) {
+		if (!cpu_online(index)) {
+			cpu_hotplug_enable_after_thaw();
+			pr_err("%s: error, core%d is down.\n", __func__, index);
+			return -1;
+		}
+	}
+
+	atomic_set(&in_jog_process, 0);
+	smp_call_function(spin_while_jogging, NULL, 0);
+
+	local_irq_save(flags);
+
+	/* Wait for the other core to wake. */
+	if (!spin_event_timeout(atomic_read(&in_jog_process) == 1, 1000, 100)) {
+		pr_err("%s: timeout, the other core is not at running state.\n",
+					__func__);
+		ret = -1;
+		goto err;
+	}
+
+	out_be32(guts + POWMGTCSR, POWMGTCSR_JOG | POWMGTCSR_INT_MASK);
+
+	if (!spin_event_timeout(
+		(in_be32(guts + POWMGTCSR) & POWMGTCSR_JOG) == 0, 1000, 100)) {
+		pr_err("%s: timeout, fail to switch the core frequency.\n",
+				__func__);
+		ret = -1;
+		goto err;
+	}
+
+	clrbits32(guts + POWMGTCSR, POWMGTCSR_INT_MASK);
+	in_be32(guts + POWMGTCSR);
+
+	atomic_set(&in_jog_process, 0);
+err:
+	local_irq_restore(flags);
+	cpu_hotplug_enable_after_thaw();
+
+	/* verify */
+	cur_pll =  get_pll(hw_cpu);
+	if (cur_pll != pll) {
+		pr_err("%s: error, the current PLL of core %d is %d instead of %d.\n",
+				__func__, hw_cpu, cur_pll, pll);
+		return -1;
+	}
+
+	return ret;
+}
+
+/*
+ * cpufreq functions
+ */
+static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+	unsigned int i, cur_pll;
+	int hw_cpu = get_hard_smp_processor_id(policy->cpu);
+
+	if (!cpu_present(policy->cpu))
+		return -ENODEV;
+
+	/* the latency of a transition, the unit is ns */
+	policy->cpuinfo.transition_latency = 2000;
+
+	cur_pll = get_pll(hw_cpu);
+
+	/* initialize frequency table */
+	pr_debug("core%d frequency table:\n", hw_cpu);
+	for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
+		if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
+			/* The frequency unit is kHz. */
+			mpc85xx_freqs[i].frequency =
+				(sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
+		} else {
+			mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
+		}
+
+		pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
+
+		if (mpc85xx_freqs[i].index == cur_pll)
+			policy->cur = mpc85xx_freqs[i].frequency;
+	}
+	pr_debug("current pll is at %d, and core freq is%d\n",
+			cur_pll, policy->cur);
+
+	cpufreq_frequency_table_get_attr(mpc85xx_freqs, policy->cpu);
+
+	/*
+	 * This ensures that policy->cpuinfo_min
+	 * and policy->cpuinfo_max are set correctly.
+	 */
+	return cpufreq_frequency_table_cpuinfo(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	return 0;
+}
+
+static int mpc85xx_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_target(struct cpufreq_policy *policy,
+			      unsigned int target_freq,
+			      unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned int new;
+	int ret = 0;
+
+	if (!set_pll)
+		return -ENODEV;
+
+	cpufreq_frequency_table_target(policy,
+				       mpc85xx_freqs,
+				       target_freq,
+				       relation,
+				       &new);
+
+	freqs.old = policy->cur;
+	freqs.new = mpc85xx_freqs[new].frequency;
+	freqs.cpu = policy->cpu;
+
+	mutex_lock(&mpc85xx_switch_mutex);
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
+	if (!ret) {
+		pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
+			 policy->cpu, mpc85xx_freqs[new].frequency,
+			 mpc85xx_freqs[new].index);
+
+		ppc_proc_freq = freqs.new * 1000ul;
+	}
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	mutex_unlock(&mpc85xx_switch_mutex);
+
+	return ret;
+}
+
+static struct cpufreq_driver mpc85xx_cpufreq_driver = {
+	.verify		= mpc85xx_cpufreq_verify,
+	.target		= mpc85xx_cpufreq_target,
+	.init		= mpc85xx_cpufreq_cpu_init,
+	.exit		= mpc85xx_cpufreq_cpu_exit,
+	.name		= "mpc85xx-JOG",
+	.owner		= THIS_MODULE,
+	.flags		= CPUFREQ_CONST_LOOPS,
+};
+
+static struct of_device_id mpc85xx_jog_ids[] = {
+	{ .compatible = "fsl,mpc8536-guts", },
+	{ .compatible = "fsl,p1022-guts", },
+	{}
+};
+
+int mpc85xx_jog_probe(void)
+{
+	struct device_node *np;
+	unsigned int svr;
+
+	np = of_find_matching_node(NULL, mpc85xx_jog_ids);
+	if (!np)
+		return -ENODEV;
+
+	guts = of_iomap(np, 0);
+	if (!guts) {
+		of_node_put(np);
+		return -ENODEV;
+	}
+
+	sysfreq = fsl_get_sys_freq();
+
+	if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
+		svr = mfspr(SPRN_SVR);
+		if ((svr & 0x7fff) == 0x10) {
+			pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
+			of_node_put(np);
+			return -ENODEV;
+		}
+		mpc85xx_freqs = mpc8536_freqs_table;
+		set_pll = mpc8536_set_pll;
+		max_pll[0] = get_pll(0);
+
+	} else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
+		mpc85xx_freqs = p1022_freqs_table;
+		set_pll = p1022_set_pll;
+		max_pll[0] = get_pll(0);
+		max_pll[1] = get_pll(1);
+	}
+
+	pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
+
+	of_node_put(np);
+	return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
+}
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index a35ca44..7dbd239 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -204,6 +204,17 @@ config CPU_FREQ_PMAC64
 	  This adds support for frequency switching on Apple iMac G5,
 	  and some of the more recent desktop G5 machines as well.
 
+config MPC85xx_CPUFREQ
+	bool "Support for Freescale MPC85xx CPU freq"
+	depends on PPC_85xx && FSL_PMC
+	default n
+	select CPU_FREQ_TABLE
+	help
+	  This adds support for dynamic frequency switching on
+	  Freescale MPC85xx by cpufreq interface. MPC8536 and P1022
+	  have a JOG feature, which provides a dynamic mechanism
+	  to lower or raise the CPU core clock at runtime.
+
 config PPC_PASEMI_CPUFREQ
 	bool "Support for PA Semi PWRficient"
 	depends on PPC_PASEMI
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c
index b6c8c8f..b809a1b 100644
--- a/arch/powerpc/sysdev/fsl_pmc.c
+++ b/arch/powerpc/sysdev/fsl_pmc.c
@@ -202,6 +202,9 @@ static int pmc_probe(struct platform_device *pdev)
 
 	suspend_set_ops(&pmc_suspend_ops);
 
+#ifdef CONFIG_MPC85xx_CPUFREQ
+	mpc85xx_jog_probe();
+#endif
 	pr_info("Freescale PMC driver: sleep(standby)%s\n",
 		(pmc_flag & PMC_DEEP_SLEEP) ? ", deep sleep(mem)" : "");
 	return 0;
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index b1510ef..25be25c 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -65,5 +65,7 @@ void fsl_hv_halt(void);
  * code can be compatible with both 32-bit & 36-bit.
  */
 extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq);
+
+extern int mpc85xx_jog_probe(void);
 #endif
 #endif
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 2e9b9eb..c1ba260 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -145,6 +145,8 @@ void notify_cpu_starting(unsigned int cpu);
 extern void cpu_maps_update_begin(void);
 extern void cpu_maps_update_done(void);
 
+extern void cpu_hotplug_disable_before_freeze(void);
+extern void cpu_hotplug_enable_after_thaw(void);
 #else	/* CONFIG_SMP */
 
 #define cpu_notifier(fn, pri)	do { (void)(fn); } while (0)
@@ -166,6 +168,8 @@ static inline void cpu_maps_update_done(void)
 {
 }
 
+static inline void cpu_hotplug_disable_before_freeze(void)	{}
+static inline void cpu_hotplug_enable_after_thaw(void)	{}
 #endif /* CONFIG_SMP */
 extern struct bus_type cpu_subsys;
 
-- 
1.6.4.1

^ permalink raw reply related

* [PATCH] mpc85xx_defconfig: add IDE support for MPC85xxCDS
From: Zhao Chenhui @ 2012-07-20 12:45 UTC (permalink / raw)
  To: linuxppc-dev, galak; +Cc: linux-kernel

Add IDE support for MPC85xxCDS.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
 arch/powerpc/configs/mpc85xx_defconfig |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index 03ee911..45eda33 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -105,6 +105,8 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=131072
 CONFIG_MISC_DEVICES=y
 CONFIG_EEPROM_LEGACY=y
+CONFIG_IDE=y
+CONFIG_BLK_DEV_VIA82CXXX=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
-- 
1.6.4.1

^ permalink raw reply related

* [PATCH] powerpc/smp: Do not disable IPI interrupts during suspend
From: Zhao Chenhui @ 2012-07-20 12:47 UTC (permalink / raw)
  To: linuxppc-dev, galak; +Cc: linux-kernel

During suspend, all interrupts including IPI will be disabled. In this case,
the suspend process will hang in SMP. To prevent this, pass the flag
IRQF_NO_SUSPEND when requesting IPI irq.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
 arch/powerpc/kernel/smp.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index fecb038..d26bbf8 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -171,7 +171,7 @@ int smp_request_message_ipi(int virq, int msg)
 	}
 #endif
 	err = request_irq(virq, smp_ipi_action[msg],
-			  IRQF_PERCPU | IRQF_NO_THREAD,
+			  IRQF_PERCPU | IRQF_NO_THREAD | IRQF_NO_SUSPEND,
 			  smp_ipi_name[msg], 0);
 	WARN(err < 0, "unable to request_irq %d for %s (rc %d)\n",
 		virq, smp_ipi_name[msg], err);
-- 
1.6.4.1

^ permalink raw reply related

* [PATCH] powerpc/mm: add ZONE_NORMAL zone for 64 bit kernel
From: Shaohui Xie @ 2012-07-20 12:21 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Mingkai Hu, Shaohui Xie, Chen Yuanquan

PowerPC platform only supports ZONE_DMA zone for 64bit kernel, so all the
memory will be put into this zone. If the memory size is greater than
the device's DMA capability and device uses dma_alloc_coherent to allocate
memory, it will get an address which is over the device's DMA addressing,
the device will fail.

So we split the memory to two zones by adding a zone ZONE_NORMAL, since
we already allocate PCICSRBAR/PEXCSRBAR right below the 4G boundary (if the
lowest PCI address is above 4G), so we constrain the DMA zone ZONE_DMA
to 2GB, also, we clear the flag __GFP_DMA and set it only if the device's
dma_mask < total memory size. By doing this, devices which cannot DMA all
the memory will be limited to ZONE_DMA, but devices which can DMA all the
memory will not be affected by this limitation.

Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
Signed-off-by: Chen Yuanquan <B41889@freescale.com>
---
 arch/powerpc/kernel/dma.c |   13 ++++++++++++-
 arch/powerpc/mm/mem.c     |    4 +++-
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index b1ec983..8029295 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -30,6 +30,7 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 				struct dma_attrs *attrs)
 {
 	void *ret;
+	phys_addr_t top_ram_pfn = memblock_end_of_DRAM();
 #ifdef CONFIG_NOT_COHERENT_CACHE
 	ret = __dma_alloc_coherent(dev, size, dma_handle, flag);
 	if (ret == NULL)
@@ -40,8 +41,18 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size,
 	struct page *page;
 	int node = dev_to_node(dev);
 
+	/*
+	 * check for crappy device which has dma_mask < ZONE_DMA, and
+	 * we are not going to support it, just warn and fail.
+	 */
+	if (*dev->dma_mask < DMA_BIT_MASK(31)) {
+		dev_err(dev, "Unsupported dma_mask 0x%llx\n", *dev->dma_mask);
+		return NULL;
+	}
 	/* ignore region specifiers */
-	flag  &= ~(__GFP_HIGHMEM);
+	flag  &= ~(__GFP_HIGHMEM | __GFP_DMA);
+	if (*dev->dma_mask < top_ram_pfn - 1)
+		flag |= GFP_DMA;
 
 	page = alloc_pages_node(node, flag, get_order(size));
 	if (page == NULL)
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index baaafde..a494555 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -281,7 +281,9 @@ void __init paging_init(void)
 	max_zone_pfns[ZONE_DMA] = lowmem_end_addr >> PAGE_SHIFT;
 	max_zone_pfns[ZONE_HIGHMEM] = top_of_ram >> PAGE_SHIFT;
 #else
-	max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
+	max_zone_pfns[ZONE_DMA] = min_t(phys_addr_t, top_of_ram,
+					1ull << 31) >> PAGE_SHIFT;
+	max_zone_pfns[ZONE_NORMAL] = top_of_ram >> PAGE_SHIFT;
 #endif
 	free_area_init_nodes(max_zone_pfns);
 
-- 
1.6.4

^ permalink raw reply related

* [PATCH] pm: add power node to dts
From: Zhao Chenhui @ 2012-07-20 12:53 UTC (permalink / raw)
  To: linuxppc-dev, galak; +Cc: linux-kernel

The Power Management device tree stub indicated that the platform
supports Power Management feature.

Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
---
 arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi |   14 ++++++-
 arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi |    2 +
 arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi |    2 +
 arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi |    2 +
 arch/powerpc/boot/dts/fsl/p1010si-post.dtsi   |    8 ++++
 arch/powerpc/boot/dts/fsl/p1020si-post.dtsi   |    5 +++
 arch/powerpc/boot/dts/fsl/p1021si-post.dtsi   |    5 +++
 arch/powerpc/boot/dts/fsl/p1022si-post.dtsi   |   11 ++++--
 arch/powerpc/boot/dts/fsl/p2020si-post.dtsi   |   14 +++++++
 arch/powerpc/boot/dts/fsl/pq3-power.dtsi      |   48 +++++++++++++++++++++++++
 10 files changed, 106 insertions(+), 5 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/fsl/pq3-power.dtsi

diff --git a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
index c8b2daa..900f117 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi
@@ -199,6 +199,10 @@
 
 /include/ "pq3-dma-0.dtsi"
 /include/ "pq3-etsec1-0.dtsi"
+	enet0: ethernet@24000 {
+		fsl,wake-on-filer;
+		fsl,pmc-handle = <&etsec1_clk>;
+	};
 /include/ "pq3-etsec1-timer-0.dtsi"
 
 	usb@22000 {
@@ -222,9 +226,10 @@
 	};
 
 /include/ "pq3-etsec1-2.dtsi"
-
-	ethernet@26000 {
+	enet2: ethernet@26000 {
 		cell-index = <1>;
+		fsl,wake-on-filer;
+		fsl,pmc-handle = <&etsec3_clk>;
 	};
 
 	usb@2b000 {
@@ -249,4 +254,9 @@
 		reg = <0xe0000 0x1000>;
 		fsl,has-rstcr;
 	};
+
+/include/ "pq3-power.dtsi"
+	power@e0070 {
+		compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
+	};
 };
diff --git a/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi
index b68eb11..ea7416a 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8544si-post.dtsi
@@ -188,4 +188,6 @@
 		reg = <0xe0000 0x1000>;
 		fsl,has-rstcr;
 	};
+
+/include/ "pq3-power.dtsi"
 };
diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
index 579d76c..dddb737 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi
@@ -156,4 +156,6 @@
 		reg = <0xe0000 0x1000>;
 		fsl,has-rstcr;
 	};
+
+/include/ "pq3-power.dtsi"
 };
diff --git a/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi
index d44e25a..7313351 100644
--- a/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/mpc8572si-post.dtsi
@@ -193,4 +193,6 @@
 		reg = <0xe0000 0x1000>;
 		fsl,has-rstcr;
 	};
+
+/include/ "pq3-power.dtsi"
 };
diff --git a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
index 0bde9ee..108daa5 100644
--- a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi
@@ -171,6 +171,8 @@
 
 /include/ "pq3-etsec2-0.dtsi"
 	enet0: ethernet@b0000 {
+		fsl,pmc-handle = <&etsec1_clk>;
+
 		queue-group@b0000 {
 			fsl,rx-bit-map = <0xff>;
 			fsl,tx-bit-map = <0xff>;
@@ -179,6 +181,8 @@
 
 /include/ "pq3-etsec2-1.dtsi"
 	enet1: ethernet@b1000 {
+		fsl,pmc-handle = <&etsec2_clk>;
+
 		queue-group@b1000 {
 			fsl,rx-bit-map = <0xff>;
 			fsl,tx-bit-map = <0xff>;
@@ -187,6 +191,8 @@
 
 /include/ "pq3-etsec2-2.dtsi"
 	enet2: ethernet@b2000 {
+		fsl,pmc-handle = <&etsec3_clk>;
+
 		queue-group@b2000 {
 			fsl,rx-bit-map = <0xff>;
 			fsl,tx-bit-map = <0xff>;
@@ -199,4 +205,6 @@
 		reg = <0xe0000 0x1000>;
 		fsl,has-rstcr;
 	};
+
+/include/ "pq3-power.dtsi"
 };
diff --git a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
index 68cc5e7..410e6e5 100644
--- a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
@@ -162,14 +162,17 @@
 
 /include/ "pq3-etsec2-0.dtsi"
 	enet0: enet0_grp2: ethernet@b0000 {
+		fsl,pmc-handle = <&etsec1_clk>;
 	};
 
 /include/ "pq3-etsec2-1.dtsi"
 	enet1: enet1_grp2: ethernet@b1000 {
+		fsl,pmc-handle = <&etsec2_clk>;
 	};
 
 /include/ "pq3-etsec2-2.dtsi"
 	enet2: enet2_grp2: ethernet@b2000 {
+		fsl,pmc-handle = <&etsec3_clk>;
 	};
 
 	global-utilities@e0000 {
@@ -177,6 +180,8 @@
 		reg = <0xe0000 0x1000>;
 		fsl,has-rstcr;
 	};
+
+/include/ "pq3-power.dtsi"
 };
 
 /include/ "pq3-etsec2-grp2-0.dtsi"
diff --git a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
index adb82fd..02df574 100644
--- a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
@@ -158,14 +158,17 @@
 
 /include/ "pq3-etsec2-0.dtsi"
 	enet0: enet0_grp2: ethernet@b0000 {
+		fsl,pmc-handle = <&etsec1_clk>;
 	};
 
 /include/ "pq3-etsec2-1.dtsi"
 	enet1: enet1_grp2: ethernet@b1000 {
+		fsl,pmc-handle = <&etsec2_clk>;
 	};
 
 /include/ "pq3-etsec2-2.dtsi"
 	enet2: enet2_grp2: ethernet@b2000 {
+		fsl,pmc-handle = <&etsec3_clk>;
 	};
 
 	global-utilities@e0000 {
@@ -173,6 +176,8 @@
 		reg = <0xe0000 0x1000>;
 		fsl,has-rstcr;
 	};
+
+/include/ "pq3-power.dtsi"
 };
 
 &qe {
diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
index 06216b8..e5c0e27 100644
--- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
@@ -223,10 +223,14 @@
 
 /include/ "pq3-etsec2-0.dtsi"
 	enet0: enet0_grp2: ethernet@b0000 {
+		fsl,wake-on-filer;
+		fsl,pmc-handle = <&etsec1_clk>;
 	};
 
 /include/ "pq3-etsec2-1.dtsi"
 	enet1: enet1_grp2: ethernet@b1000 {
+		fsl,wake-on-filer;
+		fsl,pmc-handle = <&etsec2_clk>;
 	};
 
 	global-utilities@e0000 {
@@ -235,9 +239,10 @@
 		fsl,has-rstcr;
 	};
 
-	power@e0070{
-		compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
-		reg = <0xe0070 0x20>;
+/include/ "pq3-power.dtsi"
+	power@e0070 {
+		compatible = "fsl,p1022-pmc", "fsl,mpc8536-pmc",
+				"fsl,mpc8548-pmc";
 	};
 
 };
diff --git a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
index 884e01b..2c4787c 100644
--- a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi
@@ -175,6 +175,10 @@
 		compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr";
 	};
 /include/ "pq3-etsec1-0.dtsi"
+	enet0: ethernet@24000 {
+		fsl,pmc-handle = <&etsec1_clk>;
+
+	};
 /include/ "pq3-etsec1-timer-0.dtsi"
 
 	ptp_clock@24e00 {
@@ -183,7 +187,15 @@
 
 
 /include/ "pq3-etsec1-1.dtsi"
+	enet1: ethernet@25000 {
+		fsl,pmc-handle = <&etsec2_clk>;
+	};
+
 /include/ "pq3-etsec1-2.dtsi"
+	enet2: ethernet@26000 {
+		fsl,pmc-handle = <&etsec3_clk>;
+	};
+
 /include/ "pq3-esdhc-0.dtsi"
 	sdhc@2e000 {
 		compatible = "fsl,p2020-esdhc", "fsl,esdhc";
@@ -198,4 +210,6 @@
 		reg = <0xe0000 0x1000>;
 		fsl,has-rstcr;
 	};
+
+/include/ "pq3-power.dtsi"
 };
diff --git a/arch/powerpc/boot/dts/fsl/pq3-power.dtsi b/arch/powerpc/boot/dts/fsl/pq3-power.dtsi
new file mode 100644
index 0000000..5aa854c
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/pq3-power.dtsi
@@ -0,0 +1,48 @@
+/*
+ * PQ3 Power Management device tree stub
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Freescale Semiconductor 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") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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.
+ */
+
+power@e0070 {
+	compatible = "fsl,mpc8548-pmc";
+	reg = <0xe0070 0x20>;
+
+	etsec1_clk: soc-clk@24 {
+		fsl,pmcdr-mask = <0x00000080>;
+	};
+	etsec2_clk: soc-clk@25 {
+		fsl,pmcdr-mask = <0x00000040>;
+	};
+	etsec3_clk: soc-clk@26 {
+		fsl,pmcdr-mask = <0x00000020>;
+	};
+};
-- 
1.6.4.1

^ permalink raw reply related

* Re: [PATCH][upstream] TDM Framework
From: Michael Ellerman @ 2012-07-20 12:54 UTC (permalink / raw)
  To: sandeep; +Cc: Poonam Aggrwal, linuxppc-dev
In-Reply-To: <1342787714-8415-1-git-send-email-sandeep@freescale.com>

On Fri, 2012-07-20 at 18:05 +0530, sandeep@freescale.com wrote:
> From: Sandeep Singh <Sandeep@freescale.com>
> 
> TDM Framework is an attempt to provide a platform independent layer which can
> offer a standard interface  for TDM access to different client modules.
> Beneath, the framework layer can house different types of TDM drivers to handle
> various TDM devices, the hardware intricacies of the devices being completely
> taken care by TDM drivers.

TDM ?

cheers

^ permalink raw reply

* Re: [PATCH][upstream] TDM Framework
From: Josh Boyer @ 2012-07-20 13:27 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: sandeep, linuxppc-dev, Poonam Aggrwal
In-Reply-To: <1342788865.28608.0.camel@concordia>

On Fri, Jul 20, 2012 at 8:54 AM, Michael Ellerman
<michael@ellerman.id.au> wrote:
> On Fri, 2012-07-20 at 18:05 +0530, sandeep@freescale.com wrote:
>> From: Sandeep Singh <Sandeep@freescale.com>
>>
>> TDM Framework is an attempt to provide a platform independent layer which can
>> offer a standard interface  for TDM access to different client modules.
>> Beneath, the framework layer can house different types of TDM drivers to handle
>> various TDM devices, the hardware intricacies of the devices being completely
>> taken care by TDM drivers.
>
> TDM ?

And here I was thinking I was the only one scratching his head.  All I
could come up with was Time Division Multiplexing.

Protip: If you use an acronym a billion times in a patch, expand it at
least in one place.

josh

^ permalink raw reply

* Re: [PATCH 3/4] powerpc/crypto: add 842 hardware compression driver
From: Seth Jennings @ 2012-07-20 14:01 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: Robert Jennings, Herbert Xu, linux-kernel, Paul Mackerras,
	Jeff Kirsher, Greg Kroah-Hartman, Andrew Morton, Kent Yoder,
	linuxppc-dev, David S. Miller, linux-crypto
In-Reply-To: <1342762410.15356.7.camel@concordia>

On 07/20/2012 12:33 AM, Michael Ellerman wrote:
> On Thu, 2012-07-19 at 09:42 -0500, Seth Jennings wrote:
>> This patch adds the driver for interacting with the 842
>> compression accelerator on IBM Power7+ systems.
> 
> ...
> 
>> +struct nx842_slentry {
>> +	unsigned long ptr; /* Absolute address (use virt_to_abs()) */
>> /+	unsigned long len;
>> +};
> 
> These days virt_to_abs() is just __pa() - ie. convert to a real address.

Thanks, I'll make that change.

Is it a blocker to the code being pulled in though? I'm
hoping to get this in ASAP for the 3.6 merge window.  As
this isn't a functional defect (I assume __pa() and
virt_to_abs() still achieve the same result), can I get an
OK from you that this isn't a blocker to the code being
accepted?

I'll submit a patch later to make this change.

Thanks again!

Seth

^ permalink raw reply

* Re: [PATCH] mpc85xx_defconfig: add IDE support for MPC85xxCDS
From: Alan Cox @ 2012-07-20 14:09 UTC (permalink / raw)
  To: Zhao Chenhui; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <1342788325-27609-1-git-send-email-chenhui.zhao@freescale.com>

On Fri, 20 Jul 2012 20:45:25 +0800
Zhao Chenhui <chenhui.zhao@freescale.com> wrote:

> Add IDE support for MPC85xxCDS.
> 
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> ---
>  arch/powerpc/configs/mpc85xx_defconfig |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
> index 03ee911..45eda33 100644
> --- a/arch/powerpc/configs/mpc85xx_defconfig
> +++ b/arch/powerpc/configs/mpc85xx_defconfig
> @@ -105,6 +105,8 @@ CONFIG_BLK_DEV_RAM=y
>  CONFIG_BLK_DEV_RAM_SIZE=131072
>  CONFIG_MISC_DEVICES=y
>  CONFIG_EEPROM_LEGACY=y
> +CONFIG_IDE=y
> +CONFIG_BLK_DEV_VIA82CXXX=y

CONFIG_IDE is obsolete we shouldn't be adding it to anything as it will
eventually go away. Please use the ATA drivers.

^ permalink raw reply

* Re: [PATCH][upstream] TDM Framework
From: Stephen Rothwell @ 2012-07-20 14:50 UTC (permalink / raw)
  To: sandeep; +Cc: Sandeep Singh, Poonam Aggrwal, linuxppc-dev
In-Reply-To: <1342787714-8415-1-git-send-email-sandeep@freescale.com>

[-- Attachment #1: Type: text/plain, Size: 890 bytes --]

Hi,

On Fri, 20 Jul 2012 18:05:13 +0530 <sandeep@freescale.com> wrote:
>
> From: Sandeep Singh <Sandeep@freescale.com>
> 
> TDM Framework is an attempt to provide a platform independent layer which can
> offer a standard interface  for TDM access to different client modules.

I also wondered what TDM is.

> +++ b/drivers/tdm/Kconfig
> @@ -0,0 +1,18 @@
> +#
> +# TDM subsystem configuration
> +#
> +
> +menuconfig TDM
> +	tristate "TDM support"
> +	---help---
> +	  More information is contained in the directory <file:Documentation/tdm/>,
                                                               ^^^^^^^^^^^^^^^^^^
> +	  especially in the file called "summary" there.
                                         ^^^^^^^

It might help if those files were included in the patch set ...

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Errors related to i2c-powermac on the G4
From: Andrey Gusev @ 2012-07-20 14:46 UTC (permalink / raw)
  To: linuxppc-dev@lists.ozlabs.org

Hi!
I build kernel from git and can see errors in dmesg on boot. 3.4.5 
doesn't have such issue.
git show | head -n2
commit 85efc72a0218335324d358ac479a04c16316fd4d
Merge: 3e4b945 6a3ca4f

dmesg:
[    0.000000] Using PowerMac machine description
[    0.000000] Total memory = 1536MB; using 4096kB for hash table (at 
cfc00000)
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Linux version 3.5.0-rc7+ (andrey@power-debian) (gcc 
version 4.6.3 (Debian 4.6.3-8) ) #2 SMP PREEMPT Fri Jul 20 18:04:08 MSK 2012
[    0.000000] Found initrd at 0xc1300000:0xc16f8000
[    0.000000] Found UniNorth memory controller & host bridge @ 
0xf8000000 revision: 0x24
[    0.000000] Mapped at 0xff7c0000
[    0.000000] Found a Keylargo mac-io controller, rev: 3, mapped at 
0xff740000
[    0.000000] PowerMac motherboard: PowerMac G4 Windtunnel
[    0.000000] CPU maps initialized for 1 thread per core
[    0.000000]  (thread shift is 0)
[    0.000000] bootconsole [udbg0] enabled
[    0.000000] Found UniNorth PCI host bridge at 0x00000000f0000000. 
Firmware bus number: 0->0
[    0.000000] PCI host bridge /pci@f0000000  ranges:
[    0.000000]  MEM 0x00000000f1000000..0x00000000f1ffffff -> 
0x00000000f1000000
[    0.000000]   IO 0x00000000f0000000..0x00000000f07fffff -> 
0x0000000000000000
[    0.000000]  MEM 0x0000000090000000..0x00000000afffffff -> 
0x0000000090000000
[    0.000000] Found UniNorth PCI host bridge at 0x00000000f2000000. 
Firmware bus number: 0->0
[    0.000000] PCI host bridge /pci@f2000000 (primary) ranges:
[    0.000000]  MEM 0x00000000f3000000..0x00000000f3ffffff -> 
0x00000000f3000000
[    0.000000]   IO 0x00000000f2000000..0x00000000f27fffff -> 
0x0000000000000000
[    0.000000]  MEM 0x0000000080000000..0x000000008fffffff -> 
0x0000000080000000
[    0.000000] Found UniNorth PCI host bridge at 0x00000000f4000000. 
Firmware bus number: 0->0
[    0.000000] PCI host bridge /pci@f4000000  ranges:
[    0.000000]  MEM 0x00000000f5000000..0x00000000f5ffffff -> 
0x00000000f5000000
[    0.000000]   IO 0x00000000f4000000..0x00000000f47fffff -> 
0x0000000000000000
[    0.000000] via-pmu: Server Mode is disabled
[    0.000000] PMU driver v2 initialized for Core99, firmware: 0c
[    0.000000] nvram: Checking bank 0...
[    0.000000] nvram: gen0=1492, gen1=1493
[    0.000000] nvram: Active bank is: 1
[    0.000000] nvram: OF partition at 0x410
[    0.000000] nvram: XP partition at 0x1020
[    0.000000] nvram: NR partition at 0x1120
[    0.000000] Top of RAM: 0x60000000, Total RAM: 0x60000000
[    0.000000] Memory hole size: 0MB
[    0.000000] Zone ranges:
[    0.000000]   DMA      [mem 0x00000000-0x2fffffff]
[    0.000000]   Normal   empty
[    0.000000]   HighMem  [mem 0x30000000-0x5fffffff]
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x00000000-0x5fffffff]
[    0.000000] On node 0 totalpages: 393216
[    0.000000] free_area_init_node: node 0, pgdat c0567ca0, node_mem_map 
c05c2000
[    0.000000]   DMA zone: 1536 pages used for memmap
[    0.000000]   DMA zone: 0 pages reserved
[    0.000000]   DMA zone: 195072 pages, LIFO batch:31
[    0.000000]   HighMem zone: 1536 pages used for memmap
[    0.000000]   HighMem zone: 195072 pages, LIFO batch:31
[    0.000000] PERCPU: Embedded 7 pages/cpu @c11cd000 s7072 r8192 d13408 
u32768
[    0.000000] pcpu-alloc: s7072 r8192 d13408 u32768 alloc=8*4096
[    0.000000] pcpu-alloc: [0] 0 [0] 1
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  
Total pages: 390144
[    0.000000] Kernel command line: root=/dev/mapper/power--group-root 
ro nouveau.modeset=0 libata.force=2:pio4 drm.debug=0x04
[    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 
bytes)
[    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 
bytes)
[    0.000000] High memory: 786432k
[    0.000000] Memory: 1545224k/1572864k available (5392k kernel code, 
27640k reserved, 204k data, 244k bss, 236k init)
[    0.000000] Kernel virtual memory layout:
[    0.000000]   * 0xfffbf000..0xfffff000  : fixmap
[    0.000000]   * 0xff800000..0xffc00000  : highmem PTEs
[    0.000000]   * 0xfdcda000..0xff800000  : early ioremap
[    0.000000]   * 0xf1000000..0xfdcda000  : vmalloc & ioremap
[    0.000000] SLUB: Genslabs=15, HWalign=32, Order=0-3, MinObjects=0, 
CPUs=2, Nodes=1
[    0.000000] Preemptible hierarchical RCU implementation.
[    0.000000]     Dump stacks of tasks blocking RCU-preempt GP.
[    0.000000] NR_IRQS:128 nr_irqs:128 16
[    0.000000] mpic: Resetting
[    0.000000] mpic: Setting up MPIC " MPIC 1   " version 1.2 at 
80040000, max 2 CPUs
[    0.000000] mpic: ISU size: 64, shift: 6, mask: 3f
[    0.000000] mpic: Initializing for 64 sources
[    0.000000] GMT Delta read from XPRAM: 240 minutes, DST: on
[    0.000000] time_init: decrementer frequency = 33.304672 MHz
[    0.000000] time_init: processor frequency   = 866.666664 MHz
[    0.000000] clocksource: timebase mult[1e069bf8] shift[24] registered
[    0.000000] clockevent: decrementer mult[886a7ad] shift[32] cpu[0]
[    0.000000] Console: colour dummy device 80x25
[    0.000000] console [tty0] enabled, bootconsole disabled
[    0.001299] pid_max: default: 32768 minimum: 301
[    0.001485] Mount-cache hash table entries: 512
[    0.002003] device-tree: Duplicate name in 
/cpus/PowerPC,G4@0/l2-cache, renamed to "l2-cache#1"
[    0.002103] device-tree: Duplicate name in /cpus/PowerPC,G4@0, 
renamed to "l2-cache#1"
[    0.002239] device-tree: Duplicate name in 
/cpus/PowerPC,G4@1/l2-cache, renamed to "l2-cache#1"
[    0.002335] device-tree: Duplicate name in /cpus/PowerPC,G4@1, 
renamed to "l2-cache#1"
[    0.005927] Initializing cgroup subsys freezer
[    0.006500] PowerMac SMP probe found 2 cpus
[    0.006621] KeyWest i2c @0xf8001003 irq 42 /uni-n@f8000000/i2c@f8001000
[    0.006642]  channel 0 bus <multibus>
[    0.006654]  channel 1 bus <multibus>
[    0.006699] KeyWest i2c @0x80018000 irq 26 
/pci@f2000000/mac-io@17/i2c@18000
[    0.006717]  channel 0 bus <multibus>
[    0.006734] PMU i2c /pci@f2000000/mac-io@17/via-pmu@16000/pmu-i2c
[    0.006750]  channel 1 bus <multibus>
[    0.006762]  channel 2 bus <multibus>
[    0.006783] pmf: no parser for command 17 !
[    0.006826] Processor timebase sync using GPIO 0x73
[    0.006840] mpic: requesting IPIs...
[    0.006922] CPU0: L2CR is 80080000
[    0.006939] CPU0: L3CR is 8f0b0000
[    0.006956] MPC7450 family performance monitor hardware support 
registered
[476246925.023023] CPU1: L2CR was 80000
[476246925.023054] CPU1: L2CR set to 80080000
[476246925.023057] CPU1: L3CR was 0
[476246925.023215] CPU1: L3CR set to 8f0b0000
[    0.018176] Brought up 2 CPUs
[    0.019123] NET: Registered protocol family 16
[    0.021924] PCI: Probing PCI hardware
[    0.022130] PCI host bridge to bus 0000:00
[    0.022162] pci_bus 0000:00: root bus resource [io  
0x802000-0x1001fff] (bus address [0x0000-0x7fffff])
[    0.022193] pci_bus 0000:00: root bus resource [mem 
0xf1000000-0xf1ffffff]
[    0.022215] pci_bus 0000:00: root bus resource [mem 
0x90000000-0xafffffff]
[    0.022290] pci 0000:00:0b.0: [106b:0034] type 00 class 0x060000
[    0.022396] pci 0000:00:10.0: [10de:0172] type 00 class 0x030000
[    0.022421] pci 0000:00:10.0: reg 10: [mem 0x91000000-0x91ffffff]
[    0.022436] pci 0000:00:10.0: reg 14: [mem 0x98000000-0x9fffffff pref]
[    0.022451] pci 0000:00:10.0: reg 18: [mem 0x00000000-0x0007ffff pref]
[    0.022484] pci 0000:00:10.0: reg 30: [mem 0x90000000-0x9001ffff pref]
[    0.023104] PCI host bridge to bus 0001:10
[    0.023133] pci_bus 0001:10: root bus resource [io  0x0000-0x7fffff]
[    0.023155] pci_bus 0001:10: root bus resource [mem 
0xf3000000-0xf3ffffff]
[    0.023177] pci_bus 0001:10: root bus resource [mem 
0x80000000-0x8fffffff]
[    0.023231] pci 0001:10:0b.0: [106b:0035] type 00 class 0x060000
[    0.023318] pci 0001:10:15.0: [12eb:0002] type 00 class 0x040100
[    0.023341] pci 0001:10:15.0: reg 10: [mem 0x800c0000-0x800fffff]
[    0.023356] pci 0001:10:15.0: reg 14: [io  0x0410-0x0417]
[    0.023371] pci 0001:10:15.0: reg 18: [io  0x0400-0x0407]
[    0.023427] pci 0001:10:15.0: supports D2
[    0.023454] pci 0001:10:17.0: [106b:0022] type 00 class 0xff0000
[    0.023472] pci 0001:10:17.0: reg 10: [mem 0x80000000-0x8007ffff]
[    0.023546] pci 0001:10:18.0: [106b:0019] type 00 class 0x0c0310
[    0.023565] pci 0001:10:18.0: reg 10: [mem 0x80081000-0x80081fff]
[    0.023639] pci 0001:10:19.0: [106b:0019] type 00 class 0x0c0310
[    0.023659] pci 0001:10:19.0: reg 10: [mem 0x80080000-0x80080fff]
[    0.024952] PCI host bridge to bus 0002:20
[    0.024981] pci_bus 0002:20: root bus resource [io  
0xff7fe000-0xffffdfff] (bus address [0x0000-0x7fffff])
[    0.025012] pci_bus 0002:20: root bus resource [mem 
0xf5000000-0xf5ffffff]
[    0.025066] pci 0002:20:0b.0: [106b:0036] type 00 class 0x060000
[    0.025126] pci 0002:20:0d.0: [106b:0033] type 00 class 0xff0000
[    0.025144] pci 0002:20:0d.0: reg 10: [mem 0xf5004000-0xf5007fff]
[    0.025212] pci 0002:20:0e.0: [106b:0031] type 00 class 0x0c0010
[    0.025233] pci 0002:20:0e.0: reg 10: [mem 0xf5000000-0xf5000fff]
[    0.025292] pci 0002:20:0e.0: supports D1 D2
[    0.025300] pci 0002:20:0e.0: PME# supported from D0 D1 D2 D3hot
[    0.025329] pci 0002:20:0f.0: [106b:0032] type 00 class 0x020000
[    0.025347] pci 0002:20:0f.0: reg 10: [mem 0xf5200000-0xf53fffff]
[    0.025391] pci 0002:20:0f.0: reg 30: [mem 0xf5100000-0xf51fffff pref]
[    0.026420] PCI 0001:10 Cannot reserve Legacy IO [io  0x0000-0x0fff]
[    0.026443] pci 0000:00:10.0: BAR 2: assigned [mem 
0xf1000000-0xf107ffff pref]
[    0.026485] pci_bus 0000:00: resource 4 [io  0x802000-0x1001fff]
[    0.026493] pci_bus 0000:00: resource 5 [mem 0xf1000000-0xf1ffffff]
[    0.026501] pci_bus 0000:00: resource 6 [mem 0x90000000-0xafffffff]
[    0.026509] pci_bus 0001:10: resource 4 [io  0x0000-0x7fffff]
[    0.026517] pci_bus 0001:10: resource 5 [mem 0xf3000000-0xf3ffffff]
[    0.026525] pci_bus 0001:10: resource 6 [mem 0x80000000-0x8fffffff]
[    0.026533] pci_bus 0002:20: resource 4 [io  0xff7fe000-0xffffdfff]
[    0.026541] pci_bus 0002:20: resource 5 [mem 0xf5000000-0xf5ffffff]
[    0.040171] bio: create slab <bio-0> at 0
[    0.041044] vgaarb: device added: 
PCI:0000:00:10.0,decodes=io+mem,owns=mem,locks=none
[    0.041124] vgaarb: loaded
[    0.041138] vgaarb: bridge control possible 0000:00:10.0
[    0.041767] SCSI subsystem initialized
[    0.042242] libata version 3.00 loaded.
[    0.042661] usbcore: registered new interface driver usbfs
[    0.042839] usbcore: registered new interface driver hub
[    0.043046] usbcore: registered new device driver usb
[    0.043610] Advanced Linux Sound Architecture Driver Version 1.0.25.
[    0.044434] Switching to clocksource timebase
[    0.056661] NET: Registered protocol family 2
[    0.056832] IP route cache hash table entries: 32768 (order: 5, 
131072 bytes)
[    0.057466] TCP established hash table entries: 131072 (order: 8, 
1048576 bytes)
[    0.059937] TCP bind hash table entries: 65536 (order: 7, 786432 bytes)
[    0.061777] TCP: Hash tables configured (established 131072 bind 65536)
[    0.061818] TCP: reno registered
[    0.061845] UDP hash table entries: 512 (order: 2, 16384 bytes)
[    0.061899] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
[    0.062184] NET: Registered protocol family 1
[    0.062301] pci 0001:10:18.0: enabling device (0000 -> 0002)
[    0.112542] pci 0001:10:19.0: enabling device (0000 -> 0002)
[    0.163532] PCI: CLS mismatch (32 != 1020), using 32 bytes
[    0.163724] Trying to unpack rootfs image as initramfs...
[    0.374104] Freeing initrd memory: 4064k freed
[    0.375276] Thermal assist unit not available
[    0.377113] highmem bounce pool size: 64 pages
[    0.393582] fuse init (API version 7.19)
[    0.394172] msgmni has been set to 1489
[    0.396965] alg: No test for stdrng (krng)
[    0.418813] Block layer SCSI generic (bsg) driver version 0.4 loaded 
(major 253)
[    0.418856] io scheduler noop registered
[    0.419099] io scheduler cfq registered (default)
[    0.419447] Using unsupported 1600x1200 NVDA,Display-B at 98004000, 
depth=8, pitch=2048
[    0.450602] Console: switching to colour frame buffer device 200x75
[    0.479372] fb0: Open Firmware frame buffer device on 
/pci@f0000000/NVDA,Parent@10/NVDA,Display-B@1
[    0.479661] Using unsupported 640x480 NVDA,Display-A at 99000000, 
depth=8, pitch=640
[    0.479898] checking generic (98004000 258000) vs hw (99000000 4b000)
[    0.480124] fb1: Open Firmware frame buffer device on 
/pci@f0000000/NVDA,Parent@10/NVDA,Display-A@0
[    0.480587] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[    0.481886] pmac_zilog: 0.6 (Benjamin Herrenschmidt 
<benh@kernel.crashing.org>)
[    0.482291] Generic non-volatile memory driver v1.1
[    0.482593] Linux agpgart interface v0.103
[    0.482736] agpgart-uninorth 0000:00:0b.0: Apple UniNorth 2 chipset
[    0.484460] agpgart-uninorth 0000:00:0b.0: configuring for size idx: 64
[    0.484827] agpgart-uninorth 0000:00:0b.0: AGP aperture is 256M @ 0x0
[    0.491700] brd: module loaded
[    0.495335] loop: module loaded
[    0.495689] MacIO PCI driver attached to Keylargo chipset
[    0.498235] 0.00013020:ch-a: ttyPZ0 at MMIO 0x80013020 (irq = 22) is 
a Z85c30 ESCC - Serial port
[    0.498968] 0.00013000:ch-b: ttyPZ1 at MMIO 0x80013000 (irq = 23) is 
a Z85c30 ESCC - Serial port
[    0.500475] pata-pci-macio 0002:20:0d.0: enabling device (0000 -> 0002)
[    0.511513] pata-pci-macio 0002:20:0d.0: Activating pata-macio 
chipset UniNorth ATA-6, Apple bus ID 3
[    0.512635] scsi0 : pata_macio
[    0.513093] ata1: PATA max UDMA/100 irq 39
[    0.667968] ata1.00: ATA-5: IBM-IC35L060AVVA07-0, VA3BA52A, max UDMA/100
[    0.668179] ata1.00: 120103200 sectors, multi 16: LBA
[    0.676945] ata1.00: configured for UDMA/100
[    0.677456] scsi 0:0:0:0: Direct-Access     ATA      IBM-IC35L060AVVA 
VA3B PQ: 0 ANSI: 5
[    1.525510] pata-macio 0.0001f000:ata-4: Activating pata-macio 
chipset KeyLargo ATA-4, Apple bus ID 2
[    1.526619] scsi1 : pata_macio
[    1.527015] ata2: PATA max UDMA/66 irq 19
[    1.697163] ata2.00: HPA detected: current 40130390, native 40132503
[    1.697343] ata2.00: ATA-5: QUANTUM FIREBALLP LM20.5, A35.0700, max 
UDMA/66
[    1.697535] ata2.00: 40130390 sectors, multi 0: LBA
[    1.697675] ata2.00: FORCE: xfer_mask set to pio4
[    1.720124] ata2.00: configured for PIO4
[    1.720481] scsi 1:0:0:0: Direct-Access     ATA      QUANTUM FIREBALL 
A35. PQ: 0 ANSI: 5
[    2.538510] pata-macio 0.00020000:ata-3: Activating pata-macio 
chipset KeyLargo ATA-3, Apple bus ID 0
[    2.539571] scsi2 : pata_macio
[    2.539987] ata3: PATA max MWDMA2 irq 20
[    2.540364] sungem.c:v1.0 David S. Miller <davem@redhat.com>
[    2.541529] gem 0002:20:0f.0: eth0: Sun GEM (PCI) 10/100/1000BaseT 
Ethernet 00:03:93:ab:d1:a6
[    2.542312] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    2.542818] ohci_hcd 0001:10:18.0: OHCI Host Controller
[    2.542980] ohci_hcd 0001:10:18.0: new USB bus registered, assigned 
bus number 1
[    2.543251] ohci_hcd 0001:10:18.0: irq 27, io mem 0x80081000
[    2.613408] usb usb1: New USB device found, idVendor=1d6b, idProduct=0001
[    2.613604] usb usb1: New USB device strings: Mfr=3, Product=2, 
SerialNumber=1
[    2.613797] usb usb1: Product: OHCI Host Controller
[    2.613926] usb usb1: Manufacturer: Linux 3.5.0-rc7+ ohci_hcd
[    2.622108] usb usb1: SerialNumber: 0001:10:18.0
[    2.622663] hub 1-0:1.0: USB hub found
[    2.622683] hub 1-0:1.0: 2 ports detected
[    2.622841] ohci_hcd 0001:10:19.0: OHCI Host Controller
[    2.622856] ohci_hcd 0001:10:19.0: new USB bus registered, assigned 
bus number 2
[    2.622907] ohci_hcd 0001:10:19.0: irq 28, io mem 0x80080000
[    2.692391] usb usb2: New USB device found, idVendor=1d6b, idProduct=0001
[    2.700756] ata3.00: ATAPI: TSSTcorp CDDVDW SH-S222A, SB02, max UDMA/66
[    2.708672] usb usb2: New USB device strings: Mfr=3, Product=2, 
SerialNumber=1
[    2.716736] usb usb2: Product: OHCI Host Controller
[    2.724896] usb usb2: Manufacturer: Linux 3.5.0-rc7+ ohci_hcd
[    2.733113] ata3.00: configured for MWDMA2
[    2.737517] usb usb2: SerialNumber: 0001:10:19.0
[    2.749518] hub 2-0:1.0: USB hub found
[    2.757747] hub 2-0:1.0: 2 ports detected
[    2.766328] uhci_hcd: USB Universal Host Controller Interface driver
[    2.766676] scsi 2:0:0:0: CD-ROM            TSSTcorp CDDVDW SH-S222A  
SB02 PQ: 0 ANSI: 5
[    2.783116] mousedev: PS/2 mouse device common for all mice
[    2.784565] sr0: scsi3-mmc drive: 48x/48x writer dvd-ram cd/rw 
xa/form2 cdda tray
[    2.784571] cdrom: Uniform CD-ROM driver Revision: 3.20
[    2.785023] sr 2:0:0:0: Attached scsi CD-ROM sr0
[    2.808056] rtc-generic rtc-generic: rtc core: registered rtc-generic 
as rtc0
[    2.816567] i2c /dev entries driver
[    2.825370] i2c i2c-0: therm_windtunnel: attach_adapter method is 
deprecated
[    2.833666] i2c i2c-0: Please use another way to instantiate your 
i2c_client
[    2.841935] PowerMac i2c bus pmu 2 registered
[    2.850440] i2c i2c-1: therm_windtunnel: attach_adapter method is 
deprecated
[    2.858624] i2c i2c-1: Please use another way to instantiate your 
i2c_client
[    2.866754] PowerMac i2c bus pmu 1 registered
[    2.875415] i2c i2c-2: therm_windtunnel: attach_adapter method is 
deprecated
[    2.883473] i2c i2c-2: Please use another way to instantiate your 
i2c_client
[    2.891500] PowerMac i2c bus mac-io 0 registered
[    2.899496] i2c i2c-2: i2c-powermac: invalid reg on 
/pci@f2000000/mac-io@17/i2c@18000/cereal
[    2.907626] i2c i2c-2: i2c-powermac: invalid reg on 
/pci@f2000000/mac-io@17/i2c@18000/deq
[    2.915711] i2c i2c-2: i2c-powermac: invalid reg on 
/pci@f2000000/mac-io@17/i2c@18000/i2c-modem
[    2.924148] i2c i2c-3: therm_windtunnel: attach_adapter method is 
deprecated
[    2.932259] i2c i2c-3: Please use another way to instantiate your 
i2c_client
[    2.941370] PowerMac i2c bus uni-n 1 registered
[    2.949523] i2c i2c-3: i2c-powermac: invalid reg on 
/uni-n@f8000000/i2c@f8001000/cereal
[    2.958084] i2c i2c-4: therm_windtunnel: attach_adapter method is 
deprecated
[    2.958531] usb 1-1: new full-speed USB device number 2 using ohci_hcd
[    2.974633] i2c i2c-4: Please use another way to instantiate your 
i2c_client
[    2.984188] DS1775 digital thermometer [@49]
[    2.992590] Temp: 58.1 C  Hyst: 70.0 C  OS: 75.0 C
[    3.001592] ADM1030 fan controller [@2c]
[    3.009847] PowerMac i2c bus uni-n 0 registered
[    3.018007] i2c i2c-4: Failed to register i2c client MAC,adm1030 at 
0x2c (-16)
[    3.026299] i2c i2c-4: i2c-powermac: Failure to register 
/uni-n@f8000000/i2c@f8001000/fan@58
[    3.034827] i2c i2c-4: Failed to register i2c client MAC,ds1775 at 
0x49 (-16)
[    3.043106] i2c i2c-4: i2c-powermac: Failure to register 
/uni-n@f8000000/i2c@f8001000/temp-monitor@92
[    3.051420] i2c i2c-4: i2c-powermac: invalid reg on 
/uni-n@f8000000/i2c@f8001000/cereal
[    3.060750] device-mapper: ioctl: 4.22.0-ioctl (2011-10-19) 
initialised: dm-devel@redhat.com
[    3.071757] usbcore: registered new interface driver usbhid
[    3.080215] usbhid: USB HID core driver
[    3.088767] TCP: cubic registered
[    3.097981] NET: Registered protocol family 10
[    3.106997] sit: IPv6 over IPv4 tunneling driver
[    3.116214] NET: Registered protocol family 17
[    3.125056] registered taskstats version 1
[    3.133221] usb 1-1: New USB device found, idVendor=05e3, idProduct=0608
[    3.141806] usb 1-1: New USB device strings: Mfr=0, Product=1, 
SerialNumber=0
[    3.142123] input: PMU as /devices/virtual/input/input0
[    3.158220] usb 1-1: Product: USB2.0 Hub
[    3.158235] rtc-generic rtc-generic: setting system clock to 
2012-07-20 14:13:40 UTC (1342793620)
[    3.158267] ALSA device list:
[    3.158269]   No soundcards found.
[    3.191467] Freeing unused kernel memory: 236k freed
[    3.200129] hub 1-1:1.0: USB hub found
[    3.209554] hub 1-1:1.0: 4 ports detected
[    3.506533] usb 1-1.1: new full-speed USB device number 3 using ohci_hcd
[    3.604581] usb 1-1.1: New USB device found, idVendor=05e3, 
idProduct=0608
[    3.614028] usb 1-1.1: New USB device strings: Mfr=0, Product=1, 
SerialNumber=0
[    3.622455] usb 1-1.1: Product: USB2.0 Hub
[    3.632649] hub 1-1.1:1.0: USB hub found
[    3.641563] hub 1-1.1:1.0: 4 ports detected
[    3.676594] sd 1:0:0:0: [sdb] 40130390 512-byte logical blocks: (20.5 
GB/19.1 GiB)
[    3.685049] sd 0:0:0:0: [sda] 120103200 512-byte logical blocks: 
(61.4 GB/57.2 GiB)
[    3.693552] sd 0:0:0:0: [sda] Write Protect is off
[    3.701893] sd 1:0:0:0: [sdb] Write Protect is off
[    3.710039] sd 0:0:0:0: [sda] Mode Sense: 00 3a 00 00
[    3.710088] sd 1:0:0:0: [sdb] Mode Sense: 00 3a 00 00
[    3.710185] sd 0:0:0:0: [sda] Write cache: enabled, read cache: 
enabled, doesn't support DPO or FUA
[    3.718425] sd 1:0:0:0: [sdb] Write cache: enabled, read cache: 
enabled, doesn't support DPO or FUA
[    3.733521]  sdb: [mac] sdb1 sdb2
[    3.741916]  sda: [mac] sda1 sda2 sda3 sda4
[    3.752562] sd 0:0:0:0: [sda] Attached SCSI disk
[    3.760667] sd 1:0:0:0: [sdb] Attached SCSI disk
[    3.765386] firewire_ohci 0002:20:0e.0: enabling device (0000 -> 0002)
[    3.818016] firewire_ohci 0002:20:0e.0: added OHCI v1.10 device as 
card 0, 8 IR + 8 IT contexts, quirks 0x0
[    3.952567] usb 1-1.1.2: new low-speed USB device number 4 using ohci_hcd
[    4.059556] usb 1-1.1.2: New USB device found, idVendor=046d, 
idProduct=c05f
[    4.067674] usb 1-1.1.2: New USB device strings: Mfr=1, Product=2, 
SerialNumber=0
[    4.075979] usb 1-1.1.2: Product: USB Optical Mouse
[    4.084184] usb 1-1.1.2: Manufacturer: Logitech
[    4.100649] input: Logitech USB Optical Mouse as 
/devices/pci0001:10/0001:10:18.0/usb1/1-1/1-1.1/1-1.1.2/1-1.1.2:1.0/input/input1
[    4.109222] hid-generic 0003:046D:C05F.0001: input,hidraw0: USB HID 
v1.11 Mouse [Logitech USB Optical Mouse] on usb-0001:10:18.0-1.1.2/input0
[    4.187566] usb 1-1.1.4: new low-speed USB device number 5 using ohci_hcd
[    4.298550] usb 1-1.1.4: New USB device found, idVendor=04d9, 
idProduct=0022
[    4.307154] usb 1-1.1.4: New USB device strings: Mfr=0, Product=2, 
SerialNumber=0
[    4.315731] usb 1-1.1.4: Product: USB Keyboard
[    4.325248] firewire_core 0002:20:0e.0: created device fw0: GUID 
000393fffeabd1a6, S400
[    4.344770] input: USB Keyboard as 
/devices/pci0001:10/0001:10:18.0/usb1/1-1/1-1.1/1-1.1.4/1-1.1.4:1.0/input/input2
[    4.353865] hid-generic 0003:04D9:0022.0002: input,hidraw1: USB HID 
v1.10 Keyboard [USB Keyboard] on usb-0001:10:18.0-1.1.4/input0
[    4.383826] input: USB Keyboard as 
/devices/pci0001:10/0001:10:18.0/usb1/1-1/1-1.1/1-1.1.4/1-1.1.4:1.1/input/input3
[    4.393591] hid-generic 0003:04D9:0022.0003: input,hidraw2: USB HID 
v1.10 Device [USB Keyboard] on usb-0001:10:18.0-1.1.4/input1
[   11.071787] CPU-temp: 58.3 C, Case: 42.0 C,  Fan: 4 (tuned -7)
[   17.491115] EXT3-fs (dm-1): mounted filesystem with writeback data mode
[   17.500095] kjournald starting.  Commit interval 5 seconds
[   19.988537] udevd[844]: starting version 175
[   21.035940] [drm] Initialized drm 1.1.0 20060810
[   21.761861] snd-aoa-fabric-layout: Using direct GPIOs
[   21.789148] i2c i2c-0: aoa_codec_tas: attach_adapter method is deprecated
[   21.798499] i2c i2c-0: Please use another way to instantiate your 
i2c_client
[   21.807708] i2c i2c-1: aoa_codec_tas: attach_adapter method is deprecated
[   21.817284] i2c i2c-1: Please use another way to instantiate your 
i2c_client
[   21.826853] i2c i2c-2: aoa_codec_tas: attach_adapter method is deprecated
[   21.836126] i2c i2c-2: Please use another way to instantiate your 
i2c_client
[   21.836133] snd-aoa-codec-tas: found 'deq' node
[   21.843569] snd-aoa-fabric-layout: can use this codec
[   21.891167] snd-aoa-codec-tas: tas found, addr 0x35 on 
/pci@f2000000/mac-io@17/i2c@18000/deq
[   21.891216] i2c i2c-3: aoa_codec_tas: attach_adapter method is deprecated
[   21.904528] i2c i2c-3: Please use another way to instantiate your 
i2c_client
[   21.914716] i2c i2c-4: aoa_codec_tas: attach_adapter method is deprecated
[   21.924114] i2c i2c-4: Please use another way to instantiate your 
i2c_client
[   22.422901] snd_au8830 0001:10:15.0: enabling device (0004 -> 0007)
[   22.432683] Vortex: init....
[   22.765728] done.
[   25.615272] EXT3-fs (dm-1): using internal journal
[   28.262558] Adding 1048572k swap on /dev/mapper/power--group-swap_1.  
Priority:-1 extents:1 across:1048572k
[   30.133666] kjournald starting.  Commit interval 5 seconds
[   30.142936] EXT3-fs (dm-3): using internal journal
[   30.151909] EXT3-fs (dm-3): mounted filesystem with writeback data mode
[   30.182230] REISERFS (device dm-4): found reiserfs format "3.6" with 
standard journal
[   30.191216] REISERFS (device dm-4): using ordered data mode
[   30.200049] reiserfs: using flush barriers
[   30.214671] REISERFS (device dm-4): journal params: device dm-4, size 
8192, journal first block 18, max trans len 1024, max batch 900, max 
commit age 30, max trans age 30
[   30.226596] REISERFS (device dm-4): checking transaction log (dm-4)
[   30.279661] REISERFS (device dm-4): Using r5 hash to sort names
[   30.562935] EXT4-fs (sdb2): barriers disabled
[   30.577379] EXT4-fs (sdb2): mounted filesystem with writeback data 
mode. Opts: barrier=0,data=writeback
[   32.871229] usb 1-1.1.2: USB disconnect, device number 4
[   35.075732] CPU-temp: 58.8 C, Case: 41.7 C,  Fan: 5 (tuned +1)
[   35.217224] usb 1-1.1.2: new low-speed USB device number 6 using ohci_hcd
[   35.326226] usb 1-1.1.2: New USB device found, idVendor=046d, 
idProduct=c05f
[   35.338929] usb 1-1.1.2: New USB device strings: Mfr=1, Product=2, 
SerialNumber=0
[   35.352827] usb 1-1.1.2: Product: USB Optical Mouse
[   35.362657] usb 1-1.1.2: Manufacturer: Logitech
[   35.371432] input: Logitech USB Optical Mouse as 
/devices/pci0001:10/0001:10:18.0/usb1/1-1/1-1.1/1-1.1.2/1-1.1.2:1.0/input/input4
[   35.371620] hid-generic 0003:046D:C05F.0004: input,hidraw0: USB HID 
v1.11 Mouse [Logitech USB Optical Mouse] on usb-0001:10:18.0-1.1.2/input0
[   36.152910] sungem_phy: PHY ID: 2060e1, addr: 0
[   36.153154] gem 0002:20:0f.0: eth0: Found BCM5421 PHY
[   36.164232] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
[   38.569869] gem 0002:20:0f.0: eth0: Link is up at 100 Mbps, full-duplex
[   38.579574] gem 0002:20:0f.0: eth0: Pause is enabled (rxfifo: 10240 
off: 7168 on: 5632)

On kernel 3.4.5: lspci -vvv

0000:00:0b.0 Host bridge: Apple Inc. UniNorth 2 AGP
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort+ >SERR- <PERR- INTx-
     Latency: 16, Cache Line Size: 32 bytes
     Capabilities: [80] AGP version 1.0
         Status: RQ=8 Iso- ArqSz=0 Cal=0 SBA+ ITACoh- GART64- HTrans- 
64bit- FW+ AGP3- Rate=x1,x2,x4
         Command: RQ=1 ArqSz=0 Cal=0 SBA- AGP- GART64- 64bit- FW- 
Rate=<none>
     Kernel driver in use: agpgart-uninorth

0000:00:10.0 VGA compatible controller: NVIDIA Corporation NV17 
[GeForce4 MX 420] (rev a3) (prog-if 00 [VGA controller])
     Subsystem: NVIDIA Corporation Device 0008
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort- >SERR- <PERR- INTx-
     Latency: 248 (1250ns min, 250ns max)
     Interrupt: pin A routed to IRQ 48
     Region 0: Memory at 91000000 (32-bit, non-prefetchable) [size=16M]
     Region 1: Memory at 98000000 (32-bit, prefetchable) [size=128M]
     Region 2: Memory at f1000000 (32-bit, prefetchable) [size=512K]
     Expansion ROM at 90000000 [disabled] [size=128K]
     Capabilities: [60] Power Management version 2
         Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA 
PME(D0-,D1-,D2-,D3hot-,D3cold-)
         Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
     Capabilities: [44] AGP version 2.0
         Status: RQ=32 Iso- ArqSz=0 Cal=0 SBA- ITACoh- GART64- HTrans- 
64bit- FW+ AGP3- Rate=x1,x2,x4
         Command: RQ=1 ArqSz=0 Cal=0 SBA- AGP- GART64- 64bit- FW- 
Rate=<none>

0001:10:0b.0 Host bridge: Apple Inc. UniNorth 2 PCI
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort+ >SERR- <PERR- INTx-
     Latency: 16, Cache Line Size: 32 bytes

0001:10:15.0 Multimedia audio controller: Aureal Semiconductor Vortex 2 
(rev fe)
     Subsystem: Diamond Multimedia Systems Monster Sound II
     Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort- >SERR- <PERR- INTx-
     Latency: 16 (1000ns min, 3000ns max), Cache Line Size: 32 bytes
     Interrupt: pin A routed to IRQ 58
     Region 0: Memory at 800c0000 (32-bit, non-prefetchable) [size=256K]
     Region 1: I/O ports at 0410 [size=8]
     Region 2: I/O ports at 0400 [size=8]
     Capabilities: [dc] Power Management version 1
         Flags: PMEClk- DSI+ D1- D2+ AuxCurrent=0mA 
PME(D0-,D1-,D2-,D3hot-,D3cold-)
         Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
     Kernel driver in use: snd_au8830

0001:10:17.0 Unassigned class [ff00]: Apple Inc. KeyLargo Mac I/O (rev 03)
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort- >SERR- <PERR- INTx-
     Latency: 16, Cache Line Size: 32 bytes
     Region 0: Memory at 80000000 (32-bit, non-prefetchable) [size=512K]
     Kernel driver in use: macio

0001:10:18.0 USB controller: Apple Inc. KeyLargo USB (prog-if 10 [OHCI])
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort- >SERR- <PERR- INTx-
     Latency: 16 (750ns min, 21500ns max)
     Interrupt: pin A routed to IRQ 27
     Region 0: Memory at 80081000 (32-bit, non-prefetchable) [size=4K]
     Kernel driver in use: ohci_hcd

0001:10:19.0 USB controller: Apple Inc. KeyLargo USB (prog-if 10 [OHCI])
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort- >SERR- <PERR- INTx-
     Latency: 16 (750ns min, 21500ns max)
     Interrupt: pin A routed to IRQ 28
     Region 0: Memory at 80080000 (32-bit, non-prefetchable) [size=4K]
     Kernel driver in use: ohci_hcd

0002:20:0b.0 Host bridge: Apple Inc. UniNorth 2 Internal PCI
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort+ >SERR- <PERR- INTx-
     Latency: 16, Cache Line Size: 32 bytes

0002:20:0d.0 Unassigned class [ff00]: Apple Inc. UniNorth 2 ATA/100
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort- >SERR- <PERR+ INTx-
     Latency: 32, Cache Line Size: 32 bytes
     Interrupt: pin ? routed to IRQ 39
     Region 0: Memory at f5004000 (32-bit, non-prefetchable) [size=16K]
     Kernel driver in use: pata-pci-macio

0002:20:0e.0 FireWire (IEEE 1394): Apple Inc. UniNorth 2 FireWire (rev 
01) (prog-if 10 [OHCI])
     Subsystem: Apple Inc. iBook G4 2004
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- 
<TAbort- <MAbort- >SERR- <PERR- INTx-
     Latency: 64 (3000ns min, 6000ns max), Cache Line Size: 32 bytes
     Interrupt: pin A routed to IRQ 40
     Region 0: Memory at f5000000 (32-bit, non-prefetchable) [size=4K]
     Capabilities: [44] Power Management version 2
         Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA 
PME(D0+,D1+,D2+,D3hot+,D3cold-)
         Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME+
     Kernel driver in use: firewire_ohci

0002:20:0f.0 Ethernet controller: Apple Inc. UniNorth 2 GMAC (Sun GEM)
     Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- 
Stepping- SERR- FastB2B- DisINTx-
     Status: Cap- 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=slow >TAbort- 
<TAbort- <MAbort- >SERR- <PERR+ INTx-
     Latency: 16 (16000ns min, 16000ns max), Cache Line Size: 32 bytes
     Interrupt: pin A routed to IRQ 41
     Region 0: Memory at f5200000 (32-bit, non-prefetchable) [size=2M]
     Expansion ROM at f5100000 [disabled] [size=1M]
     Kernel driver in use: gem


cat /proc/ioports
00000000-007fffff : /pci@f2000000
   00000400-00000407 : 0001:10:15.0
     00000400-00000407 : au8830
   00000410-00000417 : 0001:10:15.0
     00000410-00000417 : au8830
00802000-01001fff : /pci@f0000000
   00802000-00802fff : Legacy IO
ff7fe000-ffffdfff : /pci@f4000000
   ff7fe000-ff7fefff : Legacy IO

cat /proc/iomem
00000000-5fffffff : System RAM
80000000-8fffffff : /pci@f2000000
   80000000-8007ffff : 0001:10:17.0
     80000000-8007ffff : 0.80000000:mac-io
       80000050-8000007f : 0.00000050:gpio
       80008000-800080ff : 0.00010000:i2s
         80008000-800080ff : i2sbus: i2s-a (tx)
       80008100-800081ff : 0.00010000:i2s
         80008100-800081ff : i2sbus: i2s-a (rx)
       80008200-800082ff : 0.00010000:i2s
       80008300-800083ff : 0.00010000:i2s
       80008a00-80008aff : 0.0001f000:ata-4
         80008a00-80008aff : pata-macio-dma
       80008b00-80008bff : 0.00020000:ata-3
         80008b00-80008bff : pata-macio-dma
       80010000-80010fff : 0.00010000:i2s
         80010000-80010fff : i2sbus: i2s-a (control)
       80013000-80013000 : 0.00013000:ch-b
         80013000-80013000 : pmac_zilog
       80013010-80013010 : 0.00013000:ch-b
         80013010-80013010 : pmac_zilog
       80013020-80013020 : 0.00013020:ch-a
         80013020-80013020 : pmac_zilog
       80013030-80013030 : 0.00013020:ch-a
         80013030-80013030 : pmac_zilog
       80013040-80013040 : 0.00013000:ch-b
         80013040-80013040 : pmac_zilog
       80013050-80013050 : 0.00013020:ch-a
         80013050-80013050 : pmac_zilog
       80015000-80015fff : 0.00015000:timer
       80016000-80017fff : 0.00016000:via-pmu
       80018000-80018fff : 0.00018000:i2c
       8001f000-8001ffff : 0.0001f000:ata-4
         8001f000-8001ffff : pata-macio
       80020000-80020fff : 0.00020000:ata-3
         80020000-80020fff : pata-macio
       80040000-8007ffff : 0.00040000:interrup
   80080000-80080fff : 0001:10:19.0
     80080000-80080fff : ohci_hcd
   80081000-80081fff : 0001:10:18.0
     80081000-80081fff : ohci_hcd
   800c0000-800fffff : 0001:10:15.0
     800c0000-800fffff : au8830
90000000-afffffff : /pci@f0000000
   90000000-9001ffff : 0000:00:10.0
   91000000-91ffffff : 0000:00:10.0
   98000000-9fffffff : 0000:00:10.0
     98004000-9825bfff : offb
     99000000-9904afff : offb
f1000000-f1ffffff : /pci@f0000000
   f1000000-f107ffff : 0000:00:10.0
f3000000-f3ffffff : /pci@f2000000
f5000000-f5ffffff : /pci@f4000000
   f5000000-f5000fff : 0002:20:0e.0
     f5000000-f5000fff : firewire_ohci
   f5004000-f5007fff : 0002:20:0d.0
     f5004000-f5007fff : pata-macio
   f5100000-f51fffff : 0002:20:0f.0
   f5200000-f53fffff : 0002:20:0f.0
     f5200000-f53fffff : sungem

cat /proc/interrupts
            CPU0       CPU1
  19:     102335     246416   MPIC 1    Level     pata-macio
  20:       1880       4818   MPIC 1    Level     pata-macio
  25:          0          2   MPIC 1    Level     VIA-PMU
  26:          7         49   MPIC 1    Level     keywest i2c
  27:       6878      18995   MPIC 1    Level     ohci_hcd:usb1
  28:          0          1   MPIC 1    Level     ohci_hcd:usb2
  30:          0          0   MPIC 1    Level     i2sbus: i2s-a (control)
  31:          0          0   MPIC 1    Edge      i2sbus: i2s-a (tx)
  33:          0          0   MPIC 1    Edge      i2sbus: i2s-a (rx)
  39:       6376      17040   MPIC 1    Level     pata-pci-macio
  40:          8         14   MPIC 1    Level     firewire_ohci
  41:        752       2018   MPIC 1    Level     eth0
  42:        994       2269   MPIC 1    Level     keywest i2c
  47:          0          0   MPIC 1    Level     GPIO1 ADB
  58:          0          0   MPIC 1    Level     snd_au8830
  60:          0          0   MPIC 1    Edge      lineout-detect
  61:          0          0   MPIC 1    Edge      headphone-detect
123:          0          0   MPIC 1    Edge      ipi call function
124:      20414      17465   MPIC 1    Edge      ipi reschedule
125:       9766       4066   MPIC 1    Edge      ipi call function single
LOC:    1420948    1414212   Local timer interrupts
SPU:          0          3   Spurious interrupts
CNT:          0          0   Performance monitoring interrupts
MCE:          0          0   Machine check exceptions

power-debian:/home/andrey/personal/pbliga/pbliga# cat /proc/cpuinfo
processor    : 0
cpu        : 7455, altivec supported
clock        : 866.666664MHz
revision    : 2.1 (pvr 8001 0201)
bogomips    : 66.60

processor    : 1
cpu        : 7455, altivec supported
clock        : 866.666664MHz
revision    : 2.1 (pvr 8001 0201)
bogomips    : 66.60

total bogomips    : 133.21
timebase    : 33304672
platform    : PowerMac
model        : PowerMac3,6
machine        : PowerMac3,6
motherboard    : PowerMac3,6 MacRISC2 MacRISC Power Macintosh
detected as    : 129 (PowerMac G4 Windtunnel)
pmac flags    : 00000010
L2 cache    : 256K unified
pmac-generation    : NewWorld
Memory        : 1536 MB

Best,
Andrey

^ permalink raw reply

* Re: mpc8xxx PCIe hotplug needs fixing, some clues ..
From: Kumar Gala @ 2012-07-20 18:53 UTC (permalink / raw)
  To: Joakim Tjernlund; +Cc: scottwood, linuxppc-dev
In-Reply-To: <OFDEF2A72A.01F68496-ONC1257A41.0025B7CE-C1257A41.0028192F@transmode.se>


On Jul 20, 2012, at 2:17 AM, Joakim Tjernlund wrote:

>=20
> Hi Guys
>=20
> I see that you have been hacking Freescale PCI before so I send this =
to you(and the list)
>=20
> We are using PCIe(as RC) on P2010(basically a mpc85xx) and have PCI =
device that
> started from user space (needs advance clock conf) so when linux boots =
there is
> no device at all.
> Trying to "hotplug" the device after it is enabled fails, no amount of =
recan/remove using
> either fake or real hotplug makes a difference.
>=20
> I found the cause eventually but I can't fix it properly as I known =
almost nothing about PCI.
> Cause:
> indirect_pci.c:indirect_read_config() tests for if =
(hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK)
> and returns  PCIBIOS_DEVICE_NOT_FOUND
>=20
> PPC_INDIRECT_TYPE_NO_PCIE_LINK get set by fsl_pci.c (look for =
fsl_pcie_check_link) but is never cleared.
> Clearing it as appropriate makes a small difference. If you
> remove the RC and do a few of rescan's then the device appears.
>=20
> Hacking some more, like so:
>=20
> int fsl_pcie_check_link(struct pci_controller *hose)
> {
> 	u32 val;
>=20
> 	early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
> 	hose->indirect_type |=3D PPC_INDIRECT_TYPE_NO_PCIE_LINK;
> 	if (val < PCIE_LTSSM_L0)
> 		return 1;
> 	hose->indirect_type &=3D ~PPC_INDIRECT_TYPE_NO_PCIE_LINK;
> 	return 0;
> }
> and then using it carefully(it is easy to make linux hang) in =
indirect_read_config():
> indirect_read_config(struct pci_bus *bus, unsigned int devfn, int =
offset,
> 		     int len, u32 *val)
> {
> 	struct pci_controller *hose =3D pci_bus_to_host(bus);
> 	volatile void __iomem *cfg_data;
> 	u8 cfg_type =3D 0;
> 	u32 bus_no, reg;
>=20
> 	if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) {
> 		if (bus->number !=3D hose->first_busno ||
> 		    devfn !=3D 0) {
> 			fsl_pcie_check_link(hose);
> 			return PCIBIOS_DEVICE_NOT_FOUND;
> 		}
> 	}
>=20
> Now it works, just one rescan and the device appears!
> This is a hack, I don't known what other trouble it can cause, I hope =
you can
> sort this out.

How are you forcing the re-scan?  We can see if we can add a re-check of =
the link state in that flow somewhere.

Can you do a dump_stack() or something to get a call chain?

- k=

^ permalink raw reply

* RE: [PATCH][upstream] TDM Framework
From: Aggrwal Poonam-B10812 @ 2012-07-21  7:36 UTC (permalink / raw)
  To: Stephen Rothwell, Singh Sandeep-B37400
  Cc: linuxppc-dev@lists.ozlabs.org, Singh Sandeep-B37400
In-Reply-To: <20120721005005.ace23a85cf3f0d2589990d00@canb.auug.org.au>

Sorry the documentation patch got missed in this patchset.

Will send it again.

Regards
Poonam

> -----Original Message-----
> From: Stephen Rothwell [mailto:sfr@canb.auug.org.au]
> Sent: Friday, July 20, 2012 8:20 PM
> To: Singh Sandeep-B37400
> Cc: linuxppc-dev@lists.ozlabs.org; Singh Sandeep-B37400; Aggrwal Poonam-
> B10812
> Subject: Re: [PATCH][upstream] TDM Framework
>=20
> Hi,
>=20
> On Fri, 20 Jul 2012 18:05:13 +0530 <sandeep@freescale.com> wrote:
> >
> > From: Sandeep Singh <Sandeep@freescale.com>
> >
> > TDM Framework is an attempt to provide a platform independent layer
> > which can offer a standard interface  for TDM access to different
> client modules.
>=20
> I also wondered what TDM is.
>=20
> > +++ b/drivers/tdm/Kconfig
> > @@ -0,0 +1,18 @@
> > +#
> > +# TDM subsystem configuration
> > +#
> > +
> > +menuconfig TDM
> > +	tristate "TDM support"
> > +	---help---
> > +	  More information is contained in the directory
> > +<file:Documentation/tdm/>,
>=20
> ^^^^^^^^^^^^^^^^^^
> > +	  especially in the file called "summary" there.
>                                          ^^^^^^^
>=20
> It might help if those files were included in the patch set ...
>=20
> --
> Cheers,
> Stephen Rothwell                    sfr@canb.auug.org.au

^ permalink raw reply

* RE: [PATCH][upstream] TDM Framework
From: Aggrwal Poonam-B10812 @ 2012-07-21  7:36 UTC (permalink / raw)
  To: Josh Boyer, Michael Ellerman
  Cc: linuxppc-dev@lists.ozlabs.org, Singh Sandeep-B37400
In-Reply-To: <CA+5PVA7XSv7Fbg8DLCZMPmOzMX6uDnxzsAna2gW4RCfH7=eCUg@mail.gmail.com>



> -----Original Message-----
> From: Josh Boyer [mailto:jwboyer@gmail.com]
> Sent: Friday, July 20, 2012 6:57 PM
> To: Michael Ellerman
> Cc: Singh Sandeep-B37400; Aggrwal Poonam-B10812; linuxppc-
> dev@lists.ozlabs.org
> Subject: Re: [PATCH][upstream] TDM Framework
>=20
> On Fri, Jul 20, 2012 at 8:54 AM, Michael Ellerman
> <michael@ellerman.id.au> wrote:
> > On Fri, 2012-07-20 at 18:05 +0530, sandeep@freescale.com wrote:
> >> From: Sandeep Singh <Sandeep@freescale.com>
> >>
> >> TDM Framework is an attempt to provide a platform independent layer
> >> which can offer a standard interface  for TDM access to different
> client modules.
> >> Beneath, the framework layer can house different types of TDM drivers
> >> to handle various TDM devices, the hardware intricacies of the
> >> devices being completely taken care by TDM drivers.
> >
> > TDM ?
>=20
> And here I was thinking I was the only one scratching his head.  All I
> could come up with was Time Division Multiplexing.
>=20
Sorry for that. TDM refers to Time Division Multiplexing. Actually the firs=
t version of this patch set also had a patch which documented TDM basics.
We missed it this time.

Will just send the TDM documentation patch also.

Regards
Poonam

For your reference:

> Protip: If you use an acronym a billion times in a patch, expand it at
> least in one place.
>=20
> josh

^ permalink raw reply

* RE: [PATCH][upstream] TDM Framework
From: Aggrwal Poonam-B10812 @ 2012-07-21  9:20 UTC (permalink / raw)
  To: Aggrwal Poonam-B10812, Josh Boyer, Michael Ellerman
  Cc: linuxppc-dev@lists.ozlabs.org, Singh Sandeep-B37400
In-Reply-To: <ACB6D0C0104CFF42A45A5D82A0DD4F3D079B37CA@039-SN2MPN1-013.039d.mgd.msft.net>



> -----Original Message-----
> From: Linuxppc-dev [mailto:linuxppc-dev-
> bounces+poonam.aggrwal=3Dfreescale.com@lists.ozlabs.org] On Behalf Of
> Aggrwal Poonam-B10812
> Sent: Saturday, July 21, 2012 1:07 PM
> To: Josh Boyer; Michael Ellerman
> Cc: linuxppc-dev@lists.ozlabs.org; Singh Sandeep-B37400
> Subject: RE: [PATCH][upstream] TDM Framework
>=20
>=20
>=20
> > -----Original Message-----
> > From: Josh Boyer [mailto:jwboyer@gmail.com]
> > Sent: Friday, July 20, 2012 6:57 PM
> > To: Michael Ellerman
> > Cc: Singh Sandeep-B37400; Aggrwal Poonam-B10812; linuxppc-
> > dev@lists.ozlabs.org
> > Subject: Re: [PATCH][upstream] TDM Framework
> >
> > On Fri, Jul 20, 2012 at 8:54 AM, Michael Ellerman
> > <michael@ellerman.id.au> wrote:
> > > On Fri, 2012-07-20 at 18:05 +0530, sandeep@freescale.com wrote:
> > >> From: Sandeep Singh <Sandeep@freescale.com>
> > >>
> > >> TDM Framework is an attempt to provide a platform independent layer
> > >> which can offer a standard interface  for TDM access to different
> > client modules.
> > >> Beneath, the framework layer can house different types of TDM
> > >> drivers to handle various TDM devices, the hardware intricacies of
> > >> the devices being completely taken care by TDM drivers.
> > >
> > > TDM ?
> >
> > And here I was thinking I was the only one scratching his head.  All I
> > could come up with was Time Division Multiplexing.
> >
> Sorry for that. TDM refers to Time Division Multiplexing. Actually the
> first version of this patch set also had a patch which documented TDM
> basics.
> We missed it this time.
>=20
> Will just send the TDM documentation patch also.
The documentation patch is at:
http://patchwork.ozlabs.org/patch/145857/

>=20
> Regards
> Poonam
>=20
> For your reference:
>=20
> > Protip: If you use an acronym a billion times in a patch, expand it at
> > least in one place.
> >
> > josh
>=20
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox