2014-02-21 06:39:46

by Alistair Popple

[permalink] [raw]
Subject: [PATCH 0/7] IBM Akebono/PPC476GTR Support

The IBM Akebono board is a development board for the new PPC476GTR
system on chip (SoC).

This is just a resubmission of the previous patches rebased on kernel
v3.13. Ben H has indicated the subsystem specific changes should be
merged via the appropriate kernel trees.

Alistair Popple (7):
IBM Akebono: Add a SDHCI platform driver
IBM Akebono: Add support for a new PHY interface to the IBM emac
driver
IBM Akebono: Add support to the OHCI platform driver for PPC476GTR
ECHI Platform: Merge ppc-of EHCI driver into the ehci-platform driver
IBM Currituck: Clean up board specific code before adding Akebono
code
IBM Akebono: Add the Akebono platform
powerpc: Added PCI MSI support using the HSTA module

.../devicetree/bindings/powerpc/4xx/akebono.txt | 54 +++
.../devicetree/bindings/powerpc/4xx/emac.txt | 9 +
arch/powerpc/boot/Makefile | 3 +
arch/powerpc/boot/dcr.h | 4 +
arch/powerpc/boot/dts/akebono.dts | 415 ++++++++++++++++++++
arch/powerpc/boot/treeboot-akebono.c | 163 ++++++++
arch/powerpc/boot/wrapper | 3 +
arch/powerpc/configs/44x/akebono_defconfig | 148 +++++++
arch/powerpc/platforms/44x/Kconfig | 28 ++
arch/powerpc/platforms/44x/Makefile | 3 +-
arch/powerpc/platforms/44x/currituck.c | 233 -----------
arch/powerpc/platforms/44x/ppc476.c | 299 ++++++++++++++
arch/powerpc/sysdev/Kconfig | 6 +
arch/powerpc/sysdev/Makefile | 1 +
arch/powerpc/sysdev/ppc4xx_hsta_msi.c | 215 ++++++++++
arch/powerpc/sysdev/ppc4xx_pci.c | 21 +-
drivers/mmc/host/Kconfig | 12 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-of-476gtr.c | 60 +++
drivers/net/ethernet/ibm/emac/Kconfig | 4 +
drivers/net/ethernet/ibm/emac/Makefile | 1 +
drivers/net/ethernet/ibm/emac/core.c | 50 ++-
drivers/net/ethernet/ibm/emac/core.h | 12 +
drivers/net/ethernet/ibm/emac/rgmii_wol.c | 244 ++++++++++++
drivers/net/ethernet/ibm/emac/rgmii_wol.h | 62 +++
drivers/usb/host/Kconfig | 7 +-
drivers/usb/host/ehci-hcd.c | 5 -
drivers/usb/host/ehci-platform.c | 87 +++-
drivers/usb/host/ehci-ppc-of.c | 238 -----------
drivers/usb/host/ohci-platform.c | 22 +-
30 files changed, 1912 insertions(+), 498 deletions(-)
create mode 100644 Documentation/devicetree/bindings/powerpc/4xx/akebono.txt
create mode 100644 arch/powerpc/boot/dts/akebono.dts
create mode 100644 arch/powerpc/boot/treeboot-akebono.c
create mode 100644 arch/powerpc/configs/44x/akebono_defconfig
delete mode 100644 arch/powerpc/platforms/44x/currituck.c
create mode 100644 arch/powerpc/platforms/44x/ppc476.c
create mode 100644 arch/powerpc/sysdev/ppc4xx_hsta_msi.c
create mode 100644 drivers/mmc/host/sdhci-of-476gtr.c
create mode 100644 drivers/net/ethernet/ibm/emac/rgmii_wol.c
create mode 100644 drivers/net/ethernet/ibm/emac/rgmii_wol.h
delete mode 100644 drivers/usb/host/ehci-ppc-of.c

--
1.7.10.4


2014-02-21 06:39:49

by Alistair Popple

[permalink] [raw]
Subject: [PATCH 2/7] IBM Akebono: Add support for a new PHY interface to the IBM emac driver

The IBM PPC476GTR SoC that is used on the Akebono board uses a
different ethernet PHY interface that has wake on lan (WOL) support
with the IBM emac. This patch adds support to the IBM emac driver for
this new PHY interface.

At this stage the wake on lan functionality has not been implemented.

Signed-off-by: Alistair Popple <[email protected]>
Acked-by: Benjamin Herrenschmidt <[email protected]>
Cc: "David S. Miller" <[email protected]>
---
.../devicetree/bindings/powerpc/4xx/emac.txt | 9 +
drivers/net/ethernet/ibm/emac/Kconfig | 4 +
drivers/net/ethernet/ibm/emac/Makefile | 1 +
drivers/net/ethernet/ibm/emac/core.c | 50 +++-
drivers/net/ethernet/ibm/emac/core.h | 12 +
drivers/net/ethernet/ibm/emac/rgmii_wol.c | 244 ++++++++++++++++++++
drivers/net/ethernet/ibm/emac/rgmii_wol.h | 62 +++++
7 files changed, 376 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/ethernet/ibm/emac/rgmii_wol.c
create mode 100644 drivers/net/ethernet/ibm/emac/rgmii_wol.h

diff --git a/Documentation/devicetree/bindings/powerpc/4xx/emac.txt b/Documentation/devicetree/bindings/powerpc/4xx/emac.txt
index 712baf6..0c20529 100644
--- a/Documentation/devicetree/bindings/powerpc/4xx/emac.txt
+++ b/Documentation/devicetree/bindings/powerpc/4xx/emac.txt
@@ -61,6 +61,8 @@
Fox Axon: present, whatever value is appropriate for each
EMAC, that is the content of the current (bogus) "phy-port"
property.
+ - rgmii-wol-device : 1 cell, required iff connected to a RGMII in the WKUP
+ power domain. phandle of the RGMII-WOL device node.

Optional properties:
- phy-address : 1 cell, optional, MDIO address of the PHY. If absent,
@@ -146,3 +148,10 @@
available.
For Axon: 0x0000012a

+ iv) RGMII-WOL node
+
+ Required properties:
+ - compatible : compatible list, containing 2 entries, first is
+ "ibm,rgmii-wol-CHIP" where CHIP is the host ASIC (like
+ EMAC) and the second is "ibm,rgmii-wol".
+ - reg : <registers mapping>
diff --git a/drivers/net/ethernet/ibm/emac/Kconfig b/drivers/net/ethernet/ibm/emac/Kconfig
index 3f44a30..56ea346 100644
--- a/drivers/net/ethernet/ibm/emac/Kconfig
+++ b/drivers/net/ethernet/ibm/emac/Kconfig
@@ -55,6 +55,10 @@ config IBM_EMAC_RGMII
bool
default n

+config IBM_EMAC_RGMII_WOL
+ bool "IBM EMAC RGMII wake-on-LAN support" if COMPILE_TEST
+ default n
+
config IBM_EMAC_TAH
bool
default n
diff --git a/drivers/net/ethernet/ibm/emac/Makefile b/drivers/net/ethernet/ibm/emac/Makefile
index eba2183..8843803 100644
--- a/drivers/net/ethernet/ibm/emac/Makefile
+++ b/drivers/net/ethernet/ibm/emac/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_IBM_EMAC) += ibm_emac.o
ibm_emac-y := mal.o core.o phy.o
ibm_emac-$(CONFIG_IBM_EMAC_ZMII) += zmii.o
ibm_emac-$(CONFIG_IBM_EMAC_RGMII) += rgmii.o
+ibm_emac-$(CONFIG_IBM_EMAC_RGMII_WOL) += rgmii_wol.o
ibm_emac-$(CONFIG_IBM_EMAC_TAH) += tah.o
ibm_emac-$(CONFIG_IBM_EMAC_DEBUG) += debug.o
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index ae342fd..ff58474 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -632,6 +632,8 @@ static int emac_configure(struct emac_instance *dev)
if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
rgmii_set_speed(dev->rgmii_dev, dev->rgmii_port,
dev->phy.speed);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII_WOL))
+ rgmii_wol_set_speed(dev->rgmii_wol_dev, dev->phy.speed);
if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
zmii_set_speed(dev->zmii_dev, dev->zmii_port, dev->phy.speed);

@@ -799,6 +801,8 @@ static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
zmii_get_mdio(dev->zmii_dev, dev->zmii_port);
if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII_WOL))
+ rgmii_wol_get_mdio(dev->rgmii_wol_dev);

/* Wait for management interface to become idle */
n = 20;
@@ -846,6 +850,8 @@ static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
DBG2(dev, "mdio_read -> %04x" NL, r);
err = 0;
bail:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII_WOL))
+ rgmii_wol_put_mdio(dev->rgmii_wol_dev);
if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);
if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
@@ -871,6 +877,8 @@ static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
zmii_get_mdio(dev->zmii_dev, dev->zmii_port);
if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII_WOL))
+ rgmii_wol_get_mdio(dev->rgmii_wol_dev);

/* Wait for management interface to be idle */
n = 20;
@@ -909,6 +917,8 @@ static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
}
err = 0;
bail:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII_WOL))
+ rgmii_wol_put_mdio(dev->rgmii_wol_dev);
if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);
if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
@@ -2277,10 +2287,11 @@ struct emac_depentry {
#define EMAC_DEP_MAL_IDX 0
#define EMAC_DEP_ZMII_IDX 1
#define EMAC_DEP_RGMII_IDX 2
-#define EMAC_DEP_TAH_IDX 3
-#define EMAC_DEP_MDIO_IDX 4
-#define EMAC_DEP_PREV_IDX 5
-#define EMAC_DEP_COUNT 6
+#define EMAC_DEP_RGMII_WOL_IDX 3
+#define EMAC_DEP_TAH_IDX 4
+#define EMAC_DEP_MDIO_IDX 5
+#define EMAC_DEP_PREV_IDX 6
+#define EMAC_DEP_COUNT 7

static int emac_check_deps(struct emac_instance *dev,
struct emac_depentry *deps)
@@ -2358,6 +2369,7 @@ static int emac_wait_deps(struct emac_instance *dev)
deps[EMAC_DEP_MAL_IDX].phandle = dev->mal_ph;
deps[EMAC_DEP_ZMII_IDX].phandle = dev->zmii_ph;
deps[EMAC_DEP_RGMII_IDX].phandle = dev->rgmii_ph;
+ deps[EMAC_DEP_RGMII_WOL_IDX].phandle = dev->rgmii_wol_ph;
if (dev->tah_ph)
deps[EMAC_DEP_TAH_IDX].phandle = dev->tah_ph;
if (dev->mdio_ph)
@@ -2380,6 +2392,7 @@ static int emac_wait_deps(struct emac_instance *dev)
dev->mal_dev = deps[EMAC_DEP_MAL_IDX].ofdev;
dev->zmii_dev = deps[EMAC_DEP_ZMII_IDX].ofdev;
dev->rgmii_dev = deps[EMAC_DEP_RGMII_IDX].ofdev;
+ dev->rgmii_wol_dev = deps[EMAC_DEP_RGMII_WOL_IDX].ofdev;
dev->tah_dev = deps[EMAC_DEP_TAH_IDX].ofdev;
dev->mdio_dev = deps[EMAC_DEP_MDIO_IDX].ofdev;
}
@@ -2585,6 +2598,8 @@ static int emac_init_config(struct emac_instance *dev)
dev->rgmii_ph = 0;
if (emac_read_uint_prop(np, "rgmii-channel", &dev->rgmii_port, 0))
dev->rgmii_port = 0xffffffff;
+ if (emac_read_uint_prop(np, "rgmii-wol-device", &dev->rgmii_wol_ph, 0))
+ dev->rgmii_wol_ph = 0;
if (emac_read_uint_prop(np, "fifo-entry-size", &dev->fifo_entry_size, 0))
dev->fifo_entry_size = 16;
if (emac_read_uint_prop(np, "mal-burst-size", &dev->mal_burst_size, 0))
@@ -2671,6 +2686,16 @@ static int emac_init_config(struct emac_instance *dev)
#endif
}

+ if (dev->rgmii_wol_ph != 0) {
+#ifdef CONFIG_IBM_EMAC_RGMII_WOL
+ dev->features |= EMAC_FTR_HAS_RGMII_WOL;
+#else
+ printk(KERN_ERR "%s: RGMII WOL support not enabled !\n",
+ np->full_name);
+ return -ENXIO;
+#endif
+ }
+
/* Read MAC-address */
p = of_get_property(np, "local-mac-address", NULL);
if (p == NULL) {
@@ -2844,10 +2869,15 @@ static int emac_probe(struct platform_device *ofdev)
(err = rgmii_attach(dev->rgmii_dev, dev->rgmii_port, dev->phy_mode)) != 0)
goto err_detach_zmii;

+ /* Attach to RGMII_WOL, if needed */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII_WOL) &&
+ (err = rgmii_wol_attach(dev->rgmii_wol_dev, dev->phy_mode)) != 0)
+ goto err_detach_rgmii;
+
/* Attach to TAH, if needed */
if (emac_has_feature(dev, EMAC_FTR_HAS_TAH) &&
(err = tah_attach(dev->tah_dev, dev->tah_port)) != 0)
- goto err_detach_rgmii;
+ goto err_detach_rgmii_wol;

/* Set some link defaults before we can find out real parameters */
dev->phy.speed = SPEED_100;
@@ -2920,6 +2950,9 @@ static int emac_probe(struct platform_device *ofdev)
err_detach_tah:
if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
tah_detach(dev->tah_dev, dev->tah_port);
+ err_detach_rgmii_wol:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII_WOL))
+ rgmii_wol_detach(dev->rgmii_wol_dev);
err_detach_rgmii:
if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
rgmii_detach(dev->rgmii_dev, dev->rgmii_port);
@@ -3081,12 +3114,17 @@ static int __init emac_init(void)
rc = tah_init();
if (rc)
goto err_rgmii;
- rc = platform_driver_register(&emac_driver);
+ rc = rgmii_wol_init();
if (rc)
goto err_tah;
+ rc = platform_driver_register(&emac_driver);
+ if (rc)
+ goto err_rgmii_wol;

return 0;

