From: Matt Porter <mporter@kernel.crashing.org>
To: akpm@osdl.org
Cc: benh@kernel.crashing.org, linux-kernel@vger.kernel.org,
linuxppc-dev@lists.linuxppc.org
Subject: [PATCH 1/2] PPC32: New OCP core support
Date: Tue, 11 May 2004 17:01:50 -0700 [thread overview]
Message-ID: <20040511170150.A4743@home.com> (raw)
New OCP infrastructure ported from 2.4 along with several
enhancements. Please apply.
-Matt
diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig Tue May 11 14:56:45 2004
+++ b/arch/ppc/Kconfig Tue May 11 14:56:45 2004
@@ -1238,7 +1238,7 @@
bool "Support for early boot texts over serial port"
depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550
-config OCP
+config PPC_OCP
bool
depends on IBM_OCP
default y
diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile Tue May 11 14:56:45 2004
+++ b/arch/ppc/Makefile Tue May 11 14:56:45 2004
@@ -43,7 +43,6 @@
drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/
drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/
drivers-$(CONFIG_8260) += arch/ppc/8260_io/
-drivers-$(CONFIG_OCP) += arch/ppc/ocp/
BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm
diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c Tue May 11 14:56:45 2004
+++ b/arch/ppc/kernel/setup.c Tue May 11 14:56:45 2004
@@ -37,6 +37,7 @@
#include <asm/sections.h>
#include <asm/nvram.h>
#include <asm/xmon.h>
+#include <asm/ocp.h>
#if defined CONFIG_KGDB
#include <asm/kgdb.h>
@@ -682,6 +683,12 @@
/* set up the bootmem stuff with available memory */
do_init_bootmem();
if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
+
+#ifdef CONFIG_PPC_OCP
+ /* Initialize OCP device list */
+ ocp_early_init();
+ if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab);
+#endif
ppc_md.setup_arch();
if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
diff -Nru a/arch/ppc/ocp/Makefile b/arch/ppc/ocp/Makefile
--- a/arch/ppc/ocp/Makefile Tue May 11 14:56:45 2004
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,6 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-obj-y := ocp.o ocp-driver.o ocp-probe.o
-
diff -Nru a/arch/ppc/ocp/ocp-driver.c b/arch/ppc/ocp/ocp-driver.c
--- a/arch/ppc/ocp/ocp-driver.c Tue May 11 14:56:45 2004
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,195 +0,0 @@
-/*
- * FILE NAME: ocp-driver.c
- *
- * BRIEF MODULE DESCRIPTION:
- * driver callback, id matching and registration
- * Based on drivers/pci/pci-driver, Copyright (c) 1997--1999 Martin Mares
- *
- * Maintained by: Armin <akuster@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR 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.
- *
- * 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 <asm/ocp.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-/*
- * Registration of OCP drivers and handling of hot-pluggable devices.
- */
-
-static int
-ocp_device_probe(struct device *dev)
-{
- int error = 0;
- struct ocp_driver *drv;
- struct ocp_device *ocp_dev;
-
- drv = to_ocp_driver(dev->driver);
- ocp_dev = to_ocp_dev(dev);
-
- if (drv->probe) {
- error = drv->probe(ocp_dev);
- DBG("probe return code %d\n", error);
- if (error >= 0) {
- ocp_dev->driver = drv;
- error = 0;
- }
- }
- return error;
-}
-
-static int
-ocp_device_remove(struct device *dev)
-{
- struct ocp_device *ocp_dev = to_ocp_dev(dev);
-
- if (ocp_dev->driver) {
- if (ocp_dev->driver->remove)
- ocp_dev->driver->remove(ocp_dev);
- ocp_dev->driver = NULL;
- }
- return 0;
-}
-
-static int
-ocp_device_suspend(struct device *dev, u32 state, u32 level)
-{
- struct ocp_device *ocp_dev = to_ocp_dev(dev);
-
- int error = 0;
-
- if (ocp_dev->driver) {
- if (level == SUSPEND_SAVE_STATE && ocp_dev->driver->save_state)
- error = ocp_dev->driver->save_state(ocp_dev, state);
- else if (level == SUSPEND_POWER_DOWN
- && ocp_dev->driver->suspend)
- error = ocp_dev->driver->suspend(ocp_dev, state);
- }
- return error;
-}
-
-static int
-ocp_device_resume(struct device *dev, u32 level)
-{
- struct ocp_device *ocp_dev = to_ocp_dev(dev);
-
- if (ocp_dev->driver) {
- if (level == RESUME_POWER_ON && ocp_dev->driver->resume)
- ocp_dev->driver->resume(ocp_dev);
- }
- return 0;
-}
-
-/**
- * ocp_bus_match - Works out whether an OCP device matches any
- * of the IDs listed for a given OCP driver.
- * @dev: the generic device struct for the OCP device
- * @drv: the generic driver struct for the OCP driver
- *
- * Used by a driver to check whether a OCP device present in the
- * system is in its list of supported devices. Returns 1 for a
- * match, or 0 if there is no match.
- */
-static int
-ocp_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct ocp_device *ocp_dev = to_ocp_dev(dev);
- struct ocp_driver *ocp_drv = to_ocp_driver(drv);
- const struct ocp_device_id *ids = ocp_drv->id_table;
-
- if (!ids)
- return 0;
-
- while (ids->vendor || ids->device) {
- if ((ids->vendor == OCP_ANY_ID
- || ids->vendor == ocp_dev->vendor)
- && (ids->device == OCP_ANY_ID
- || ids->device == ocp_dev->device)) {
- DBG("Bus match -vendor:%x device:%x\n", ids->vendor,
- ids->device);
- return 1;
- }
- ids++;
- }
- return 0;
-}
-
-struct bus_type ocp_bus_type = {
- .name = "ocp",
- .match = ocp_bus_match,
-};
-
-static int __init
-ocp_driver_init(void)
-{
- return bus_register(&ocp_bus_type);
-}
-
-postcore_initcall(ocp_driver_init);
-
-/**
- * ocp_register_driver - register a new ocp driver
- * @drv: the driver structure to register
- *
- * Adds the driver structure to the list of registered drivers
- * Returns the number of ocp devices which were claimed by the driver
- * during registration. The driver remains registered even if the
- * return value is zero.
- */
-int
-ocp_register_driver(struct ocp_driver *drv)
-{
- int count = 0;
-
- /* initialize common driver fields */
- drv->driver.name = drv->name;
- drv->driver.bus = &ocp_bus_type;
- drv->driver.probe = ocp_device_probe;
- drv->driver.resume = ocp_device_resume;
- drv->driver.suspend = ocp_device_suspend;
- drv->driver.remove = ocp_device_remove;
-
- /* register with core */
- count = driver_register(&drv->driver);
- return count ? count : 1;
-}
-
-/**
- * ocp_unregister_driver - unregister a ocp driver
- * @drv: the driver structure to unregister
- *
- * Deletes the driver structure from the list of registered OCP drivers,
- * gives it a chance to clean up by calling its remove() function for
- * each device it was responsible for, and marks those devices as
- * driverless.
- */
-
-void
-ocp_unregister_driver(struct ocp_driver *drv)
-{
- driver_unregister(&drv->driver);
-}
-
-EXPORT_SYMBOL(ocp_register_driver);
-EXPORT_SYMBOL(ocp_unregister_driver);
-EXPORT_SYMBOL(ocp_bus_type);
diff -Nru a/arch/ppc/ocp/ocp-probe.c b/arch/ppc/ocp/ocp-probe.c
--- a/arch/ppc/ocp/ocp-probe.c Tue May 11 14:56:45 2004
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,113 +0,0 @@
-/*
- * FILE NAME: ocp-probe.c
- *
- * BRIEF MODULE DESCRIPTION:
- * Device scanning & bus set routines
- * Based on drivers/pci/probe, Copyright (c) 1997--1999 Martin Mares
- *
- * Maintained by: Armin <akuster@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR 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.
- *
- * 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/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <asm/ocp.h>
-
-LIST_HEAD(ocp_devices);
-struct device *ocp_bus;
-
-static struct ocp_device * __devinit
-ocp_setup_dev(struct ocp_def *odef, unsigned int index)
-{
- struct ocp_device *dev;
-
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return NULL;
- memset(dev, 0, sizeof(*dev));
-
- dev->vendor = odef->vendor;
- dev->device = odef->device;
- dev->num = ocp_get_num(dev->device);
- dev->paddr = odef->paddr;
- dev->irq = odef->irq;
- dev->pm = odef->pm;
- dev->current_state = 4;
-
- sprintf(dev->name, "OCP device %04x:%04x", dev->vendor, dev->device);
-
- DBG("%s %s 0x%lx irq:%d pm:0x%lx \n", dev->slot_name, dev->name,
- (unsigned long) dev->paddr, dev->irq, dev->pm);
-
- /* now put in global tree */
- sprintf(dev->dev.bus_id, "%d", index);
- dev->dev.parent = ocp_bus;
- dev->dev.bus = &ocp_bus_type;
- device_register(&dev->dev);
-
- return dev;
-}
-
-static struct device * __devinit ocp_alloc_primary_bus(void)
-{
- struct device *b;
-
- b = kmalloc(sizeof(struct device), GFP_KERNEL);
- if (b == NULL)
- return NULL;
- memset(b, 0, sizeof(struct device));
- strcpy(b->bus_id, "ocp");
-
- device_register(b);
-
- return b;
-}
-
-void __devinit ocp_setup_devices(struct ocp_def *odef)
-{
- int index;
- struct ocp_device *dev;
-
- if (ocp_bus == NULL)
- ocp_bus = ocp_alloc_primary_bus();
- for (index = 0; odef->vendor != OCP_VENDOR_INVALID; ++index, ++odef) {
- dev = ocp_setup_dev(odef, index);
- if (dev != NULL)
- list_add_tail(&dev->global_list, &ocp_devices);
- }
-}
-
-extern struct ocp_def core_ocp[];
-
-static int __init
-ocparch_init(void)
-{
- ocp_setup_devices(core_ocp);
- return 0;
-}
-
-subsys_initcall(ocparch_init);
-
-EXPORT_SYMBOL(ocp_devices);
diff -Nru a/arch/ppc/ocp/ocp.c b/arch/ppc/ocp/ocp.c
--- a/arch/ppc/ocp/ocp.c Tue May 11 14:56:45 2004
+++ /dev/null Wed Dec 31 16:00:00 1969
@@ -1,109 +0,0 @@
-/*
- * ocp.c
- *
- * The is drived from pci.c
- *
- * Current Maintainer
- * Armin Kuster akuster@dslextreme.com
- * Jan, 2002
- *
- *
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR 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.
- *
- * 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/list.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <asm/ocp.h>
-#include <asm/errno.h>
-
-/**
- * ocp_get_num - This determines how many OCP devices of a given
- * device are registered
- * @device: OCP device such as HOST, PCI, GPT, UART, OPB, IIC, GPIO, EMAC, ZMII,
- *
- * The routine returns the number that devices which is registered
- */
-unsigned int ocp_get_num(unsigned int device)
-{
- unsigned int count = 0;
- struct ocp_device *ocp;
- struct list_head *ocp_l;
-
- list_for_each(ocp_l, &ocp_devices) {
- ocp = list_entry(ocp_l, struct ocp_device, global_list);
- if (device == ocp->device)
- count++;
- }
- return count;
-}
-
-/**
- * ocp_get_dev - get ocp driver pointer for ocp device and instance of it
- * @device: OCP device such as PCI, GPT, UART, OPB, IIC, GPIO, EMAC, ZMII
- * @dev_num: ocp device number whos paddr you want
- *
- * The routine returns ocp device pointer
- * in list based on device and instance of that device
- *
- */
-struct ocp_device *
-ocp_get_dev(unsigned int device, int dev_num)
-{
- struct ocp_device *ocp;
- struct list_head *ocp_l;
- int count = 0;
-
- list_for_each(ocp_l, &ocp_devices) {
- ocp = list_entry(ocp_l, struct ocp_device, global_list);
- if (device == ocp->device) {
- if (dev_num == count)
- return ocp;
- count++;
- }
- }
- return NULL;
-}
-
-EXPORT_SYMBOL(ocp_get_dev);
-EXPORT_SYMBOL(ocp_get_num);
-
-#ifdef CONFIG_PM
-int ocp_generic_suspend(struct ocp_device *pdev, u32 state)
-{
- ocp_force_power_off(pdev);
- return 0;
-}
-
-int ocp_generic_resume(struct ocp_device *pdev)
-{
- ocp_force_power_on(pdev);
-}
-
-EXPORT_SYMBOL(ocp_generic_suspend);
-EXPORT_SYMBOL(ocp_generic_resume);
-#endif /* CONFIG_PM */
diff -Nru a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
--- a/arch/ppc/syslib/Makefile Tue May 11 14:56:45 2004
+++ b/arch/ppc/syslib/Makefile Tue May 11 14:56:45 2004
@@ -13,6 +13,7 @@
CFLAGS_btext.o += -mrelocatable-lib
obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o
+obj-$(CONFIG_PPC_OCP) += ocp.o
obj-$(CONFIG_44x) += ibm44x_common.o
obj-$(CONFIG_440GP) += ibm440gp_common.o
ifeq ($(CONFIG_4xx),y)
diff -Nru a/arch/ppc/syslib/ocp.c b/arch/ppc/syslib/ocp.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ocp.c Tue May 11 14:56:45 2004
@@ -0,0 +1,584 @@
+/*
+ * ocp.c
+ *
+ * (c) Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ * Mipsys - France
+ *
+ * Derived from work (c) Armin Kuster akuster@pacbell.net
+ *
+ * Additional support and port to 2.6 LDM/sysfs by
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2004 MontaVista Software, 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/bootmem.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/ocp.h>
+#include <asm/errno.h>
+#include <asm/rwsem.h>
+#include <asm/semaphore.h>
+
+//#define DBG(x) printk x
+#define DBG(x)
+
+extern int mem_init_done;
+
+extern struct ocp_def core_ocp[]; /* Static list of devices, provided by
+ CPU core */
+
+LIST_HEAD(ocp_devices); /* List of all OCP devices */
+DECLARE_RWSEM(ocp_devices_sem); /* Global semaphores for those lists */
+
+static int ocp_inited;
+
+/* Sysfs support */
+#define OCP_DEF_ATTR(field, format_string) \
+static ssize_t \
+show_##field(struct device *dev, char *buf) \
+{ \
+ struct ocp_device *odev = to_ocp_dev(dev); \
+ \
+ return sprintf(buf, format_string, odev->def->field); \
+} \
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+OCP_DEF_ATTR(vendor, "0x%04x\n");
+OCP_DEF_ATTR(function, "0x%04x\n");
+OCP_DEF_ATTR(index, "0x%04x\n");
+#ifdef CONFIG_PTE_64BIT
+OCP_DEF_ATTR(paddr, "0x%16Lx\n");
+#else
+OCP_DEF_ATTR(paddr, "0x%08lx\n");
+#endif
+OCP_DEF_ATTR(irq, "%d\n");
+OCP_DEF_ATTR(pm, "%lu\n");
+
+void ocp_create_sysfs_dev_files(struct ocp_device *odev)
+{
+ struct device *dev = &odev->dev;
+
+ /* Current OCP device def attributes */
+ device_create_file(dev, &dev_attr_vendor);
+ device_create_file(dev, &dev_attr_function);
+ device_create_file(dev, &dev_attr_index);
+ device_create_file(dev, &dev_attr_paddr);
+ device_create_file(dev, &dev_attr_irq);
+ device_create_file(dev, &dev_attr_pm);
+ /* Current OCP device additions attributes */
+ if (odev->def->additions && odev->def->show)
+ odev->def->show(dev);
+}
+
+/**
+ * ocp_device_match - Match one driver to one device
+ * @drv: driver to match
+ * @dev: device to match
+ *
+ * This function returns 0 if the driver and device don't match
+ */
+static int
+ocp_device_match(struct device *dev, struct device_driver *drv)
+{
+ struct ocp_device *ocp_dev = to_ocp_dev(dev);
+ struct ocp_driver *ocp_drv = to_ocp_drv(drv);
+ const struct ocp_device_id *ids = ocp_drv->id_table;
+
+ if (!ids)
+ return 0;
+
+ while (ids->vendor || ids->function) {
+ if ((ids->vendor == OCP_ANY_ID
+ || ids->vendor == ocp_dev->def->vendor)
+ && (ids->function == OCP_ANY_ID
+ || ids->function == ocp_dev->def->function))
+ return 1;
+ ids++;
+ }
+ return 0;
+}
+
+static int
+ocp_device_probe(struct device *dev)
+{
+ int error = 0;
+ struct ocp_driver *drv;
+ struct ocp_device *ocp_dev;
+
+ drv = to_ocp_drv(dev->driver);
+ ocp_dev = to_ocp_dev(dev);
+
+ if (drv->probe) {
+ error = drv->probe(ocp_dev);
+ if (error >= 0) {
+ ocp_dev->driver = drv;
+ error = 0;
+ }
+ }
+ return error;
+}
+
+static int
+ocp_device_remove(struct device *dev)
+{
+ struct ocp_device *ocp_dev = to_ocp_dev(dev);
+
+ if (ocp_dev->driver) {
+ if (ocp_dev->driver->remove)
+ ocp_dev->driver->remove(ocp_dev);
+ ocp_dev->driver = NULL;
+ }
+ return 0;
+}
+
+static int
+ocp_device_suspend(struct device *dev, u32 state)
+{
+ struct ocp_device *ocp_dev = to_ocp_dev(dev);
+ struct ocp_driver *ocp_drv = to_ocp_drv(dev->driver);
+
+ if (dev->driver && ocp_drv->suspend)
+ return ocp_drv->suspend(ocp_dev, state);
+ return 0;
+}
+
+static int
+ocp_device_resume(struct device *dev)
+{
+ struct ocp_device *ocp_dev = to_ocp_dev(dev);
+ struct ocp_driver *ocp_drv = to_ocp_drv(dev->driver);
+
+ if (dev->driver && ocp_drv->resume)
+ return ocp_drv->resume(ocp_dev);
+ return 0;
+}
+
+struct bus_type ocp_bus_type = {
+ .name = "ocp",
+ .match = ocp_device_match,
+ .suspend = ocp_device_suspend,
+ .resume = ocp_device_resume,
+};
+
+/**
+ * ocp_register_driver - Register an OCP driver
+ * @drv: pointer to statically defined ocp_driver structure
+ *
+ * The driver's probe() callback is called either recursively
+ * by this function or upon later call of ocp_driver_init
+ *
+ * NOTE: Detection of devices is a 2 pass step on this implementation,
+ * hotswap isn't supported. First, all OCP devices are put in the device
+ * list, _then_ all drivers are probed on each match.
+ *
+ * This function returns a count of how many devices actually matched
+ * (whether the probe routine returned 0 or -ENODEV, a different error
+ * code isn't considered as a match).
+ */
+int
+ocp_register_driver(struct ocp_driver *drv)
+{
+ int count = 0;
+
+ /* initialize common driver fields */
+ drv->driver.name = drv->name;
+ drv->driver.bus = &ocp_bus_type;
+ drv->driver.probe = ocp_device_probe;
+ drv->driver.remove = ocp_device_remove;
+
+ /* register with core */
+ count = driver_register(&drv->driver);
+
+ return count ? count : 1;
+}
+
+/**
+ * ocp_unregister_driver - Unregister an OCP driver
+ * @drv: pointer to statically defined ocp_driver structure
+ *
+ * The driver's remove() callback is called recursively
+ * by this function for any device already registered
+ */
+void
+ocp_unregister_driver(struct ocp_driver *drv)
+{
+ DBG(("ocp: ocp_unregister_driver(%s)...\n", drv->name));
+
+ driver_unregister(&drv->driver);
+
+ DBG(("ocp: ocp_unregister_driver(%s)... done.\n", drv->name));
+}
+
+/* Core of ocp_find_device(). Caller must hold ocp_devices_sem */
+static struct ocp_device *
+__ocp_find_device(unsigned int vendor, unsigned int function, int index)
+{
+ struct list_head *entry;
+ struct ocp_device *dev, *found = NULL;
+
+ DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index));
+
+ list_for_each(entry, &ocp_devices) {
+ dev = list_entry(entry, struct ocp_device, link);
+ if (vendor != OCP_ANY_ID && vendor != dev->def->vendor)
+ continue;
+ if (function != OCP_ANY_ID && function != dev->def->function)
+ continue;
+ if (index != OCP_ANY_INDEX && index != dev->def->index)
+ continue;
+ found = dev;
+ break;
+ }
+
+ DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)... done\n", vendor, function, index));
+
+ return found;
+}
+
+/**
+ * ocp_find_device - Find a device by function & index
+ * @vendor: vendor ID of the device (or OCP_ANY_ID)
+ * @function: function code of the device (or OCP_ANY_ID)
+ * @idx: index of the device (or OCP_ANY_INDEX)
+ *
+ * This function allows a lookup of a given function by it's
+ * index, it's typically used to find the MAL or ZMII associated
+ * with an EMAC or similar horrors.
+ * You can pass vendor, though you usually want OCP_ANY_ID there...
+ */
+struct ocp_device *
+ocp_find_device(unsigned int vendor, unsigned int function, int index)
+{
+ struct ocp_device *dev;
+
+ down_read(&ocp_devices_sem);
+ dev = __ocp_find_device(vendor, function, index);
+ up_read(&ocp_devices_sem);
+
+ return dev;
+}
+
+/**
+ * ocp_get_one_device - Find a def by function & index
+ * @vendor: vendor ID of the device (or OCP_ANY_ID)
+ * @function: function code of the device (or OCP_ANY_ID)
+ * @idx: index of the device (or OCP_ANY_INDEX)
+ *
+ * This function allows a lookup of a given ocp_def by it's
+ * vendor, function, and index. The main purpose for is to
+ * allow modification of the def before binding to the driver
+ */
+struct ocp_def *
+ocp_get_one_device(unsigned int vendor, unsigned int function, int index)
+{
+ struct ocp_device *dev;
+ struct ocp_def *found = NULL;
+
+ DBG(("ocp: ocp_get_one_device(vendor: %x, function: %x, index: %d)...\n",
+ vendor, function, index));
+
+ dev = ocp_find_device(vendor, function, index);
+
+ if (dev)
+ found = dev->def;
+
+ DBG(("ocp: ocp_get_one_device(vendor: %x, function: %x, index: %d)... done.\n",
+ vendor, function, index));
+
+ return found;
+}
+
+/**
+ * ocp_add_one_device - Add a device
+ * @def: static device definition structure
+ *
+ * This function adds a device definition to the
+ * device list. It may only be called before
+ * ocp_driver_init() and will return an error
+ * otherwise.
+ */
+int
+ocp_add_one_device(struct ocp_def *def)
+{
+ struct ocp_device *dev;
+
+ DBG(("ocp: ocp_add_one_device()...\n"));
+
+ /* Can't be called after ocp driver init */
+ if (ocp_inited)
+ return 1;
+
+ if (mem_init_done)
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ else
+ dev = alloc_bootmem(sizeof(*dev));
+
+ if (dev == NULL)
+ return 1;
+ memset(dev, 0, sizeof(*dev));
+ dev->def = def;
+ dev->current_state = 4;
+ sprintf(dev->name, "OCP device %04x:%04x:%04x",
+ dev->def->vendor, dev->def->function, dev->def->index);
+ down_write(&ocp_devices_sem);
+ list_add_tail(&dev->link, &ocp_devices);
+ up_write(&ocp_devices_sem);
+
+ DBG(("ocp: ocp_add_one_device()...done\n"));
+
+ return 0;
+}
+
+/**
+ * ocp_remove_one_device - Remove a device by function & index
+ * @vendor: vendor ID of the device (or OCP_ANY_ID)
+ * @function: function code of the device (or OCP_ANY_ID)
+ * @idx: index of the device (or OCP_ANY_INDEX)
+ *
+ * This function allows removal of a given function by its
+ * index. It may only be called before ocp_driver_init()
+ * and will return an error otherwise.
+ */
+int
+ocp_remove_one_device(unsigned int vendor, unsigned int function, int index)
+{
+ struct ocp_device *dev;
+
+ DBG(("ocp: ocp_remove_one_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index));
+
+ /* Can't be called after ocp driver init */
+ if (ocp_inited)
+ return 1;
+
+ down_write(&ocp_devices_sem);
+ dev = __ocp_find_device(vendor, function, index);
+ list_del((struct list_head *)dev);
+ up_write(&ocp_devices_sem);
+
+ DBG(("ocp: ocp_remove_one_device(vendor: %x, function: %x, index: %d)... done.\n", vendor, function, index));
+
+ return 0;
+}
+
+/**
+ * ocp_for_each_device - Iterate over OCP devices
+ * @callback: routine to execute for each ocp device.
+ * @arg: user data to be passed to callback routine.
+ *
+ * This routine holds the ocp_device semaphore, so the
+ * callback routine cannot modify the ocp_device list.
+ */
+void
+ocp_for_each_device(void(*callback)(struct ocp_device *, void *arg), void *arg)
+{
+ struct list_head *entry;
+
+ if (callback) {
+ down_read(&ocp_devices_sem);
+ list_for_each(entry, &ocp_devices)
+ callback(list_entry(entry, struct ocp_device, link),
+ arg);
+ up_read(&ocp_devices_sem);
+ }
+}
+
+#ifdef CONFIG_PM
+/**
+ * OCP Power management..
+ *
+ * This needs to be done centralized, so that we power manage PCI
+ * devices in the right order: we should not shut down PCI bridges
+ * before we've shut down the devices behind them, and we should
+ * not wake up devices before we've woken up the bridge to the
+ * device.. Eh?
+ *
+ * We do not touch devices that don't have a driver that exports
+ * a suspend/resume function. That is just too dangerous. If the default
+ * PCI suspend/resume functions work for a device, the driver can
+ * easily implement them (ie just have a suspend function that calls
+ * the pci_set_power_state() function).
+ *
+ * BenH: Implementation here couldn't work properly. This version
+ * slightly modified and _might_ be more useable, but real
+ * PM support will probably have to wait for 2.5
+ */
+
+static int ocp_pm_save_state_device(struct ocp_device *dev, u32 state)
+{
+ int error = 0;
+ if (dev) {
+ struct ocp_driver *driver = dev->driver;
+ if (driver && driver->save_state)
+ error = driver->save_state(dev,state);
+ }
+ return error;
+}
+
+static int ocp_pm_suspend_device(struct ocp_device *dev, u32 state)
+{
+ int error = 0;
+ if (dev) {
+ struct ocp_driver *driver = dev->driver;
+ if (driver && driver->suspend)
+ error = driver->suspend(dev,state);
+ }
+ return error;
+}
+
+static int ocp_pm_resume_device(struct ocp_device *dev)
+{
+ int error = 0;
+ if (dev) {
+ struct ocp_driver *driver = dev->driver;
+ if (driver && driver->resume)
+ error = driver->resume(dev);
+ }
+ return error;
+}
+
+static int
+ocp_pm_callback(struct pm_dev *pm_device, pm_request_t rqst, void *data)
+{
+ int error = 0;
+ struct list_head *entry;
+ struct ocp_device *dev;
+
+ down_read(&ocp_devices_sem);
+
+ list_for_each(entry, &ocp_devices) {
+ dev = list_entry(entry, struct ocp_device, link);
+ switch (rqst) {
+ case PM_SAVE_STATE:
+ error = ocp_pm_save_state_device(dev, 3);
+ break;
+ case PM_SUSPEND:
+ error = ocp_pm_suspend_device(dev, 3);
+ break;
+ case PM_RESUME:
+ error = ocp_pm_resume_device(dev);
+ break;
+ default: break;
+ }
+ if (error)
+ break;
+ }
+
+ up_read(&ocp_devices_sem);
+
+ return error;
+}
+
+/*
+ * Is this ever used ?
+ */
+void
+ppc4xx_cpm_fr(u32 bits, int val)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (val)
+ mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | bits);
+ else
+ mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) & ~bits);
+
+ restore_flags(flags);
+}
+#endif /* CONFIG_PM */
+
+/**
+ * ocp_early_init - Init OCP device management
+ *
+ * This function builds the list of devices before setup_arch.
+ * This allows platform code to modify the device lists before
+ * they are bound to drivers (changes to paddr, removing devices
+ * etc)
+ */
+int __init
+ocp_early_init(void)
+{
+ struct ocp_def *def;
+
+ DBG(("ocp: ocp_early_init()...\n"));
+
+ /* Fill the devices list */
+ for (def = core_ocp; def->vendor != OCP_VENDOR_INVALID; def++)
+ ocp_add_one_device(def);
+
+ DBG(("ocp: ocp_early_init()... done.\n"));
+
+ return 0;
+}
+
+/**
+ * ocp_driver_init - Init OCP device management
+ *
+ * This function is meant to be called via OCP bus registration.
+ */
+static int __init
+ocp_driver_init(void)
+{
+ int ret = 0, index = 0;
+ struct device *ocp_bus;
+ struct list_head *entry;
+ struct ocp_device *dev;
+
+ if (ocp_inited)
+ return ret;
+ ocp_inited = 1;
+
+ DBG(("ocp: ocp_driver_init()...\n"));
+
+#ifdef CONFIG_PM
+ pm_register(PM_SYS_DEV, 0, ocp_pm_callback);
+#endif
+
+ /* Allocate/register primary OCP bus */
+ ocp_bus = kmalloc(sizeof(struct device), GFP_KERNEL);
+ if (ocp_bus == NULL)
+ return 1;
+ memset(ocp_bus, 0, sizeof(struct device));
+ strcpy(ocp_bus->bus_id, "ocp");
+
+ bus_register(&ocp_bus_type);
+
+ device_register(ocp_bus);
+
+ /* Put each OCP device into global device list */
+ list_for_each(entry, &ocp_devices) {
+ dev = list_entry(entry, struct ocp_device, link);
+ sprintf(dev->dev.bus_id, "%2.2x", index);
+ dev->dev.parent = ocp_bus;
+ dev->dev.bus = &ocp_bus_type;
+ device_register(&dev->dev);
+ ocp_create_sysfs_dev_files(dev);
+ index++;
+ }
+
+ DBG(("ocp: ocp_driver_init()... done.\n"));
+
+ return 0;
+}
+
+postcore_initcall(ocp_driver_init);
+
+EXPORT_SYMBOL(ocp_bus_type);
+EXPORT_SYMBOL(ocp_find_device);
+EXPORT_SYMBOL(ocp_register_driver);
+EXPORT_SYMBOL(ocp_unregister_driver);
diff -Nru a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h
--- a/include/asm-ppc/ocp.h Tue May 11 14:56:45 2004
+++ b/include/asm-ppc/ocp.h Tue May 11 14:56:45 2004
@@ -1,103 +1,114 @@
/*
* ocp.h
*
+ * (c) Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ * Mipsys - France
*
- * Current Maintainer
- * Armin Kuster akuster@pacbell.net
- * Jan, 2002
- *
+ * Derived from work (c) Armin Kuster akuster@pacbell.net
*
+ * Additional support and port to 2.6 LDM/sysfs by
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2003-2004 MontaVista Software, 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
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR 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.
- *
- * 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.
+ * 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.
+ *
+ * TODO: - Add get/put interface & fixup locking to provide same API for
+ * 2.4 and 2.5
+ * - Rework PM callbacks
*/
#ifdef __KERNEL__
#ifndef __OCP_H__
#define __OCP_H__
+#include <linux/init.h>
#include <linux/list.h>
#include <linux/config.h>
+#include <linux/devfs_fs_kernel.h>
#include <linux/device.h>
-#include <linux/errno.h>
+#include <asm/mmu.h>
#include <asm/ocp_ids.h>
-#include <asm/mmu.h> /* For phys_addr_t */
-#undef DEBUG
-/* #define DEBUG*/
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
+#include <asm/rwsem.h>
+#include <asm/semaphore.h>
+#define OCP_MAX_IRQS 7
+#define MAX_EMACS 4
#define OCP_IRQ_NA -1 /* used when ocp device does not have an irq */
-#define OCP_IRQ_MUL -2 /* used for ocp devices with multiple irqs */
-#define OCP_NULL_TYPE 0 /* used to mark end of list */
-#define OCP_DEV_NA -1
+#define OCP_IRQ_MUL -2 /* used for ocp devices with multiply irqs */
+#define OCP_NULL_TYPE -1 /* used to mark end of list */
#define OCP_CPM_NA 0 /* No Clock or Power Management avaliable */
+#define OCP_PADDR_NA 0 /* No MMIO registers */
#define OCP_ANY_ID (~0)
+#define OCP_ANY_INDEX -1
-
-extern struct list_head ocp_root_buses;
-extern struct list_head ocp_devices;
+extern struct list_head ocp_devices;
+extern struct rw_semaphore ocp_devices_sem;
struct ocp_device_id {
- unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */
- char name[16];
- char desc[50];
- unsigned long driver_data; /* Data private to the driver */
+ unsigned int vendor, function; /* Vendor and function ID or OCP_ANY_ID */
+ unsigned long driver_data; /* Data private to the driver */
};
-struct func_info {
- char name[16];
- char desc[50];
-};
+/*
+ * Static definition of an OCP device.
+ *
+ * @vendor: Vendor code. It is _STRONGLY_ discouraged to use
+ * the vendor code as a way to match a unique device,
+ * though I kept that possibility open, you should
+ * really define different function codes for different
+ * device types
+ * @function: This is the function code for this device.
+ * @index: This index is used for mapping the Nth function of a
+ * given core. This is typically used for cross-driver
+ * matching, like looking for a given MAL or ZMII from
+ * an EMAC or for getting to the proper set of DCRs.
+ * Indices are no longer magically calculated based on
+ * structure ordering, they have to be actually coded
+ * into the ocp_def to avoid any possible confusion
+ * I _STRONGLY_ (again ? wow !) encourage anybody relying
+ * on index mapping to encode the "target" index in an
+ * associated structure pointed to by "additions", see
+ * how it's done for the EMAC driver.
+ * @paddr: Device physical address (may not mean anything...)
+ * @irq: Interrupt line for this device (TODO: think about making
+ * an array with this)
+ * @pm: Currently, contains the bitmask in CPMFR DCR for the device
+ * @additions: Optionally points to a function specific structure
+ * providing additional informations for a given device
+ * instance. It's currently used by the EMAC driver for MAL
+ * channel & ZMII port mapping among others.
+ * @show: Optionally points to a function specific structure
+ * providing a sysfs show routine for additions fields.
+ */
struct ocp_def {
- unsigned int vendor;
- unsigned int device;
- phys_addr_t paddr;
- int irq;
- unsigned long pm;
+ unsigned int vendor;
+ unsigned int function;
+ int index;
+ phys_addr_t paddr;
+ int irq;
+ unsigned long pm;
+ void *additions;
+ void (*show)(struct device *);
};
-/* Struct for single ocp device managment */
+/* Struct for a given device instance */
struct ocp_device {
- struct list_head global_list;
- unsigned int num; /* instance of device */
- char name[80]; /* device name */
- unsigned int vendor;
- unsigned int device;
- phys_addr_t paddr;
- int irq;
- unsigned long pm;
- void *ocpdev; /* driver data for this device */
- struct ocp_driver *driver;
- u32 current_state; /* Current operating state. In ACPI-speak,
- this is D0-D3, D0 being fully functional,
- and D3 being off. */
- struct device dev;
+ struct list_head link;
+ char name[80]; /* device name */
+ struct ocp_def *def; /* device definition */
+ void *drvdata; /* driver data for this device */
+ struct ocp_driver *driver;
+ u32 current_state; /* Current operating state. In ACPI-speak,
+ this is D0-D3, D0 being fully functional,
+ and D3 being off. */
+ struct device dev;
};
struct ocp_driver {
@@ -106,23 +117,13 @@
const struct ocp_device_id *id_table; /* NULL if wants all devices */
int (*probe) (struct ocp_device *dev); /* New device inserted */
void (*remove) (struct ocp_device *dev); /* Device removed (NULL if not a hot-plug capable driver) */
- int (*save_state) (struct ocp_device *dev, u32 state); /* Save Device Context */
int (*suspend) (struct ocp_device *dev, u32 state); /* Device suspended */
int (*resume) (struct ocp_device *dev); /* Device woken up */
- int (*enable_wake) (struct ocp_device *dev, u32 state, int enable); /* Enable wake event */
struct device_driver driver;
};
-#define to_ocp_dev(n) container_of(n, struct ocp_device, dev)
-#define to_ocp_driver(n) container_of(n, struct ocp_driver, driver)
-
-extern int ocp_register_driver(struct ocp_driver *drv);
-extern void ocp_unregister_driver(struct ocp_driver *drv);
-
-#define ocp_dev_g(n) list_entry(n, struct ocp_device, global_list)
-
-#define ocp_for_each_dev(dev) \
- for(dev = ocp_dev_g(ocp_devices.next); dev != ocp_dev_g(&ocp_devices); dev = ocp_dev_g(dev->global_list.next))
+#define to_ocp_dev(n) container_of(n, struct ocp_device, dev)
+#define to_ocp_drv(n) container_of(n, struct ocp_driver, driver)
/* Similar to the helpers above, these manipulate per-ocp_dev
* driver-specific data. Currently stored as ocp_dev::ocpdev,
@@ -131,45 +132,13 @@
static inline void *
ocp_get_drvdata(struct ocp_device *pdev)
{
- return pdev->ocpdev;
+ return pdev->drvdata;
}
static inline void
ocp_set_drvdata(struct ocp_device *pdev, void *data)
{
- pdev->ocpdev = data;
-}
-
-/*
- * a helper function which helps ensure correct pci_driver
- * setup and cleanup for commonly-encountered hotplug/modular cases
- *
- * This MUST stay in a header, as it checks for -DMODULE
- */
-static inline int ocp_module_init(struct ocp_driver *drv)
-{
- int rc = ocp_register_driver(drv);
-
- if (rc > 0)
- return 0;
-
- /* iff CONFIG_HOTPLUG and built into kernel, we should
- * leave the driver around for future hotplug events.
- * For the module case, a hotplug daemon of some sort
- * should load a module in response to an insert event. */
-#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
- if (rc == 0)
- return 0;
-#else
- if (rc == 0)
- rc = -ENODEV;
-#endif
-
- /* if we get here, we need to clean up pci driver instance
- * and return some sort of error */
- ocp_unregister_driver (drv);
-
- return rc;
+ pdev->drvdata = data;
}
#if defined (CONFIG_PM)
@@ -180,26 +149,56 @@
static inline void
ocp_force_power_off(struct ocp_device *odev)
{
- mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | odev->pm);
+ mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | odev->def->pm);
}
static inline void
ocp_force_power_on(struct ocp_device *odev)
{
- mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) & ~odev->pm);
+ mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) & ~odev->def->pm);
}
#else
#define ocp_force_power_off(x) (void)(x)
#define ocp_force_power_on(x) (void)(x)
#endif
-extern void ocp_init(void);
-extern struct bus_type ocp_bus_type;
-extern struct ocp_device *ocp_get_dev(unsigned int device, int index);
-extern unsigned int ocp_get_num(unsigned int device);
+/* Register/Unregister an OCP driver */
+extern int ocp_register_driver(struct ocp_driver *drv);
+extern void ocp_unregister_driver(struct ocp_driver *drv);
+
+/* Build list of devices */
+extern int ocp_early_init(void) __init;
-extern int ocp_generic_suspend(struct ocp_device *pdev, u32 state);
-extern int ocp_generic_resume(struct ocp_device *pdev);
+/* Find a device by index */
+extern struct ocp_device *ocp_find_device(unsigned int vendor, unsigned int function, int index);
+
+/* Get a def by index */
+extern struct ocp_def *ocp_get_one_device(unsigned int vendor, unsigned int function, int index);
+
+/* Add a device by index */
+extern int ocp_add_one_device(struct ocp_def *def);
+
+/* Remove a device by index */
+extern int ocp_remove_one_device(unsigned int vendor, unsigned int function, int index);
+
+/* Iterate over devices and execute a routine */
+extern void ocp_for_each_device(void(*callback)(struct ocp_device *, void *arg), void *arg);
+
+/* Sysfs support */
+#define OCP_SYSFS_ADDTL(type, format, name, field) \
+static ssize_t \
+show_##name##_##field(struct device *dev, char *buf) \
+{ \
+ struct ocp_device *odev = to_ocp_dev(dev); \
+ type *add = odev->def->additions; \
+ \
+ return sprintf(buf, format, add->field); \
+} \
+static DEVICE_ATTR(name##_##field, S_IRUGO, show_##name##_##field, NULL);
+
+#ifdef CONFIG_IBM_OCP
+#include <asm/ibm_ocp.h>
+#endif
#endif /* __OCP_H__ */
#endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/ocp_ids.h b/include/asm-ppc/ocp_ids.h
--- a/include/asm-ppc/ocp_ids.h Tue May 11 14:56:45 2004
+++ b/include/asm-ppc/ocp_ids.h Tue May 11 14:56:45 2004
@@ -1,34 +1,15 @@
/*
- * FILE NAME: ocp_ids.h
+ * ocp_ids.h
*
- * BRIEF MODULE DESCRIPTION:
* OCP device ids based on the ideas from PCI
*
- * Maintained by: Armin <akuster@mvista.com>
+ * The numbers below are almost completely arbitrary, and in fact
+ * strings might work better. -- paulus
*
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR 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.
- *
- * 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.
- *
- * Version 1.0 08/22/02 -Armin
- * initial release
+ * 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.
*/
/*
@@ -42,8 +23,9 @@
#define OCP_VENDOR_INVALID 0x0000
#define OCP_VENDOR_ARM 0x0004
+#define OCP_VENDOR_FREESCALE 0x1057
#define OCP_VENDOR_IBM 0x1014
-#define OCP_VENDOR_MOTOROLA 0x1057
+#define OCP_VENDOR_MOTOROLA OCP_VENDOR_FREESCALE
#define OCP_VENDOR_XILINX 0x10ee
#define OCP_VENDOR_UNKNOWN 0xFFFF
@@ -53,33 +35,20 @@
#define OCP_FUNC_INVALID 0x0000
/* system 0x0001 - 0x001F */
-#define OCP_FUNC_UIC 0x0001
/* Timers 0x0020 - 0x002F */
-#define OCP_FUNC_GPT 0x0020 /* General purpose timers */
-#define OCP_FUNC_RTC 0x0021
/* Serial 0x0030 - 0x006F*/
#define OCP_FUNC_16550 0x0031
-#define OCP_FUNC_SSP 0x0032 /* sync serial port */
-#define OCP_FUNC_SCP 0x0033 /* serial controller port */
-#define OCP_FUNC_SCC 0x0034 /* serial contoller */
-#define OCP_FUNC_SCI 0x0035 /* Smart card */
-#define OCP_FUNC_IIC 0x0040
-#define OCP_FUNC_USB 0x0050
-#define OCP_FUNC_IR 0x0060
+#define OCP_FUNC_IIC 0x0032
+#define OCP_FUNC_USB 0x0033
/* Memory devices 0x0090 - 0x009F */
-#define OCP_FUNC_SDRAM 0x0091
-#define OCP_FUNC_DMA 0x0092
+#define OCP_FUNC_MAL 0x0090
/* Display 0x00A0 - 0x00AF */
-#define OCP_FUNC_VIDEO 0x00A0
-#define OCP_FUNC_LED 0x00A1
-#define OCP_FUNC_LCD 0x00A2
/* Sound 0x00B0 - 0x00BF */
-#define OCP_FUNC_AUDIO 0x00B0
/* Mass Storage 0x00C0 - 0xxCF */
#define OCP_FUNC_IDE 0x00C0
@@ -87,17 +56,15 @@
/* Misc 0x00D0 - 0x00DF*/
#define OCP_FUNC_GPIO 0x00D0
#define OCP_FUNC_ZMII 0x00D1
+#define OCP_FUNC_PERFMON 0x00D2 /* Performance Monitor */
+#define OCP_FUNC_RGMII 0x00D3
+#define OCP_FUNC_TAH 0x00D4
/* Network 0x0200 - 0x02FF */
#define OCP_FUNC_EMAC 0x0200
+#define OCP_FUNC_ENET 0x0201 /* TSEC & FEC */
/* Bridge devices 0xE00 - 0xEFF */
-#define OCP_FUNC_HOST 0x0E00
-#define OCP_FUNC_DCR 0x0E01
-#define OCP_FUNC_OPB 0x0E02
-#define OCP_FUNC_PHY 0x0E03
-#define OCP_FUNC_EXT 0x0E04
-#define OCP_FUNC_PCI 0x0E05
-#define OCP_FUNC_PLB 0x0E06
+#define OCP_FUNC_OPB 0x0E00
#define OCP_FUNC_UNKNOWN 0xFFFF
next reply other threads:[~2004-05-12 0:12 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-05-12 0:01 Matt Porter [this message]
2004-05-12 0:39 ` [PATCH 1/2] PPC32: New OCP core support Valdis.Kletnieks
2004-05-12 1:01 ` Matt Porter
2004-05-12 1:10 ` Valdis.Kletnieks
2004-05-12 3:00 ` Valdis.Kletnieks
2004-05-12 13:32 ` Matt Porter
2004-05-12 3:15 ` Valdis.Kletnieks
2004-05-12 1:45 ` Matt Porter
2004-05-12 2:00 ` Matt Porter
2004-05-12 0:57 ` Andrew Morton
2004-05-12 1:06 ` Matt Porter
2004-05-12 1:45 ` Matt Porter
2004-05-12 2:38 ` Daniel Jacobowitz
2004-05-12 3:15 ` Daniel Jacobowitz
2004-05-12 1:30 ` Andrew Morton
2004-05-12 3:00 ` Valdis.Kletnieks
2004-05-12 3:15 ` Valdis.Kletnieks
2004-05-12 5:48 ` Christoph Hellwig
2004-05-12 6:15 ` Christoph Hellwig
2004-05-12 13:39 ` Matt Porter
2004-05-12 6:30 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20040511170150.A4743@home.com \
--to=mporter@kernel.crashing.org \
--cc=akpm@osdl.org \
--cc=benh@kernel.crashing.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxppc-dev@lists.linuxppc.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.