linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 8/15] Supporting PCI bus and base of I/O
@ 2006-12-12  3:37 Ishizaki Kou
  2006-12-12 20:03 ` Arnd Bergmann
  0 siblings, 1 reply; 4+ messages in thread
From: Ishizaki Kou @ 2006-12-12  3:37 UTC (permalink / raw)
  To: paulus, linuxppc-dev

This patch includes support for pci buses, base of Celleb specific
devices, and etc. It works on of_platform bus.

Signed-off-by: Kou Ishizaki <kou.ishizaki.co.jp>
---

Index: linux-powerpc-git/arch/powerpc/platforms/celleb/pci.c
diff -u /dev/null linux-powerpc-git/arch/powerpc/platforms/celleb/pci.c:1.7
--- /dev/null	Mon Dec 11 20:37:34 2006
+++ linux-powerpc-git/arch/powerpc/platforms/celleb/pci.c	Mon Dec 11 17:32:43 2006
@@ -0,0 +1,563 @@
+/*
+ * Support for PCI on Celleb platform.
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on arch/powerpc/kernel/rtas_pci.c:
+ * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
+ * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/threads.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/pci_regs.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+#include "scc.h"
+#include "interrupt.h"
+
+#define MAX_PCI_DEVICES    32
+#define MAX_PCI_FUNCTIONS   8
+#define MAX_PCI_BASE_ADDRS  6
+
+
+/* definition for fake pci configuration area for GbE, .... ,and etc. */
+
+struct celleb_pci_iodata {
+	unsigned long iobase[MAX_PCI_BASE_ADDRS];
+	unsigned long iosize[MAX_PCI_BASE_ADDRS];
+};
+
+struct celleb_pci_private {
+	unsigned char *fake_config[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS];
+	struct celleb_pci_iodata *iodata[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS];
+};
+
+static inline u8 celleb_fake_config_readb(void *addr)
+{
+	u8 *p = addr;
+	return *p;
+}
+
+static inline u16 celleb_fake_config_readw(void *addr)
+{
+	u16 *p = addr;
+	return le16_to_cpu(*p);
+}
+
+static inline u32 celleb_fake_config_readl(void *addr)
+{
+	u32 *p = addr;
+	return le32_to_cpu(*p);
+}
+
+static inline void celleb_fake_config_writeb(u32 val, void *addr)
+{
+	u8 *p = addr;
+	*p = val;
+}
+
+static inline void celleb_fake_config_writew(u32 val, void *addr)
+{
+	u16 val16;
+	u16 *p = addr;
+	val16 = cpu_to_le16(val);
+	*p = val16;
+}
+
+static inline void celleb_fake_config_writel(u32 val, void *addr)
+{
+	u32 val32;
+	u32 *p = addr;
+	val32 = cpu_to_le32(val);
+	*p = val32;
+}
+
+static unsigned char *get_fake_config_start(struct pci_controller *hose,
+					    int devno, int fn)
+{
+	struct celleb_pci_private *private = hose->private_data;
+
+	if (private == NULL)
+		return NULL;
+
+	return private->fake_config[devno][fn];
+}
+
+static unsigned long *get_iobase_start(struct pci_controller *hose,
+				       int devno, int fn)
+{
+	struct celleb_pci_private *private = hose->private_data;
+
+	if (private == NULL || private->iodata[devno][fn] == NULL)
+		return NULL;
+
+	return private->iodata[devno][fn]->iobase;
+}
+
+static unsigned long *get_iosize_start(struct pci_controller *hose,
+				       int devno, int fn)
+{
+	struct celleb_pci_private *private = hose->private_data;
+
+	if (private == NULL || private->iodata[devno][fn] == NULL)
+		return NULL;
+
+	return private->iodata[devno][fn]->iosize;
+}
+
+static void celleb_config_read_fake(unsigned char *config, int where,
+				    int size, u32 *val)
+{
+	char *p = config + where;
+
+	switch (size) {
+	case 1:
+		*val = celleb_fake_config_readb(p);
+		break;
+	case 2:
+		*val = celleb_fake_config_readw(p);
+		break;
+	case 4:
+		*val = celleb_fake_config_readl(p);
+		break;
+	}
+
+	return;
+}
+
+static void celleb_config_write_fake(unsigned char *config, int where,
+				     int size, u32 val)
+{
+	char *p = config + where;
+
+	switch (size) {
+	case 1:
+		celleb_fake_config_writeb(val, p);
+		break;
+	case 2:
+		celleb_fake_config_writew(val, p);
+		break;
+	case 4:
+		celleb_fake_config_writel(val, p);
+		break;
+	}
+	return;
+}
+
+static int celleb_fake_pci_read_config(struct pci_bus *bus,
+		unsigned int devfn, int where, int size, u32 *val)
+{
+	char *config;
+	struct device_node *node;
+	struct pci_controller *hose;
+	unsigned int devno = devfn >> 3;
+	unsigned int fn = devfn & 0x7;
+
+	/* allignment check */
+	BUG_ON(where % size);
+
+	pr_debug("    fake read: bus=0x%x, ", bus->number);
+	node = (struct device_node *)bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+	config = get_fake_config_start(hose, devno, fn);
+
+	pr_debug("devno=0x%x, where=0x%x, size=0x%x, ", devno, where, size);
+	if (!config) {
+		pr_debug("failed\n");
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	celleb_config_read_fake(config, where, size, val);
+	pr_debug("val=0x%x\n", *val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int celleb_fake_pci_write_config(struct pci_bus *bus,
+		 unsigned int devfn, int where, int size, u32 val)
+{
+	char *config;
+	struct device_node *node;
+	struct pci_controller *hose;
+	unsigned long *iosize;
+	unsigned int devno = devfn >> 3;
+	unsigned int fn = devfn & 0x7;
+
+	/* allignment check */
+	BUG_ON(where % size);
+
+	node = (struct device_node *)bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+	config = get_fake_config_start(hose, devno, fn);
+
+	if (!config)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (val == ~0) {
+		int i = (where - PCI_BASE_ADDRESS_0) >> 3;
+
+		switch (where) {
+		case PCI_BASE_ADDRESS_0:
+		case PCI_BASE_ADDRESS_2:
+			if (size != 4)
+				return PCIBIOS_DEVICE_NOT_FOUND;
+			iosize = get_iosize_start(hose, devno, fn);
+			if (!iosize)
+				return PCIBIOS_DEVICE_NOT_FOUND;
+			celleb_config_write_fake(config, where, size,
+						 iosize[i]);
+			return PCIBIOS_SUCCESSFUL;
+		case PCI_BASE_ADDRESS_1:
+		case PCI_BASE_ADDRESS_3:
+		case PCI_BASE_ADDRESS_4:
+		case PCI_BASE_ADDRESS_5:
+			break;
+		default:
+			break;
+		}
+	}
+
+	celleb_config_write_fake(config, where, size, val);
+	pr_debug("    fake write: where=%x, size=%d, val=%x\n",
+		 where, size, val);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops celleb_fake_pci_ops = {
+	celleb_fake_pci_read_config,
+	celleb_fake_pci_write_config
+};
+
+static void celleb_setup_pci_base_addrs(struct pci_controller *hose,
+			unsigned int devno, unsigned int fn,
+			unsigned int num_base_addr)
+{
+	u32 val;
+	unsigned char *config;
+	unsigned long *iobase;
+
+	config = get_fake_config_start(hose, devno, fn);
+	iobase = get_iobase_start(hose, devno, fn);
+
+	if (!config || !iobase)
+		return;
+
+	switch (num_base_addr) {
+	case 3:
+		val = (iobase[2] & 0xfffffff0)
+		    | PCI_BASE_ADDRESS_MEM_TYPE_64;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_4, 4,
+					 val);
+		val = iobase[2] >> 32;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_5, 4,
+					 val);
+		/* FALLTHROUGH */
+	case 2:
+		val = (iobase[1] & 0xfffffff0)
+		    | PCI_BASE_ADDRESS_MEM_TYPE_64;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_2, 4,
+					 val);
+		val = iobase[1] >> 32;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_3, 4,
+					 val);
+		/* FALLTHROUGH */
+	case 1:
+		val = (iobase[0] & 0xfffffff0)
+		    | PCI_BASE_ADDRESS_MEM_TYPE_64;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_0, 4,
+					 val);
+		val = iobase[0] >> 32;
+		celleb_config_write_fake(config, PCI_BASE_ADDRESS_1, 4,
+					 val);
+		break;
+	}
+
+	val = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+	celleb_config_write_fake(config, PCI_COMMAND, 2, val);
+}
+
+
+static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
+						  struct pci_controller *hose)
+{
+	unsigned int rlen, num_base_addr;
+	u32 val;
+	const u32 *wi0, *wi1, *wi2, *wi3, *wi4;
+	unsigned int devno, fn;
+	struct celleb_pci_private *private = hose->private_data;
+	unsigned char **config = NULL;
+	struct celleb_pci_iodata **iodata = NULL;
+	unsigned long *iobase, *iosize;
+	const char *name;
+	const unsigned long *li;
+	int size;
+	int i;
+
+	if (private == NULL) {
+		printk(KERN_ERR "PCI: "
+		       "memory space for pci controller is not assigned\n");
+		goto error;
+	}
+
+	name = get_property(node, "model", &rlen);
+	if (!name) {
+		printk(KERN_ERR "PCI: model property not found.\n");
+		goto error;
+	}
+
+	wi4 = get_property(node, "reg", &rlen);
+	if (wi4 == NULL)
+		goto error;
+
+	devno = ((wi4[0] >> 8) & 0xff) >> 3;
+	fn = (wi4[0] >> 8) & 0x7;
+
+	pr_debug("PCI: celleb_setup_fake_pci() %s devno=%x fn=%x\n", name,
+		 devno, fn);
+
+	size = 256;
+	config = &private->fake_config[devno][fn];
+	if (mem_init_done)
+		*config = kzalloc(size, GFP_KERNEL);
+	else
+		*config = alloc_bootmem(size);
+	if (*config == NULL) {
+		printk(KERN_ERR "PCI: "
+		       "not enough memory for fake configuration space\n");
+		goto error;
+	}
+	pr_debug("PCI: fake config area assigned 0x%016lx\n",
+		 (unsigned long)*config);
+
+	size = sizeof(struct celleb_pci_iodata);
+	iodata = &private->iodata[devno][fn];
+	if (mem_init_done)
+		*iodata = kzalloc(size, GFP_KERNEL);
+	else
+		*iodata = alloc_bootmem(size);
+	if (*iodata == NULL) {
+		printk(KERN_ERR
+		       "PCI: not enough memory for iobase data space\n");
+		goto error;
+	}
+	pr_debug("PCI: iodata assigned 0x%016lx\n", (unsigned long)*iodata);
+
+	iobase = get_iobase_start(hose, devno, fn);
+	iosize = get_iosize_start(hose, devno, fn);
+	pr_debug("PCI: "
+		 "iobase info addr = 0x%016lx, iosize info addr=0x%016lx\n",
+		 (unsigned long)iobase, (unsigned long)iosize);
+
+	wi0 = get_property(node, "device-id", NULL);
+	wi1 = get_property(node, "vendor-id", NULL);
+	wi2 = get_property(node, "class-code", NULL);
+	wi3 = get_property(node, "revision-id", NULL);
+
+	celleb_config_write_fake(*config, PCI_DEVICE_ID, 2,
+				 wi0[0] & 0xffff);
+	celleb_config_write_fake(*config, PCI_VENDOR_ID, 2,
+				 wi1[0] & 0xffff);
+	pr_debug("class-code = 0x%08x\n", wi2[0]);
+
+	celleb_config_write_fake(*config, PCI_CLASS_PROG, 1, wi2[0] & 0xff);
+	celleb_config_write_fake(*config, PCI_CLASS_DEVICE, 2,
+				 (wi2[0] >> 8) & 0xffff);
+	celleb_config_write_fake(*config, PCI_REVISION_ID, 1, wi3[0]);
+
+	li = get_property(node, "toshiba,reg", &rlen);
+
+	if (li) {
+		num_base_addr = rlen >> 4;
+
+		if (num_base_addr > 3)
+			num_base_addr = 3;
+		pr_debug("PCI: %s: number of base addresses is %d\n",
+			 name, num_base_addr);
+
+		for (i = 0; i < num_base_addr; i++) {
+			iobase[i] = li[i * 2];
+			iosize[i] = li[i * 2 + 1];
+			pr_debug("PCI: base address %d: 0x%lx-0x%lx\n",
+				 i, li[i * 2], li[i * 2 + 1]);
+		}
+
+	} else {
+		printk(KERN_ERR "PCI: No toshiba,reg property\n");
+		goto error;
+	}
+
+	celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr);
+
+	li = get_property(node, "interrupts", &rlen);
+	val = li[0];
+	celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1);
+	celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val);
+
+#ifdef DEBUG
+	pr_debug("PCI: %s irq=%ld\n", name, li[0]);
+	for (i = 0; i < 6; i++) {
+		celleb_config_read_fake(*config,
+					PCI_BASE_ADDRESS_0 + 0x4 * i, 4,
+					&val);
+		pr_debug("PCI: %s fn=%d base_address_%d=0x%x\n",
+			 name, fn, i, val);
+	}
+#endif
+
+	celleb_config_write_fake(*config, PCI_HEADER_TYPE, 1,
+				 PCI_HEADER_TYPE_NORMAL);
+
+	return 0;
+
+error:
+	if (mem_init_done) {
+		if (config && *config)
+			kfree(*config);
+		if (iodata && *iodata)
+			kfree(*iodata);
+
+	} else {
+		if (config && *config) {
+			size = 256;
+			free_bootmem((unsigned long)(*config), size);
+		}
+		if (iodata && *iodata) {
+			size = sizeof(struct celleb_pci_iodata);
+			free_bootmem((unsigned long)(*iodata), size);
+		}
+	}
+
+	return 1;
+}
+
+
+void __devinit celleb_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+	struct pci_bus *bus;
+	struct list_head *ln;
+
+	for_each_pci_dev(dev) {
+		bus = dev->bus;
+		if (bus && ppc_md.pci_probe_mode(bus) == PCI_PROBE_NORMAL)
+			continue;
+
+		pci_read_irq_line(dev);
+	}
+
+	list_for_each(ln, &pci_root_buses) {
+		bus = pci_bus_b(ln);
+		if (ppc_md.pci_probe_mode(bus) == PCI_PROBE_NORMAL) {
+			dev = NULL;
+
+#if 1				/* XXX: This is for SYSCON workaround */
+			list_for_each_entry(dev, &bus->devices, bus_list) {
+				int i;
+				if ((dev->class >> 8) != PCI_CLASS_BRIDGE_HOST)
+					continue;
+
+				for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+					struct resource *r = NULL;
+					struct resource *root = NULL;
+					r = &dev->resource[i];
+					root = pcibios_select_root(dev, r);
+					if (!(r->flags) || r->parent)
+						continue;
+
+					insert_resource(root, r);
+				}
+			}
+#endif
+			pci_bus_assign_resources(bus);
+			pci_enable_bridges(bus);
+		}
+	}
+
+	return;
+}
+
+static int __devinit phb_set_bus_ranges(struct device_node *dev,
+					struct pci_controller *phb)
+{
+	const int *bus_range;
+	unsigned int len;
+
+	bus_range = get_property(dev, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int))
+		return 1;
+
+	phb->first_busno = bus_range[0];
+	phb->last_busno = bus_range[1];
+
+	return 0;
+}
+
+static void __devinit celleb_alloc_private_mem(struct pci_controller *hose)
+{
+	if (mem_init_done)
+		hose->private_data =
+			kzalloc(sizeof(struct celleb_pci_private), GFP_KERNEL);
+	else
+		hose->private_data =
+			alloc_bootmem(sizeof(struct celleb_pci_private));
+}
+
+int __devinit celleb_setup_phb(struct pci_controller *phb)
+{
+	const char *name;
+	struct device_node *dev = phb->arch_data;
+	struct device_node *node;
+	unsigned int rlen;
+	
+	name = get_property(dev, "name", &rlen);
+	if (!name)
+		return 1;
+
+	pr_debug("PCI: celleb_setup_phb() %s\n", name);
+	phb_set_bus_ranges(dev, phb);
+
+	if (strcmp(name, "epci") == 0) {
+		phb->ops = &celleb_epci_ops;
+		celleb_setup_epci(dev, phb);
+
+	} else if (strcmp(name, "pci-pseudo") == 0) {
+		phb->ops = &celleb_fake_pci_ops;
+		celleb_alloc_private_mem(phb);
+		for (node = of_get_next_child(dev, NULL);
+		     node != NULL; node = of_get_next_child(dev, node))
+			celleb_setup_fake_pci_device(node, phb);
+
+	} else
+		return 1;
+
+	return 0;
+}
Index: linux-powerpc-git/arch/powerpc/platforms/celleb/scc.h
diff -u /dev/null linux-powerpc-git/arch/powerpc/platforms/celleb/scc.h:1.3
--- /dev/null	Mon Dec 11 20:37:34 2006
+++ linux-powerpc-git/arch/powerpc/platforms/celleb/scc.h	Mon Dec 11 18:11:35 2006
@@ -0,0 +1,176 @@
+/*
+ * SCC (Super Companion Chip) definitions
+ *
+ * (C) Copyright 2004-2006 TOSHIBA CORPORATION
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _CELLEB_SCC_H
+#define _CELLEB_SCC_H
+
+#include <linux/pci.h>
+
+#define	PCI_VENDOR_ID_TOSHIBA_2                 0x102f
+#define	PCI_DEVICE_ID_TOSHIBA_SCC_PCIEXC_BRIDGE 0x01b0
+#define	PCI_DEVICE_ID_TOSHIBA_SCC_EPCI_BRIDGE   0x01b1
+#define	PCI_DEVICE_ID_TOSHIBA_SCC_BRIDGE        0x01b2
+#define	PCI_DEVICE_ID_TOSHIBA_SCC_GBE           0x01b3
+#define	PCI_DEVICE_ID_TOSHIBA_SCC_ATA           0x01b4
+#define	PCI_DEVICE_ID_TOSHIBA_SCC_USB2          0x01b5
+#define	PCI_DEVICE_ID_TOSHIBA_SCC_USB           0x01b6
+#define	PCI_DEVICE_ID_TOSHIBA_SCC_ENCDEC        0x01b7
+
+#define SCC_EPCI_REG  0x0000d000
+
+/* EPCI registers */
+#define SCC_EPCI_CNF10_REG     0x010
+#define SCC_EPCI_CNF14_REG     0x014
+#define SCC_EPCI_CNF18_REG     0x018
+#define SCC_EPCI_PVBAT         0x100
+#define SCC_EPCI_VPMBAT        0x104
+#define SCC_EPCI_VPIBAT        0x108
+#define SCC_EPCI_VCSR          0x110
+#define SCC_EPCI_VIENAB        0x114
+#define SCC_EPCI_VISTAT        0x118
+#define SCC_EPCI_VRDCOUNT      0x124
+#define SCC_EPCI_BAM0          0x12c
+#define SCC_EPCI_BAM1          0x134
+#define SCC_EPCI_BAM2          0x13c
+#define SCC_EPCI_IADR          0x164
+#define SCC_EPCI_CLKRST        0x800
+#define SCC_EPCI_INTSET        0x804
+#define SCC_EPCI_STATUS        0x808
+#define SCC_EPCI_ABTSET        0x80c
+#define SCC_EPCI_WATRP         0x810
+#define SCC_EPCI_DUMMYRADR     0x814
+#define SCC_EPCI_SWRESP        0x818
+#define SCC_EPCI_CNTOPT        0x81c
+#define SCC_EPCI_ECMODE        0xf00
+#define SCC_EPCI_IOM_AC_NUM    5
+#define SCC_EPCI_IOM_ACTE(n)   (0xf10 + (n) * 4)
+#define SCC_EPCI_IOT_AC_NUM    4
+#define SCC_EPCI_IOT_ACTE(n)   (0xf30 + (n) * 4)
+#define SCC_EPCI_MAEA          0xf50
+#define SCC_EPCI_MAEC          0xf54
+#define SCC_EPCI_CKCTRL        0xff0
+
+/* bits for SCC_EPCI_VCSR */
+#define SCC_EPCI_VCSR_FRE      0x00020000
+#define SCC_EPCI_VCSR_FWE      0x00010000
+#define SCC_EPCI_VCSR_DR       0x00000400
+#define SCC_EPCI_VCSR_SR       0x00000008
+#define SCC_EPCI_VCSR_AT       0x00000004
+
+/* bits for SCC_EPCI_VIENAB/SCC_EPCI_VISTAT */
+#define SCC_EPCI_VISTAT_PMPE   0x00000008
+#define SCC_EPCI_VISTAT_PMFE   0x00000004
+#define SCC_EPCI_VISTAT_PRA    0x00000002
+#define SCC_EPCI_VISTAT_PRD    0x00000001
+#define SCC_EPCI_VISTAT_ALL    0x0000000f
+
+#define SCC_EPCI_VIENAB_PMPEE  0x00000008
+#define SCC_EPCI_VIENAB_PMFEE  0x00000004
+#define SCC_EPCI_VIENAB_PRA    0x00000002
+#define SCC_EPCI_VIENAB_PRD    0x00000001
+#define SCC_EPCI_VIENAB_ALL    0x0000000f
+
+/* bits for SCC_EPCI_CLKRST */
+#define SCC_EPCI_CLKRST_CKS_MASK 0x00030000
+#define SCC_EPCI_CLKRST_CKS_2    0x00000000
+#define SCC_EPCI_CLKRST_CKS_4    0x00010000
+#define SCC_EPCI_CLKRST_CKS_8    0x00020000
+#define SCC_EPCI_CLKRST_PCICRST  0x00000400
+#define SCC_EPCI_CLKRST_BC       0x00000200
+#define SCC_EPCI_CLKRST_PCIRST   0x00000100
+#define SCC_EPCI_CLKRST_PCKEN    0x00000001
+
+/* bits for SCC_EPCI_INTSET/SCC_EPCI_STATUS */
+#define SCC_EPCI_INT_2M     0x01000000
+#define SCC_EPCI_INT_RERR   0x00200000
+#define SCC_EPCI_INT_SERR   0x00100000
+#define SCC_EPCI_INT_PRTER  0x00080000
+#define SCC_EPCI_INT_SER    0x00040000
+#define SCC_EPCI_INT_PER    0x00020000
+#define SCC_EPCI_INT_PAI    0x00010000
+#define SCC_EPCI_INT_1M     0x00000100
+#define SCC_EPCI_INT_PME    0x00000010
+#define SCC_EPCI_INT_INTD   0x00000008
+#define SCC_EPCI_INT_INTC   0x00000004
+#define SCC_EPCI_INT_INTB   0x00000002
+#define SCC_EPCI_INT_INTA   0x00000001
+#define SCC_EPCI_INT_DEVINT 0x0000000f
+#define SCC_EPCI_INT_ALL    0x003f001f
+#define SCC_EPCI_INT_ALLERR 0x003f0000
+
+/* bits for SCC_EPCI_CKCTRL */
+#define SCC_EPCI_CKCTRL_CRST0    0x00010000
+#define SCC_EPCI_CKCTRL_CRST1    0x00020000
+#define SCC_EPCI_CKCTRL_OCLKEN   0x00000100
+#define SCC_EPCI_CKCTRL_LCLKEN   0x00000001
+
+#define SCC_EPCI_IDSEL_AD_TO_SLOT(ad)       ((ad) - 10)
+#define SCC_EPCI_MAX_DEVNU  SCC_EPCI_IDSEL_AD_TO_SLOT(32)
+
+/* bits for SCC_EPCI_CNTOPT */
+#define SCC_EPCI_CNTOPT_O2PMB    0x00000002
+
+/* PCICFG registers */
+#define SCC_PCICFG_CNFADD   0x00c
+#define SCC_PCICFG_CNFSET   0x010
+#define SCC_PCICFG_CNFWDT   0x014
+#define SCC_PCICFG_CNFRDT   0x018
+#define SCC_PCICFG_CCKCTRL  0xff0
+
+/* bits for SCC_PCICFG_CCKCTRL */
+#define SCC_PCICFG_CCKCTRL_RST      0x00010000
+#define SCC_PCICFG_CCKCTRL_CLKEN    0x00000001
+
+/* bits for SCC_CFG_BUSCLKCTL */
+#define SCC_CFG_BUSCLKCTL_BBUSCLKEN         0x00000010
+#define SCC_CFG_BUSCLKCTL_SBSBUSCLKEN       0x00000008
+#define SCC_CFG_BUSCLKCTL_SBHBUSCLKEN       0x00000004
+#define SCC_CFG_BUSCLKCTL_SBMBUSCLKEN       0x00000002
+#define SCC_CFG_BUSCLKCTL_SBTBUSCLKEN       0x00000001
+
+/* bits for SCC_CFG_BUSRSTCTL */
+#define SCC_CFG_BUSRSTCTL_BBUSRSTEN         0x00000010
+#define SCC_CFG_BUSRSTCTL_SBSBUSRSTEN       0x00000008
+#define SCC_CFG_BUSRSTCTL_SBHBUSRSTEN       0x00000004
+#define SCC_CFG_BUSRSTCTL_SBMBUSRSTEN       0x00000002
+#define SCC_CFG_BUSRSTCTL_SBTBUSRSTEN       0x00000001
+
+/* UHC registers */
+#define SCC_UHC_CKRCTRL     0xff0
+#define SCC_UHC_ECMODE      0xf00
+
+/* bits for SCC_UHC_CKRCTRL */
+#define SCC_UHC_F48MCKLEN       0x00000001
+#define SCC_UHC_P_SUSPEND       0x00000002
+#define SCC_UHC_PHY_SUSPEND_SEL 0x00000004
+#define SCC_UHC_HCLKEN          0x00000100
+#define SCC_UHC_USBEN           0x00010000
+#define SCC_UHC_USBCEN          0x00020000
+#define SCC_UHC_PHYEN           0x00040000
+
+/* bits for SCC_UHC_ECMODE */
+#define SCC_UHC_ECMODE_BY_BYTE  0x00000555
+#define SCC_UHC_ECMODE_BY_WORD  0x00000aaa
+
+
+extern struct pci_ops celleb_epci_ops;
+extern int __devinit celleb_setup_epci(struct device_node *,
+				       struct pci_controller *);
+#endif
Index: linux-powerpc-git/arch/powerpc/platforms/celleb/scc_epci.c
diff -u /dev/null linux-powerpc-git/arch/powerpc/platforms/celleb/scc_epci.c:1.5
--- /dev/null	Mon Dec 11 20:37:35 2006
+++ linux-powerpc-git/arch/powerpc/platforms/celleb/scc_epci.c	Mon Dec 11 15:30:41 2006
@@ -0,0 +1,546 @@
+/*
+ * Support for SCC external PCI
+ *
+ * (C) Copyright 2004-2006 TOSHIBA CORPORATION
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/threads.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/pci_regs.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+
+#include "scc.h"
+#include "interrupt.h"
+
+#define MAX_PCI_DEVICES   32
+#define MAX_PCI_FUNCTIONS  8
+
+#define iob()  __asm__ __volatile__("eieio; sync":::"memory")
+
+
+struct celleb_epci_private {
+	unsigned int epci_ext_irq;
+	unsigned int epci_int_irq;
+};
+
+
+#if 0
+static void celleb_epci_dummy_read(struct pci_dev *dev)
+{
+	unsigned long epci_base;
+	struct device_node *node;
+	struct pci_controller *hose;
+	u32 val;
+
+	node = (struct device_node *)dev->bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+
+	if (!hose)
+		return;
+
+	epci_base = (unsigned long)hose->cfg_addr;
+
+	val = in_be32((void *)(epci_base + SCC_EPCI_WATRP));
+	iosync();
+
+	return;
+}
+#endif
+
+static inline void clear_and_disable_master_abort_interrupt(
+					struct pci_controller *hose)
+{
+	unsigned long addr;
+	addr = (unsigned long)hose->cfg_addr + PCI_COMMAND;
+	out_be32((void *)addr,
+		 in_be32((void *)addr) | (PCI_STATUS_REC_MASTER_ABORT << 16));
+}
+
+static int celleb_epci_check_abort(struct pci_controller *hose,
+				   unsigned long addr)
+{
+	unsigned long reg;
+	unsigned long epci_base;
+	u32 val;
+
+	iob();
+	epci_base = (unsigned long)hose->cfg_addr;
+
+	reg = epci_base + PCI_COMMAND;
+	val = in_be32((void *)reg);
+
+	if (val & (PCI_STATUS_REC_MASTER_ABORT << 16)) {
+		out_be32((void *)reg,
+			 (val & 0xffff) | (PCI_STATUS_REC_MASTER_ABORT << 16));
+
+		/* clear PCI Controller error, FRE, PMFE */
+		reg = epci_base + SCC_EPCI_STATUS;
+		out_be32((void *)reg, SCC_EPCI_INT_PAI);
+
+		reg = epci_base + SCC_EPCI_VCSR;
+		val = in_be32((void *)reg) & 0xffff;
+		val |= SCC_EPCI_VCSR_FRE;
+		out_be32((void *)reg, val);
+
+		reg = epci_base + SCC_EPCI_VISTAT;
+		out_be32((void *)reg, SCC_EPCI_VISTAT_PMFE);
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int celleb_epci_subordinate_read_config(struct pci_controller *hose,
+					       int bus, unsigned int devfn,
+					       int where, int size, u32 *val)
+{
+	unsigned long addr;
+
+	if (!hose->cfg_data)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (where == PCI_INTERRUPT_LINE) {
+		struct celleb_epci_private *private = hose->private_data;
+		if (private == NULL)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		*val = irq_create_mapping(NULL, private->epci_ext_irq);
+		return PCIBIOS_SUCCESSFUL;
+	} else if (where == PCI_INTERRUPT_PIN) {
+		*val = 1;
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	clear_and_disable_master_abort_interrupt(hose);
+
+	/* address for PCI configuration access */
+	addr = (unsigned long)hose->cfg_data +
+		(((bus & 0xff) << 16)
+		 | ((devfn & 0xff) << 8)
+		 | (where & 0xff)
+		 | 0x01000000);
+
+	switch (size) {
+	case 1:
+		*val = in_8((u8 *)addr);
+		break;
+	case 2:
+		*val = in_le16((u16 *)addr);
+		break;
+	case 4:
+		*val = in_le32((u32 *)addr);
+		break;
+	default:
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	return celleb_epci_check_abort(hose, 0);
+}
+
+static int celleb_epci_subordinate_write_config(struct pci_controller *hose,
+						int bus, unsigned int devfn,
+						int where, int size, u32 val)
+{
+	unsigned long addr;
+
+	if (!hose->cfg_data)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	clear_and_disable_master_abort_interrupt(hose);
+
+	/* address for PCI configuration access */
+	addr = (unsigned long)hose->cfg_data +
+		(((bus & 0xff) << 16)
+		 | ((devfn & 0xff) << 8)
+		 | (where & 0xff)
+		 | 0x01000000);
+
+	switch (size) {
+	case 1:
+		out_8((u8 *)addr, val);
+		break;
+	case 2:
+		out_le16((u16 *)addr, val);
+		break;
+	case 4:
+		out_le32((u32 *)addr, val);
+		break;
+	default:
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	return celleb_epci_check_abort(hose, addr);
+}
+
+static int celleb_epci_read_config(struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 * val)
+{
+	unsigned long addr;
+	struct device_node *node;
+	struct pci_controller *hose;
+
+	/* allignment check */
+	BUG_ON(where % size);
+
+	node = (struct device_node *)bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+
+	if (bus->self)
+		return celleb_epci_subordinate_read_config(hose,
+					bus->number, devfn, where, size, val);
+
+	if (!hose->cfg_data)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (bus->number == hose->first_busno && devfn == 0) {
+		/* EPCI controller self */
+
+		if (where == PCI_INTERRUPT_LINE) {
+			struct celleb_epci_private *private = hose->private_data;
+			if (private == NULL)
+				return PCIBIOS_DEVICE_NOT_FOUND;
+			*val = irq_create_mapping(NULL, private->epci_int_irq);
+			return PCIBIOS_SUCCESSFUL;
+		} else if (where == PCI_INTERRUPT_PIN) {
+			*val = 1;
+			return PCIBIOS_SUCCESSFUL;
+		}
+
+		addr = (unsigned long)hose->cfg_addr + where;
+
+		switch (size) {
+		case 1:
+			*val = in_8((u8 *)addr);
+			break;
+		case 2:
+			*val = in_be16((u16 *)addr);
+			break;
+		case 4:
+			*val = in_be32((u32 *)addr);
+			break;
+		default:
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+
+	} else {
+
+		if (where == PCI_INTERRUPT_LINE) {
+			struct celleb_epci_private *private = hose->private_data;
+			if (private == NULL)
+				return PCIBIOS_DEVICE_NOT_FOUND;
+			*val = irq_create_mapping(NULL, private->epci_ext_irq);
+			return PCIBIOS_SUCCESSFUL;
+		} else if (where == PCI_INTERRUPT_PIN) {
+			*val = 1;
+			return PCIBIOS_SUCCESSFUL;
+		}
+
+		clear_and_disable_master_abort_interrupt(hose);
+
+		/* address for PCI configuration access */
+		addr = (unsigned long)hose->cfg_data +
+			(((devfn & 0xff) << 8) | (where & 0xff));
+
+		switch (size) {
+		case 1:
+			*val = in_8((u8 *)addr);
+			break;
+		case 2:
+			*val = in_le16((u16 *)addr);
+			break;
+		case 4:
+			*val = in_le32((u32 *)addr);
+			break;
+		default:
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+	}
+
+	pr_debug("    epci read: "
+		 "addr=0x%lx, devfn=0x%x, where=0x%x, size=0x%x, val=0x%x\n",
+		 addr, devfn, where, size, *val);
+
+	return celleb_epci_check_abort(hose, 0);
+}
+
+static int celleb_epci_write_config(struct pci_bus *bus,
+			unsigned int devfn, int where, int size, u32 val)
+{
+	unsigned long addr;
+	struct device_node *node;
+	struct pci_controller *hose;
+
+	/* allignment check */
+	BUG_ON(where % size);
+
+	node = (struct device_node *)bus->sysdata;
+	hose = pci_find_hose_for_OF_device(node);
+
+	if (bus->self)
+		return celleb_epci_subordinate_write_config(hose,
+					bus->number, devfn, where, size, val);
+
+	if (!hose->cfg_data)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (bus->number == hose->first_busno && devfn == 0) {
+		/* EPCI controller self */
+
+		addr = (unsigned long)hose->cfg_addr + where;
+
+		switch (size) {
+		case 1:
+			out_8((u8 *)addr, val);
+			break;
+		case 2:
+			out_be16((u16 *)addr, val);
+			break;
+		case 4:
+			out_be32((u32 *)addr, val);
+			break;
+		default:
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+
+	} else {
+
+		clear_and_disable_master_abort_interrupt(hose);
+
+		/* address for PCI configuration access */
+		addr = (unsigned long)hose->cfg_data +
+			(((devfn & 0xff) << 8) | (where & 0xff));
+
+		switch (size) {
+		case 1:
+			out_8((u8 *)addr, val);
+			break;
+		case 2:
+			out_le16((u16 *)addr, val);
+			break;
+		case 4:
+			out_le32((u32 *)addr, val);
+			break;
+		default:
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+	}
+
+	return celleb_epci_check_abort(hose, addr);
+}
+
+struct pci_ops celleb_epci_ops = {
+	celleb_epci_read_config,
+	celleb_epci_write_config,
+};
+
+static int __devinit celleb_epci_init(struct pci_controller *hose)
+{
+	u32 val;
+	unsigned long reg;
+	unsigned long epci_base;
+	int hwres = 0;
+
+	epci_base = (unsigned long)hose->cfg_addr;
+
+	/* PCI core reset(Internal bus and PCI clock) */
+	reg = epci_base + SCC_EPCI_CKCTRL;
+	val = in_be32((void *)reg);
+	if (val == 0x00030101)
+		hwres = 1;
+	else {
+		val &= ~(SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1);
+		out_be32((void *)reg, val);
+
+		/* set PCI core clock */
+		val = in_be32((void *)reg);
+		val |= (SCC_EPCI_CKCTRL_OCLKEN | SCC_EPCI_CKCTRL_LCLKEN);
+		out_be32((void *)reg, val);
+
+		/* release PCI core reset (internal bus) */
+		val = in_be32((void *)reg);
+		val |= SCC_EPCI_CKCTRL_CRST0;
+		out_be32((void *)reg, val);
+
+		/* set PCI clock select */
+		reg = epci_base + SCC_EPCI_CLKRST;
+		val = in_be32((void *)reg);
+		val &= ~SCC_EPCI_CLKRST_CKS_MASK;
+		val |= SCC_EPCI_CLKRST_CKS_2;
+		out_be32((void *)reg, val);
+
+		/* set arbiter */
+		reg = epci_base + SCC_EPCI_ABTSET;
+		out_be32((void *)reg, 0x0f1f001f);	/* temporary value */
+
+		/* buffer on */
+		reg = epci_base + SCC_EPCI_CLKRST;
+		val = in_be32((void *)reg);
+		val |= SCC_EPCI_CLKRST_BC;
+		out_be32((void *)reg, val);
+
+		/* PCI clock enable */
+		val = in_be32((void *)reg);
+		val |= SCC_EPCI_CLKRST_PCKEN;
+		out_be32((void *)reg, val);
+
+		/* release PCI core reset (all) */
+		reg = epci_base + SCC_EPCI_CKCTRL;
+		val = in_be32((void *)reg);
+		val |= (SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1);
+		out_be32((void *)reg, val);
+
+		/* set base translation registers. (already set by Beat) */
+
+		/* set base address masks. (already set by Beat) */
+	}
+
+	/* release interrupt masks and clear all interrupts */
+	reg = epci_base + SCC_EPCI_INTSET;
+	out_be32((void *)reg, 0x013f011f);	/* all interrupts enable */
+	reg = epci_base + SCC_EPCI_VIENAB;
+	val = SCC_EPCI_VIENAB_PMPEE | SCC_EPCI_VIENAB_PMFEE;
+	out_be32((void *)reg, val);
+	reg = epci_base + SCC_EPCI_STATUS;
+	out_be32((void *)reg, 0xffffffff);
+	reg = epci_base + SCC_EPCI_VISTAT;
+	out_be32((void *)reg, 0xffffffff);
+
+	/* disable PCI->IB address translation */
+	reg = epci_base + SCC_EPCI_VCSR;
+	val = in_be32((void *)reg);
+	val &= ~(SCC_EPCI_VCSR_DR | SCC_EPCI_VCSR_AT);
+	out_be32((void *)reg, val);
+
+	/* set base addresses. (no need to set?) */
+
+	/* memory space, bus master enable */
+	reg = epci_base + PCI_COMMAND;
+	val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+	out_be32((void *)reg, val);
+
+	/* endian mode setup */
+	reg = epci_base + SCC_EPCI_ECMODE;
+	//val = 0x00ff03ff;
+	val = 0x00550155;
+	//val = 0x00550000;
+	out_be32((void *)reg, val);
+
+	/* set control option */
+	reg = epci_base + SCC_EPCI_CNTOPT;
+	val = in_be32((void *)reg);
+	val |= SCC_EPCI_CNTOPT_O2PMB;
+	out_be32((void *)reg, val);
+
+	/* XXX: temporay: set registers for address conversion setup */
+	reg = epci_base + SCC_EPCI_CNF10_REG;
+	out_be32((void *)reg, 0x80000008);
+	reg = epci_base + SCC_EPCI_CNF14_REG;
+	out_be32((void *)reg, 0x40000008);
+
+	reg = epci_base + SCC_EPCI_BAM0;
+	out_be32((void *)reg, 0x80000000);
+	reg = epci_base + SCC_EPCI_BAM1;
+	out_be32((void *)reg, 0xe0000000);
+
+	reg = epci_base + SCC_EPCI_PVBAT;
+	out_be32((void *)reg, 0x80000000);
+
+	if (!hwres) {
+		/* release external PCI reset */
+		reg = epci_base + SCC_EPCI_CLKRST;
+		val = in_be32((void *)reg);
+		val |= SCC_EPCI_CLKRST_PCIRST;
+		out_be32((void *)reg, val);
+	}
+
+	return 0;
+}
+
+int __devinit celleb_setup_epci(struct device_node *node,
+				struct pci_controller *hose)
+{
+	const unsigned long *li, *li2;
+	unsigned int rlen;
+	struct celleb_epci_private *private;
+
+
+	pr_debug("PCI: celleb_setup_epci()\n");
+
+	li = get_property(node, "toshiba,reg", &rlen);
+
+	if (!li || ((rlen >> 4) != 4)) {
+		printk(KERN_ERR "PCI: No toshiba,reg property\n");
+		goto error;
+	}
+
+	hose->cfg_addr = ioremap(li[0], li[1]);
+	if (!hose->cfg_addr)
+		goto error;
+
+	hose->cfg_data = ioremap(li[4], li[5]);
+	if (!hose->cfg_data)
+		goto error;
+
+	if (mem_init_done)
+		hose->private_data = private =
+		    kzalloc(sizeof(struct celleb_epci_private), GFP_KERNEL);
+	else
+		hose->private_data = private =
+		    alloc_bootmem(sizeof(struct celleb_epci_private));
+
+
+	li2 = get_property(node, "interrupts", &rlen);
+	if (!li2) {
+		printk(KERN_ERR "PCI: No interrupts property");
+		goto error;
+	}
+
+	if (private){
+		private->epci_ext_irq = li2[0];
+		private->epci_int_irq = li2[1];
+	}
+
+	pr_debug("PCI: epci_ext_irq %x epci_int_irq %x\n",
+		 private->epci_ext_irq, private->epci_int_irq);
+	pr_debug("PCI: cfg_addr 0x%016lx->0x%016lx + 0x%016lx\n",
+		 li[0], (unsigned long)hose->cfg_addr, li[1]);
+	pr_debug("PCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n",
+		 li[4], (unsigned long)hose->cfg_data, li[5]);
+
+	celleb_epci_init(hose);
+
+	return 0;
+
+error:
+	if (hose->cfg_addr)
+		iounmap((void *)hose->cfg_addr);
+
+	if (hose->cfg_data)
+		iounmap((void *)hose->cfg_data);
+
+	return 1;
+}
Index: linux-powerpc-git/arch/powerpc/platforms/celleb/scc_uhc.c
diff -u /dev/null linux-powerpc-git/arch/powerpc/platforms/celleb/scc_uhc.c:1.1
--- /dev/null	Mon Dec 11 20:37:35 2006
+++ linux-powerpc-git/arch/powerpc/platforms/celleb/scc_uhc.c	Mon Dec 11 18:11:35 2006
@@ -0,0 +1,88 @@
+/*
+ * SCC (Super Companion Chip) UHC setup
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "scc.h"
+
+#define UHC_RESET_WAIT_MAX 10000
+
+static inline int uhc_clkctrl_ready(u32 val)
+{
+	const u32 mask = SCC_UHC_USBCEN | SCC_UHC_USBCEN;
+	return((val & mask) == mask);
+}
+
+/*
+ * UHC(usb host controler) enable function.
+ * affect to both of OHCI and EHCI core module.
+ */
+static void quirk_scc_uhc_enable(struct pci_dev *dev)
+{
+	void __iomem *uhc_base;
+	u32 __iomem *uhc_clkctrl;
+	u32 __iomem *uhc_ecmode;
+	u32 val = 0;
+	int i;
+
+	uhc_base = ioremap(pci_resource_start(dev, 0),
+			   pci_resource_len(dev, 0));
+	if (!uhc_base) {
+		printk(KERN_ERR "failed to map UHC register base.\n");
+		return;
+	}
+	uhc_clkctrl = uhc_base + SCC_UHC_CKRCTRL; 
+	uhc_ecmode  = uhc_base + SCC_UHC_ECMODE; 
+
+	/* setup for normal mode */
+	val |= SCC_UHC_F48MCKLEN;
+	out_be32(uhc_clkctrl, val);
+	val |= SCC_UHC_PHY_SUSPEND_SEL;
+	out_be32(uhc_clkctrl, val);
+	udelay(10);
+	val |= SCC_UHC_PHYEN;
+	out_be32(uhc_clkctrl, val);
+	udelay(50);
+
+	/* disable reset */
+	val |= SCC_UHC_HCLKEN;
+	out_be32(uhc_clkctrl, val);
+	val |= (SCC_UHC_USBCEN | SCC_UHC_USBEN);
+	out_be32(uhc_clkctrl, val);
+	i = 0;
+	while (!uhc_clkctrl_ready(in_be32(uhc_clkctrl))) {
+		udelay(10);
+		if (i++ > UHC_RESET_WAIT_MAX) {
+			printk(KERN_ERR "Failed to disable UHC reset %x\n",
+			       in_be32(uhc_clkctrl));
+			break;
+		}
+	}
+
+	/* Endian Conversion Mode for Master ALL area */
+	out_be32(uhc_ecmode, SCC_UHC_ECMODE_BY_BYTE);
+
+	iounmap(uhc_base);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+		 PCI_DEVICE_ID_TOSHIBA_SCC_USB, quirk_scc_uhc_enable);

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 8/15] Supporting PCI bus and base of I/O
  2006-12-12  3:37 [PATCH 8/15] Supporting PCI bus and base of I/O Ishizaki Kou
@ 2006-12-12 20:03 ` Arnd Bergmann
  2006-12-12 20:49   ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 4+ messages in thread