+ err_rgmii_wol:
+ rgmii_wol_exit();
err_tah:
tah_exit();
err_rgmii:
diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h
index 7007479..930a6f6 100644
--- a/drivers/net/ethernet/ibm/emac/core.h
+++ b/drivers/net/ethernet/ibm/emac/core.h
@@ -43,6 +43,7 @@
#include "phy.h"
#include "zmii.h"
#include "rgmii.h"
+#include "rgmii_wol.h"
#include "mal.h"
#include "tah.h"
#include "debug.h"
@@ -210,6 +211,10 @@ struct emac_instance {
u32 rgmii_port;
struct platform_device *rgmii_dev;

+ /* RGMII WOL infos if any */
+ u32 rgmii_wol_ph;
+ struct platform_device *rgmii_wol_dev;
+
/* TAH infos if any */
u32 tah_ph;
u32 tah_port;
@@ -333,6 +338,10 @@ struct emac_instance {
* APM821xx does not support Half Duplex mode
*/
#define EMAC_FTR_APM821XX_NO_HALF_DUPLEX 0x00001000
+/*
+ * Set if we have a RGMII with wake on LAN.
+ */
+#define EMAC_FTR_HAS_RGMII_WOL 0x00020000

/* Right now, we don't quite handle the always/possible masks on the
* most optimal way as we don't have a way to say something like
@@ -356,6 +365,9 @@ enum {
#ifdef CONFIG_IBM_EMAC_RGMII
EMAC_FTR_HAS_RGMII |
#endif
+#ifdef CONFIG_IBM_EMAC_RGMII_WOL
+ EMAC_FTR_HAS_RGMII_WOL |
+#endif
#ifdef CONFIG_IBM_EMAC_NO_FLOW_CTRL
EMAC_FTR_NO_FLOW_CONTROL_40x |
#endif
diff --git a/drivers/net/ethernet/ibm/emac/rgmii_wol.c b/drivers/net/ethernet/ibm/emac/rgmii_wol.c
new file mode 100644
index 0000000..730f127
--- /dev/null
+++ b/drivers/net/ethernet/ibm/emac/rgmii_wol.c
@@ -0,0 +1,244 @@
+/* drivers/net/ethernet/ibm/emac/rgmii_wol.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge with
+ * wake on LAN support.
+ *
+ * Copyright 2013 Alistair Popple, IBM Corp.
+ * <[email protected]>
+ *
+ * Based on rgmii.h:
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+
+#include "emac.h"
+#include "debug.h"
+
+/* RGMII_WOL_REG */
+
+#define WKUP_ETH_RGSPD 0xC0000000
+#define WKUP_ETH_FCSEN 0x20000000
+#define WKUP_ETH_CRSEN 0x02000000
+#define WKUP_ETH_COLEN 0x01000000
+#define WKUP_ETH_TX_OE 0x00040000
+#define WKUP_ETH_RX_IE 0x00020000
+#define WKUP_ETH_RGMIIEN 0x00010000
+
+#define WKUP_ETH_RGSPD_10 0x00000000
+#define WKUP_ETH_RGSPD_100 0x40000000
+#define WKUP_ETH_RGSPD_1000 0x80000000
+
+/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */
+static inline int rgmii_valid_mode(int phy_mode)
+{
+ return phy_mode == PHY_MODE_GMII ||
+ phy_mode == PHY_MODE_MII ||
+ phy_mode == PHY_MODE_RGMII ||
+ phy_mode == PHY_MODE_TBI ||
+ phy_mode == PHY_MODE_RTBI;
+}
+
+int rgmii_wol_attach(struct platform_device *ofdev, int mode)
+{
+ struct rgmii_wol_instance *dev = platform_get_drvdata(ofdev);
+
+ dev_dbg(&ofdev->dev, "attach\n");
+
+ /* Check if we need to attach to a RGMII */
+ if (!rgmii_valid_mode(mode)) {
+ dev_err(&ofdev->dev, "unsupported settings !\n");
+ return -ENODEV;
+ }
+
+ mutex_lock(&dev->lock);
+
+ /* Enable this input */
+ out_be32(dev->reg, in_be32(dev->reg) | WKUP_ETH_RGMIIEN
+ | WKUP_ETH_TX_OE | WKUP_ETH_RX_IE);
+
+ ++dev->users;
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+void rgmii_wol_set_speed(struct platform_device *ofdev, int speed)
+{
+ struct rgmii_wol_instance *dev = platform_get_drvdata(ofdev);
+ u32 reg;
+
+ mutex_lock(&dev->lock);
+
+ reg = in_be32(dev->reg) & ~WKUP_ETH_RGSPD;
+
+ dev_dbg(&ofdev->dev, "speed(%d)\n", speed);
+
+ switch (speed) {
+ case SPEED_1000:
+ reg |= WKUP_ETH_RGSPD_1000;
+ break;
+ case SPEED_100:
+ reg |= WKUP_ETH_RGSPD_100;
+ break;
+ case SPEED_10:
+ reg |= WKUP_ETH_RGSPD_10;
+ break;
+ default:
+ dev_err(&ofdev->dev, "invalid speed set!\n");
+ }
+
+ out_be32(dev->reg, reg);
+
+ mutex_unlock(&dev->lock);
+}
+
+void rgmii_wol_get_mdio(struct platform_device *ofdev)
+{
+ /* MDIO is always enabled when RGMII_WOL is enabled, so we
+ * don't have to do anything here.
+ */
+ dev_dbg(&ofdev->dev, "get_mdio\n");
+}
+
+void rgmii_wol_put_mdio(struct platform_device *ofdev)
+{
+ dev_dbg(&ofdev->dev, "put_mdio\n");
+}
+
+void rgmii_wol_detach(struct platform_device *ofdev)
+{
+ struct rgmii_wol_instance *dev = platform_get_drvdata(ofdev);
+
+ BUG_ON(!dev || dev->users == 0);
+
+ mutex_lock(&dev->lock);
+
+ dev_dbg(&ofdev->dev, "detach\n");
+
+ /* Disable this input */
+ out_be32(dev->reg, 0);
+
+ --dev->users;
+
+ mutex_unlock(&dev->lock);
+}
+
+int rgmii_wol_get_regs_len(struct platform_device *ofdev)
+{
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ sizeof(u32);
+}
+
+void *rgmii_wol_dump_regs(struct platform_device *ofdev, void *buf)
+{
+ struct rgmii_wol_instance *dev = platform_get_drvdata(ofdev);
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+ u32 *regs = (u32 *)(hdr + 1);
+
+ hdr->version = 0;
+ hdr->index = 0; /* for now, are there chips with more than one
+ * rgmii ? if yes, then we'll add a cell_index
+ * like we do for emac
+ */
+ memcpy_fromio(regs, dev->reg, sizeof(u32));
+ return regs + 1;
+}
+
+
+static int rgmii_wol_probe(struct platform_device *ofdev)
+{
+ struct device_node *np = ofdev->dev.of_node;
+ struct rgmii_wol_instance *dev;
+ int rc;
+
+ rc = -ENOMEM;
+ dev = kzalloc(sizeof(struct rgmii_wol_instance), GFP_KERNEL);
+ if (dev == NULL)
+ goto err_gone;
+
+ mutex_init(&dev->lock);
+
+ dev->reg = of_iomap(np, 0);
+ if (!dev->reg) {
+ dev_err(&ofdev->dev, "Can't map registers\n");
+ rc = -ENXIO;
+ goto err_free;
+ }
+
+ /* Check for RGMII flags */
+ if (of_get_property(ofdev->dev.of_node, "has-mdio", NULL))
+ dev->flags |= EMAC_RGMII_FLAG_HAS_MDIO;
+
+ dev_dbg(&ofdev->dev, " Boot REG = 0x%08x\n", in_be32(dev->reg));
+
+ /* Disable all inputs by default */
+ out_be32(dev->reg, 0);
+
+ dev_info(&ofdev->dev,
+ "RGMII %s initialized with%s MDIO support\n",
+ ofdev->dev.of_node->full_name,
+ (dev->flags & EMAC_RGMII_FLAG_HAS_MDIO) ? "" : "out");
+
+ wmb();
+ platform_set_drvdata(ofdev, dev);
+
+ return 0;
+
+ err_free:
+ kfree(dev);
+ err_gone:
+ return rc;
+}
+
+static int rgmii_wol_remove(struct platform_device *ofdev)
+{
+ struct rgmii_wol_instance *dev = platform_get_drvdata(ofdev);
+
+ WARN_ON(dev->users != 0);
+
+ iounmap(dev->reg);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct of_device_id rgmii_wol_match[] = {
+ {
+ .compatible = "ibm,rgmii-wol",
+ },
+ {
+ .type = "emac-rgmii-wol",
+ },
+ {},
+};
+
+static struct platform_driver rgmii_wol_driver = {
+ .driver = {
+ .name = "emac-rgmii-wol",
+ .owner = THIS_MODULE,
+ .of_match_table = rgmii_wol_match,
+ },
+ .probe = rgmii_wol_probe,
+ .remove = rgmii_wol_remove,
+};
+
+int __init rgmii_wol_init(void)
+{
+ return platform_driver_register(&rgmii_wol_driver);
+}
+
+void rgmii_wol_exit(void)
+{
+ platform_driver_unregister(&rgmii_wol_driver);
+}
diff --git a/drivers/net/ethernet/ibm/emac/rgmii_wol.h b/drivers/net/ethernet/ibm/emac/rgmii_wol.h
new file mode 100644
index 0000000..9f0b589
--- /dev/null
+++ b/drivers/net/ethernet/ibm/emac/rgmii_wol.h
@@ -0,0 +1,62 @@
+/* drivers/net/ethernet/ibm/emac/rgmii_wol.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge with
+ * wake on LAN support.
+ *
+ * Copyright 2013 Alistair Popple, IBM Corp.
+ * <[email protected]>
+ *
+ * Based on rgmii.h:
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef __IBM_NEWEMAC_RGMII_WOL_H
+#define __IBM_NEWEMAC_RGMII_WOL_H
+
+/* RGMII device */
+struct rgmii_wol_instance {
+ u32 __iomem *reg;
+
+ /* RGMII bridge flags */
+ int flags;
+#define EMAC_RGMII_FLAG_HAS_MDIO 0x00000001
+
+ /* Only one EMAC whacks us at a time */
+ struct mutex lock;
+
+ /* number of EMACs using this RGMII bridge */
+ int users;
+};
+
+#ifdef CONFIG_IBM_EMAC_RGMII_WOL
+
+extern int rgmii_wol_init(void);
+extern void rgmii_wol_exit(void);
+extern int rgmii_wol_attach(struct platform_device *ofdev, int mode);
+extern void rgmii_wol_detach(struct platform_device *ofdev);
+extern void rgmii_wol_get_mdio(struct platform_device *ofdev);
+extern void rgmii_wol_put_mdio(struct platform_device *ofdev);
+extern void rgmii_wol_set_speed(struct platform_device *ofdev, int speed);
+extern int rgmii_wol_get_regs_len(struct platform_device *ofdev);
+extern void *rgmii_wol_dump_regs(struct platform_device *ofdev, void *buf);
+
+#else
+
+# define rgmii_wol_init() 0
+# define rgmii_wol_exit() do { } while (0)
+# define rgmii_wol_attach(x, y) (-ENXIO)
+# define rgmii_wol_detach(x) do { } while (0)
+# define rgmii_wol_get_mdio(o) do { } while (0)
+# define rgmii_wol_put_mdio(o) do { } while (0)
+# define rgmii_wol_set_speed(x, y) do { } while (0)
+# define rgmii_wol_get_regs_len(x) 0
+# define rgmii_wol_dump_regs(x, buf) (buf)
+#endif /* !CONFIG_IBM_EMAC_RGMII_WOL */
+
+#endif /* __IBM_NEWEMAC_RGMII_WOL_H */
--
1.7.10.4

2014-02-21 06:40:04

by Alistair Popple

[permalink] [raw]
Subject: [PATCH 5/7] IBM Currituck: Clean up board specific code before adding Akebono code

The IBM Akebono code uses the same initialisation functions as the
earlier Currituck board. Rather than create a copy of this code for
Akebono we will instead integrate support for it into the same file as
the Currituck code.

This patch just renames the board support file and updates the Makefile.

Signed-off-by: Alistair Popple <[email protected]>
---
arch/powerpc/platforms/44x/Makefile | 2 +-
arch/powerpc/platforms/44x/currituck.c | 233 --------------------------------
arch/powerpc/platforms/44x/ppc476.c | 233 ++++++++++++++++++++++++++++++++
3 files changed, 234 insertions(+), 234 deletions(-)
delete mode 100644 arch/powerpc/platforms/44x/currituck.c
create mode 100644 arch/powerpc/platforms/44x/ppc476.c

diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index d03833a..f896b89 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -10,4 +10,4 @@ obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
obj-$(CONFIG_XILINX_ML510) += virtex_ml510.o
obj-$(CONFIG_ISS4xx) += iss4xx.o
obj-$(CONFIG_CANYONLANDS)+= canyonlands.o
-obj-$(CONFIG_CURRITUCK) += currituck.o
+obj-$(CONFIG_CURRITUCK) += ppc476.o
diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c
deleted file mode 100644
index 7f1b71a..0000000
--- a/arch/powerpc/platforms/44x/currituck.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Currituck board specific routines
- *
- * Copyright © 2011 Tony Breeds IBM Corporation
- *
- * Based on earlier code:
- * Matt Porter <[email protected]>
- * Copyright 2002-2005 MontaVista Software Inc.
- *
- * Eugene Surovegin <[email protected]> or <[email protected]>
- * Copyright (c) 2003-2005 Zultys Technologies
- *
- * Rewritten and ported to the merged powerpc tree:
- * Copyright 2007 David Gibson <[email protected]>, IBM Corporation.
- * Copyright © 2011 David Kliekamp IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/rtc.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/ppc4xx.h>
-#include <asm/mpic.h>
-#include <asm/mmu.h>
-
-#include <linux/pci.h>
-
-static __initdata struct of_device_id ppc47x_of_bus[] = {
- { .compatible = "ibm,plb4", },
- { .compatible = "ibm,plb6", },
- { .compatible = "ibm,opb", },
- { .compatible = "ibm,ebc", },
- {},
-};
-
-/* The EEPROM is missing and the default values are bogus. This forces USB in
- * to EHCI mode */
-static void quirk_ppc_currituck_usb_fixup(struct pci_dev *dev)
-{
- if (of_machine_is_compatible("ibm,currituck")) {
- pci_write_config_dword(dev, 0xe0, 0x0114231f);
- pci_write_config_dword(dev, 0xe4, 0x00006c40);
- }
-}
-DECLARE_PCI_FIXUP_HEADER(0x1033, 0x0035, quirk_ppc_currituck_usb_fixup);
-
-static int __init ppc47x_device_probe(void)
-{
- of_platform_bus_probe(NULL, ppc47x_of_bus, NULL);
-
- return 0;
-}
-machine_device_initcall(ppc47x, ppc47x_device_probe);
-
-/* We can have either UICs or MPICs */
-static void __init ppc47x_init_irq(void)
-{
- struct device_node *np;
-
- /* Find top level interrupt controller */
- for_each_node_with_property(np, "interrupt-controller") {
- if (of_get_property(np, "interrupts", NULL) == NULL)
- break;
- }
- if (np == NULL)
- panic("Can't find top level interrupt controller");
-
- /* Check type and do appropriate initialization */
- if (of_device_is_compatible(np, "chrp,open-pic")) {
- /* The MPIC driver will get everything it needs from the
- * device-tree, just pass 0 to all arguments
- */
- struct mpic *mpic =
- mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC ");
- BUG_ON(mpic == NULL);
- mpic_init(mpic);
- ppc_md.get_irq = mpic_get_irq;
- } else
- panic("Unrecognized top level interrupt controller");
-}
-
-#ifdef CONFIG_SMP
-static void smp_ppc47x_setup_cpu(int cpu)
-{
- mpic_setup_this_cpu();
-}
-
-static int smp_ppc47x_kick_cpu(int cpu)
-{
- struct device_node *cpunode = of_get_cpu_node(cpu, NULL);
- const u64 *spin_table_addr_prop;
- u32 *spin_table;
- extern void start_secondary_47x(void);
-
- BUG_ON(cpunode == NULL);
-
- /* Assume spin table. We could test for the enable-method in
- * the device-tree but currently there's little point as it's
- * our only supported method
- */
- spin_table_addr_prop =
- of_get_property(cpunode, "cpu-release-addr", NULL);
-
- if (spin_table_addr_prop == NULL) {
- pr_err("CPU%d: Can't start, missing cpu-release-addr !\n",
- cpu);
- return 1;
- }
-
- /* Assume it's mapped as part of the linear mapping. This is a bit
- * fishy but will work fine for now
- *
- * XXX: Is there any reason to assume differently?
- */
- spin_table = (u32 *)__va(*spin_table_addr_prop);
- pr_debug("CPU%d: Spin table mapped at %p\n", cpu, spin_table);
-
- spin_table[3] = cpu;
- smp_wmb();
- spin_table[1] = __pa(start_secondary_47x);
- mb();
-
- return 0;
-}
-
-static struct smp_ops_t ppc47x_smp_ops = {
- .probe = smp_mpic_probe,
- .message_pass = smp_mpic_message_pass,
- .setup_cpu = smp_ppc47x_setup_cpu,
- .kick_cpu = smp_ppc47x_kick_cpu,
- .give_timebase = smp_generic_give_timebase,
- .take_timebase = smp_generic_take_timebase,
-};
-
-static void __init ppc47x_smp_init(void)
-{
- if (mmu_has_feature(MMU_FTR_TYPE_47x))
- smp_ops = &ppc47x_smp_ops;
-}
-
-#else /* CONFIG_SMP */
-static void __init ppc47x_smp_init(void) { }
-#endif /* CONFIG_SMP */
-
-static void __init ppc47x_setup_arch(void)
-{
-
- /* No need to check the DMA config as we /know/ our windows are all of
- * RAM. Lets hope that doesn't change */
- swiotlb_detect_4g();
-
- ppc47x_smp_init();
-}
-
-/*
- * Called very early, MMU is off, device-tree isn't unflattened
- */
-static int __init ppc47x_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- if (!of_flat_dt_is_compatible(root, "ibm,currituck"))
- return 0;
-
- return 1;
-}
-
-static int board_rev = -1;
-static int __init ppc47x_get_board_rev(void)
-{
- u8 fpga_reg0;
- void *fpga;
- struct device_node *np;
-
- np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
- if (!np)
- goto fail;
-
- fpga = of_iomap(np, 0);
- of_node_put(np);
- if (!fpga)
- goto fail;
-
- fpga_reg0 = ioread8(fpga);
- board_rev = fpga_reg0 & 0x03;
- pr_info("%s: Found board revision %d\n", __func__, board_rev);
- iounmap(fpga);
- return 0;
-
-fail:
- pr_info("%s: Unable to find board revision\n", __func__);
- return 0;
-}
-machine_arch_initcall(ppc47x, ppc47x_get_board_rev);
-
-/* Use USB controller should have been hardware swizzled but it wasn't :( */
-static void ppc47x_pci_irq_fixup(struct pci_dev *dev)
-{
- if (dev->vendor == 0x1033 && (dev->device == 0x0035 ||
- dev->device == 0x00e0)) {
- if (board_rev == 0) {
- dev->irq = irq_create_mapping(NULL, 47);
- pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
- } else if (board_rev == 2) {
- dev->irq = irq_create_mapping(NULL, 49);
- pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
- } else {
- pr_alert("%s: Unknown board revision\n", __func__);
- }
- }
-}
-
-define_machine(ppc47x) {
- .name = "PowerPC 47x",
- .probe = ppc47x_probe,
- .progress = udbg_progress,
- .init_IRQ = ppc47x_init_irq,
- .setup_arch = ppc47x_setup_arch,
- .pci_irq_fixup = ppc47x_pci_irq_fixup,
- .restart = ppc4xx_reset_system,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/ppc476.c b/arch/powerpc/platforms/44x/ppc476.c
new file mode 100644
index 0000000..c6c5a6f
--- /dev/null
+++ b/arch/powerpc/platforms/44x/ppc476.c
@@ -0,0 +1,233 @@
+/*
+ * PowerPC 476FPE board specific routines
+ *
+ * Copyright © 2011 Tony Breeds IBM Corporation
+ *
+ * Based on earlier code:
+ * Matt Porter <[email protected]>
+ * Copyright 2002-2005 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <[email protected]> or <[email protected]>
+ * Copyright (c) 2003-2005 Zultys Technologies
+ *
+ * Rewritten and ported to the merged powerpc tree:
+ * Copyright 2007 David Gibson <[email protected]>, IBM Corporation.
+ * Copyright © 2011 David Kliekamp IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/rtc.h>
+
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/time.h>
+#include <asm/uic.h>
+#include <asm/ppc4xx.h>
+#include <asm/mpic.h>
+#include <asm/mmu.h>
+
+#include <linux/pci.h>
+
+static struct of_device_id ppc47x_of_bus[] __initdata = {
+ { .compatible = "ibm,plb4", },
+ { .compatible = "ibm,plb6", },
+ { .compatible = "ibm,opb", },
+ { .compatible = "ibm,ebc", },
+ {},
+};
+
+/* The EEPROM is missing and the default values are bogus. This forces USB in
+ * to EHCI mode */
+static void quirk_ppc_currituck_usb_fixup(struct pci_dev *dev)
+{
+ if (of_machine_is_compatible("ibm,currituck")) {
+ pci_write_config_dword(dev, 0xe0, 0x0114231f);
+ pci_write_config_dword(dev, 0xe4, 0x00006c40);
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(0x1033, 0x0035, quirk_ppc_currituck_usb_fixup);
+
+static int __init ppc47x_device_probe(void)
+{
+ of_platform_bus_probe(NULL, ppc47x_of_bus, NULL);
+
+ return 0;
+}
+machine_device_initcall(ppc47x, ppc47x_device_probe);
+
+/* We can have either UICs or MPICs */
+static void __init ppc47x_init_irq(void)
+{
+ struct device_node *np;
+
+ /* Find top level interrupt controller */
+ for_each_node_with_property(np, "interrupt-controller") {
+ if (of_get_property(np, "interrupts", NULL) == NULL)
+ break;
+ }
+ if (np == NULL)
+ panic("Can't find top level interrupt controller");
+
+ /* Check type and do appropriate initialization */
+ if (of_device_is_compatible(np, "chrp,open-pic")) {
+ /* The MPIC driver will get everything it needs from the
+ * device-tree, just pass 0 to all arguments
+ */
+ struct mpic *mpic =
+ mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC ");
+ BUG_ON(mpic == NULL);
+ mpic_init(mpic);
+ ppc_md.get_irq = mpic_get_irq;
+ } else
+ panic("Unrecognized top level interrupt controller");
+}
+
+#ifdef CONFIG_SMP
+static void smp_ppc47x_setup_cpu(int cpu)
+{
+ mpic_setup_this_cpu();
+}
+
+static int smp_ppc47x_kick_cpu(int cpu)
+{
+ struct device_node *cpunode = of_get_cpu_node(cpu, NULL);
+ const u64 *spin_table_addr_prop;
+ u32 *spin_table;
+ extern void start_secondary_47x(void);
+
+ BUG_ON(cpunode == NULL);
+
+ /* Assume spin table. We could test for the enable-method in
+ * the device-tree but currently there's little point as it's
+ * our only supported method
+ */
+ spin_table_addr_prop =
+ of_get_property(cpunode, "cpu-release-addr", NULL);
+
+ if (spin_table_addr_prop == NULL) {
+ pr_err("CPU%d: Can't start, missing cpu-release-addr !\n",
+ cpu);
+ return 1;
+ }
+
+ /* Assume it's mapped as part of the linear mapping. This is a bit
+ * fishy but will work fine for now
+ *
+ * XXX: Is there any reason to assume differently?
+ */
+ spin_table = (u32 *)__va(*spin_table_addr_prop);
+ pr_debug("CPU%d: Spin table mapped at %p\n", cpu, spin_table);
+
+ spin_table[3] = cpu;
+ smp_wmb();
+ spin_table[1] = __pa(start_secondary_47x);
+ mb();
+
+ return 0;
+}
+
+static struct smp_ops_t ppc47x_smp_ops = {
+ .probe = smp_mpic_probe,
+ .message_pass = smp_mpic_message_pass,
+ .setup_cpu = smp_ppc47x_setup_cpu,
+ .kick_cpu = smp_ppc47x_kick_cpu,
+ .give_timebase = smp_generic_give_timebase,
+ .take_timebase = smp_generic_take_timebase,
+};
+
+static void __init ppc47x_smp_init(void)
+{
+ if (mmu_has_feature(MMU_FTR_TYPE_47x))
+ smp_ops = &ppc47x_smp_ops;
+}
+
+#else /* CONFIG_SMP */
+static void __init ppc47x_smp_init(void) { }
+#endif /* CONFIG_SMP */
+
+static void __init ppc47x_setup_arch(void)
+{
+
+ /* No need to check the DMA config as we /know/ our windows are all of
+ * RAM. Lets hope that doesn't change */
+ swiotlb_detect_4g();
+
+ ppc47x_smp_init();
+}
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init ppc47x_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (!of_flat_dt_is_compatible(root, "ibm,currituck"))
+ return 0;
+
+ return 1;
+}
+
+static int board_rev = -1;
+static int __init ppc47x_get_board_rev(void)
+{
+ u8 fpga_reg0;
+ void *fpga;
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
+ if (!np)
+ goto fail;
+
+ fpga = of_iomap(np, 0);
+ of_node_put(np);
+ if (!fpga)
+ goto fail;
+
+ fpga_reg0 = ioread8(fpga);
+ board_rev = fpga_reg0 & 0x03;
+ pr_info("%s: Found board revision %d\n", __func__, board_rev);
+ iounmap(fpga);
+ return 0;
+
+fail:
+ pr_info("%s: Unable to find board revision\n", __func__);
+ return 0;
+}
+machine_arch_initcall(ppc47x, ppc47x_get_board_rev);
+
+/* Use USB controller should have been hardware swizzled but it wasn't :( */
+static void ppc47x_pci_irq_fixup(struct pci_dev *dev)
+{
+ if (dev->vendor == 0x1033 && (dev->device == 0x0035 ||
+ dev->device == 0x00e0)) {
+ if (board_rev == 0) {
+ dev->irq = irq_create_mapping(NULL, 47);
+ pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
+ } else if (board_rev == 2) {
+ dev->irq = irq_create_mapping(NULL, 49);
+ pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
+ } else {
+ pr_alert("%s: Unknown board revision\n", __func__);
+ }
+ }
+}
+
+define_machine(ppc47x) {
+ .name = "PowerPC 47x",
+ .probe = ppc47x_probe,
+ .progress = udbg_progress,
+ .init_IRQ = ppc47x_init_irq,
+ .setup_arch = ppc47x_setup_arch,
+ .pci_irq_fixup = ppc47x_pci_irq_fixup,
+ .restart = ppc4xx_reset_system,
+ .calibrate_decr = generic_calibrate_decr,
+};
--
1.7.10.4

2014-02-21 06:40:14

by Alistair Popple

[permalink] [raw]
Subject: [PATCH 6/7] IBM Akebono: Add the Akebono platform

This patch adds support for the IBM Akebono board.

Signed-off-by: Alistair Popple <[email protected]>
---
.../devicetree/bindings/powerpc/4xx/akebono.txt | 54 +++
arch/powerpc/boot/Makefile | 3 +
arch/powerpc/boot/dcr.h | 4 +
arch/powerpc/boot/dts/akebono.dts | 385 ++++++++++++++++++++
arch/powerpc/boot/treeboot-akebono.c | 178 +++++++++
arch/powerpc/boot/wrapper | 3 +
arch/powerpc/configs/44x/akebono_defconfig | 148 ++++++++
arch/powerpc/platforms/44x/Kconfig | 26 ++
arch/powerpc/platforms/44x/Makefile | 1 +
arch/powerpc/platforms/44x/ppc476.c | 112 ++++--
arch/powerpc/sysdev/ppc4xx_pci.c | 13 +-
11 files changed, 901 insertions(+), 26 deletions(-)
create mode 100644 Documentation/devicetree/bindings/powerpc/4xx/akebono.txt
create mode 100644 arch/powerpc/boot/dts/akebono.dts
create mode 100644 arch/powerpc/boot/treeboot-akebono.c
create mode 100644 arch/powerpc/configs/44x/akebono_defconfig

diff --git a/Documentation/devicetree/bindings/powerpc/4xx/akebono.txt b/Documentation/devicetree/bindings/powerpc/4xx/akebono.txt
new file mode 100644
index 0000000..75adb84
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/4xx/akebono.txt
@@ -0,0 +1,54 @@
+
+IBM Akebono board device tree
+=============================
+
+The IBM Akebono board is a development board for the PPC476GTR SoC.
+
+0) The root node
+
+ Required properties:
+
+ - model : "ibm,akebono".
+ - compatible : "ibm,akebono" , "ibm,476gtr".
+
+1.a) The Secure Digital Host Controller Interface (SDHCI) node
+
+ Represent the Secure Digital Host Controller Interfaces.
+
+ Required properties:
+
+ - compatible : should be "ibm,476gtr-sdhci","sdhci".
+ - reg : should contain the SDHCI registers location and length.
+ - interrupt-parent : a phandle for the interrupt controller.
+ - interrupts : should contain the SDHCI interrupt.
+
+1.b) The Advanced Host Controller Interface (AHCI) SATA node
+
+ Represents the advanced host controller SATA interface.
+
+ Required properties:
+
+ - compatible : should be "ibm,476gtr-ahci".
+ - reg : should contain the AHCI registers location and length.
+ - interrupt-parent : a phandle for the interrupt controller.
+ - interrupts : should contain the AHCI interrupt.
+
+1.c) The FPGA node
+
+ The Akebono board stores some board information such as the revision
+ number in an FPGA which is represented by this node.
+
+ Required properties:
+
+ - compatible : should be "ibm,akebono-fpga".
+ - reg : should contain the FPGA registers location and length.
+
+1.d) The AVR node
+
+ The Akebono board has an Atmel AVR microprocessor attached to the I2C
+ bus as a power controller for the board.
+
+ Required properties:
+
+ - compatible : should be "ibm,akebono-avr".
+ - reg : should contain the I2C bus address for the AVR.
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index ca7f08c..dd77cca 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -47,6 +47,7 @@ $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405
$(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405
$(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405
$(obj)/treeboot-currituck.o: BOOTCFLAGS += -mcpu=405
+$(obj)/treeboot-akebono.o: BOOTCFLAGS += -mcpu=405
$(obj)/virtex405-head.o: BOOTAFLAGS += -mcpu=405


@@ -86,6 +87,7 @@ src-plat-$(CONFIG_44x) += treeboot-ebony.c cuboot-ebony.c treeboot-bamboo.c \
cuboot-taishan.c cuboot-katmai.c \
cuboot-warp.c cuboot-yosemite.c \
treeboot-iss4xx.c treeboot-currituck.c \
+ treeboot-akebono.c \
simpleboot.c fixed-head.S virtex.c
src-plat-$(CONFIG_8xx) += cuboot-8xx.c fixed-head.S ep88xc.c redboot-8xx.c
src-plat-$(CONFIG_PPC_MPC52xx) += cuboot-52xx.c
@@ -236,6 +238,7 @@ image-$(CONFIG_YOSEMITE) += cuImage.yosemite
image-$(CONFIG_ISS4xx) += treeImage.iss4xx \
treeImage.iss4xx-mpic
image-$(CONFIG_CURRITUCK) += treeImage.currituck
+image-$(CONFIG_AKEBONO) += treeImage.akebono

# Board ports in arch/powerpc/platform/8xx/Kconfig
image-$(CONFIG_MPC86XADS) += cuImage.mpc866ads
diff --git a/arch/powerpc/boot/dcr.h b/arch/powerpc/boot/dcr.h
index cc73f7a..bf8f4ed 100644
--- a/arch/powerpc/boot/dcr.h
+++ b/arch/powerpc/boot/dcr.h
@@ -15,6 +15,10 @@
asm volatile("mfdcrx %0,%1" : "=r"(rval) : "r"(rn)); \
rval; \
})
+#define mtdcrx(rn, val) \
+ ({ \
+ asm volatile("mtdcrx %0,%1" : : "r"(rn), "r" (val)); \
+ })

