From e58ca3de64927e96beb2f1594975dc4a29b79459 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 13 Jun 2007 14:53:00 +1000 Subject: [POWERPC] Fix problems with device tree representation of TSI-1xx bridges This fixes some problems with the way the some things represented in the device tree for the Holly and Taiga boards. This means changes both to the dts files, and to the code which instantiates the tsi108 ethernet platform devices based on the device tree. - First, and most importantly, the ethernet PHYs are given with an identical 'reg' property. This reg currently encodes the accessible register used to initiate mdio interaction with the PHYs, rather than a meaningful address on the parent bus (mdio in this case), which is incorrect. Instead we give the address of these registers as 'reg' in the mdio node itself, and encode the ID of each phy in their 'reg' propertyies. - Currently the platform device constructor enables a workaround in the tsi108 ethernet driver based on the compatible property of the PHY. This is incorrect, because the workaround in question is necessary due to the board's wiring of the PHY, not the model of PHY itself. This patch alters the constructor to instead enable the workaround based on a new special property in the PHY node. - The compatible properties on a number of nodes in the device tree are insufficiently precise. In particular the PHYs give only "bcm54xx", which is broken, since there are many bcm54xx PHY models, and they have differences which matter. The mdio had a compatible property of "tsi-ethernet" identical to the ethernet MAC nodes, which doesn't make sense. The ethernet, i2c, bridge and PCI nodes were given only as "tsi-*" which is somewhat inprecise, we replace with "tsi108-*" in the case of Taiga (which has a TSI108 bridge), and "tsi109-*", "tsi108-*" in the case of Holly (which has a TSI109 bridge). - We remove some "model" properties from the ethernets on Taiga board which were neither useful nor adequately precise. - On Holly we change to using a dtc label instead of a full path to reference the MPIC node, which makes the dts a little more readable. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/tsi108_dev.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c index 7d3b09b7d544..a113d800cbf0 100644 --- a/arch/powerpc/sysdev/tsi108_dev.c +++ b/arch/powerpc/sysdev/tsi108_dev.c @@ -72,12 +72,11 @@ static int __init tsi108_eth_of_init(void) int ret; for (np = NULL, i = 0; - (np = of_find_compatible_node(np, "network", "tsi-ethernet")) != NULL; + (np = of_find_compatible_node(np, "network", "tsi108-ethernet")) != NULL; i++) { struct resource r[2]; - struct device_node *phy; + struct device_node *phy, *mdio; hw_info tsi_eth_data; - const unsigned int *id; const unsigned int *phy_id; const void *mac_addr; const phandle *ph; @@ -111,6 +110,13 @@ static int __init tsi108_eth_of_init(void) if (mac_addr) memcpy(tsi_eth_data.mac_addr, mac_addr, 6); + ph = of_get_property(np, "mdio-handle", NULL); + mdio = of_find_node_by_phandle(*ph); + ret = of_address_to_resource(mdio, 0, &res); + of_node_put(mdio); + if (ret) + goto unreg; + ph = of_get_property(np, "phy-handle", NULL); phy = of_find_node_by_phandle(*ph); @@ -119,20 +125,25 @@ static int __init tsi108_eth_of_init(void) goto unreg; } - id = of_get_property(phy, "reg", NULL); - phy_id = of_get_property(phy, "phy-id", NULL); - ret = of_address_to_resource(phy, 0, &res); - if (ret) { - of_node_put(phy); - goto unreg; - } + phy_id = of_get_property(phy, "reg", NULL); + tsi_eth_data.regs = r[0].start; tsi_eth_data.phyregs = res.start; tsi_eth_data.phy = *phy_id; tsi_eth_data.irq_num = irq_of_parse_and_map(np, 0); - if (of_device_is_compatible(phy, "bcm54xx")) + + /* Some boards with the TSI108 bridge (e.g. Holly) + * have a miswiring of the ethernet PHYs which + * requires a workaround. The special + * "txc-rxc-delay-disable" property enables this + * workaround. FIXME: Need to port the tsi108_eth + * driver itself to phylib and use a non-misleading + * name for the workaround flag - it's not actually to + * do with the model of PHY in use */ + if (of_get_property(phy, "txc-rxc-delay-disable", NULL)) tsi_eth_data.phy_type = TSI108_PHY_BCM54XX; of_node_put(phy); + ret = platform_device_add_data(tsi_eth_dev, &tsi_eth_data, sizeof(hw_info)); -- cgit v1.2.3 From 0c358e70762861f8d479f3fa8bec358c599ba04a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 May 2007 00:25:42 +1000 Subject: [POWERPC] Use mktime in timer sysdev This makes the timer sysdev use mktime instead of rtc_tm_to_time, since rtc_tm_to_time just calls mktime anyway, and this means we don't have a dependency on rtc-lib. Signed-off-by: Johannes Berg Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 5 ----- arch/powerpc/sysdev/timer.c | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 882f8a1d2c7c..29012204c295 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -6,11 +6,6 @@ mainmenu "Linux/PowerPC Kernel Configuration" source "arch/powerpc/platforms/Kconfig.cputype" -config PPC_PM_NEEDS_RTC_LIB - bool - select RTC_LIB - default y if PM - config PPC32 bool default y if !PPC64 diff --git a/arch/powerpc/sysdev/timer.c b/arch/powerpc/sysdev/timer.c index 4a01748b4217..e81e7ec2e799 100644 --- a/arch/powerpc/sysdev/timer.c +++ b/arch/powerpc/sysdev/timer.c @@ -24,7 +24,12 @@ static int timer_resume(struct sys_device *dev) /* get current RTC time and convert to seconds */ get_rtc_time(&cur_rtc_tm); - rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time); + cur_rtc_time = mktime(cur_rtc_tm.tm_year + 1900, + cur_rtc_tm.tm_mon + 1, + cur_rtc_tm.tm_mday, + cur_rtc_tm.tm_hour, + cur_rtc_tm.tm_min, + cur_rtc_tm.tm_sec); diff = cur_rtc_time - suspend_rtc_time; @@ -44,7 +49,12 @@ static int timer_suspend(struct sys_device *dev, pm_message_t state) WARN_ON(!ppc_md.get_rtc_time); get_rtc_time(&suspend_rtc_tm); - rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time); + suspend_rtc_time = mktime(suspend_rtc_tm.tm_year + 1900, + suspend_rtc_tm.tm_mon + 1, + suspend_rtc_tm.tm_mday, + suspend_rtc_tm.tm_hour, + suspend_rtc_tm.tm_min, + suspend_rtc_tm.tm_sec); return 0; } -- cgit v1.2.3 From 1a06e0fe96526e43bab90fbab2263b55fb3d45d1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 17 May 2007 18:56:32 +1000 Subject: [POWERPC] Don't link timer.o for powerpc systems using generic rtc With both generic rtc and powerpc timer suspend / resume code now in the (powerpc.git) tree, powerpc platforms using the generic timer and enabling power management will have timer.o linked in the kernel, which they don't need. Moreover, it will likely WARN_ON(!ppc_md.get_rtc_time), save zero-time and return no error on suspend... As a possible solution we can choose not to build timer.o when RTC_CLASS is enabled. However, I can imagine systems with 2 rtc's, one served by the ppc-rtc, another one generic built as a module, in which case using the ppc-rtc for suspend / resume will be impossible. Not to say, that such a configuration would be ugly... Signed-off-by: G. Liakhovetski Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/Makefile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index c3ce0bd12c0b..31da3b3dc993 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -20,7 +20,9 @@ mv64x60-$(CONFIG_PCI) += mv64x60_pci.o obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o # contains only the suspend handler for time +ifeq ($(CONFIG_RTC_CLASS),) obj-$(CONFIG_PM) += timer.o +endif ifeq ($(CONFIG_PPC_MERGE),y) obj-$(CONFIG_PPC_I8259) += i8259.o -- cgit v1.2.3 From 542c98c06712fdbbbfe6b9e92a8d0023cf45102a Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Thu, 7 Jun 2007 10:38:00 +1000 Subject: [POWERPC] Call add_preferred_console when MPSC is console When a Marvell MPSC (serial controller) port is the specified /chosen/stdout-path device, call 'add_preferred_console()' so the user doesn't have to specify a 'console=ttyMMx' cmdline argument. Signed-off-by: Mark A. Greer Acked-by: Dale Farnsworth Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mv64x60_dev.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c index 4b0a9c88eeb3..b618fa60aef3 100644 --- a/arch/powerpc/sysdev/mv64x60_dev.c +++ b/arch/powerpc/sysdev/mv64x60_dev.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -420,3 +421,30 @@ error: return err; } arch_initcall(mv64x60_device_setup); + +static int __init mv64x60_add_mpsc_console(void) +{ + struct device_node *np = NULL; + const char *prop; + + prop = of_get_property(of_chosen, "linux,stdout-path", NULL); + if (prop == NULL) + goto not_mpsc; + + np = of_find_node_by_path(prop); + if (!np) + goto not_mpsc; + + if (!of_device_is_compatible(np, "marvell,mpsc")) + goto not_mpsc; + + prop = of_get_property(np, "block-index", NULL); + if (!prop) + goto not_mpsc; + + add_preferred_console("ttyMM", *(int *)prop, NULL); + +not_mpsc: + return 0; +} +console_initcall(mv64x60_add_mpsc_console); -- cgit v1.2.3 From 5ab9c4524d7edd6ae3711bdfd03e4a0deb17fc6e Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 21 Jun 2007 11:22:47 -0500 Subject: [POWERPC] Remove set_cfg_type for PCI indirect users that don't need it The Freescale and Marvell PCI controllers dont require explicit setting for type 1 config cycles. They handle producing them by implicitly looking at the bus, devfn. The TSI108 and 52xx don't use the generic PCI indirect code and thus don't bother with set_cfg_type. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/52xx/mpc52xx_pci.c | 1 - arch/powerpc/platforms/82xx/mpc82xx_ads.c | 3 --- arch/powerpc/platforms/83xx/pci.c | 1 - arch/powerpc/platforms/85xx/pci.c | 1 - arch/powerpc/platforms/86xx/pci.c | 1 - arch/powerpc/sysdev/mv64x60_pci.c | 1 - arch/powerpc/sysdev/tsi108_pci.c | 1 - 7 files changed, 9 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 34d34a26d305..51164c851cac 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -390,7 +390,6 @@ mpc52xx_add_bridge(struct device_node *node) return -ENOMEM; hose->arch_data = node; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 081c0abe4f18..04bf57079c1e 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -548,14 +548,11 @@ static void __init mpc82xx_add_bridge(struct device_node *np) return; hose->arch_data = np; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; hose->bus_offset = 0; - hose->set_cfg_type = 1; - setup_indirect_pci(hose, r.start + offsetof(pci_cpm2_t, pci_cfg_addr), r.start + offsetof(pci_cpm2_t, pci_cfg_data)); diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 1752d4577aaf..34716024ed1a 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -70,7 +70,6 @@ int __init mpc83xx_add_bridge(struct device_node *dev) if (!hose) return -ENOMEM; hose->arch_data = dev; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c index 3c38ae4b76c7..72a1bc5e0c2d 100644 --- a/arch/powerpc/platforms/85xx/pci.c +++ b/arch/powerpc/platforms/85xx/pci.c @@ -61,7 +61,6 @@ int __init mpc85xx_add_bridge(struct device_node *dev) if (!hose) return -ENOMEM; hose->arch_data = dev; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index c1d65fac690d..1e47c145d54d 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -172,7 +172,6 @@ int __init mpc86xx_add_bridge(struct device_node *dev) if (!hose) return -ENOMEM; hose->arch_data = dev; - hose->set_cfg_type = 1; /* last_busno = 0xfe cause by MPC8641 PCIE bug */ hose->first_busno = bus_range ? bus_range[0] : 0x0; diff --git a/arch/powerpc/sysdev/mv64x60_pci.c b/arch/powerpc/sysdev/mv64x60_pci.c index b5aef4cbc8d2..6b08e76de5a2 100644 --- a/arch/powerpc/sysdev/mv64x60_pci.c +++ b/arch/powerpc/sysdev/mv64x60_pci.c @@ -142,7 +142,6 @@ static int __init mv64x60_add_bridge(struct device_node *dev) return -ENOMEM; hose->arch_data = dev; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 2153163fa593..33177b60c7ed 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -226,7 +226,6 @@ int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary) return -ENOMEM; } hose->arch_data = dev; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; -- cgit v1.2.3 From 7d52c7b0cd46f42ae2c9df37f1a385d9aaf95842 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 22 Jun 2007 00:23:57 -0500 Subject: [POWERPC] Pass the pci_controller into pci_exclude_device There are times that we need to know which controller we are on to decide how to exclude devices properly. We now pass the pci_controller that we are going to use down to the pci_exclude_device function. This will greatly simplify being able to exclude the PHBs in multiple controller setups. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/52xx/mpc52xx_pci.c | 4 +- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 3 +- arch/powerpc/platforms/83xx/mpc83xx.h | 4 +- arch/powerpc/platforms/83xx/pci.c | 2 +- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 3 +- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 3 +- arch/powerpc/platforms/86xx/mpc86xx.h | 3 +- arch/powerpc/platforms/86xx/pci.c | 2 +- arch/powerpc/platforms/embedded6xx/holly.c | 2 +- arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | 3 +- arch/powerpc/sysdev/Makefile | 2 +- arch/powerpc/sysdev/fsl_pcie.c | 4 +- arch/powerpc/sysdev/indirect_pci.c | 8 +- arch/powerpc/sysdev/tsi108_pci.c | 6 +- arch/ppc/syslib/Makefile | 1 + arch/ppc/syslib/indirect_pci.c | 134 ++++++++++++++++++++++ include/asm-powerpc/machdep.h | 2 +- 17 files changed, 165 insertions(+), 21 deletions(-) create mode 100644 arch/ppc/syslib/indirect_pci.c (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 57ca2feb0799..69a04217c79d 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -112,7 +112,7 @@ mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, u32 value; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; out_be32(hose->cfg_addr, @@ -169,7 +169,7 @@ mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, u32 value, mask; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; out_be32(hose->cfg_addr, diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 04bf57079c1e..715107b6d784 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -507,7 +507,8 @@ void m82xx_pci_init_irq(void) return; } -static int m82xx_pci_exclude_device(u_char bus, u_char devfn) +static int m82xx_pci_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 9bd85f5e9a56..f5c5034a8461 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -3,6 +3,7 @@ #include #include +#include /* System Clock Control Register */ #define MPC83XX_SCCR_OFFS 0xA08 @@ -28,7 +29,8 @@ */ extern int mpc83xx_add_bridge(struct device_node *dev); -extern int mpc83xx_exclude_device(u_char bus, u_char devfn); +extern int mpc83xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn); extern void mpc83xx_restart(char *cmd); extern long mpc83xx_time_init(void); diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 34716024ed1a..f92e71f2ed6b 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -35,7 +35,7 @@ int mpc83xx_pci2_busno; -int mpc83xx_exclude_device(u_char bus, u_char devfn) +int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 4100e17f4cb2..1262d1b8a442 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -39,7 +39,8 @@ #endif #ifdef CONFIG_PCI -static int mpc85xx_exclude_device(u_char bus, u_char devfn) +static int mpc85xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index fa6b6be6cada..fcea5ab5eb77 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -57,7 +57,8 @@ static volatile u8 *cadmus; extern int mpc85xx_pci2_busno; -static int mpc85xx_exclude_device(u_char bus, u_char devfn) +static int mpc85xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h index dc2f6fdc8de4..4c2789de045e 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx.h +++ b/arch/powerpc/platforms/86xx/mpc86xx.h @@ -17,7 +17,8 @@ extern int mpc86xx_add_bridge(struct device_node *dev); -extern int mpc86xx_exclude_device(u_char bus, u_char devfn); +extern int mpc86xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn); extern void setup_indirect_pcie(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data); diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 1e47c145d54d..7659259cc974 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -140,7 +140,7 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps); } -int mpc86xx_exclude_device(u_char bus, u_char devfn) +int mpc86xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 3a0b4a01401c..6292e36dc577 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -45,7 +45,7 @@ #define HOLLY_PCI_CFG_PHYS 0x7c000000 -int holly_exclude_device(u_char bus, u_char devfn) +int holly_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 69eab173ae09..1e3cc69487b5 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -56,7 +56,8 @@ extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); -int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn) +int mpc7448_hpc2_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 31da3b3dc993..337b56a73247 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -5,7 +5,6 @@ endif mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) -obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPC_MPC106) += grackle.o obj-$(CONFIG_PPC_DCR) += dcr.o obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o @@ -25,6 +24,7 @@ obj-$(CONFIG_PM) += timer.o endif ifeq ($(CONFIG_PPC_MERGE),y) +obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPC_I8259) += i8259.o obj-$(CONFIG_PPC_83xx) += ipic.o obj-$(CONFIG_4xx) += uic.o diff --git a/arch/powerpc/sysdev/fsl_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c index 041c07e8b665..6bbd7f84b4e2 100644 --- a/arch/powerpc/sysdev/fsl_pcie.c +++ b/arch/powerpc/sysdev/fsl_pcie.c @@ -39,7 +39,7 @@ indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, u32 temp; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; /* Possible artifact of CDCpp50937 needs further investigation */ @@ -90,7 +90,7 @@ indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, u32 temp; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; /* Possible artifact of CDCpp50937 needs further investigation */ diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index e71488469704..3dedf8f5bfb4 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -35,14 +35,14 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, u8 cfg_type = 0; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; if (hose->set_cfg_type) if (bus->number != hose->first_busno) cfg_type = 1; - PCI_CFG_OUT(hose->cfg_addr, + PCI_CFG_OUT(hose->cfg_addr, (0x80000000 | ((bus->number - hose->bus_offset) << 16) | (devfn << 8) | ((offset & 0xfc) | cfg_type))); @@ -74,14 +74,14 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, u8 cfg_type = 0; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; if (hose->set_cfg_type) if (bus->number != hose->first_busno) cfg_type = 1; - PCI_CFG_OUT(hose->cfg_addr, + PCI_CFG_OUT(hose->cfg_addr, (0x80000000 | ((bus->number - hose->bus_offset) << 16) | (devfn << 8) | ((offset & 0xfc) | cfg_type))); diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 33177b60c7ed..298e2dd34e89 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -64,9 +64,10 @@ tsi108_direct_write_config(struct pci_bus *bus, unsigned int devfunc, int offset, int len, u32 val) { volatile unsigned char *cfg_addr; + struct pci_controller *hose = bus->sysdata; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfunc)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfunc)) return PCIBIOS_DEVICE_NOT_FOUND; cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number, @@ -149,10 +150,11 @@ tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 * val) { volatile unsigned char *cfg_addr; + struct pci_controller *hose = bus->sysdata; u32 temp; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number, diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 95694159b226..543795be58c8 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -7,6 +7,7 @@ CFLAGS_btext.o += -fPIC wdt-mpc8xx-$(CONFIG_8xx_WDT) += m8xx_wdt.o +obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o obj-$(CONFIG_PPC_OCP) += ocp.o obj-$(CONFIG_IBM_OCP) += ibm_ocp.o diff --git a/arch/ppc/syslib/indirect_pci.c b/arch/ppc/syslib/indirect_pci.c new file mode 100644 index 000000000000..83b323a7d029 --- /dev/null +++ b/arch/ppc/syslib/indirect_pci.c @@ -0,0 +1,134 @@ +/* + * Support for indirect PCI bridges. + * + * Copyright (C) 1998 Gabriel Paubert. + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_PPC_INDIRECT_PCI_BE +#define PCI_CFG_OUT out_be32 +#else +#define PCI_CFG_OUT out_le32 +#endif + +static int +indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + volatile void __iomem *cfg_data; + u8 cfg_type = 0; + + if (ppc_md.pci_exclude_device) + if (ppc_md.pci_exclude_device(bus->number, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (hose->set_cfg_type) + if (bus->number != hose->first_busno) + cfg_type = 1; + + PCI_CFG_OUT(hose->cfg_addr, + (0x80000000 | ((bus->number - hose->bus_offset) << 16) + | (devfn << 8) | ((offset & 0xfc) | cfg_type))); + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + (offset & 3); + switch (len) { + case 1: + *val = in_8(cfg_data); + break; + case 2: + *val = in_le16(cfg_data); + break; + default: + *val = in_le32(cfg_data); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int +indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + volatile void __iomem *cfg_data; + u8 cfg_type = 0; + + if (ppc_md.pci_exclude_device) + if (ppc_md.pci_exclude_device(bus->number, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (hose->set_cfg_type) + if (bus->number != hose->first_busno) + cfg_type = 1; + + PCI_CFG_OUT(hose->cfg_addr, + (0x80000000 | ((bus->number - hose->bus_offset) << 16) + | (devfn << 8) | ((offset & 0xfc) | cfg_type))); + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + cfg_data = hose->cfg_data + (offset & 3); + switch (len) { + case 1: + out_8(cfg_data, val); + break; + case 2: + out_le16(cfg_data, val); + break; + default: + out_le32(cfg_data, val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops indirect_pci_ops = +{ + indirect_read_config, + indirect_write_config +}; + +void __init +setup_indirect_pci_nomap(struct pci_controller* hose, void __iomem * cfg_addr, + void __iomem * cfg_data) +{ + hose->cfg_addr = cfg_addr; + hose->cfg_data = cfg_data; + hose->ops = &indirect_pci_ops; +} + +void __init +setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) +{ + unsigned long base = cfg_addr & PAGE_MASK; + void __iomem *mbase, *addr, *data; + + mbase = ioremap(base, PAGE_SIZE); + addr = mbase + (cfg_addr & ~PAGE_MASK); + if ((cfg_data & PAGE_MASK) != base) + mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE); + data = mbase + (cfg_data & ~PAGE_MASK); + setup_indirect_pci_nomap(hose, addr, data); +} diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index 6cf1a831f550..71c6e7eb2a26 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -218,7 +218,7 @@ struct machdep_calls { int (*pcibios_enable_device_hook)(struct pci_dev *, int initial); /* Called in indirect_* to avoid touching devices */ - int (*pci_exclude_device)(unsigned char, unsigned char); + int (*pci_exclude_device)(struct pci_controller *, unsigned char, unsigned char); /* Called at then very end of pcibios_init() */ void (*pcibios_after_init)(void); -- cgit v1.2.3 From 2a5ccbc5bb471c10b58ea85ac463e70faead1c8a Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 25 Jun 2007 12:53:51 -0500 Subject: [POWERPC] Remove bus_offset in places its not really used The user of the fsl_pcie code doesn't set bus_offset and 82xx doesn't require it either. Remove the places in the code that reference it so we can remove it all together. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 1 - arch/powerpc/sysdev/fsl_pcie.c | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 715107b6d784..d1e0919a3dee 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -552,7 +552,6 @@ static void __init mpc82xx_add_bridge(struct device_node *np) hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; - hose->bus_offset = 0; setup_indirect_pci(hose, r.start + offsetof(pci_cpm2_t, pci_cfg_addr), diff --git a/arch/powerpc/sysdev/fsl_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c index 6bbd7f84b4e2..ea3ec6bfd577 100644 --- a/arch/powerpc/sysdev/fsl_pcie.c +++ b/arch/powerpc/sysdev/fsl_pcie.c @@ -50,12 +50,12 @@ indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, if (bus->number == 0xff) { PCI_CFG_OUT(hose->cfg_addr, (0x80000000 | ((offset & 0xf00) << 16) | - ((bus->number - hose->bus_offset) << 16) + (bus->number<< 16) | (devfn << 8) | ((offset & 0xfc) ))); } else { PCI_CFG_OUT(hose->cfg_addr, (0x80000001 | ((offset & 0xf00) << 16) | - ((bus->number - hose->bus_offset) << 16) + (bus->number<< 16) | (devfn << 8) | ((offset & 0xfc) ))); } @@ -101,12 +101,12 @@ indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, if (bus->number == 0xff) { PCI_CFG_OUT(hose->cfg_addr, (0x80000000 | ((offset & 0xf00) << 16) | - ((bus->number - hose->bus_offset) << 16) + (bus->number << 16) | (devfn << 8) | ((offset & 0xfc) ))); } else { PCI_CFG_OUT(hose->cfg_addr, (0x80000001 | ((offset & 0xf00) << 16) | - ((bus->number - hose->bus_offset) << 16) + (bus->number << 16) | (devfn << 8) | ((offset & 0xfc) ))); } -- cgit v1.2.3 From 5ab65ecdaffd85753e7ad957622afcd709a39deb Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 25 Jun 2007 13:09:42 -0500 Subject: [POWERPC] Added self_busno to indicate which bus number the PHB is Added self_busno to pci_controller and indirect PCI ops to be set by board code to indicate which bus number to use when talking to the PHB. By default we use zero since the majority of controllers that have implicit mechanisms to talk to the PHBs use a bus number of zero. Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/indirect_pci.c | 12 ++++++++++-- include/asm-ppc/pci-bridge.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index 3dedf8f5bfb4..d490e71f0533 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -33,6 +33,7 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, struct pci_controller *hose = bus->sysdata; volatile void __iomem *cfg_data; u8 cfg_type = 0; + u32 bus_no; if (ppc_md.pci_exclude_device) if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) @@ -42,8 +43,11 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, if (bus->number != hose->first_busno) cfg_type = 1; + bus_no = (bus->number == hose->first_busno) ? + hose->self_busno : bus->number - hose->bus_offset; + PCI_CFG_OUT(hose->cfg_addr, - (0x80000000 | ((bus->number - hose->bus_offset) << 16) + (0x80000000 | (bus_no << 16) | (devfn << 8) | ((offset & 0xfc) | cfg_type))); /* @@ -72,6 +76,7 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, struct pci_controller *hose = bus->sysdata; volatile void __iomem *cfg_data; u8 cfg_type = 0; + u32 bus_no; if (ppc_md.pci_exclude_device) if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) @@ -81,8 +86,11 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, if (bus->number != hose->first_busno) cfg_type = 1; + bus_no = (bus->number == hose->first_busno) ? + hose->self_busno : bus->number - hose->bus_offset; + PCI_CFG_OUT(hose->cfg_addr, - (0x80000000 | ((bus->number - hose->bus_offset) << 16) + (0x80000000 | (bus_no << 16) | (devfn << 8) | ((offset & 0xfc) | cfg_type))); /* diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index 4d35b844bc58..2c2abdaad42f 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -47,6 +47,7 @@ struct pci_controller { int first_busno; int last_busno; + int self_busno; int bus_offset; void __iomem *io_base_virt; -- cgit v1.2.3 From 0a3786c5f7575c0739ad94057213b931a9423502 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 25 Jun 2007 13:32:48 -0500 Subject: [POWERPC] Removed remnants of bus_offset Removed the remants of bus_offset and use self_busno in the mv64x60 case and use pci_assign_all_buses on 83xx/85xx. 83xx/85xx have multiple PHBs and the firmwares on these devices tend not to handle topologies with P2P bridges well so we let Linux just reassign the bus numbers to match. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/pci.c | 2 +- arch/powerpc/platforms/85xx/pci.c | 2 +- arch/powerpc/sysdev/indirect_pci.c | 4 ++-- arch/powerpc/sysdev/mv64x60_pci.c | 2 +- include/asm-ppc/pci-bridge.h | 1 + 5 files changed, 6 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 8da935c6e269..f49ed277e843 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -61,6 +61,7 @@ int __init mpc83xx_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); } + pci_assign_all_buses = 1; hose = pcibios_alloc_controller(); if (!hose) return -ENOMEM; @@ -80,7 +81,6 @@ int __init mpc83xx_add_bridge(struct device_node *dev) if ((rsrc.start & 0xfffff) == 0x8600) { setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384); primary = 0; - hose->bus_offset = hose->first_busno; } printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. " diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c index be67f67ee6f4..a25b3e77a7d2 100644 --- a/arch/powerpc/platforms/85xx/pci.c +++ b/arch/powerpc/platforms/85xx/pci.c @@ -55,6 +55,7 @@ int __init mpc85xx_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); } + pci_assign_all_buses = 1; hose = pcibios_alloc_controller(); if (!hose) return -ENOMEM; @@ -71,7 +72,6 @@ int __init mpc85xx_add_bridge(struct device_node *dev) if ((rsrc.start & 0xfffff) == 0x9000) { setup_indirect_pci(hose, immr + 0x9000, immr + 0x9004); primary = 0; - hose->bus_offset = hose->first_busno; } printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. " diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index d490e71f0533..efe3cff8dcd1 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -44,7 +44,7 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, cfg_type = 1; bus_no = (bus->number == hose->first_busno) ? - hose->self_busno : bus->number - hose->bus_offset; + hose->self_busno : bus->number; PCI_CFG_OUT(hose->cfg_addr, (0x80000000 | (bus_no << 16) @@ -87,7 +87,7 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, cfg_type = 1; bus_no = (bus->number == hose->first_busno) ? - hose->self_busno : bus->number - hose->bus_offset; + hose->self_busno : bus->number; PCI_CFG_OUT(hose->cfg_addr, (0x80000000 | (bus_no << 16) diff --git a/arch/powerpc/sysdev/mv64x60_pci.c b/arch/powerpc/sysdev/mv64x60_pci.c index 6b08e76de5a2..2e7738455ae5 100644 --- a/arch/powerpc/sysdev/mv64x60_pci.c +++ b/arch/powerpc/sysdev/mv64x60_pci.c @@ -147,7 +147,7 @@ static int __init mv64x60_add_bridge(struct device_node *dev) hose->last_busno = bus_range ? bus_range[1] : 0xff; setup_indirect_pci(hose, rsrc.start, rsrc.start + 4); - hose->bus_offset = hose->first_busno; + hose->self_busno = hose->first_busno; printk(KERN_INFO "Found MV64x60 PCI host bridge at 0x%016llx. " "Firmware bus number: %d->%d\n", diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index 2c2abdaad42f..70aab6691043 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -48,6 +48,7 @@ struct pci_controller { int first_busno; int last_busno; int self_busno; + /* bus_offset is only used by ARCH=ppc */ int bus_offset; void __iomem *io_base_virt; -- cgit v1.2.3 From bf7c036fb48a6176635f2e7b749d7398728d4b7d Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Tue, 22 May 2007 11:38:26 +0800 Subject: [POWERPC] Remove PCI-e errata for MPC8641 silicon ver 1.0 Remove errata for PCI-e support of Rev 1.0 of MPC8641 since its considered obselete and is not production level silicon from Freescale. Signed-off-by: Zhang Wei Acked-by: Roy Zang Signed-off-by: Kumar Gala --- arch/powerpc/Kconfig | 4 - arch/powerpc/boot/dts/mpc8641_hpcn.dts | 2 +- arch/powerpc/platforms/86xx/mpc86xx.h | 6 - arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 2 - arch/powerpc/platforms/86xx/pci.c | 18 +-- arch/powerpc/platforms/Kconfig | 1 - arch/powerpc/sysdev/Makefile | 1 - arch/powerpc/sysdev/fsl_pcie.c | 171 ----------------------------- 8 files changed, 3 insertions(+), 202 deletions(-) delete mode 100644 arch/powerpc/sysdev/fsl_pcie.c (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 7c1bae5c2204..cbfbd981cdcd 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -419,10 +419,6 @@ config SBUS config FSL_SOC bool -config FSL_PCIE - bool - depends on PPC_86xx - # Yes MCA RS/6000s exist but Linux-PPC does not currently support any config MCA bool diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts index 260b264c869e..748f7b90f5db 100644 --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts @@ -186,7 +186,7 @@ #size-cells = <2>; #address-cells = <3>; reg = <8000 1000>; - bus-range = <0 fe>; + bus-range = <0 ff>; ranges = <02000000 0 80000000 80000000 0 20000000 01000000 0 00000000 e2000000 0 00100000>; clock-frequency = <1fca055>; diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h index 4c2789de045e..23f7ed2a7f88 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx.h +++ b/arch/powerpc/platforms/86xx/mpc86xx.h @@ -20,12 +20,6 @@ extern int mpc86xx_add_bridge(struct device_node *dev); extern int mpc86xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn); -extern void setup_indirect_pcie(struct pci_controller *hose, - u32 cfg_addr, u32 cfg_data); -extern void setup_indirect_pcie_nomap(struct pci_controller *hose, - void __iomem *cfg_addr, - void __iomem *cfg_data); - extern void __init mpc86xx_smp_init(void); #endif /* __MPC86XX_H__ */ diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 042dbce89771..afa82371979f 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -358,8 +358,6 @@ mpc86xx_hpcn_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) mpc86xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc86xx_exclude_device; #endif printk("MPC86xx HPCN board from Freescale Semiconductor\n"); diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 7659259cc974..0db51e8ab5d4 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -133,19 +133,6 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd); early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); - - /* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */ - early_read_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, &temps); - temps = (temps & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16); - early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps); -} - -int mpc86xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) -{ - if (bus == 0 && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; - - return PCIBIOS_SUCCESSFUL; } int __init mpc86xx_add_bridge(struct device_node *dev) @@ -173,11 +160,10 @@ int __init mpc86xx_add_bridge(struct device_node *dev) return -ENOMEM; hose->arch_data = dev; - /* last_busno = 0xfe cause by MPC8641 PCIE bug */ hose->first_busno = bus_range ? bus_range[0] : 0x0; - hose->last_busno = bus_range ? bus_range[1] : 0xfe; + hose->last_busno = bus_range ? bus_range[1] : 0xff; - setup_indirect_pcie(hose, rsrc.start, rsrc.start + 0x4); + setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4); /* Setup the PCIE host controller. */ mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1); diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index df67ff50c0da..33545d352e92 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -31,7 +31,6 @@ config PPC_86xx bool "Freescale 86xx" depends on 6xx select FSL_SOC - select FSL_PCIE select ALTIVEC help The Freescale E600 SoCs have 74xx cores. diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 337b56a73247..7d8ac1bfef84 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_PPC_PMI) += pmi.o obj-$(CONFIG_U3_DART) += dart_iommu.o obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o obj-$(CONFIG_FSL_SOC) += fsl_soc.o -obj-$(CONFIG_FSL_PCIE) += fsl_pcie.o obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ mv64x60-$(CONFIG_PCI) += mv64x60_pci.o diff --git a/arch/powerpc/sysdev/fsl_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c deleted file mode 100644 index ea3ec6bfd577..000000000000 --- a/arch/powerpc/sysdev/fsl_pcie.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Support for indirect PCI bridges. - * - * Copyright (C) 1998 Gabriel Paubert. - * - * 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. - * - * "Temporary" MPC8548 Errata file - - * The standard indirect_pci code should work with future silicon versions. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define PCI_CFG_OUT out_be32 - -/* ERRATA PCI-Ex 14 PCIE Controller timeout */ -#define PCIE_FIX out_be32(hose->cfg_addr+0x4, 0x0400ffff) - - -static int -indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 *val) -{ - struct pci_controller *hose = bus->sysdata; - volatile void __iomem *cfg_data; - u32 temp; - - if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) - return PCIBIOS_DEVICE_NOT_FOUND; - - /* Possible artifact of CDCpp50937 needs further investigation */ - if (devfn != 0x0 && bus->number == 0xff) - return PCIBIOS_DEVICE_NOT_FOUND; - - PCIE_FIX; - if (bus->number == 0xff) { - PCI_CFG_OUT(hose->cfg_addr, - (0x80000000 | ((offset & 0xf00) << 16) | - (bus->number<< 16) - | (devfn << 8) | ((offset & 0xfc) ))); - } else { - PCI_CFG_OUT(hose->cfg_addr, - (0x80000001 | ((offset & 0xf00) << 16) | - (bus->number<< 16) - | (devfn << 8) | ((offset & 0xfc) ))); - } - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ - cfg_data = hose->cfg_data; - PCIE_FIX; - temp = in_le32(cfg_data); - switch (len) { - case 1: - *val = (temp >> (((offset & 3))*8)) & 0xff; - break; - case 2: - *val = (temp >> (((offset & 3))*8)) & 0xffff; - break; - default: - *val = temp; - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int -indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 val) -{ - struct pci_controller *hose = bus->sysdata; - volatile void __iomem *cfg_data; - u32 temp; - - if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) - return PCIBIOS_DEVICE_NOT_FOUND; - - /* Possible artifact of CDCpp50937 needs further investigation */ - if (devfn != 0x0 && bus->number == 0xff) - return PCIBIOS_DEVICE_NOT_FOUND; - - PCIE_FIX; - if (bus->number == 0xff) { - PCI_CFG_OUT(hose->cfg_addr, - (0x80000000 | ((offset & 0xf00) << 16) | - (bus->number << 16) - | (devfn << 8) | ((offset & 0xfc) ))); - } else { - PCI_CFG_OUT(hose->cfg_addr, - (0x80000001 | ((offset & 0xf00) << 16) | - (bus->number << 16) - | (devfn << 8) | ((offset & 0xfc) ))); - } - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ - cfg_data = hose->cfg_data; - switch (len) { - case 1: - PCIE_FIX; - temp = in_le32(cfg_data); - temp = (temp & ~(0xff << ((offset & 3) * 8))) | - (val << ((offset & 3) * 8)); - PCIE_FIX; - out_le32(cfg_data, temp); - break; - case 2: - PCIE_FIX; - temp = in_le32(cfg_data); - temp = (temp & ~(0xffff << ((offset & 3) * 8))); - temp |= (val << ((offset & 3) * 8)) ; - PCIE_FIX; - out_le32(cfg_data, temp); - break; - default: - PCIE_FIX; - out_le32(cfg_data, val); - break; - } - PCIE_FIX; - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops indirect_pcie_ops = { - indirect_read_config_pcie, - indirect_write_config_pcie -}; - -void __init -setup_indirect_pcie_nomap(struct pci_controller* hose, void __iomem * cfg_addr, - void __iomem * cfg_data) -{ - hose->cfg_addr = cfg_addr; - hose->cfg_data = cfg_data; - hose->ops = &indirect_pcie_ops; -} - -void __init -setup_indirect_pcie(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) -{ - unsigned long base = cfg_addr & PAGE_MASK; - void __iomem *mbase, *addr, *data; - - mbase = ioremap(base, PAGE_SIZE); - addr = mbase + (cfg_addr & ~PAGE_MASK); - if ((cfg_data & PAGE_MASK) != base) - mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE); - data = mbase + (cfg_data & ~PAGE_MASK); - setup_indirect_pcie_nomap(hose, addr, data); -} -- cgit v1.2.3 From ab0f9ad34d1eb31bb13cc4218d7717f8a85b12ed Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 25 Jun 2007 15:19:48 -0500 Subject: [POWERPC] Added indirect_type to handle variants of PCI ops The generic PCI config ops indirect support for ppc32 covers only two cases (implicit vs explicit) type 0/1 config cycles via set_cfg_type. Added a indirect_type bit mask to handle other variants. Added support for PCI-e extended registers and moved the cfg_type handling into the bit mask for ARCH=powerpc. We can also use this to handle indirect quirks. Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/indirect_pci.c | 22 ++++++++++++++++------ include/asm-ppc/pci-bridge.h | 10 ++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index efe3cff8dcd1..3a1612253c60 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -33,22 +33,27 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, struct pci_controller *hose = bus->sysdata; volatile void __iomem *cfg_data; u8 cfg_type = 0; - u32 bus_no; + u32 bus_no, reg; if (ppc_md.pci_exclude_device) if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; - if (hose->set_cfg_type) + if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE) if (bus->number != hose->first_busno) cfg_type = 1; bus_no = (bus->number == hose->first_busno) ? hose->self_busno : bus->number; + if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG) + reg = ((offset & 0xf00) << 16) | (offset & 0xfc); + else + reg = offset & 0xfc; + PCI_CFG_OUT(hose->cfg_addr, (0x80000000 | (bus_no << 16) - | (devfn << 8) | ((offset & 0xfc) | cfg_type))); + | (devfn << 8) | reg | cfg_type)); /* * Note: the caller has already checked that offset is @@ -76,22 +81,27 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, struct pci_controller *hose = bus->sysdata; volatile void __iomem *cfg_data; u8 cfg_type = 0; - u32 bus_no; + u32 bus_no, reg; if (ppc_md.pci_exclude_device) if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; - if (hose->set_cfg_type) + if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE) if (bus->number != hose->first_busno) cfg_type = 1; bus_no = (bus->number == hose->first_busno) ? hose->self_busno : bus->number; + if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG) + reg = ((offset & 0xf00) << 16) | (offset & 0xfc); + else + reg = offset & 0xfc; + PCI_CFG_OUT(hose->cfg_addr, (0x80000000 | (bus_no << 16) - | (devfn << 8) | ((offset & 0xfc) | cfg_type))); + | (devfn << 8) | reg | cfg_type)); /* * Note: the caller has already checked that offset is diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index 70aab6691043..0dee56b839a4 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -65,9 +65,19 @@ struct pci_controller { /* * If set, indirect method will set the cfg_type bit as * needed to generate type 1 configuration transactions. + * use only on ARCH=ppc */ int set_cfg_type; + /* + * Used for variants of PCI indirect handling and possible quirks: + * SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1 + * EXT_REG - provides access to PCI-e extended registers + */ +#define PPC_INDIRECT_TYPE_SET_CFG_TYPE (0x00000001) +#define PPC_INDIRECT_TYPE_EXT_REG (0x00000002) + u32 indirect_type; + /* Currently, we limit ourselves to 1 IO range and 3 mem * ranges since the common pci_bus structure can't handle more */ -- cgit v1.2.3 From 476f5779b77a919f0ced5953de2bf3e0f2d02c07 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 26 Jun 2007 12:12:55 -0500 Subject: [POWERPC] 86xx: Workaround PCI_PRIMARY_BUS usage The Freescale PCI-e controllers have an issue in that they use the PCI_PRIMARY_BUS register in the virtual P2P bridge to determine which bus number to match on when generating a type 0 config cycle. The issue is if we are renumbering bus numbers to match Linux we will try setting the PCI_PRIMARY_BUS and will not know which bus number to use for generating type 0 config cycles. We surpress writing the register in the P2P bridge and always keep it at zero. In the future when proper PCI domain support is working we should be able to remove this. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/86xx/pci.c | 4 +++- arch/powerpc/sysdev/indirect_pci.c | 6 ++++++ include/asm-ppc/pci-bridge.h | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 3825e1ac5312..6f3c0f674bbf 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -158,11 +158,13 @@ int __init mpc86xx_add_bridge(struct device_node *dev) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); + pci_assign_all_buses = 1; hose = pcibios_alloc_controller(); if (!hose) return -ENOMEM; hose->arch_data = dev; - hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG; + hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG | + PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS; hose->first_busno = bus_range ? bus_range[0] : 0x0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index 3a1612253c60..c7e6e859b393 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -103,6 +103,12 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, (0x80000000 | (bus_no << 16) | (devfn << 8) | reg | cfg_type)); + /* surpress setting of PCI_PRIMARY_BUS */ + if (hose->indirect_type & PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS) + if ((offset == PCI_PRIMARY_BUS) && + (bus->number == hose->first_busno)) + val &= 0xffffff00; + /* * Note: the caller has already checked that offset is * suitably aligned and that len is 1, 2 or 4. diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index 0dee56b839a4..c09fbf02ef24 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -73,9 +73,14 @@ struct pci_controller { * Used for variants of PCI indirect handling and possible quirks: * SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1 * EXT_REG - provides access to PCI-e extended registers + * SURPRESS_PRIMARY_BUS - we surpress the setting of PCI_PRIMARY_BUS + * on Freescale PCI-e controllers since they used the PCI_PRIMARY_BUS + * to determine which bus number to match on when generating type0 + * config cycles */ #define PPC_INDIRECT_TYPE_SET_CFG_TYPE (0x00000001) #define PPC_INDIRECT_TYPE_EXT_REG (0x00000002) +#define PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS (0x00000004) u32 indirect_type; /* Currently, we limit ourselves to 1 IO range and 3 mem -- cgit v1.2.3 From dbf8471f5294b27ba9b6232ffc177dcd4e0a2fa5 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 27 Jun 2007 01:56:50 -0500 Subject: [POWERPC] Merge ppc32 and ppc64 pcibios_alloc_controller() prototypes Make the ppc32 pcibios_alloc_controller take a device node to match the ppc64 prototypes and have it set arch_data. Signed-off-by: Kumar Gala --- arch/powerpc/kernel/pci_32.c | 3 ++- arch/powerpc/platforms/52xx/efika.c | 3 +-- arch/powerpc/platforms/52xx/mpc52xx_pci.c | 4 +--- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 4 +--- arch/powerpc/platforms/83xx/pci.c | 3 +-- arch/powerpc/platforms/85xx/pci.c | 3 +-- arch/powerpc/platforms/86xx/pci.c | 4 ++-- arch/powerpc/platforms/chrp/pci.c | 3 +-- arch/powerpc/platforms/embedded6xx/linkstation.c | 3 +-- arch/powerpc/platforms/powermac/pci.c | 6 ------ arch/powerpc/sysdev/mv64x60_pci.c | 4 +--- arch/powerpc/sysdev/tsi108_pci.c | 3 +-- include/asm-powerpc/pci-bridge.h | 8 +++----- 13 files changed, 16 insertions(+), 35 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 56deb316efd3..df3251ccca0f 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -610,7 +610,7 @@ pcibios_enable_resources(struct pci_dev *dev, int mask) static int next_controller_index; struct pci_controller * __init -pcibios_alloc_controller(void) +pcibios_alloc_controller(struct device_node *dev) { struct pci_controller *hose; @@ -621,6 +621,7 @@ pcibios_alloc_controller(void) hose_tail = &hose->next; hose->global_number = next_controller_index++; + hose->arch_data = dev; return hose; } diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 010be5c082d5..0256423c99d6 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -128,7 +128,7 @@ void __init efika_pcisetup(void) printk(" controlled by %s\n", pcictrl->full_name); printk("\n"); - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(of_node_get(pcictrl)); if (!hose) { printk(KERN_WARNING EFIKA_PLATFORM_NAME ": Can't allocate PCI controller structure for %s\n", @@ -136,7 +136,6 @@ void __init efika_pcisetup(void) return; } - hose->arch_data = of_node_get(pcictrl); hose->first_busno = bus_range[0]; hose->last_busno = bus_range[1]; hose->ops = &rtas_pci_ops; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 69a04217c79d..4c6c82a684b1 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -385,12 +385,10 @@ mpc52xx_add_bridge(struct device_node *node) * tree are needed to configure the 52xx PCI controller. Rather * than parse the tree here, let pci_process_bridge_OF_ranges() * do it for us and extract the values after the fact */ - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(node); if (!hose) return -ENOMEM; - hose->arch_data = node; - hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index d1e0919a3dee..da20832b27f1 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -543,13 +543,11 @@ static void __init mpc82xx_add_bridge(struct device_node *np) pci_assign_all_buses = 1; - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(np); if (!hose) return; - hose->arch_data = np; - hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index f49ed277e843..c0e2b89154e5 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -62,10 +62,9 @@ int __init mpc83xx_add_bridge(struct device_node *dev) } pci_assign_all_buses = 1; - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; - hose->arch_data = dev; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c index a25b3e77a7d2..8118417b7364 100644 --- a/arch/powerpc/platforms/85xx/pci.c +++ b/arch/powerpc/platforms/85xx/pci.c @@ -56,10 +56,9 @@ int __init mpc85xx_add_bridge(struct device_node *dev) } pci_assign_all_buses = 1; - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; - hose->arch_data = dev; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 2d7254c91ad9..5cb2188ee406 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -196,10 +196,10 @@ int __init mpc86xx_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); pci_assign_all_buses = 1; - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; - hose->arch_data = dev; + hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG | PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS; diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index d8408632b1a9..3690624e49d4 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -254,13 +254,12 @@ chrp_find_bridges(void) printk(" at %llx", (unsigned long long)r.start); printk("\n"); - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) { printk("Can't allocate PCI controller structure for %s\n", dev->full_name); continue; } - hose->arch_data = dev; hose->first_busno = bus_range[0]; hose->last_busno = bus_range[1]; diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 885c789a8c2d..f4d0a7a603f5 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -68,12 +68,11 @@ static int __init linkstation_add_bridge(struct device_node *dev) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (hose == NULL) return -ENOMEM; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; - hose->arch_data = dev; setup_indirect_pci(hose, 0xfec00000, 0xfee00000); /* Interpret the "ranges" property */ diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index fb853c0affcc..92586db19754 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -916,15 +916,9 @@ static int __init pmac_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); } - /* XXX Different prototypes, to be merged */ -#ifdef CONFIG_PPC64 hose = pcibios_alloc_controller(dev); -#else - hose = pcibios_alloc_controller(); -#endif if (!hose) return -ENOMEM; - hose->arch_data = dev; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/sysdev/mv64x60_pci.c b/arch/powerpc/sysdev/mv64x60_pci.c index 2e7738455ae5..45db86c2363c 100644 --- a/arch/powerpc/sysdev/mv64x60_pci.c +++ b/arch/powerpc/sysdev/mv64x60_pci.c @@ -137,12 +137,10 @@ static int __init mv64x60_add_bridge(struct device_node *dev) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 298e2dd34e89..90db8a720fed 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -221,13 +221,12 @@ int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary) " bus 0\n", dev->full_name); } - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) { printk("PCI Host bridge init failed\n"); return -ENOMEM; } - hose->arch_data = dev; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index 80cfb4a75053..d5a9c9f9ade3 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -9,9 +9,6 @@ struct device_node; struct pci_controller; -/* Allocate a new PCI host bridge structure */ -extern struct pci_controller* pcibios_alloc_controller(void); - /* Get the PCI host controller for a bus */ extern struct pci_controller* pci_bus_to_hose(int bus); @@ -232,8 +229,6 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus) return PCI_DN(busdn)->phb; } -extern struct pci_controller * -pcibios_alloc_controller(struct device_node *dev); extern void pcibios_free_controller(struct pci_controller *phb); extern void isa_bridge_find_early(struct pci_controller *hose); @@ -263,6 +258,9 @@ extern void pci_process_bridge_OF_ranges(struct pci_controller *hose, struct device_node *dev, int primary); +/* Allocate a new PCI host bridge structure */ +extern struct pci_controller * +pcibios_alloc_controller(struct device_node *dev); #ifdef CONFIG_PCI extern unsigned long pci_address_to_pio(phys_addr_t address); #else -- cgit v1.2.3 From 65482ccf9d00bf4f68e17eb9c656d045d26e5d1f Mon Sep 17 00:00:00 2001 From: Li Yang Date: Mon, 28 May 2007 18:48:06 +0800 Subject: [POWERPC] qe_lib: export symbols for QE driver to compile as module Export symbols of qe_lib to be used by QE driver. Signed-off-by: Li Yang Signed-off-by: Selvamuthukumar V Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/qe_lib/ucc.c | 2 ++ arch/powerpc/sysdev/qe_lib/ucc_fast.c | 8 ++++++++ 2 files changed, 10 insertions(+) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c index ac12a44d516f..f970e5415ac0 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc.c +++ b/arch/powerpc/sysdev/qe_lib/ucc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,7 @@ int ucc_set_qe_mux_mii_mng(int ucc_num) return 0; } +EXPORT_SYMBOL(ucc_set_qe_mux_mii_mng); int ucc_set_type(int ucc_num, struct ucc_common *regs, enum ucc_speed_type speed) diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c index 9143236853fc..3df202e8d332 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -70,6 +71,7 @@ void ucc_fast_dump_regs(struct ucc_fast_private * uccf) printk(KERN_INFO "guemr : addr - 0x%08x, val - 0x%02x", (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr); } +EXPORT_SYMBOL(ucc_fast_dump_regs); u32 ucc_fast_get_qe_cr_subblock(int uccf_num) { @@ -85,11 +87,13 @@ u32 ucc_fast_get_qe_cr_subblock(int uccf_num) default: return QE_CR_SUBBLOCK_INVALID; } } +EXPORT_SYMBOL(ucc_fast_get_qe_cr_subblock); void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf) { out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD); } +EXPORT_SYMBOL(ucc_fast_transmit_on_demand); void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode) { @@ -110,6 +114,7 @@ void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode) } out_be32(&uf_regs->gumr, gumr); } +EXPORT_SYMBOL(ucc_fast_enable); void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode) { @@ -130,6 +135,7 @@ void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode) } out_be32(&uf_regs->gumr, gumr); } +EXPORT_SYMBOL(ucc_fast_disable); int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret) { @@ -341,6 +347,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc *uccf_ret = uccf; return 0; } +EXPORT_SYMBOL(ucc_fast_init); void ucc_fast_free(struct ucc_fast_private * uccf) { @@ -355,3 +362,4 @@ void ucc_fast_free(struct ucc_fast_private * uccf) kfree(uccf); } +EXPORT_SYMBOL(ucc_fast_free); -- cgit v1.2.3 From 80128ff79d282cf71b1819dbca9b8dd47d8ed3e8 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Mon, 9 Jul 2007 11:37:35 -0700 Subject: [POWERPC] 8xx: mpc885ads pcmcia support Adds support for PowerQuicc on-chip PCMCIA. The driver is implemented as of_device, so only arch/powerpc stuff is capable to use it, which now implies only mpc885ads reference board. To cope with the code that should be hooked inside driver, but is really board specific (like set_voltage), global structure mpc8xx_pcmcia_ops holds necessary function pointers that are filled in the BSP code. [akpm@linux-foundation.org: whitespace diddles] Signed-off-by: Vitaly Bordug Acked-by: Arnd Bergmann Acked-by: Olof Johansson Cc: Dominik Brodowski Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc885ads.dts | 11 + arch/powerpc/platforms/8xx/m8xx_setup.c | 5 + arch/powerpc/platforms/8xx/mpc885ads_setup.c | 71 ++++++ arch/powerpc/sysdev/fsl_soc.c | 13 + arch/powerpc/sysdev/mpc8xx_pic.h | 11 +- drivers/pcmcia/Kconfig | 17 +- drivers/pcmcia/m8xx_pcmcia.c | 351 +++++++++++++-------------- include/asm-powerpc/mpc8xx.h | 4 + include/linux/fsl_devices.h | 5 + 9 files changed, 294 insertions(+), 194 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts index 110bf6170603..aee01087a932 100644 --- a/arch/powerpc/boot/dts/mpc885ads.dts +++ b/arch/powerpc/boot/dts/mpc885ads.dts @@ -112,6 +112,17 @@ compatible = "CPM"; }; + pcmcia@0080 { + #address-cells = <3>; + #interrupt-cells = <1>; + #size-cells = <2>; + compatible = "fsl,pq-pcmcia"; + device_type = "pcmcia"; + reg = <80 80>; + interrupt-parent = ; + interrupts = ; + }; + cpm@ff000000 { linux,phandle = ; #address-cells = <1>; diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 0901dbada350..f1693550c70c 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,10 @@ #include "sysdev/mpc8xx_pic.h" +#ifdef CONFIG_PCMCIA_M8XX +struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; +#endif + void m8xx_calibrate_decr(void); extern void m8xx_wdt_handler_install(bd_t *bp); extern int cpm_pic_init(void); diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index c36e475d93dc..dc27dab48df0 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -51,6 +52,70 @@ static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); static void init_scc3_ioports(struct fs_platform_info* ptr); +#ifdef CONFIG_PCMCIA_M8XX +static void pcmcia_hw_setup(int slot, int enable) +{ + unsigned *bcsr_io; + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + if (enable) + clrbits32(bcsr_io, BCSR1_PCCEN); + else + setbits32(bcsr_io, BCSR1_PCCEN); + + iounmap(bcsr_io); +} + +static int pcmcia_set_voltage(int slot, int vcc, int vpp) +{ + u32 reg = 0; + unsigned *bcsr_io; + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + switch(vcc) { + case 0: + break; + case 33: + reg |= BCSR1_PCCVCC0; + break; + case 50: + reg |= BCSR1_PCCVCC1; + break; + default: + return 1; + } + + switch(vpp) { + case 0: + break; + case 33: + case 50: + if(vcc == vpp) + reg |= BCSR1_PCCVPP1; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= BCSR1_PCCVPP0; + else + return 1; + default: + return 1; + } + + /* first, turn off all power */ + clrbits32(bcsr_io, 0x00610000); + + /* enable new powersettings */ + setbits32(bcsr_io, reg); + + iounmap(bcsr_io); + return 0; +} +#endif + void __init mpc885ads_board_setup(void) { cpm8xx_t *cp; @@ -115,6 +180,12 @@ void __init mpc885ads_board_setup(void) immr_unmap(io_port); #endif + +#ifdef CONFIG_PCMCIA_M8XX + /*Set up board specific hook-ups*/ + m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup; + m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage; +#endif } diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index cad175724359..c0ddc80d8160 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -1028,6 +1028,19 @@ err: arch_initcall(fs_enet_of_init); +static int __init fsl_pcmcia_of_init(void) +{ + struct device_node *np = NULL; + /* + * Register all the devices which type is "pcmcia" + */ + while ((np = of_find_compatible_node(np, + "pcmcia", "fsl,pq-pcmcia")) != NULL) + of_platform_device_create(np, "m8xx-pcmcia", NULL); + return 0; +} + +arch_initcall(fsl_pcmcia_of_init); static const char *smc_regs = "regs"; static const char *smc_pram = "pram"; diff --git a/arch/powerpc/sysdev/mpc8xx_pic.h b/arch/powerpc/sysdev/mpc8xx_pic.h index afa2ee6717c1..9fe00eebdc8b 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.h +++ b/arch/powerpc/sysdev/mpc8xx_pic.h @@ -4,9 +4,16 @@ #include #include -extern struct hw_interrupt_type mpc8xx_pic; - int mpc8xx_pic_init(void); unsigned int mpc8xx_get_irq(void); +/* + * Some internal interrupt registers use an 8-bit mask for the interrupt + * level instead of a number. + */ +static inline uint mk_int_int_mask(uint mask) +{ + return (1 << (7 - (mask/2))); +} + #endif /* _PPC_KERNEL_PPC8xx_H */ diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 35f88649d3b7..c0c77f82d051 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -180,14 +180,15 @@ config TCIC PCMCIA cards are plugged into. If unsure, say N. config PCMCIA_M8XX - tristate "MPC8xx PCMCIA support" - depends on PCMCIA && PPC && 8xx - select PCCARD_IODYN - help - Say Y here to include support for PowerPC 8xx series PCMCIA - controller. - - This driver is also available as a module called m8xx_pcmcia. + tristate "MPC8xx PCMCIA support" + depends on PCMCIA && PPC && 8xx + select PCCARD_IODYN + select PCCARD_NONSTATIC + help + Say Y here to include support for PowerPC 8xx series PCMCIA + controller. + + This driver is also available as a module called m8xx_pcmcia. config HD64465_PCMCIA tristate "HD64465 host bridge support" diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 9721ed7bf502..3b40f9623cc9 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -10,7 +10,7 @@ * Further fixes, v2.6 kernel port * * - * Some fixes, additions (C) 2005 Montavista Software, Inc. + * Some fixes, additions (C) 2005-2007 Montavista Software, Inc. * * * "The ExCA standard specifies that socket controllers should provide @@ -40,10 +40,6 @@ #include #include -#include -#include -#include - #include #include #include @@ -51,11 +47,18 @@ #include #include #include -#include +#include +#include +#include +#include +#include #include #include #include +#include +#include +#include #include #include @@ -146,27 +149,17 @@ MODULE_LICENSE("Dual MPL/GPL"); #define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0 */ #define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte */ #define PCMCIA_IO_WIN_BASE _IO_BASE /* base address for io window 0 */ - -#define PCMCIA_SCHLVL PCMCIA_INTERRUPT /* Status Change Interrupt Level */ - /* ------------------------------------------------------------------------- */ -/* 2.4.x and newer has this always in HZ */ -#define M8XX_BUSFREQ ((((bd_t *)&(__res))->bi_busfreq)) - -static int pcmcia_schlvl = PCMCIA_SCHLVL; +static int pcmcia_schlvl; static DEFINE_SPINLOCK(events_lock); - #define PCMCIA_SOCKET_KEY_5V 1 #define PCMCIA_SOCKET_KEY_LV 2 /* look up table for pgcrx registers */ -static u32 *m8xx_pgcrx[2] = { - &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcra, - &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcrb -}; +static u32 *m8xx_pgcrx[2]; /* * This structure is used to address each window in the PCMCIA controller. @@ -228,11 +221,16 @@ struct event_table { u32 eventbit; }; +static const char driver_name[] = "m8xx-pcmcia"; + struct socket_info { void (*handler)(void *info, u32 events); void *info; u32 slot; + pcmconf8xx_t *pcmcia; + u32 bus_freq; + int hwirq; socket_state_t state; struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO]; @@ -408,78 +406,21 @@ static void hardware_disable(int slot) #if defined(CONFIG_MPC885ADS) #define PCMCIA_BOARD_MSG "MPC885ADS" +#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V -static int voltage_set(int slot, int vcc, int vpp) +static inline void hardware_enable(int slot) { - u32 reg = 0; - unsigned *bcsr_io; - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); - - switch(vcc) { - case 0: - break; - case 33: - reg |= BCSR1_PCCVCC0; - break; - case 50: - reg |= BCSR1_PCCVCC1; - break; - default: - goto out_unmap; - } - - switch(vpp) { - case 0: - break; - case 33: - case 50: - if(vcc == vpp) - reg |= BCSR1_PCCVPP1; - else - goto out_unmap; - break; - case 120: - if ((vcc == 33) || (vcc == 50)) - reg |= BCSR1_PCCVPP0; - else - goto out_unmap; - default: - goto out_unmap; - } - - /* first, turn off all power */ - out_be32(bcsr_io, in_be32(bcsr_io) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK)); - - /* enable new powersettings */ - out_be32(bcsr_io, in_be32(bcsr_io) | reg); - - iounmap(bcsr_io); - return 0; - -out_unmap: - iounmap(bcsr_io); - return 1; + m8xx_pcmcia_ops.hw_ctrl(slot, 1); } -#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V - -static void hardware_enable(int slot) +static inline void hardware_disable(int slot) { - unsigned *bcsr_io; - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); - out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_PCCEN); - iounmap(bcsr_io); + m8xx_pcmcia_ops.hw_ctrl(slot, 0); } -static void hardware_disable(int slot) +static inline int voltage_set(int slot, int vcc, int vpp) { - unsigned *bcsr_io; - - bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); - out_be32(bcsr_io, in_be32(bcsr_io) | BCSR1_PCCEN); - iounmap(bcsr_io); + return m8xx_pcmcia_ops.voltage_set(slot, vcc, vpp); } #endif @@ -604,48 +545,6 @@ static int voltage_set(int slot, int vcc, int vpp) #endif /* CONFIG_PRxK */ -static void m8xx_shutdown(void) -{ - u32 m, i; - struct pcmcia_win *w; - - for(i = 0; i < PCMCIA_SOCKETS_NO; i++){ - w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; - - out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, M8XX_PCMCIA_MASK(i)); - out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & ~M8XX_PCMCIA_MASK(i)); - - /* turn off interrupt and disable CxOE */ - out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE); - - /* turn off memory windows */ - for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { - out_be32(&w->or, 0); /* set to not valid */ - w++; - } - - /* turn off voltage */ - voltage_set(i, 0, 0); - - /* disable external hardware */ - hardware_disable(i); - } - - free_irq(pcmcia_schlvl, NULL); -} - -static struct device_driver m8xx_driver = { - .name = "m8xx-pcmcia", - .bus = &platform_bus_type, - .suspend = pcmcia_socket_dev_suspend, - .resume = pcmcia_socket_dev_resume, -}; - -static struct platform_device m8xx_device = { - .name = "m8xx-pcmcia", - .id = 0, -}; - static u32 pending_events[PCMCIA_SOCKETS_NO]; static DEFINE_SPINLOCK(pending_event_lock); @@ -654,13 +553,14 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev) struct socket_info *s; struct event_table *e; unsigned int i, events, pscr, pipr, per; + pcmconf8xx_t *pcmcia = socket[0].pcmcia; dprintk("Interrupt!\n"); /* get interrupt sources */ - pscr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr); - pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr); - per = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per); + pscr = in_be32(&pcmcia->pcmc_pscr); + pipr = in_be32(&pcmcia->pcmc_pipr); + per = in_be32(&pcmcia->pcmc_per); for(i = 0; i < PCMCIA_SOCKETS_NO; i++) { s = &socket[i]; @@ -724,7 +624,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev) per &= ~M8XX_PCMCIA_RDY_L(0); per &= ~M8XX_PCMCIA_RDY_L(1); - out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, per); + out_be32(&pcmcia->pcmc_per, per); if (events) pcmcia_parse_events(&socket[i].socket, events); @@ -732,7 +632,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev) } /* clear the interrupt sources */ - out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, pscr); + out_be32(&pcmcia->pcmc_pscr, pscr); dprintk("Interrupt done.\n"); @@ -753,7 +653,7 @@ static u32 m8xx_get_graycode(u32 size) return k; } -static u32 m8xx_get_speed(u32 ns, u32 is_io) +static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq) { u32 reg, clocks, psst, psl, psht; @@ -781,7 +681,7 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io) #define ADJ 180 /* 80 % longer accesstime - to be sure */ - clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000; + clocks = ((bus_freq / 1000) * ns) / 1000; clocks = (clocks * ADJ) / (100*1000); if(clocks >= PCMCIA_BMT_LIMIT) { printk( "Max access time limit reached\n"); @@ -806,8 +706,9 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value) int lsock = container_of(sock, struct socket_info, socket)->slot; struct socket_info *s = &socket[lsock]; unsigned int pipr, reg; + pcmconf8xx_t *pcmcia = s->pcmcia; - pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr); + pipr = in_be32(&pcmcia->pcmc_pipr); *value = ((pipr & (M8XX_PCMCIA_CD1(lsock) | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0; @@ -918,6 +819,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) struct event_table *e; unsigned int reg; unsigned long flags; + pcmconf8xx_t *pcmcia = socket[0].pcmcia; dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags, @@ -927,6 +829,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) if(voltage_set(lsock, state->Vcc, state->Vpp)) return -EINVAL; + /* Take care of reset... */ if(state->flags & SS_RESET) out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET); /* active high */ @@ -982,7 +885,8 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) * If io_irq is non-zero we should enable irq. */ if(state->io_irq) { - out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(state->io_irq) << 24); + out_be32(M8XX_PGCRX(lsock), + in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(s->hwirq) << 24); /* * Strange thing here: * The manual does not tell us which interrupt @@ -1027,7 +931,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) * Writing ones will clear the bits. */ - out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, reg); + out_be32(&pcmcia->pcmc_pscr, reg); /* * Write the mask. @@ -1036,15 +940,8 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) * Ones will enable the interrupt. */ - /* - reg |= ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per - & M8XX_PCMCIA_MASK(lsock); - */ - - reg |= in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & - (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1)); - - out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, reg); + reg |= in_be32(&pcmcia->pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1)); + out_be32(&pcmcia->pcmc_per, reg); spin_unlock_irqrestore(&events_lock, flags); @@ -1062,6 +959,8 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) struct socket_info *s = &socket[lsock]; struct pcmcia_win *w; unsigned int reg, winnr; + pcmconf8xx_t *pcmcia = s->pcmcia; + #define M8XX_SIZE (io->stop - io->start + 1) #define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start) @@ -1086,7 +985,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) /* setup registers */ - w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w = (void *) &pcmcia->pcmc_pbr0; w += winnr; out_be32(&w->or, 0); /* turn off window first */ @@ -1095,12 +994,13 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) reg <<= 27; reg |= M8XX_PCMCIA_POR_IO |(lsock << 2); - reg |= m8xx_get_speed(io->speed, 1); + reg |= m8xx_get_speed(io->speed, 1, s->bus_freq); if(io->flags & MAP_WRPROT) reg |= M8XX_PCMCIA_POR_WRPROT; - if(io->flags & (MAP_16BIT | MAP_AUTOSZ)) + /*if(io->flags & (MAP_16BIT | MAP_AUTOSZ))*/ + if(io->flags & MAP_16BIT) reg |= M8XX_PCMCIA_POR_16BIT; if(io->flags & MAP_ACTIVE) @@ -1117,7 +1017,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) /* setup registers */ - w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w = (void *) &pcmcia->pcmc_pbr0; w += winnr; out_be32(&w->or, 0); /* turn off window */ @@ -1144,6 +1044,7 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m struct pcmcia_win *w; struct pccard_mem_map *old; unsigned int reg, winnr; + pcmconf8xx_t *pcmcia = s->pcmcia; dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, " "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags, @@ -1166,12 +1067,12 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m /* Setup the window in the pcmcia controller */ - w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; + w = (void *) &pcmcia->pcmc_pbr0; w += winnr; reg |= lsock << 2; - reg |= m8xx_get_speed(mem->speed, 0); + reg |= m8xx_get_speed(mem->speed, 0, s->bus_freq); if(mem->flags & MAP_ATTRIB) reg |= M8XX_PCMCIA_POR_ATTRMEM; @@ -1236,60 +1137,69 @@ static int m8xx_sock_init(struct pcmcia_socket *sock) } -static int m8xx_suspend(struct pcmcia_socket *sock) +static int m8xx_sock_suspend(struct pcmcia_socket *sock) { return m8xx_set_socket(sock, &dead_socket); } static struct pccard_operations m8xx_services = { .init = m8xx_sock_init, - .suspend = m8xx_suspend, + .suspend = m8xx_sock_suspend, .get_status = m8xx_get_status, .set_socket = m8xx_set_socket, .set_io_map = m8xx_set_io_map, .set_mem_map = m8xx_set_mem_map, }; -static int __init m8xx_init(void) +static int __init m8xx_probe(struct of_device *ofdev, const struct of_device_id *match) { struct pcmcia_win *w; - unsigned int i,m; + unsigned int i, m, hwirq; + pcmconf8xx_t *pcmcia; + int status; + struct device_node *np = ofdev->node; pcmcia_info("%s\n", version); - if (driver_register(&m8xx_driver)) - return -1; + pcmcia = of_iomap(np, 0); + if(pcmcia == NULL) + return -EINVAL; + + pcmcia_schlvl = irq_of_parse_and_map(np, 0); + hwirq = irq_map[pcmcia_schlvl].hwirq; + if (pcmcia_schlvl < 0) + return -EINVAL; + + m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra; + m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb; + pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG - " with IRQ %u.\n", pcmcia_schlvl); + " with IRQ %u (%d). \n", pcmcia_schlvl, hwirq); /* Configure Status change interrupt */ - if(request_irq(pcmcia_schlvl, m8xx_interrupt, 0, - "m8xx_pcmcia", NULL)) { + if(request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED, + driver_name, socket)) { pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n", pcmcia_schlvl); return -1; } - w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0; - - out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, - M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1)); + w = (void *) &pcmcia->pcmc_pbr0; - out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, - in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & - ~(M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1))); + out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1)); + clrbits32(&pcmcia->pcmc_per, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1)); -/* connect interrupt and disable CxOE */ + /* connect interrupt and disable CxOE */ - out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16)); - out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16)); + out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16)); + out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16)); -/* intialize the fixed memory windows */ + /* intialize the fixed memory windows */ for(i = 0; i < PCMCIA_SOCKETS_NO; i++){ - for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) { + for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) { out_be32(&w->br, PCMCIA_MEM_WIN_BASE + (PCMCIA_MEM_WIN_SIZE * (m + i * PCMCIA_MEM_WIN_NO))); @@ -1300,16 +1210,14 @@ static int __init m8xx_init(void) } } -/* turn off voltage */ + /* turn off voltage */ voltage_set(0, 0, 0); voltage_set(1, 0, 0); -/* Enable external hardware */ + /* Enable external hardware */ hardware_enable(0); hardware_enable(1); - platform_device_register(&m8xx_device); - for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) { socket[i].slot = i; socket[i].socket.owner = THIS_MODULE; @@ -1317,30 +1225,105 @@ static int __init m8xx_init(void) socket[i].socket.irq_mask = 0x000; socket[i].socket.map_size = 0x1000; socket[i].socket.io_offset = 0; - socket[i].socket.pci_irq = i ? 7 : 9; + socket[i].socket.pci_irq = pcmcia_schlvl; socket[i].socket.ops = &m8xx_services; - socket[i].socket.resource_ops = &pccard_iodyn_ops; + socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.cb_dev = NULL; - socket[i].socket.dev.parent = &m8xx_device.dev; + socket[i].socket.dev.parent = &ofdev->dev; + socket[i].pcmcia = pcmcia; + socket[i].bus_freq = ppc_proc_freq; + socket[i].hwirq = hwirq; + + } - for (i = 0; i < PCMCIA_SOCKETS_NO; i++) - pcmcia_register_socket(&socket[i].socket); + for (i = 0; i < PCMCIA_SOCKETS_NO; i++) { + status = pcmcia_register_socket(&socket[i].socket); + if (status < 0) + pcmcia_error("Socket register failed\n"); + } return 0; } -static void __exit m8xx_exit(void) +static int m8xx_remove(struct of_device* ofdev) { - int i; + u32 m, i; + struct pcmcia_win *w; + pcmconf8xx_t *pcmcia = socket[0].pcmcia; + + for (i = 0; i < PCMCIA_SOCKETS_NO; i++) { + w = (void *) &pcmcia->pcmc_pbr0; + + out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(i)); + out_be32(&pcmcia->pcmc_per, + in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i)); + /* turn off interrupt and disable CxOE */ + out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE); + + /* turn off memory windows */ + for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) { + out_be32(&w->or, 0); /* set to not valid */ + w++; + } + + /* turn off voltage */ + voltage_set(i, 0, 0); + + /* disable external hardware */ + hardware_disable(i); + } for (i = 0; i < PCMCIA_SOCKETS_NO; i++) pcmcia_unregister_socket(&socket[i].socket); - m8xx_shutdown(); + free_irq(pcmcia_schlvl, NULL); - platform_device_unregister(&m8xx_device); - driver_unregister(&m8xx_driver); + return 0; +} + +#ifdef CONFIG_PM +static int m8xx_suspend(struct platform_device *pdev, pm_message_t state) +{ + return pcmcia_socket_dev_suspend(&pdev->dev, state); +} + +static int m8xx_resume(struct platform_device *pdev) +{ + return pcmcia_socket_dev_resume(&pdev->dev); +} +#else +#define m8xx_suspend NULL +#define m8xx_resume NULL +#endif + +static struct of_device_id m8xx_pcmcia_match[] = { + { + .type = "pcmcia", + .compatible = "fsl,pq-pcmcia", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match); + +static struct of_platform_driver m8xx_pcmcia_driver = { + .name = (char *) driver_name, + .match_table = m8xx_pcmcia_match, + .probe = m8xx_probe, + .remove = m8xx_remove, + .suspend = m8xx_suspend, + .resume = m8xx_resume, +}; + +static int __init m8xx_init(void) +{ + return of_register_platform_driver(&m8xx_pcmcia_driver); +} + +static void __exit m8xx_exit(void) +{ + of_unregister_platform_driver(&m8xx_pcmcia_driver); } module_init(m8xx_init); diff --git a/include/asm-powerpc/mpc8xx.h b/include/asm-powerpc/mpc8xx.h index 580371120e1a..2be014b6f57c 100644 --- a/include/asm-powerpc/mpc8xx.h +++ b/include/asm-powerpc/mpc8xx.h @@ -23,6 +23,10 @@ #include #endif +#ifdef CONFIG_PCMCIA_M8XX +extern struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; +#endif + #endif /* CONFIG_8xx */ #endif /* __CONFIG_8xx_DEFS */ #endif /* __KERNEL__ */ diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 73710d617775..12e631f0fb77 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -120,5 +120,10 @@ struct fsl_spi_platform_data { u32 sysclk; }; +struct mpc8xx_pcmcia_ops { + void(*hw_ctrl)(int slot, int enable); + int(*voltage_set)(int slot, int vcc, int vpp); +}; + #endif /* _FSL_DEVICE_H_ */ #endif /* __KERNEL__ */ -- cgit v1.2.3 From 93ab471889c6662b42ce7da257f31f24c08d7d9e Mon Sep 17 00:00:00 2001 From: Wade Farnsworth Date: Wed, 11 Jul 2007 02:55:46 +1000 Subject: [POWERPC] Create add_rtc() function to enable the RTC CMOS driver In order to use the RTC CMOS driver, each architecture must register a platform device for the RTC. This creates a function to register the platform device based on the RTC device node and verifies that the RTC port against the hard-coded value in asm/mc146818rtc.h. Signed-off-by: Wade Farnsworth Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/Makefile | 1 + arch/powerpc/sysdev/rtc_cmos_setup.c | 49 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 arch/powerpc/sysdev/rtc_cmos_setup.c (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 7d8ac1bfef84..f65078c3d3b3 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ mv64x60-$(CONFIG_PCI) += mv64x60_pci.o obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o +obj-$(CONFIG_RTC_DRV_CMOS) += rtc_cmos_setup.o # contains only the suspend handler for time ifeq ($(CONFIG_RTC_CLASS),) diff --git a/arch/powerpc/sysdev/rtc_cmos_setup.c b/arch/powerpc/sysdev/rtc_cmos_setup.c new file mode 100644 index 000000000000..e276048b8c5f --- /dev/null +++ b/arch/powerpc/sysdev/rtc_cmos_setup.c @@ -0,0 +1,49 @@ +/* + * Setup code for PC-style Real-Time Clock. + * + * Author: Wade Farnsworth + * + * 2007 (c) MontaVista Software, Inc. 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. + */ + +#include +#include +#include +#include + +#include + +static int __init add_rtc(void) +{ + struct device_node *np; + struct platform_device *pd; + struct resource res; + int ret; + + np = of_find_compatible_node(NULL, NULL, "pnpPNP,b00"); + if (!np) + return -ENODEV; + + ret = of_address_to_resource(np, 0, &res); + of_node_put(np); + if (ret) + return ret; + + /* + * RTC_PORT(x) is hardcoded in asm/mc146818rtc.h. Verify that the + * address provided by the device node matches. + */ + if (res.start != RTC_PORT(0)) + return -EINVAL; + + pd = platform_device_register_simple("rtc_cmos", -1, + &res, 1); + if (IS_ERR(pd)) + return PTR_ERR(pd); + + return 0; +} +fs_initcall(add_rtc); -- cgit v1.2.3