From: Arnd Bergmann @ 2006-12-12 20:03 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus

On Tuesday 12 December 2006 04:37, Ishizaki Kou wrote:
> This patch includes support for pci buses, base of Celleb specific
> devices, and etc. It works on of_platform bus.
> 
> Signed-off-by: Kou Ishizaki <kou.ishizaki.co.jp>

The code looks good to me, I guess it could go in, except that
I really don't like the concept of faking a PCI bus device when
it's not actually there. I guess the EPCI part of this is
not controversial, so it would be good if you can split that
out into a separate patch that we can merge first.

	Arnd <><

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 8/15] Supporting PCI bus and base of I/O
  2006-12-12 20:03 ` Arnd Bergmann
@ 2006-12-12 20:49   ` Benjamin Herrenschmidt
  2006-12-12 23:03     ` Arnd Bergmann
  0 siblings, 1 reply; 4+ messages in thread
From: Benjamin Herrenschmidt @ 2006-12-12 20:49 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, paulus

On Tue, 2006-12-12 at 21:03 +0100, Arnd Bergmann wrote:
> On Tuesday 12 December 2006 04:37, Ishizaki Kou wrote:
> > This patch includes support for pci buses, base of Celleb specific
> > devices, and etc. It works on of_platform bus.
> > 
> > Signed-off-by: Kou Ishizaki <kou.ishizaki.co.jp>
> 
> The code looks good to me, I guess it could go in, except that
> I really don't like the concept of faking a PCI bus device when
> it's not actually there. I guess the EPCI part of this is
> not controversial, so it would be good if you can split that
> out into a separate patch that we can merge first.

I personally don't have a big problem with the fake PCI stuff. The
spider and USB drivers are already working out of the box pretty much
with PCI and that's exactly what we do on IBM blades (though the
illusion is maintained by the firmware in our case).

I agree that in the long run, it's better to move that to of_platform,
but I wouldn't nack the patches for that.

Ben.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 8/15] Supporting PCI bus and base of I/O
  2006-12-12 20:49   ` Benjamin Herrenschmidt