/* 440GP/440GX SDRAM controller DCRs */
#define DCRN_SDRAM0_CFGADDR 0x010
diff --git a/arch/powerpc/boot/dts/akebono.dts b/arch/powerpc/boot/dts/akebono.dts
new file mode 100644
index 0000000..9a21f58
--- /dev/null
+++ b/arch/powerpc/boot/dts/akebono.dts
@@ -0,0 +1,385 @@
+/*
+ * Device Tree Source for IBM Embedded PPC 476 Platform
+ *
+ * Copyright © 2013 Tony Breeds IBM Corporation
+ * Copyright © 2013 Alistair Popple IBM Corporation
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+/memreserve/ 0x01f00000 0x00100000; // spin table
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ model = "ibm,akebono";
+ compatible = "ibm,akebono", "ibm,476gtr";
+ dcr-parent = <&{/cpus/cpu@0}>;
+
+ aliases {
+ serial0 = &UART0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ model = "PowerPC,476";
+ reg = <0>;
+ clock-frequency = <1600000000>; // 1.6 GHz
+ timebase-frequency = <100000000>; // 100Mhz
+ i-cache-line-size = <32>;
+ d-cache-line-size = <32>;
+ i-cache-size = <32768>;
+ d-cache-size = <32768>;
+ dcr-controller;
+ dcr-access-method = "native";
+ status = "ok";
+ };
+ cpu@1 {
+ device_type = "cpu";
+ model = "PowerPC,476";
+ reg = <1>;
+ clock-frequency = <1600000000>; // 1.6 GHz
+ timebase-frequency = <100000000>; // 100Mhz
+ i-cache-line-size = <32>;
+ d-cache-line-size = <32>;
+ i-cache-size = <32768>;
+ d-cache-size = <32768>;
+ dcr-controller;
+ dcr-access-method = "native";
+ status = "disabled";
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x01f00000>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x0 0x0 0x0>; // filled in by zImage
+ };
+
+ MPIC: interrupt-controller {
+ compatible = "chrp,open-pic";
+ interrupt-controller;
+ dcr-reg = <0xffc00000 0x00040000>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ single-cpu-affinity;
+ };
+
+ plb {
+ compatible = "ibm,plb6";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ clock-frequency = <200000000>; // 200Mhz
+
+ MAL0: mcmal {
+ compatible = "ibm,mcmal-476gtr", "ibm,mcmal2";
+ dcr-reg = <0xc0000000 0x062>;
+ num-tx-chans = <1>;
+ num-rx-chans = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-parent = <&MPIC>;
+ interrupts = < /*TXEOB*/ 77 0x4
+ /*RXEOB*/ 78 0x4
+ /*SERR*/ 76 0x4
+ /*TXDE*/ 79 0x4
+ /*RXDE*/ 80 0x4>;
+ };
+
+ SATA0: sata@30000010000 {
+ compatible = "ibm,476gtr-ahci";
+ reg = <0x300 0x00010000 0x0 0x10000>;
+ interrupt-parent = <&MPIC>;
+ interrupts = <93 2>;
+ };
+
+ EHCI0: ehci@30010000000 {
+ compatible = "ibm,476gtr-ehci", "usb-ehci";
+ reg = <0x300 0x10000000 0x0 0x10000>;
+ interrupt-parent = <&MPIC>;
+ interrupts = <85 2>;
+ };
+
+ SD0: sd@30000000000 {
+ compatible = "ibm,476gtr-sdhci", "sdhci";
+ reg = <0x300 0x00000000 0x0 0x10000>;
+ interrupts = <91 2>;
+ interrupt-parent = <&MPIC>;
+ };
+
+ OHCI0: ohci@30010010000 {
+ compatible = "ibm,476gtr-ohci", "usb-ohci";
+ reg = <0x300 0x10010000 0x0 0x10000>;
+ interrupt-parent = <&MPIC>;
+ interrupts = <89 1>;
+ };
+
+ OHCI1: ohci@30010020000 {
+ compatible = "ibm,476gtr-ohci", "usb-ohci";
+ reg = <0x300 0x10020000 0x0 0x10000>;
+ interrupt-parent = <&MPIC>;
+ interrupts = <88 1>;
+ };
+
+ POB0: opb {
+ compatible = "ibm,opb-4xx", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* Wish there was a nicer way of specifying a full
+ * 32-bit range
+ */
+ ranges = <0x00000000 0x0000033f 0x00000000 0x80000000
+ 0x80000000 0x0000033f 0x80000000 0x80000000>;
+ clock-frequency = <100000000>;
+
+ RGMII0: emac-rgmii-wol@50004 {
+ compatible = "ibm,rgmii-wol-476gtr", "ibm,rgmii-wol";
+ reg = <0x50004 0x00000008>;
+ has-mdio;
+ };
+
+ EMAC0: ethernet@30000 {
+ device_type = "network";
+ compatible = "ibm,emac-476gtr", "ibm,emac4sync";
+ interrupt-parent = <&EMAC0>;
+ interrupts = <0x0 0x1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &MPIC 81 0x4
+ /*Wake*/ 0x1 &MPIC 82 0x4>;
+ reg = <0x30000 0x78>;
+
+ /* local-mac-address will normally be added by
+ * the wrapper. If your device doesn't support
+ * passing data to the wrapper (in the form
+ * local-mac-addr=<hwaddr>) then you will need
+ * to set it manually here. */
+ //local-mac-address = [000000000000];
+
+ mal-device = <&MAL0>;
+ mal-tx-channel = <0>;
+ mal-rx-channel = <0>;
+ cell-index = <0>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ rx-fifo-size-gige = <16384>;
+ phy-mode = "rgmii";
+ phy-map = <0x00000000>;
+ rgmii-wol-device = <&RGMII0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+
+ UART0: serial@10000 {
+ device_type = "serial";
+ compatible = "ns16750", "ns16550";
+ reg = <0x10000 0x00000008>;
+ virtual-reg = <0xe8010000>;
+ clock-frequency = <1851851>;
+ current-speed = <38400>;
+ interrupt-parent = <&MPIC>;
+ interrupts = <39 2>;
+ };
+
+ IIC0: i2c@00000000 {
+ compatible = "ibm,iic-476gtr", "ibm,iic";
+ reg = <0x0 0x00000020>;
+ interrupt-parent = <&MPIC>;
+ interrupts = <37 2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ rtc@68 {
+ compatible = "stm,m41t80", "m41st85";
+ reg = <0x68>;
+ };
+ };
+
+ IIC1: i2c@00000100 {
+ compatible = "ibm,iic-476gtr", "ibm,iic";
+ reg = <0x100 0x00000020>;
+ interrupt-parent = <&MPIC>;
+ interrupts = <38 2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ avr@58 {
+ compatible = "ibm,akebono-avr";
+ reg = <0x58>;
+ };
+ };
+
+ FPGA0: fpga@ebc00000 {
+ compatible = "ibm,akebono-fpga";
+ reg = <0xebc00000 0x8>;
+ };
+ };
+
+ PCIE0: pciex@10100000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex";
+ primary;
+ port = <0x0>; /* port number */
+ reg = <0x00000101 0x00000000 0x0 0x10000000 /* Config space access */
+ 0x00000100 0x00000000 0x0 0x00001000>; /* UTL Registers space access */
+ dcr-reg = <0xc0 0x20>;
+
+// pci_space < pci_addr > < cpu_addr > < size >
+ ranges = <0x02000000 0x00000000 0x80000000 0x00000110 0x80000000 0x0 0x80000000
+ 0x01000000 0x0 0x0 0x00000140 0x0 0x0 0x00010000>;
+
+ /* Inbound starting at 0 to memsize filled in by zImage */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
+
+ /* This drives busses 0 to 0xf */
+ bus-range = <0x0 0xf>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &MPIC 45 0x2 /* int A */
+ 0x0 0x0 0x0 0x2 &MPIC 46 0x2 /* int B */
+ 0x0 0x0 0x0 0x3 &MPIC 47 0x2 /* int C */
+ 0x0 0x0 0x0 0x4 &MPIC 48 0x2 /* int D */>;
+ };
+
+ PCIE1: pciex@20100000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex";
+ primary;
+ port = <0x1>; /* port number */
+ reg = <0x00000201 0x00000000 0x0 0x10000000 /* Config space access */
+ 0x00000200 0x00000000 0x0 0x00001000>; /* UTL Registers space access */
+ dcr-reg = <0x100 0x20>;
+
+// pci_space < pci_addr > < cpu_addr > < size >
+ ranges = <0x02000000 0x00000000 0x80000000 0x00000210 0x80000000 0x0 0x80000000
+ 0x01000000 0x0 0x0 0x00000240 0x0 0x0 0x00010000>;
+
+ /* Inbound starting at 0 to memsize filled in by zImage */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
+
+ /* This drives busses 0 to 0xf */
+ bus-range = <0x0 0xf>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &MPIC 53 0x2 /* int A */
+ 0x0 0x0 0x0 0x2 &MPIC 54 0x2 /* int B */
+ 0x0 0x0 0x0 0x3 &MPIC 55 0x2 /* int C */
+ 0x0 0x0 0x0 0x4 &MPIC 56 0x2 /* int D */>;
+ };
+
+ PCIE2: pciex@18100000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex";
+ primary;
+ port = <0x2>; /* port number */
+ reg = <0x00000181 0x00000000 0x0 0x10000000 /* Config space access */
+ 0x00000180 0x00000000 0x0 0x00001000>; /* UTL Registers space access */
+ dcr-reg = <0xe0 0x20>;
+
+// pci_space < pci_addr > < cpu_addr > < size >
+ ranges = <0x02000000 0x00000000 0x80000000 0x00000190 0x80000000 0x0 0x80000000
+ 0x01000000 0x0 0x0 0x000001c0 0x0 0x0 0x00010000>;
+
+ /* Inbound starting at 0 to memsize filled in by zImage */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
+
+ /* This drives busses 0 to 0xf */
+ bus-range = <0x0 0xf>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &MPIC 61 0x2 /* int A */
+ 0x0 0x0 0x0 0x2 &MPIC 62 0x2 /* int B */
+ 0x0 0x0 0x0 0x3 &MPIC 63 0x2 /* int C */
+ 0x0 0x0 0x0 0x4 &MPIC 64 0x2 /* int D */>;
+ };
+
+ PCIE3: pciex@28100000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-476fpe", "ibm,plb-pciex";
+ primary;
+ port = <0x3>; /* port number */
+ reg = <0x00000281 0x00000000 0x0 0x10000000 /* Config space access */
+ 0x00000280 0x00000000 0x0 0x00001000>; /* UTL Registers space access */
+ dcr-reg = <0x120 0x20>;
+
+// pci_space < pci_addr > < cpu_addr > < size >
+ ranges = <0x02000000 0x00000000 0x80000000 0x00000290 0x80000000 0x0 0x80000000
+ 0x01000000 0x0 0x0 0x000002c0 0x0 0x0 0x00010000>;
+
+ /* Inbound starting at 0 to memsize filled in by zImage */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
+
+ /* This drives busses 0 to 0xf */
+ bus-range = <0x0 0xf>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &MPIC 69 0x2 /* int A */
+ 0x0 0x0 0x0 0x2 &MPIC 70 0x2 /* int B */
+ 0x0 0x0 0x0 0x3 &MPIC 71 0x2 /* int C */
+ 0x0 0x0 0x0 0x4 &MPIC 72 0x2 /* int D */>;
+ };
+ };
+
+ chosen {
+ linux,stdout-path = &UART0;
+ };
+};
diff --git a/arch/powerpc/boot/treeboot-akebono.c b/arch/powerpc/boot/treeboot-akebono.c
new file mode 100644
index 0000000..d42ef8a
--- /dev/null
+++ b/arch/powerpc/boot/treeboot-akebono.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright © 2013 Tony Breeds IBM Corporation
+ * Copyright © 2013 Alistair Popple IBM Corporation
+ *
+ * Based on earlier code:
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * Matt Porter <[email protected]>
+ * Copyright 2002-2005 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <[email protected]> or <[email protected]>
+ * Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Copyright 2010 Ben. Herrenschmidt, IBM Corporation.
+ * Copyright © 2011 David Kleikamp IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "string.h"
+#include "stdlib.h"
+#include "stdio.h"
+#include "page.h"
+#include "ops.h"
+#include "reg.h"
+#include "io.h"
+#include "dcr.h"
+#include "4xx.h"
+#include "44x.h"
+#include "libfdt.h"
+
+BSS_STACK(4096);
+
+#define SPRN_PIR 0x11E /* Processor Indentification Register */
+#define USERDATA_LEN 256 /* Length of userdata passed in by PIBS */
+#define MAX_RANKS 0x4
+#define DDR3_MR0CF 0x80010011U
+#define CCTL0_MCO2 0x8000080FU
+#define CCTL0_MCO3 0x80000810U
+#define CCTL0_MCO4 0x80000811U
+#define CCTL0_MCO5 0x80000812U
+#define CCTL0_MCO6 0x80000813U
+
+static unsigned long long ibm_akebono_memsize;
+static long long unsigned mac_addr;
+
+static unsigned long long ibm_akebono_detect_memsize(void)
+{
+ u32 reg;
+ unsigned i;
+ unsigned long long memsize = 0;
+
+ for (i = 0; i < MAX_RANKS; i++) {
+ reg = mfdcrx(DDR3_MR0CF + i);
+
+ if (!(reg & 1))
+ continue;
+
+ reg &= 0x0000f000;
+ reg >>= 12;
+ memsize += (0x800000ULL << reg);
+ }
+
+ return memsize;
+}
+
+static void ibm_akebono_fixups(void)
+{
+ void *emac;
+ u32 reg;
+ void *devp = finddevice("/");
+ u32 dma_ranges[7];
+
+ dt_fixup_memory(0x0ULL, ibm_akebono_memsize);
+
+ while ((devp = find_node_by_devtype(devp, "pci"))) {
+ if (getprop(devp, "dma-ranges", dma_ranges,
+ sizeof(dma_ranges)) < 0) {
+ printf("%s: Failed to get dma-ranges\r\n", __func__);
+ continue;
+ }
+
+ dma_ranges[5] = ibm_akebono_memsize >> 32;
+ dma_ranges[6] = ibm_akebono_memsize & 0xffffffffUL;
+
+ setprop(devp, "dma-ranges", dma_ranges, sizeof(dma_ranges));
+ }
+
+ /* Fixup the SD timeout frequency */
+ mtdcrx(CCTL0_MCO4, 0x1);
+
+ /* Disable SD high-speed mode (which seems to be broken) */
+ reg = mfdcrx(CCTL0_MCO2) & ~0x2;
+ mtdcrx(CCTL0_MCO2, reg);
+
+ /* Set the MAC address */
+ emac = finddevice("/plb/opb/ethernet");
+ if (emac > 0) {
+ if (mac_addr)
+ setprop(emac, "local-mac-address",
+ ((u8 *) &mac_addr) + 2 , 6);
+ }
+}
+
+void platform_init(char *userdata)
+{
+ unsigned long end_of_ram, avail_ram;
+ u32 pir_reg;
+ int node, size;
+ const u32 *timebase;
+ int len, i, userdata_len;
+ char *end;
+
+ userdata[USERDATA_LEN - 1] = '\0';
+ userdata_len = strlen(userdata);
+ for (i = 0; i < userdata_len; i++) {
+ if (strncmp(&userdata[i], "local-mac-addr=", 15) == 0) {
+ if (i > 0 && userdata[i - 1] != ' ') {
+ /* We've only found a substring ending
+ * with local-mac-addr so this isn't
+ * our mac address. */
+ continue;
+ }
+
+ mac_addr = strtoull(&userdata[i + 15], &end, 16);
+
+ /* Remove the "local-mac-addr=<...>" from the kernel
+ * command line, including the tailing space if
+ * present. */
+ if (*end == ' ')
+ end++;
+
+ len = ((int) end) - ((int) &userdata[i]);
+ memmove(&userdata[i], end,
+ userdata_len - (len + i) + 1);
+ break;
+ }
+ }
+
+ loader_info.cmdline = userdata;
+ loader_info.cmdline_len = 256;
+
+ ibm_akebono_memsize = ibm_akebono_detect_memsize();
+ if (ibm_akebono_memsize >> 32)
+ end_of_ram = ~0UL;
+ else
+ end_of_ram = ibm_akebono_memsize;
+ avail_ram = end_of_ram - (unsigned long)_end;
+
+ simple_alloc_init(_end, avail_ram, 128, 64);
+ platform_ops.fixups = ibm_akebono_fixups;
+ platform_ops.exit = ibm44x_dbcr_reset;
+ pir_reg = mfspr(SPRN_PIR);
+
+ /* Make sure FDT blob is sane */
+ if (fdt_check_header(_dtb_start) != 0)
+ fatal("Invalid device tree blob\n");
+
+ node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
+ "cpu", sizeof("cpu"));
+ if (!node)
+ fatal("Cannot find cpu node\n");
+ timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
+ if (timebase && (size == 4))
+ timebase_period_ns = 1000000000 / *timebase;
+
+ fdt_set_boot_cpuid_phys(_dtb_start, pir_reg);
+ fdt_init(_dtb_start);
+
+ serial_console_init();
+}
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 2e1af74..5207498 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -257,6 +257,9 @@ gamecube|wii)
treeboot-currituck)
link_address='0x1000000'
;;
+treeboot-akebono)
+ link_address='0x1000000'
+ ;;
treeboot-iss4xx-mpic)
platformo="$object/treeboot-iss4xx.o"
;;
diff --git a/arch/powerpc/configs/44x/akebono_defconfig b/arch/powerpc/configs/44x/akebono_defconfig
new file mode 100644
index 0000000..7e2530c
--- /dev/null
+++ b/arch/powerpc/configs/44x/akebono_defconfig
@@ -0,0 +1,148 @@
+CONFIG_44x=y
+CONFIG_SMP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_EXPERT=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_SLUB_CPU_PARTIAL is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_POWERNV_MSI is not set
+CONFIG_PPC_47x=y
+# CONFIG_EBONY is not set
+CONFIG_AKEBONO=y
+CONFIG_HIGHMEM=y
+CONFIG_HZ_100=y
+CONFIG_IRQ_ALL_CPUS=y
+# CONFIG_COMPACTION is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+# CONFIG_SUSPEND is not set
+CONFIG_PCI_MSI=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=35000
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_ATA_SFF is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+CONFIG_IBM_EMAC=y
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_NET_VENDOR_XILINX is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+# CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+# CONFIG_USB_DEFAULT_PERSIST is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PCI is not set
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_M41T80=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_CRAMFS=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_DEFAULT="n"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+CONFIG_PPC_EARLY_DEBUG=y
+CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW=0x00010000
+CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH=0x33f
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1_PPC=y
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index d6c7506..b734df0 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -199,6 +199,32 @@ config CURRITUCK
help
This option enables support for the IBM Currituck (476fpe) evaluation board

+config AKEBONO
+ bool "IBM Akebono (476gtr) Support"
+ depends on PPC_47x
+ default n
+ select SWIOTLB
+ select 476FPE
+ select PPC4xx_PCI_EXPRESS
+ select I2C
+ select I2C_IBM_IIC
+ select NETDEVICES
+ select ETHERNET
+ select NET_VENDOR_IBM
+ select IBM_EMAC_EMAC4
+ select IBM_EMAC_RGMII_WOL
+ select USB
+ select USB_OHCI_HCD_PLATFORM
+ select USB_EHCI_HCD_PLATFORM
+ select MMC_SDHCI
+ select MMC_SDHCI_PLTFM
+ select MMC_SDHCI_OF_476GTR
+ select ATA
+ select SATA_AHCI_PLATFORM
+ help
+ This option enables support for the IBM Akebono (476gtr) evaluation board
+
+
config ICON
bool "Icon"
depends on 44x
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index f896b89..26d35b5 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_XILINX_ML510) += virtex_ml510.o
obj-$(CONFIG_ISS4xx) += iss4xx.o
obj-$(CONFIG_CANYONLANDS)+= canyonlands.o
obj-$(CONFIG_CURRITUCK) += ppc476.o
+obj-$(CONFIG_AKEBONO) += ppc476.o
diff --git a/arch/powerpc/platforms/44x/ppc476.c b/arch/powerpc/platforms/44x/ppc476.c
index c6c5a6f..33986c1 100644
--- a/arch/powerpc/platforms/44x/ppc476.c
+++ b/arch/powerpc/platforms/44x/ppc476.c
@@ -1,7 +1,8 @@
/*
* PowerPC 476FPE board specific routines
*
- * Copyright © 2011 Tony Breeds IBM Corporation
+ * Copyright © 2013 Tony Breeds IBM Corporation
+ * Copyright © 2013 Alistair Popple IBM Corporation
*
* Based on earlier code:
* Matt Porter <[email protected]>
@@ -35,6 +36,7 @@
#include <asm/mmu.h>

#include <linux/pci.h>
+#include <linux/i2c.h>

static struct of_device_id ppc47x_of_bus[] __initdata = {
{ .compatible = "ibm,plb4", },
@@ -55,15 +57,69 @@ static void quirk_ppc_currituck_usb_fixup(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(0x1033, 0x0035, quirk_ppc_currituck_usb_fixup);

+/* Akebono has an AVR microcontroller attached to the I2C bus
+ * which is used to power off/reset the system. */
+
+/* AVR I2C Commands */
+#define AVR_PWRCTL_CMD (0x26)
+
+/* Flags for the power control I2C commands */
+#define AVR_PWRCTL_PWROFF (0x01)
+#define AVR_PWRCTL_RESET (0x02)
+
+static struct i2c_client *avr_i2c_client;
+static void avr_halt_system(int pwrctl_flags)
+{
+ /* Request the AVR to reset the system */
+ i2c_smbus_write_byte_data(avr_i2c_client,
+ AVR_PWRCTL_CMD, pwrctl_flags);
+
+ /* Wait for system to be reset */
+ while (1)
+ ;
+}
+
+static void avr_power_off_system(void)
+{
+ avr_halt_system(AVR_PWRCTL_PWROFF);
+}
+
+static void avr_reset_system(char *cmd)
+{
+ avr_halt_system(AVR_PWRCTL_RESET);
+}
+
+static int avr_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ avr_i2c_client = client;
+ ppc_md.restart = avr_reset_system;
+ ppc_md.power_off = avr_power_off_system;
+ return 0;
+}
+
+static const struct i2c_device_id avr_id[] = {
+ { "akebono-avr", 0 },
+ { }
+};
+
+static struct i2c_driver avr_driver = {
+ .driver = {
+ .name = "akebono-avr",
+ },
+ .probe = avr_probe,
+ .id_table = avr_id,
+};
+
static int __init ppc47x_device_probe(void)
{
+ i2c_add_driver(&avr_driver);
of_platform_bus_probe(NULL, ppc47x_of_bus, NULL);

return 0;
}
machine_device_initcall(ppc47x, ppc47x_device_probe);