@ 2006-12-12 23:03     ` Arnd Bergmann
  0 siblings, 0 replies; 4+ messages in thread
From: Arnd Bergmann @ 2006-12-12 23:03 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, paulus

On Tuesday 12 December 2006 21:49, Benjamin Herrenschmidt wrote:
> 
> > The code looks good to me, I guess it could go in, except that
> > I really don't like the concept of faking a PCI bus device when
> > it's not actually there. I guess the EPCI part of this is
> > not controversial, so it would be good if you can split that
> > out into a separate patch that we can merge first.
> 
> I personally don't have a big problem with the fake PCI stuff. The
> spider and USB drivers are already working out of the box pretty much
> with PCI and that's exactly what we do on IBM blades (though the
> illusion is maintained by the firmware in our case).

Ok, fair enough. Then let's take these patches as well.

> I agree that in the long run, it's better to move that to of_platform,
> but I wouldn't nack the patches for that.

Another alternative might be for the BEAT developers to access the
config space of all buses using an hcall abstraction, but that's
something that is not in the hand of the Linux people.

	Arnd <><

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2006-12-12 23:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-12  3:37 [PATCH 8/15] Supporting PCI bus and base of I/O Ishizaki Kou
2006-12-12 20:03 ` Arnd Bergmann
2006-12-12 20:49   ` Benjamin Herrenschmidt
2006-12-12 23:03     ` Arnd Bergmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).