-/* We can have either UICs or MPICs */
static void __init ppc47x_init_irq(void)
{
struct device_node *np;
@@ -163,37 +219,30 @@ static void __init ppc47x_setup_arch(void)
ppc47x_smp_init();
}

-/*
- * Called very early, MMU is off, device-tree isn't unflattened
- */
-static int __init ppc47x_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- if (!of_flat_dt_is_compatible(root, "ibm,currituck"))
- return 0;
-
- return 1;
-}
-
static int board_rev = -1;
static int __init ppc47x_get_board_rev(void)
{
- u8 fpga_reg0;
- void *fpga;
- struct device_node *np;
+ int reg;
+ u8 *fpga;
+ struct device_node *np = NULL;
+
+ if (of_machine_is_compatible("ibm,currituck")) {
+ np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
+ reg = 0;
+ } else if (of_machine_is_compatible("ibm,akebono")) {
+ np = of_find_compatible_node(NULL, NULL, "ibm,akebono-fpga");
+ reg = 2;
+ }

- np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
if (!np)
goto fail;

- fpga = of_iomap(np, 0);
+ fpga = (u8 *) of_iomap(np, 0);
of_node_put(np);
if (!fpga)
goto fail;

- fpga_reg0 = ioread8(fpga);
- board_rev = fpga_reg0 & 0x03;
+ board_rev = ioread8(fpga + reg) & 0x03;
pr_info("%s: Found board revision %d\n", __func__, board_rev);
iounmap(fpga);
return 0;
@@ -221,13 +270,30 @@ static void ppc47x_pci_irq_fixup(struct pci_dev *dev)
}
}

+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init ppc47x_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (of_flat_dt_is_compatible(root, "ibm,akebono"))
+ return 1;
+
+ if (of_flat_dt_is_compatible(root, "ibm,currituck")) {
+ ppc_md.pci_irq_fixup = ppc47x_pci_irq_fixup;
+ return 1;
+ }
+
+ return 0;
+}
+
define_machine(ppc47x) {
.name = "PowerPC 47x",
.probe = ppc47x_probe,
.progress = udbg_progress,
.init_IRQ = ppc47x_init_irq,
.setup_arch = ppc47x_setup_arch,
- .pci_irq_fixup = ppc47x_pci_irq_fixup,
.restart = ppc4xx_reset_system,
.calibrate_decr = generic_calibrate_decr,
};
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index 64603a1..54ec1d5 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -1440,7 +1440,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops;
#endif
#ifdef CONFIG_476FPE
- if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe"))
+ if (of_device_is_compatible(np, "ibm,plb-pciex-476fpe")
+ || of_device_is_compatible(np, "ibm,plb-pciex-476gtr"))
ppc4xx_pciex_hwops = &ppc_476fpe_pcie_hwops;
#endif
if (ppc4xx_pciex_hwops == NULL) {
@@ -1751,7 +1752,10 @@ static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port,
dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
sa | DCRO_PEGPL_460SX_OMR1MSKL_UOT
| DCRO_PEGPL_OMRxMSKL_VAL);
- else if (of_device_is_compatible(port->node, "ibm,plb-pciex-476fpe"))
+ else if (of_device_is_compatible(
+ port->node, "ibm,plb-pciex-476fpe") ||
+ of_device_is_compatible(
+ port->node, "ibm,plb-pciex-476gtr"))
dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL,
sa | DCRO_PEGPL_476FPE_OMR1MSKL_UOT
| DCRO_PEGPL_OMRxMSKL_VAL);
@@ -1881,7 +1885,10 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port,
sa |= PCI_BASE_ADDRESS_MEM_PREFETCH;

if (of_device_is_compatible(port->node, "ibm,plb-pciex-460sx") ||
- of_device_is_compatible(port->node, "ibm,plb-pciex-476fpe"))
+ of_device_is_compatible(
+ port->node, "ibm,plb-pciex-476fpe") ||
+ of_device_is_compatible(
+ port->node, "ibm,plb-pciex-476gtr"))
sa |= PCI_BASE_ADDRESS_MEM_TYPE_64;

out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa));
--
1.7.10.4

2014-02-21 06:40:45

by Alistair Popple

[permalink] [raw]
Subject: [PATCH 7/7] powerpc: Added PCI MSI support using the HSTA module

The PPC476GTR SoC supports message signalled interrupts (MSI) by writing
to special addresses within the High Speed Transfer Assist (HSTA) module.

This patch adds support for PCI MSI with a new system device. The DMA
window is also updated to allow access to the entire 42-bit address range
to allow PCI devices write access to the HSTA module.

Signed-off-by: Alistair Popple <[email protected]>
---
arch/powerpc/boot/dts/akebono.dts | 46 +++++--
arch/powerpc/boot/treeboot-akebono.c | 15 ---
arch/powerpc/platforms/44x/Kconfig | 2 +
arch/powerpc/sysdev/Kconfig | 6 +
arch/powerpc/sysdev/Makefile | 1 +
arch/powerpc/sysdev/ppc4xx_hsta_msi.c | 215 +++++++++++++++++++++++++++++++++
arch/powerpc/sysdev/ppc4xx_pci.c | 8 +-
7 files changed, 268 insertions(+), 25 deletions(-)
create mode 100644 arch/powerpc/sysdev/ppc4xx_hsta_msi.c

diff --git a/arch/powerpc/boot/dts/akebono.dts b/arch/powerpc/boot/dts/akebono.dts
index 9a21f58..3d14027 100644
--- a/arch/powerpc/boot/dts/akebono.dts
+++ b/arch/powerpc/boot/dts/akebono.dts
@@ -82,6 +82,28 @@
ranges;
clock-frequency = <200000000>; // 200Mhz

+ HSTA0: hsta@310000e0000 {
+ compatible = "ibm,476gtr-hsta-msi", "ibm,hsta-msi";
+ reg = <0x310 0x000e0000 0x0 0xf0>;
+ interrupt-parent = <&MPIC>;
+ interrupts = <108 0
+ 109 0
+ 110 0
+ 111 0
+ 112 0
+ 113 0
+ 114 0
+ 115 0
+ 116 0
+ 117 0
+ 118 0
+ 119 0
+ 120 0
+ 121 0
+ 122 0
+ 123 0>;
+ };
+
MAL0: mcmal {
compatible = "ibm,mcmal-476gtr", "ibm,mcmal2";
dcr-reg = <0xc0000000 0x062>;
@@ -242,8 +264,10 @@
ranges = <0x02000000 0x00000000 0x80000000 0x00000110 0x80000000 0x0 0x80000000
0x01000000 0x0 0x0 0x00000140 0x0 0x0 0x00010000>;

- /* Inbound starting at 0 to memsize filled in by zImage */
- dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
+ /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
+ * PCI devices must be able to write to the HSTA module.
+ */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;

/* This drives busses 0 to 0xf */
bus-range = <0x0 0xf>;
@@ -280,8 +304,10 @@
ranges = <0x02000000 0x00000000 0x80000000 0x00000210 0x80000000 0x0 0x80000000
0x01000000 0x0 0x0 0x00000240 0x0 0x0 0x00010000>;

- /* Inbound starting at 0 to memsize filled in by zImage */
- dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
+ /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
+ * PCI devices must be able to write to the HSTA module.
+ */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;

/* This drives busses 0 to 0xf */
bus-range = <0x0 0xf>;
@@ -318,8 +344,10 @@
ranges = <0x02000000 0x00000000 0x80000000 0x00000190 0x80000000 0x0 0x80000000
0x01000000 0x0 0x0 0x000001c0 0x0 0x0 0x00010000>;

- /* Inbound starting at 0 to memsize filled in by zImage */
- dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
+ /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
+ * PCI devices must be able to write to the HSTA module.
+ */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;

/* This drives busses 0 to 0xf */
bus-range = <0x0 0xf>;
@@ -356,8 +384,10 @@
ranges = <0x02000000 0x00000000 0x80000000 0x00000290 0x80000000 0x0 0x80000000
0x01000000 0x0 0x0 0x000002c0 0x0 0x0 0x00010000>;

- /* Inbound starting at 0 to memsize filled in by zImage */
- dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
+ /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
+ * PCI devices must be able to write to the HSTA module.
+ */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;

/* This drives busses 0 to 0xf */
bus-range = <0x0 0xf>;
diff --git a/arch/powerpc/boot/treeboot-akebono.c b/arch/powerpc/boot/treeboot-akebono.c
index d42ef8a..ac2837f 100644
--- a/arch/powerpc/boot/treeboot-akebono.c
+++ b/arch/powerpc/boot/treeboot-akebono.c
@@ -75,24 +75,9 @@ static void ibm_akebono_fixups(void)
{
void *emac;
u32 reg;
- void *devp = finddevice("/");
- u32 dma_ranges[7];

dt_fixup_memory(0x0ULL, ibm_akebono_memsize);

- while ((devp = find_node_by_devtype(devp, "pci"))) {
- if (getprop(devp, "dma-ranges", dma_ranges,
- sizeof(dma_ranges)) < 0) {
- printf("%s: Failed to get dma-ranges\r\n", __func__);
- continue;
- }
-
- dma_ranges[5] = ibm_akebono_memsize >> 32;
- dma_ranges[6] = ibm_akebono_memsize & 0xffffffffUL;
-
- setprop(devp, "dma-ranges", dma_ranges, sizeof(dma_ranges));
- }
-
/* Fixup the SD timeout frequency */
mtdcrx(CCTL0_MCO4, 0x1);

diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index b734df0..f460225 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -206,6 +206,8 @@ config AKEBONO
select SWIOTLB
select 476FPE
select PPC4xx_PCI_EXPRESS
+ select PCI_MSI
+ select PPC4xx_HSTA_MSI
select I2C
select I2C_IBM_IIC
select NETDEVICES
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 13ec968..d743bae 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -7,6 +7,12 @@ config PPC4xx_PCI_EXPRESS
depends on PCI && 4xx
default n

+config PPC4xx_HSTA_MSI
+ bool
+ depends on PCI_MSI
+ depends on PCI && 4xx
+ default n
+
config PPC4xx_MSI
bool
depends on PCI_MSI
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index f67ac90..7657fb7 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_OF_RTC) += of_rtc.o
ifeq ($(CONFIG_PCI),y)
obj-$(CONFIG_4xx) += ppc4xx_pci.o
endif
+obj-$(CONFIG_PPC4xx_HSTA_MSI) += ppc4xx_hsta_msi.o
obj-$(CONFIG_PPC4xx_MSI) += ppc4xx_msi.o
obj-$(CONFIG_PPC4xx_CPM) += ppc4xx_cpm.o
obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o
diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
new file mode 100644
index 0000000..11c8884
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
@@ -0,0 +1,215 @@
+/*
+ * MSI support for PPC4xx SoCs using High Speed Transfer Assist (HSTA) for
+ * generation of the interrupt.
+ *
+ * Copyright © 2013 Alistair Popple <[email protected]> IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/semaphore.h>
+#include <asm/msi_bitmap.h>
+
+struct ppc4xx_hsta_msi {
+ struct device *dev;
+
+ /* The ioremapped HSTA MSI IO space */
+ u32 __iomem *data;
+
+ /* Physical address of HSTA MSI IO space */
+ u64 address;
+ struct msi_bitmap bmp;
+
+ /* An array mapping offsets to hardware IRQs */
+ int *irq_map;
+
+ /* Number of hwirqs supported */
+ int irq_count;
+};
+static struct ppc4xx_hsta_msi ppc4xx_hsta_msi;
+
+static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ struct msi_msg msg;
+ struct msi_desc *entry;
+ int irq, hwirq;
+ u64 addr;
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1);
+ if (irq < 0) {
+ pr_debug("%s: Failed to allocate msi interrupt\n",
+ __func__);
+ return irq;
+ }
+
+ hwirq = ppc4xx_hsta_msi.irq_map[irq];
+ if (hwirq == NO_IRQ) {
+ pr_err("%s: Failed mapping irq %d\n", __func__, irq);
+ return -EINVAL;
+ }
+
+ /*
+ * HSTA generates interrupts on writes to 128-bit aligned
+ * addresses.
+ */
+ addr = ppc4xx_hsta_msi.address + irq*0x10;
+ msg.address_hi = upper_32_bits(addr);
+ msg.address_lo = lower_32_bits(addr);
+
+ /* Data is not used by the HSTA. */
+ msg.data = 0;
+
+ pr_debug("%s: Setup irq %d (0x%0llx)\n", __func__, hwirq,
+ (((u64) msg.address_hi) << 32) | msg.address_lo);
+
+ if (irq_set_msi_desc(hwirq, entry)) {
+ pr_err(
+ "%s: Invalid hwirq %d specified in device tree\n",
+ __func__, hwirq);
+ msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
+ return -EINVAL;
+ }
+ write_msi_msg(hwirq, &msg);
+ }
+
+ return 0;
+}
+
+static int hsta_find_hwirq_offset(int hwirq)
+{
+ int irq;
+
+ /* Find the offset given the hwirq */
+ for (irq = 0; irq < ppc4xx_hsta_msi.irq_count; irq++)
+ if (ppc4xx_hsta_msi.irq_map[irq] == hwirq)
+ return irq;
+
+ return -EINVAL;
+}
+
+static void hsta_teardown_msi_irqs(struct pci_dev *dev)
+{
+ struct msi_desc *entry;
+ int irq;
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ if (entry->irq == NO_IRQ)
+ continue;
+
+ irq = hsta_find_hwirq_offset(entry->irq);
+
+ /* entry->irq should always be in irq_map */
+ BUG_ON(irq < 0);
+ irq_set_msi_desc(entry->irq, NULL);
+ msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
+ pr_debug("%s: Teardown IRQ %u (index %u)\n", __func__,
+ entry->irq, irq);
+ }
+}
+
+static int hsta_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+ /* We don't support MSI-X */
+ if (type == PCI_CAP_ID_MSIX) {
+ pr_debug("%s: MSI-X not supported.\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hsta_msi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *mem;
+ int irq, ret, irq_count;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (IS_ERR(mem)) {
+ dev_err(dev, "Unable to get mmio space\n");
+ return -EINVAL;
+ }
+
+ irq_count = of_irq_count(dev->of_node);
+ if (!irq_count) {
+ dev_err(dev, "Unable to find IRQ range\n");
+ return -EINVAL;
+ }
+
+ ppc4xx_hsta_msi.dev = dev;
+ ppc4xx_hsta_msi.address = mem->start;
+ ppc4xx_hsta_msi.data = ioremap(mem->start, resource_size(mem));
+ ppc4xx_hsta_msi.irq_count = irq_count;
+ if (IS_ERR(ppc4xx_hsta_msi.data)) {
+ dev_err(dev, "Unable to map memory\n");
+ return -ENOMEM;
+ }
+
+ ret = msi_bitmap_alloc(&ppc4xx_hsta_msi.bmp, irq_count, dev->of_node);
+ if (ret)
+ goto out;
+
+ ppc4xx_hsta_msi.irq_map = kmalloc(sizeof(int) * irq_count, GFP_KERNEL);
+ if (IS_ERR(ppc4xx_hsta_msi.irq_map)) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ /* Setup a mapping from irq offsets to hardware irq numbers */
+ for (irq = 0; irq < irq_count; irq++) {
+ ppc4xx_hsta_msi.irq_map[irq] =
+ irq_of_parse_and_map(dev->of_node, irq);
+ if (ppc4xx_hsta_msi.irq_map[irq] == NO_IRQ) {
+ dev_err(dev, "Unable to map IRQ\n");
+ ret = -EINVAL;
+ goto out2;
+ }
+ }
+
+ ppc_md.setup_msi_irqs = hsta_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = hsta_teardown_msi_irqs;
+ ppc_md.msi_check_device = hsta_msi_check_device;
+ return 0;
+
+out2:
+ kfree(ppc4xx_hsta_msi.irq_map);
+
+out1:
+ msi_bitmap_free(&ppc4xx_hsta_msi.bmp);
+
+out:
+ iounmap(ppc4xx_hsta_msi.data);
+ return ret;
+}
+
+static const struct of_device_id hsta_msi_ids[] = {
+ {
+ .compatible = "ibm,hsta-msi",
+ },
+ {}
+};
+
+static struct platform_driver hsta_msi_driver = {
+ .probe = hsta_msi_probe,
+ .driver = {
+ .name = "hsta-msi",
+ .owner = THIS_MODULE,
+ .of_match_table = hsta_msi_ids,
+ },
+};
+
+static int hsta_msi_init(void)
+{
+ return platform_driver_register(&hsta_msi_driver);
+}
+subsys_initcall(hsta_msi_init);
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index 54ec1d5..7cc3acc 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -176,8 +176,12 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
return -ENXIO;
}

- /* Check that we are fully contained within 32 bits space */
- if (res->end > 0xffffffff) {
+ /* Check that we are fully contained within 32 bits space if we are not
+ * running on a 460sx or 476fpe which have 64 bit bus addresses.
+ */
+ if (res->end > 0xffffffff &&
+ !(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx")
+ || of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) {
printk(KERN_ERR "%s: dma-ranges outside of 32 bits space\n",
hose->dn->full_name);
return -ENXIO;
--
1.7.10.4

2014-02-21 06:40:01

by Alistair Popple

[permalink] [raw]
Subject: [PATCH 4/7] ECHI Platform: Merge ppc-of EHCI driver into the ehci-platform driver

Currently the ppc-of driver uses the compatibility string
"usb-ehci". This means platforms that use device-tree and implement an
EHCI compatible interface have to either use the ppc-of driver or add
a compatible line to the ehci-platform driver. It would be more
appropriate for the platform driver to be compatible with "usb-ehci"
as non-powerpc platforms are also beginning to utilise device-tree.

This patch merges the device tree property parsing from ehci-ppc-of
into the platform driver and adds a "usb-ehci" compatibility
string. The existing ehci-ppc-of driver is removed and the 440EPX
specific quirks are added to the ehci-platform driver.

Signed-off-by: Alistair Popple <[email protected]>
---
drivers/usb/host/Kconfig | 7 +-
drivers/usb/host/ehci-hcd.c | 5 -
drivers/usb/host/ehci-platform.c | 87 +++++++++++++-
drivers/usb/host/ehci-ppc-of.c | 238 --------------------------------------
4 files changed, 89 insertions(+), 248 deletions(-)
delete mode 100644 drivers/usb/host/ehci-ppc-of.c

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index a9707da..5d9b3ff 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -189,12 +189,13 @@ config USB_EHCI_TEGRA
found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.

config USB_EHCI_HCD_PPC_OF
- bool "EHCI support for PPC USB controller on OF platform bus"
+ bool "EHCI support for PPC USB controller on OF platform bus (DEPRECATED)"
depends on PPC_OF
default y
+ select USB_EHCI_HCD_PLATFORM
---help---
- Enables support for the USB controller present on the PowerPC
- OpenFirmware platform bus.
+ This option is deprecated now and the driver was removed, use
+ USB_EHCI_HCD_PLATFORM instead.

config USB_EHCI_SH
bool "EHCI support for SuperH USB controller"
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index e8ba4c4..b2bbd4b 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1261,11 +1261,6 @@ MODULE_LICENSE ("GPL");
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
#endif

-#ifdef CONFIG_USB_EHCI_HCD_PPC_OF
-#include "ehci-ppc-of.c"
-#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver
-#endif
-
#ifdef CONFIG_XPS_USB_HCD_XILINX
#include "ehci-xilinx-of.c"
#define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 7f30b71..71959eb 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -25,6 +25,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@@ -36,11 +37,33 @@

static const char hcd_name[] = "ehci-platform";

+/*
+ * 440EPx Errata USBH_3
+ * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
+ */
+#define PPC440EPX_EHCI0_INSREG_BMT (0x1 << 0)
+static int
+ppc44x_enable_bmt(struct device_node *dn)
+{
+ __iomem u32 *insreg_virt;
+
+ insreg_virt = of_iomap(dn, 1);
+ if (!insreg_virt)
+ return -EINVAL;
+
+ out_be32(insreg_virt + 3, PPC440EPX_EHCI0_INSREG_BMT);
+
+ iounmap(insreg_virt);
+ return 0;
+}
+
static int ehci_platform_reset(struct usb_hcd *hcd)
{
struct platform_device *pdev = to_platform_device(hcd->self.controller);
struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct device_node *dn, *np;
+ struct resource res;
int retval;

hcd->has_tt = pdata->has_tt;
@@ -48,6 +71,43 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
ehci->big_endian_desc = pdata->big_endian_desc;
ehci->big_endian_mmio = pdata->big_endian_mmio;

+ /* Device tree properties if available will override platform data. */
+ dn = hcd_to_bus(hcd)->controller->of_node;
+ if (dn) {
+ if (of_get_property(dn, "big-endian", NULL)) {
+ ehci->big_endian_mmio = 1;
+ ehci->big_endian_desc = 1;
+ }
+ if (of_get_property(dn, "big-endian-regs", NULL))
+ ehci->big_endian_mmio = 1;
+ if (of_get_property(dn, "big-endian-desc", NULL))
+ ehci->big_endian_desc = 1;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
+ if (np != NULL) {
+ /* claim we really affected by usb23 erratum */
+ if (!of_address_to_resource(np, 0, &res))
+ ehci->ohci_hcctrl_reg =
+ devm_ioremap(&pdev->dev,
+ res.start + OHCI_HCCTRL_OFFSET,
+ OHCI_HCCTRL_LEN);
+ else
+ ehci_dbg(ehci, "%s: no ohci offset in fdt\n", __FILE__);
+ if (!ehci->ohci_hcctrl_reg) {
+ ehci_dbg(ehci, "%s: ioremap for ohci hcctrl failed\n",
+ __FILE__);
+ } else {
+ ehci->has_amcc_usb23 = 1;
+ }
+ }
+
+ if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
+ retval = ppc44x_enable_bmt(dn);
+ ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n",
+ retval ? "NOT " : "");
+ }
+
if (pdata->pre_setup) {
retval = pdata->pre_setup(hcd);
if (retval < 0)
@@ -149,6 +209,9 @@ static int ehci_platform_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct device_node *np;
+ struct resource res;

usb_remove_hcd(hcd);
usb_put_hcd(hcd);
@@ -159,6 +222,25 @@ static int ehci_platform_remove(struct platform_device *dev)
if (pdata == &ehci_platform_defaults)
dev->dev.platform_data = NULL;

+ /* use request_mem_region to test if the ohci driver is loaded. if so
+ * ensure the ohci core is operational.
+ */
+ if (ehci->has_amcc_usb23) {
+ np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
+ if (np != NULL) {
+ if (!of_address_to_resource(np, 0, &res))
+ if (!request_mem_region(res.start,
+ 0x4, hcd_name))
+ set_ohci_hcfs(ehci, 1);
+ else
+ release_mem_region(res.start, 0x4);
+ else
+ ehci_dbg(ehci, "%s: no ohci offset in fdt\n",
+ __FILE__);
+ of_node_put(np);
+ }
+ }
+
return 0;
}

@@ -203,9 +285,10 @@ static int ehci_platform_resume(struct device *dev)
#define ehci_platform_resume NULL
#endif /* CONFIG_PM */

-static const struct of_device_id vt8500_ehci_ids[] = {
+static const struct of_device_id ehci_platform_ids[] = {
{ .compatible = "via,vt8500-ehci", },
{ .compatible = "wm,prizm-ehci", },
+ { .compatible = "usb-ehci", },
{}
};

@@ -229,7 +312,7 @@ static struct platform_driver ehci_platform_driver = {
.owner = THIS_MODULE,
.name = "ehci-platform",
.pm = &ehci_platform_pm_ops,
- .of_match_table = vt8500_ehci_ids,
+ .of_match_table = ehci_platform_ids,
}
};

diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
deleted file mode 100644
index 875d2fc..0000000
--- a/drivers/usb/host/ehci-ppc-of.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * EHCI HCD (Host Controller Driver) for USB.
- *
- * Bus Glue for PPC On-Chip EHCI driver on the of_platform bus
- * Tested on AMCC PPC 440EPx
- *
- * Valentine Barshak <[email protected]>
- *
- * Based on "ehci-ppc-soc.c" by Stefan Roese <[email protected]>
- * and "ohci-ppc-of.c" by Sylvain Munaut <[email protected]>
- *
- * This file is licenced under the GPL.
- */
-
-#include <linux/err.h>
-#include <linux/signal.h>
-
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-
-
-static const struct hc_driver ehci_ppc_of_hc_driver = {
- .description = hcd_name,
- .product_desc = "OF EHCI",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
-
- /*
- * basic lifecycle operations
- */
- .reset = ehci_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
-#endif
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
-
-/*
- * 440EPx Errata USBH_3
- * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
- */
-#define PPC440EPX_EHCI0_INSREG_BMT (0x1 << 0)
-static int
-ppc44x_enable_bmt(struct device_node *dn)
-{
- __iomem u32 *insreg_virt;
-
- insreg_virt = of_iomap(dn, 1);
- if (!insreg_virt)
- return -EINVAL;
-
- out_be32(insreg_virt + 3, PPC440EPX_EHCI0_INSREG_BMT);
-
- iounmap(insreg_virt);
- return 0;
-}
-
-
-static int ehci_hcd_ppc_of_probe(struct platform_device *op)
-{
- struct device_node *dn = op->dev.of_node;
- struct usb_hcd *hcd;
- struct ehci_hcd *ehci = NULL;
- struct resource res;
- int irq;
- int rv;
-
- struct device_node *np;
-
- if (usb_disabled())
- return -ENODEV;
-
- dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
-
- rv = of_address_to_resource(dn, 0, &res);
- if (rv)
- return rv;
-
- hcd = usb_create_hcd(&ehci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
- if (!hcd)
- return -ENOMEM;
-
- hcd->rsrc_start = res.start;
- hcd->rsrc_len = resource_size(&res);
-
- irq = irq_of_parse_and_map(dn, 0);
- if (irq == NO_IRQ) {
- printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
- rv = -EBUSY;
- goto err_irq;
- }
-
- hcd->regs = devm_ioremap_resource(&op->dev, &res);
- if (IS_ERR(hcd->regs)) {
- rv = PTR_ERR(hcd->regs);
- goto err_ioremap;
- }
-
- ehci = hcd_to_ehci(hcd);
- np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
- if (np != NULL) {
- /* claim we really affected by usb23 erratum */
- if (!of_address_to_resource(np, 0, &res))
- ehci->ohci_hcctrl_reg =
- devm_ioremap(&op->dev,
- res.start + OHCI_HCCTRL_OFFSET,
- OHCI_HCCTRL_LEN);
- else
- pr_debug("%s: no ohci offset in fdt\n", __FILE__);
- if (!ehci->ohci_hcctrl_reg) {
- pr_debug("%s: ioremap for ohci hcctrl failed\n", __FILE__);
- } else {
- ehci->has_amcc_usb23 = 1;
- }
- }
-
- if (of_get_property(dn, "big-endian", NULL)) {
- ehci->big_endian_mmio = 1;
- ehci->big_endian_desc = 1;
- }
- if (of_get_property(dn, "big-endian-regs", NULL))
- ehci->big_endian_mmio = 1;
- if (of_get_property(dn, "big-endian-desc", NULL))
- ehci->big_endian_desc = 1;
-
- ehci->caps = hcd->regs;
-
- if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
- rv = ppc44x_enable_bmt(dn);
- ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n",
- rv ? "NOT ": "");
- }
-
- rv = usb_add_hcd(hcd, irq, 0);
- if (rv)
- goto err_ioremap;
-
- return 0;
-
-err_ioremap:
- irq_dispose_mapping(irq);
-err_irq:
- usb_put_hcd(hcd);
-
- return rv;
-}
-
-
-static int ehci_hcd_ppc_of_remove(struct platform_device *op)
-{
- struct usb_hcd *hcd = platform_get_drvdata(op);
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-
- struct device_node *np;
- struct resource res;
-
- dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
-
- usb_remove_hcd(hcd);
-
- irq_dispose_mapping(hcd->irq);
-
- /* use request_mem_region to test if the ohci driver is loaded. if so
- * ensure the ohci core is operational.
- */
- if (ehci->has_amcc_usb23) {
- np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
- if (np != NULL) {
- if (!of_address_to_resource(np, 0, &res))
- if (!request_mem_region(res.start,
- 0x4, hcd_name))
- set_ohci_hcfs(ehci, 1);
- else
- release_mem_region(res.start, 0x4);
- else
- pr_debug("%s: no ohci offset in fdt\n", __FILE__);
- of_node_put(np);
- }
- }
- usb_put_hcd(hcd);
-
- return 0;
-}
-
-
-static const struct of_device_id ehci_hcd_ppc_of_match[] = {
- {
- .compatible = "usb-ehci",
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
-
-
-static struct platform_driver ehci_hcd_ppc_of_driver = {
- .probe = ehci_hcd_ppc_of_probe,
- .remove = ehci_hcd_ppc_of_remove,
- .shutdown = usb_hcd_platform_shutdown,
- .driver = {
- .name = "ppc-of-ehci",
- .owner = THIS_MODULE,
- .of_match_table = ehci_hcd_ppc_of_match,
- },
-};
--
1.7.10.4

2014-02-21 06:39:56

by Alistair Popple

[permalink] [raw]
Subject: [PATCH 3/7] IBM Akebono: Add support to the OHCI platform driver for PPC476GTR

The IBM Akebono board uses the PPC476GTR SoC which has a OHCI
compliant USB host interface. This patch adds support for it to the
OHCI platform driver.

As we use device tree to pass platform specific data instead of
platform data we remove the check for platform data and instead
provide reasonable defaults if no platform data is present. This is
similar to what is currently done in ehci-platform.c.

Signed-off-by: Alistair Popple <[email protected]>
Acked-by: Alan Stern <[email protected]>
---
drivers/usb/host/ohci-platform.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index f351ff5..e5a5979 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -23,6 +23,8 @@
#include <linux/usb/ohci_pdriver.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
+#include <linux/slab.h>
+#include <linux/of.h>

#include "ohci.h"

@@ -55,6 +57,8 @@ static const struct ohci_driver_overrides platform_overrides __initconst = {
.reset = ohci_platform_reset,
};

+static struct usb_ohci_pdata ohci_platform_defaults;
+
static int ohci_platform_probe(struct platform_device *dev)
{
struct usb_hcd *hcd;
@@ -63,14 +67,16 @@ static int ohci_platform_probe(struct platform_device *dev)
int irq;
int err = -ENOMEM;

- if (!pdata) {
- WARN_ON(1);
- return -ENODEV;
- }
-
if (usb_disabled())
return -ENODEV;

+ /*
+ * Platforms using DT don't always provide platform data.
+ * This should provide reasonable defaults.
+ */
+ if (!pdata)
+ dev->dev.platform_data = pdata = &ohci_platform_defaults;
+
irq = platform_get_irq(dev, 0);
if (irq < 0) {
dev_err(&dev->dev, "no irq provided");
@@ -178,6 +184,11 @@ static int ohci_platform_resume(struct device *dev)
#define ohci_platform_resume NULL
#endif /* CONFIG_PM */

+static const struct of_device_id ohci_of_match[] = {
+ { .compatible = "usb-ohci", },
+ {},
+};
+
static const struct platform_device_id ohci_platform_table[] = {
{ "ohci-platform", 0 },
{ }
@@ -198,6 +209,7 @@ static struct platform_driver ohci_platform_driver = {
.owner = THIS_MODULE,
.name = "ohci-platform",
.pm = &ohci_platform_pm_ops,
+ .of_match_table = ohci_of_match,
}
};

--
1.7.10.4

2014-02-21 06:42:32

by Alistair Popple

[permalink] [raw]
Subject: [PATCH 1/7] IBM Akebono: Add a SDHCI platform driver

This patch adds a SDHCI platform driver for the new IBM PPC476GTR SoC
which is on the Akebono board.

Signed-off-by: Alistair Popple <[email protected]>
---
drivers/mmc/host/Kconfig | 12 ++++++++
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/sdhci-of-476gtr.c | 60 ++++++++++++++++++++++++++++++++++++
3 files changed, 73 insertions(+)
create mode 100644 drivers/mmc/host/sdhci-of-476gtr.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 7fc5099..14210df 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -130,6 +130,18 @@ config MMC_SDHCI_OF_HLWD

If unsure, say N.

+config MMC_SDHCI_OF_476GTR
+ tristate "SDHCI OF support for the IBM PPC476GTR SoC"
+ depends on MMC_SDHCI_PLTFM
+ depends on PPC_OF
+ help
+ This selects the Secure Digital Host Controller Interface (SDHCI)
+ found on the PPC476GTR SoC.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
config MMC_SDHCI_CNS3XXX
tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
depends on ARCH_CNS3XXX
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index c41d0c3..92beff3 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
+obj-$(CONFIG_MMC_SDHCI_OF_476GTR) += sdhci-of-476gtr.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o

diff --git a/drivers/mmc/host/sdhci-of-476gtr.c b/drivers/mmc/host/sdhci-of-476gtr.c
new file mode 100644
index 0000000..1310f8c
--- /dev/null
+++ b/drivers/mmc/host/sdhci-of-476gtr.c
@@ -0,0 +1,60 @@
+/*
+ * drivers/mmc/host/sdhci-of-476gtr.c
+ *
+ * Copyright © 2013 Alistair Popple <[email protected]> IBM Corporation
+ *
+ * Based on sdhci-of-hlwd.c
+ *
+ * Copyright (C) 2009 The GameCube Linux Team
+ * Copyright (C) 2009 Albert Herranz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mmc/host.h>
+#include "sdhci-pltfm.h"
+
+static const struct sdhci_ops sdhci_476gtr_ops = {
+};
+
+static const struct sdhci_pltfm_data sdhci_476gtr_pdata = {
+ .ops = &sdhci_476gtr_ops,
+};
+
+static int sdhci_476gtr_probe(struct platform_device *pdev)
+{
+ return sdhci_pltfm_register(pdev, &sdhci_476gtr_pdata, 0);
+}
+
+static int sdhci_476gtr_remove(struct platform_device *pdev)
+{
+ return sdhci_pltfm_unregister(pdev);
+}
+
+static const struct of_device_id sdhci_476gtr_of_match[] = {
+ { .compatible = "ibm,476gtr-sdhci" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sdhci_476gtr_of_match);
+
+static struct platform_driver sdhci_476gtr_driver = {
+ .driver = {
+ .name = "sdhci-476gtr",
+ .owner = THIS_MODULE,
+ .of_match_table = sdhci_476gtr_of_match,
+ .pm = SDHCI_PLTFM_PMOPS,
+ },
+ .probe = sdhci_476gtr_probe,
+ .remove = sdhci_476gtr_remove,
+};
+
+module_platform_driver(sdhci_476gtr_driver);
+
+MODULE_DESCRIPTION("PPC476GTR SDHCI OF driver");
+MODULE_AUTHOR("Alistair Popple");
+MODULE_LICENSE("GPL v2");
--
1.7.10.4

2014-02-21 11:18:48

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH 2/7] IBM Akebono: Add support for a new PHY interface to the IBM emac driver

On Fri, Feb 21, 2014 at 06:31:28AM +0000, Alistair Popple wrote:
> The IBM PPC476GTR SoC that is used on the Akebono board uses a
> different ethernet PHY interface that has wake on lan (WOL) support
> with the IBM emac. This patch adds support to the IBM emac driver for
> this new PHY interface.
>
> At this stage the wake on lan functionality has not been implemented.
>
> Signed-off-by: Alistair Popple <[email protected]>
> Acked-by: Benjamin Herrenschmidt <[email protected]>
> Cc: "David S. Miller" <[email protected]>
> ---

[...]

> + /* Check for RGMII flags */
> + if (of_get_property(ofdev->dev.of_node, "has-mdio", NULL))
> + dev->flags |= EMAC_RGMII_FLAG_HAS_MDIO;

You can use of_property_read_bool here.

Cheers,
Mark.

2014-02-21 11:48:28

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH 4/7] ECHI Platform: Merge ppc-of EHCI driver into the ehci-platform driver

[Adding Tony Prisk to Cc]

On Fri, Feb 21, 2014 at 06:31:30AM +0000, Alistair Popple wrote:
> Currently the ppc-of driver uses the compatibility string
> "usb-ehci". This means platforms that use device-tree and implement an
> EHCI compatible interface have to either use the ppc-of driver or add
> a compatible line to the ehci-platform driver. It would be more
> appropriate for the platform driver to be compatible with "usb-ehci"
> as non-powerpc platforms are also beginning to utilise device-tree.
>
> This patch merges the device tree property parsing from ehci-ppc-of
> into the platform driver and adds a "usb-ehci" compatibility
> string. The existing ehci-ppc-of driver is removed and the 440EPX
> specific quirks are added to the ehci-platform driver.
>
> Signed-off-by: Alistair Popple <[email protected]>
> ---
> drivers/usb/host/Kconfig | 7 +-
> drivers/usb/host/ehci-hcd.c | 5 -
> drivers/usb/host/ehci-platform.c | 87 +++++++++++++-
> drivers/usb/host/ehci-ppc-of.c | 238 --------------------------------------
> 4 files changed, 89 insertions(+), 248 deletions(-)
> delete mode 100644 drivers/usb/host/ehci-ppc-of.c

[...]

> + /* Device tree properties if available will override platform data. */
> + dn = hcd_to_bus(hcd)->controller->of_node;
> + if (dn) {
> + if (of_get_property(dn, "big-endian", NULL)) {
> + ehci->big_endian_mmio = 1;
> + ehci->big_endian_desc = 1;
> + }
> + if (of_get_property(dn, "big-endian-regs", NULL))
> + ehci->big_endian_mmio = 1;
> + if (of_get_property(dn, "big-endian-desc", NULL))
> + ehci->big_endian_desc = 1;
> + }

Please use of_property_read_bool for these.

This driver already handles "via,vt8500-ehci" and "wm,prizm-ehci" which
aren't documented to handle these properties, but now gain support for
them. It might be worth unifying the binding documents if there's
nothing special about those two host controllers.

We seem to have two binding documents for "via,vt8500-ehci", so some
cleanup is definitely in order.

Tony, you seem to have written both documents judging by 95e9fd10f06c
and 8ad551d150e3. Do you have any issue with merging both of these into
a common usb-ehci document?

> +
> + np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
> + if (np != NULL) {
> + /* claim we really affected by usb23 erratum */
> + if (!of_address_to_resource(np, 0, &res))
> + ehci->ohci_hcctrl_reg =
> + devm_ioremap(&pdev->dev,
> + res.start + OHCI_HCCTRL_OFFSET,
> + OHCI_HCCTRL_LEN);
> + else
> + ehci_dbg(ehci, "%s: no ohci offset in fdt\n", __FILE__);
> + if (!ehci->ohci_hcctrl_reg) {
> + ehci_dbg(ehci, "%s: ioremap for ohci hcctrl failed\n",
> + __FILE__);
> + } else {
> + ehci->has_amcc_usb23 = 1;
> + }
> + }

As this is being dropped into a generic driver, it would be nice to have
a comment explaining why we need to do this -- not everyone using this
will know the powerpc history. It certainly seems odd to look for
another node in the tree that this driver isn't necessarily handling,
and that should probably be explained.

As this bit of fixup is only needed for powerpc, it would be nice to not
have to do it elsewhere. Perhaps these could be factored out into a
ppc_platform_reset function that could be empty stub for other
architectures.

> +
> + if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
> + retval = ppc44x_enable_bmt(dn);
> + ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n",
> + retval ? "NOT " : "");
> + }
> +

Likewise.

[...]

> + /* use request_mem_region to test if the ohci driver is loaded. if so
> + * ensure the ohci core is operational.
> + */

Nit: comment code style (should have a newline after the /* according to
Documentation/CodingStyle).

> + if (ehci->has_amcc_usb23) {
> + np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
> + if (np != NULL) {
> + if (!of_address_to_resource(np, 0, &res))
> + if (!request_mem_region(res.start,
> + 0x4, hcd_name))
> + set_ohci_hcfs(ehci, 1);
> + else
> + release_mem_region(res.start, 0x4);
> + else
> + ehci_dbg(ehci, "%s: no ohci offset in fdt\n",
> + __FILE__);
> + of_node_put(np);
> + }
> + }

As with the earlier comment, this looks a bit odd. A comment explaining
why we're looking for another node would help. Also, we should only need
this for powerpc.

Cheers,
Mark.

2014-02-21 14:15:12

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 1/7] IBM Akebono: Add a SDHCI platform driver

On Friday 21 February 2014 17:31:27 Alistair Popple wrote:

>
> +config MMC_SDHCI_OF_476GTR
> + tristate "SDHCI OF support for the IBM PPC476GTR SoC"
> + depends on MMC_SDHCI_PLTFM
> + depends on PPC_OF
> + help
> + This selects the Secure Digital Host Controller Interface (SDHCI)
> + found on the PPC476GTR SoC.
> +
> + If you have a controller with this interface, say Y or M here.
> +
> + If unsure, say N.

Your driver doesn't actually do anything beyond what is in the common
sdhci-pltfm.c infrastructure. IMHO you really shoulnd't need a SoC
specific abstraction for it at all and instead add a generic
platform driver registration into sdhci-pltfm.c. I'd suggest
you use "generic-sdhci" (similar to what we do for usb-ohci and usb-ehci
now) as the compatible string and change your device tree to claim
compatibility with that and your soc-specific string.

Arnd

2014-02-21 14:16:57

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 3/7] IBM Akebono: Add support to the OHCI platform driver for PPC476GTR

On Friday 21 February 2014 17:31:29 Alistair Popple wrote:
>
> +static const struct of_device_id ohci_of_match[] = {
> + { .compatible = "usb-ohci", },
> + {},
> +};
> +
> static const struct platform_device_id ohci_platform_table[] = {
> { "ohci-platform", 0 },
> { }
> @@ -198,6 +209,7 @@ static struct platform_driver ohci_platform_driver = {
> .owner = THIS_MODULE,
> .name = "ohci-platform",
> .pm = &ohci_platform_pm_ops,
> + .of_match_table = ohci_of_match,
> }
> };
>
>

Linux-next already has a patch to add an of_match_table in this driver,
using

static const struct of_device_id ohci_platform_ids[] = {
{ .compatible = "generic-ohci", },
{ }
};

I think you should just use that string on your platform.

Arnd

2014-02-21 14:21:42

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 4/7] ECHI Platform: Merge ppc-of EHCI driver into the ehci-platform driver

On Friday 21 February 2014 11:48:03 Mark Rutland wrote:
> > +
> > + np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
> > + if (np != NULL) {
> > + /* claim we really affected by usb23 erratum */
> > + if (!of_address_to_resource(np, 0, &res))
> > + ehci->ohci_hcctrl_reg =
> > + devm_ioremap(&pdev->dev,
> > + res.start + OHCI_HCCTRL_OFFSET,
> > + OHCI_HCCTRL_LEN);
> > + else
> > + ehci_dbg(ehci, "%s: no ohci offset in fdt\n", __FILE__);
> > + if (!ehci->ohci_hcctrl_reg) {
> > + ehci_dbg(ehci, "%s: ioremap for ohci hcctrl failed\n",
> > + __FILE__);
> > + } else {
> > + ehci->has_amcc_usb23 = 1;
> > + }
> > + }
>
> As this is being dropped into a generic driver, it would be nice to have
> a comment explaining why we need to do this -- not everyone using this
> will know the powerpc history. It certainly seems odd to look for
> another node in the tree that this driver isn't necessarily handling,
> and that should probably be explained.
>
> As this bit of fixup is only needed for powerpc, it would be nice to not
> have to do it elsewhere. Perhaps these could be factored out into a
> ppc_platform_reset function that could be empty stub for other
> architectures.

How about using the .data field of the of_device_id array to point to
a structure of functions? That way you don't even have to call
of_device_is_compatible() here. Note that using of_find_compatible_node()
is the wrong approach anyway, you want to check the current device
for compatibility, not just any device I assume.

Arnd

2014-02-21 14:34:26

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 7/7] powerpc: Added PCI MSI support using the HSTA module

On Friday 21 February 2014 17:31:33 Alistair Popple wrote:
>
> + HSTA0: hsta@310000e0000 {
> + compatible = "ibm,476gtr-hsta-msi", "ibm,hsta-msi";
> + reg = <0x310 0x000e0000 0x0 0xf0>;
> + interrupt-parent = <&MPIC>;
> + interrupts = <108 0
> + 109 0
> + 110 0
> + 111 0
> + 112 0
> + 113 0
> + 114 0
> + 115 0
> + 116 0
> + 117 0
> + 118 0
> + 119 0
> + 120 0
> + 121 0
> + 122 0
> + 123 0>;
> + };

Please add a binding to Documentation/devicetree for this device.

> @@ -242,8 +264,10 @@
> ranges = <0x02000000 0x00000000 0x80000000 0x00000110 0x80000000 0x0 0x80000000
> 0x01000000 0x0 0x0 0x00000140 0x0 0x0 0x00010000>;
>
> - /* Inbound starting at 0 to memsize filled in by zImage */
> - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
> + /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
> + * PCI devices must be able to write to the HSTA module.
> + */
> + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
>
> /* This drives busses 0 to 0xf */
> bus-range = <0x0 0xf>;

Ah, I first only saw the line you are removing and was about
to suggest what you do anyway. Great!

> diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
> index 54ec1d5..7cc3acc 100644
> --- a/arch/powerpc/sysdev/ppc4xx_pci.c
> +++ b/arch/powerpc/sysdev/ppc4xx_pci.c
> @@ -176,8 +176,12 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
> return -ENXIO;
> }
>
> - /* Check that we are fully contained within 32 bits space */
> - if (res->end > 0xffffffff) {
> + /* Check that we are fully contained within 32 bits space if we are not
> + * running on a 460sx or 476fpe which have 64 bit bus addresses.
> + */
> + if (res->end > 0xffffffff &&
> + !(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx")
> + || of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) {
> printk(KERN_ERR "%s: dma-ranges outside of 32 bits space\n",
> hose->dn->full_name);
> return -ENXIO;

A more general question for BenH: Apparently this PCI implementation is
getting reused on arm64 for APM X-Gene. Do you see any value in trying to
share host controller drivers like this one across powerpc and arm64?

It's possible we are going to see the same situation with fsl_pci in the
future, if arm and powerpc qoriq chips use the same peripherals. My
plan for arm64 right now is to make PCI work without any code in arch/,
just using new helper functions in drivers/pci and sticking the host
drivers into drivers/pci/host as we started doing for arm32, but it
can require significant work to make those drivers compatible with
the powerpc pci-common.c.

Arnd

2014-02-21 15:34:34

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH 3/7] IBM Akebono: Add support to the OHCI platform driver for PPC476GTR

On Fri, 21 Feb 2014, Alistair Popple wrote:

> The IBM Akebono board uses the PPC476GTR SoC which has a OHCI
> compliant USB host interface. This patch adds support for it to the
> OHCI platform driver.
>
> As we use device tree to pass platform specific data instead of
> platform data we remove the check for platform data and instead
> provide reasonable defaults if no platform data is present. This is
> similar to what is currently done in ehci-platform.c.
>
> Signed-off-by: Alistair Popple <[email protected]>
> Acked-by: Alan Stern <[email protected]>

As Arnd pointed out, this patch is out of date. See

https://git.kernel.org/cgit/linux/kernel/git/gregkh/usb.git/commit/drivers/usb/host/ohci-platform.c?h=usb-next&id=ca52a17ba975dbf47e87c9bc63086aca0cf92806

and

https://git.kernel.org/cgit/linux/kernel/git/gregkh/usb.git/commit/drivers/usb/host/ohci-platform.c?h=usb-next&id=ce149c30b9f89d0c9addd1d71ccdb57c1051553b

Alan Stern

2014-02-21 15:41:53

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH 4/7] ECHI Platform: Merge ppc-of EHCI driver into the ehci-platform driver

On Fri, 21 Feb 2014, Alistair Popple wrote:

> Currently the ppc-of driver uses the compatibility string
> "usb-ehci". This means platforms that use device-tree and implement an
> EHCI compatible interface have to either use the ppc-of driver or add
> a compatible line to the ehci-platform driver. It would be more
> appropriate for the platform driver to be compatible with "usb-ehci"
> as non-powerpc platforms are also beginning to utilise device-tree.
>
> This patch merges the device tree property parsing from ehci-ppc-of
> into the platform driver and adds a "usb-ehci" compatibility
> string. The existing ehci-ppc-of driver is removed and the 440EPX
> specific quirks are added to the ehci-platform driver.
>
> Signed-off-by: Alistair Popple <[email protected]>

This patch is also out of date. The compatibility string used by the
ehci-platform driver is "generic-ehci".

There remains the question of whether to merge ehci-ppc-of into
ehci-platform. This would be a rather invasive change, but I suppose
we could do it. With adjustments along the lines suggested by Mark
Rutland.

Alan Stern

2014-02-21 20:42:02

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: [PATCH 7/7] powerpc: Added PCI MSI support using the HSTA module

On Fri, 2014-02-21 at 15:33 +0100, Arnd Bergmann wrote:

> > @@ -242,8 +264,10 @@
> > ranges = <0x02000000 0x00000000 0x80000000 0x00000110 0x80000000 0x0 0x80000000
> > 0x01000000 0x0 0x0 0x00000140 0x0 0x0 0x00010000>;
> >
> > - /* Inbound starting at 0 to memsize filled in by zImage */
> > - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
> > + /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
> > + * PCI devices must be able to write to the HSTA module.
> > + */
> > + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;

Should we (provided it's possible in HW) create two ranges instead ? One
covering RAM and one covering MSIs ? To avoid stray DMAs whacking random
HW registers in the chip ...

> > /* This drives busses 0 to 0xf */
> > bus-range = <0x0 0xf>;
>
> Ah, I first only saw the line you are removing and was about
> to suggest what you do anyway. Great!
>
> > diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
> > index 54ec1d5..7cc3acc 100644
> > --- a/arch/powerpc/sysdev/ppc4xx_pci.c
> > +++ b/arch/powerpc/sysdev/ppc4xx_pci.c
> > @@ -176,8 +176,12 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
> > return -ENXIO;
> > }
> >
> > - /* Check that we are fully contained within 32 bits space */
> > - if (res->end > 0xffffffff) {
> > + /* Check that we are fully contained within 32 bits space if we are not
> > + * running on a 460sx or 476fpe which have 64 bit bus addresses.
> > + */
> > + if (res->end > 0xffffffff &&
> > + !(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx")
> > + || of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) {
> > printk(KERN_ERR "%s: dma-ranges outside of 32 bits space\n",
> > hose->dn->full_name);
> > return -ENXIO;
>
> A more general question for BenH: Apparently this PCI implementation is
> getting reused on arm64 for APM X-Gene. Do you see any value in trying to
> share host controller drivers like this one across powerpc and arm64?

I would start duplicating, and see how much common code remains... Then
eventually merge.

> It's possible we are going to see the same situation with fsl_pci in the
> future, if arm and powerpc qoriq chips use the same peripherals. My
> plan for arm64 right now is to make PCI work without any code in arch/,
> just using new helper functions in drivers/pci and sticking the host
> drivers into drivers/pci/host as we started doing for arm32, but it
> can require significant work to make those drivers compatible with
> the powerpc pci-common.c.

powerpc pci-common.c is shrinking :-) At least the address remapping is
all in the core now, we could move more over I suppose...

Cheers,
Ben.

> Arnd
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2014-02-21 21:53:35

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 7/7] powerpc: Added PCI MSI support using the HSTA module

On Friday 21 February 2014, Benjamin Herrenschmidt wrote:
> On Fri, 2014-02-21 at 15:33 +0100, Arnd Bergmann wrote:
>
> > > @@ -242,8 +264,10 @@
> > > ranges = <0x02000000 0x00000000 0x80000000 0x00000110 0x80000000 0x0 0x80000000
> > > 0x01000000 0x0 0x0 0x00000140 0x0 0x0 0x00010000>;
> > >
> > > - /* Inbound starting at 0 to memsize filled in by zImage */
> > > - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x0>;
> > > + /* Inbound starting at 0x0 to 0x40000000000. In order to use MSI
> > > + * PCI devices must be able to write to the HSTA module.
> > > + */
> > > + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x400 0x0>;
>
> Should we (provided it's possible in HW) create two ranges instead ? One
> covering RAM and one covering MSIs ? To avoid stray DMAs whacking random
> HW registers in the chip ...
>
> > > /* This drives busses 0 to 0xf */
> > > bus-range = <0x0 0xf>;
> >
> > Ah, I first only saw the line you are removing and was about
> > to suggest what you do anyway. Great!
> >
> > > diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
> > > index 54ec1d5..7cc3acc 100644
> > > --- a/arch/powerpc/sysdev/ppc4xx_pci.c
> > > +++ b/arch/powerpc/sysdev/ppc4xx_pci.c
> > > @@ -176,8 +176,12 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
> > > return -ENXIO;
> > > }
> > >
> > > - /* Check that we are fully contained within 32 bits space */
> > > - if (res->end > 0xffffffff) {
> > > + /* Check that we are fully contained within 32 bits space if we are not
> > > + * running on a 460sx or 476fpe which have 64 bit bus addresses.
> > > + */
> > > + if (res->end > 0xffffffff &&
> > > + !(of_device_is_compatible(hose->dn, "ibm,plb-pciex-460sx")
> > > + || of_device_is_compatible(hose->dn, "ibm,plb-pciex-476fpe"))) {
> > > printk(KERN_ERR "%s: dma-ranges outside of 32 bits space\n",
> > > hose->dn->full_name);
> > > return -ENXIO;
> >
> > A more general question for BenH: Apparently this PCI implementation is
> > getting reused on arm64 for APM X-Gene. Do you see any value in trying to
> > share host controller drivers like this one across powerpc and arm64?
>
> I would start duplicating, and see how much common code remains... Then
> eventually merge.

Ok.

> > It's possible we are going to see the same situation with fsl_pci in the
> > future, if arm and powerpc qoriq chips use the same peripherals. My
> > plan for arm64 right now is to make PCI work without any code in arch/,
> > just using new helper functions in drivers/pci and sticking the host
> > drivers into drivers/pci/host as we started doing for arm32, but it
> > can require significant work to make those drivers compatible with
> > the powerpc pci-common.c.
>
> powerpc pci-common.c is shrinking :-) At least the address remapping is
> all in the core now, we could move more over I suppose...

Ah, good. We're currently trying to work out a generic way to parse
the DT and ioremap the I/O windows. That could probably be shared
and while I hope what we need on arm64 is compatible with what you
need on powerpc, I may always miss something. I'll make sure to add
you to the discussions.

Some parts are easier because we assume that we always scan the
entire PCI bus ourselves and don't do PCI_PROBE_DEVTREE.
Other parts are harder because for the generic case we actually
want to support loading and unloading host bridge drivers,
as well as supporting any combination of host bridges in the
same system without platform specific code.

Arnd

2014-02-22 02:32:53

by Tony Prisk

[permalink] [raw]
Subject: Re: [PATCH 4/7] ECHI Platform: Merge ppc-of EHCI driver into the ehci-platform driver


On 22/02/14 00:48, Mark Rutland wrote:
> [Adding Tony Prisk to Cc]
>
> On Fri, Feb 21, 2014 at 06:31:30AM +0000, Alistair Popple wrote:
>> Currently the ppc-of driver uses the compatibility string
>> "usb-ehci". This means platforms that use device-tree and implement an
>> EHCI compatible interface have to either use the ppc-of driver or add
>> a compatible line to the ehci-platform driver. It would be more
>> appropriate for the platform driver to be compatible with "usb-ehci"
>> as non-powerpc platforms are also beginning to utilise device-tree.
>>
>> This patch merges the device tree property parsing from ehci-ppc-of
>> into the platform driver and adds a "usb-ehci" compatibility
>> string. The existing ehci-ppc-of driver is removed and the 440EPX
>> specific quirks are added to the ehci-platform driver.
>>
>> Signed-off-by: Alistair Popple <[email protected]>
>> ---
>> drivers/usb/host/Kconfig | 7 +-
>> drivers/usb/host/ehci-hcd.c | 5 -
>> drivers/usb/host/ehci-platform.c | 87 +++++++++++++-
>> drivers/usb/host/ehci-ppc-of.c | 238 --------------------------------------
>> 4 files changed, 89 insertions(+), 248 deletions(-)
>> delete mode 100644 drivers/usb/host/ehci-ppc-of.c
> Please use of_property_read_bool for these.
>
> This driver already handles "via,vt8500-ehci" and "wm,prizm-ehci" which
> aren't documented to handle these properties, but now gain support for
> them. It might be worth unifying the binding documents if there's
> nothing special about those two host controllers.
>
> We seem to have two binding documents for "via,vt8500-ehci", so some
> cleanup is definitely in order.
>
> Tony, you seem to have written both documents judging by 95e9fd10f06c
> and 8ad551d150e3. Do you have any issue with merging both of these into
> a common usb-ehci document?
......
> Cheers,
> Mark.

I'm not sure how we ended up with two bindings for the driver anyway. I
think this was an error on my part somewhere.

None of the in-tree dts files use "wm,prizm-ehci".

I have no issue with merging all the documentation into a single
usb-ehci binding.

Regards
Tony Prisk

2014-02-24 00:20:27

by Alistair Popple

[permalink] [raw]
Subject: Re: [PATCH 3/7] IBM Akebono: Add support to the OHCI platform driver for PPC476GTR

On Fri, 21 Feb 2014 15:16:52 Arnd Bergmann wrote:
> On Friday 21 February 2014 17:31:29 Alistair Popple wrote:
> > +static const struct of_device_id ohci_of_match[] = {
> > + { .compatible = "usb-ohci", },
> > + {},
> > +};
> > +
> >
> > static const struct platform_device_id ohci_platform_table[] = {
> >
> > { "ohci-platform", 0 },
> > { }
> >
> > @@ -198,6 +209,7 @@ static struct platform_driver ohci_platform_driver = {
> >
> > .owner = THIS_MODULE,
> > .name = "ohci-platform",
> > .pm = &ohci_platform_pm_ops,
> >
> > + .of_match_table = ohci_of_match,
> >
> > }
> >
> > };
>
> Linux-next already has a patch to add an of_match_table in this driver,
> using
>
> static const struct of_device_id ohci_platform_ids[] = {
> { .compatible = "generic-ohci", },
> { }
> };
>
> I think you should just use that string on your platform.

Excellent! I will drop this patch and use "generic-ohci" instead. Thanks for
pointing this out.

- Alistair

> Arnd

2014-02-24 00:28:05

by Alistair Popple

[permalink] [raw]
Subject: Re: [PATCH 4/7] ECHI Platform: Merge ppc-of EHCI driver into the ehci-platform driver

On Fri, 21 Feb 2014 10:41:50 Alan Stern wrote:
> On Fri, 21 Feb 2014, Alistair Popple wrote:
> > Currently the ppc-of driver uses the compatibility string
> > "usb-ehci". This means platforms that use device-tree and implement an
> > EHCI compatible interface have to either use the ppc-of driver or add
> > a compatible line to the ehci-platform driver. It would be more
> > appropriate for the platform driver to be compatible with "usb-ehci"
> > as non-powerpc platforms are also beginning to utilise device-tree.
> >
> > This patch merges the device tree property parsing from ehci-ppc-of
> > into the platform driver and adds a "usb-ehci" compatibility
> > string. The existing ehci-ppc-of driver is removed and the 440EPX
> > specific quirks are added to the ehci-platform driver.
> >
> > Signed-off-by: Alistair Popple <[email protected]>
>
> This patch is also out of date. The compatibility string used by the
> ehci-platform driver is "generic-ehci".

Ok. I will switch to using "generic-ehci" in the Akebono device tree.

> There remains the question of whether to merge ehci-ppc-of into
> ehci-platform. This would be a rather invasive change, but I suppose
> we could do it. With adjustments along the lines suggested by Mark
> Rutland.

As I can use "generic-ehci" to support Akebono I will drop this patch. I can
look at merging ehci-ppc-of at some later date if desired (thanks Mark & Tony
for reviewing though).

- Alistair

> Alan Stern

2014-02-24 00:38:40

by Alistair Popple

[permalink] [raw]
Subject: Re: [PATCH 1/7] IBM Akebono: Add a SDHCI platform driver

On Fri, 21 Feb 2014 15:14:30 Arnd Bergmann wrote:
> On Friday 21 February 2014 17:31:27 Alistair Popple wrote:
> > +config MMC_SDHCI_OF_476GTR
> > + tristate "SDHCI OF support for the IBM PPC476GTR SoC"
> > + depends on MMC_SDHCI_PLTFM
> > + depends on PPC_OF
> > + help
> > + This selects the Secure Digital Host Controller Interface (SDHCI)
> > + found on the PPC476GTR SoC.
> > +
> > + If you have a controller with this interface, say Y or M here.
> > +
> > + If unsure, say N.
>
> Your driver doesn't actually do anything beyond what is in the common
> sdhci-pltfm.c infrastructure. IMHO you really shoulnd't need a SoC
> specific abstraction for it at all and instead add a generic
> platform driver registration into sdhci-pltfm.c. I'd suggest
> you use "generic-sdhci" (similar to what we do for usb-ohci and usb-ehci
> now) as the compatible string and change your device tree to claim
> compatibility with that and your soc-specific string.

That's a reasonable point. I guess I was just following the example set by the
other sdhci-* drivers. However on review they're not as generic as this one so
I will merge this into sdhci-pltfm.c as suggested.

- Alistair

> Arnd

2014-02-24 02:09:26

by Alistair Popple

[permalink] [raw]
Subject: Re: [PATCH 2/7] IBM Akebono: Add support for a new PHY interface to the IBM emac driver

On Fri, 21 Feb 2014 11:18:23 Mark Rutland wrote:
> On Fri, Feb 21, 2014 at 06:31:28AM +0000, Alistair Popple wrote:

[...]

>
> > + /* Check for RGMII flags */
> > + if (of_get_property(ofdev->dev.of_node, "has-mdio", NULL))
> > + dev->flags |= EMAC_RGMII_FLAG_HAS_MDIO;
>
> You can use of_property_read_bool here.

Thanks. I will update it.

Regards,

Alistair

>
> Cheers,
> Mark.

2014-02-25 05:55:07

by Alistair Popple

[permalink] [raw]
Subject: Re: [PATCH 7/7] powerpc: Added PCI MSI support using the HSTA module

On Sat, 22 Feb 2014 07:41:26 Benjamin Herrenschmidt wrote:
> On Fri, 2014-02-21 at 15:33 +0100, Arnd Bergmann wrote:

[...]

>
> Should we (provided it's possible in HW) create two ranges instead ? One
> covering RAM and one covering MSIs ? To avoid stray DMAs whacking random
> HW registers in the chip ...
>

The thought occurred to me but I figured if we had stray DMAs then they could
already whack random bits of system memory which would likely break your
system anyway so I wasn't sure how much we'd gain. I guess whacking random HW
registers is arguably a bit worse though.

I did a bit of digging into the HW documentation and it looks like it _may_ be
possible to create a second range that would limit access to a subset of HW
registers, although there doesn't seem to be much flexibility. Personally I'm
not sure it justifies the work, but I'm happy to look into it a bit more if
you feel it's important?

- Alistair