From patchwork Tue Jun 21 04:41:22 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Collins X-Patchwork-Id: 164284 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id 302CE1007D3 for ; Tue, 12 Jun 2012 09:06:10 +1000 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1SeDgN-0004Ul-UQ; Mon, 11 Jun 2012 23:05:59 +0000 Received: from mail-pz0-f49.google.com ([209.85.210.49]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1SeDdY-0003hC-7l for kernel-team@lists.ubuntu.com; Mon, 11 Jun 2012 23:03:04 +0000 Received: by mail-pz0-f49.google.com with SMTP id m1so6348994dad.8 for ; Mon, 11 Jun 2012 16:03:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:in-reply-to:references:from:date:subject:to; bh=DOdZOHcrSN6xUJRvxfIpdT272OaLqoQhPbTE/yW578A=; b=jLSunUtQ8odjYTLuE89ypVaMTcBzsfoHLmKnAnmk9iDX8FEoAw7w0FRvnQrOwvTfg6 Ts9EIBkTB9+V5DF7Zk9FhtplUEHmbllpkoLiuncyXjW388MXtEx1zvw6kVCV7tab5Z6M MIHlpbV50MFIsdaP3XbomT53jToCBUeLuENeBnmYFjlgOwDSXrYxAkFbMWrRMYU372Nx lX5nqii2hgijubNooOiMYOU4uee7R79BnZaZ4HuA8f4s5+hJ8//AUWo4QGizFLJqR7mk 7tXbmjJuYrPsX1pDUCA9P6ZAHuZX9H3Zw6yVocvOy8HeNpp5Zr91PlB8BZeltv1wbE2G pYGg== Received: by 10.68.217.37 with SMTP id ov5mr22130069pbc.82.1339455783757; Mon, 11 Jun 2012 16:03:03 -0700 (PDT) Received: from localhost (ip68-13-200-36.hr.hr.cox.net. [68.13.200.36]) by mx.google.com with ESMTPS id pe2sm19925465pbc.59.2012.06.11.16.03.00 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 11 Jun 2012 16:03:02 -0700 (PDT) Received: by localhost (sSMTP sendmail emulation); Mon, 11 Jun 2012 19:02:58 -0400 Message-Id: <85c75499fb1d7fb465aae6b7902e04c22fc7864c.1339455422.git.bcollins@ubuntu.com> In-Reply-To: References: From: Kumar Gala Date: Mon, 20 Jun 2011 23:41:22 -0500 Subject: [PATCH 24/27] UBUNTU: SAUCE: powerpc/85xx: Add DPAA/networking support for P4080DS To: kernel-team@lists.ubuntu.com X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com * Add fsl,dpaa to device tree nodes that are probed * setup 'private' storage needed by Qman, Bman and PME * Add MDIO driver to deal with P4080DS MDIO muxing This patch is being maintained and will eventually be merged upstream by Freescale directly. The powerpc-e500mc flavour uses this. Signed-off-by: Ioana Radulescu Signed-off-by: Kumar Gala Signed-off-by: Ben Collins --- arch/powerpc/platforms/85xx/Kconfig | 6 + arch/powerpc/platforms/85xx/Makefile | 1 + arch/powerpc/platforms/85xx/corenet_ds.c | 49 ++++ arch/powerpc/platforms/85xx/corenet_ds.h | 4 +- arch/powerpc/platforms/85xx/p4080_ds.c | 17 +- arch/powerpc/platforms/85xx/p4080_ds_mdio.c | 333 +++++++++++++++++++++++++++ 6 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/platforms/85xx/p4080_ds_mdio.c diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index f96d56a..750bfbe 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -252,6 +252,7 @@ config P4080_DS select HAS_FSL_PAMU select HAS_FSL_QBMAN select HAS_FSL_PME + select FSL_P4080_DS_MDIO if PHYLIB help This option enables support for the P4080 DS board @@ -276,5 +277,10 @@ config P5020_DS endif # FSL_SOC_BOOKE +config FSL_P4080_DS_MDIO + bool + select VITESSE_PHY + depends on PHYLIB + config TQM85xx bool diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 2125d4c..19f75f1 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_P3041_DS) += p3041_ds.o corenet_ds.o obj-$(CONFIG_P3060_QDS) += p3060_qds.o corenet_ds.o obj-$(CONFIG_P4080_DS) += p4080_ds.o corenet_ds.o obj-$(CONFIG_P5020_DS) += p5020_ds.o corenet_ds.o +obj-$(CONFIG_FSL_P4080_DS_MDIO) += p4080_ds_mdio.o obj-$(CONFIG_STX_GP3) += stx_gp3.o obj-$(CONFIG_TQM85xx) += tqm85xx.o obj-$(CONFIG_SBC8560) += sbc8560.o diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c index dd3617c..9177ad5 100644 --- a/arch/powerpc/platforms/85xx/corenet_ds.c +++ b/arch/powerpc/platforms/85xx/corenet_ds.c @@ -91,6 +91,9 @@ static const struct of_device_id of_device_ids[] __devinitconst = { .compatible = "simple-bus" }, { + .compatible = "fsl,dpaa" + }, + { .compatible = "fsl,srio", }, { @@ -113,3 +116,49 @@ int __init corenet_ds_publish_devices(void) { return of_platform_bus_probe(NULL, of_device_ids, NULL); } + +int __init declare_of_platform_devices(void) +{ + struct device_node *np; + int err; + + err = of_platform_bus_probe(NULL, of_device_ids, NULL); + if (err) + return err; + + /* Now probe the fake MDIO buses */ + for_each_compatible_node(np, NULL, "fsl,p4080ds-mdio") + of_platform_device_create(np, NULL, NULL); + + for_each_compatible_node(np, NULL, "fsl,p4080ds-xmdio") + of_platform_device_create(np, NULL, NULL); + + return 0; +} + +/* Early setup is required for large chunks of contiguous (and coarsely-aligned) + * memory. The following shoe-horns Qman/Bman "init_early" calls into the + * platform setup to let them parse their CCSR nodes early on. */ +#ifdef CONFIG_FSL_QMAN_CONFIG +void __init qman_init_early(void); +#endif +#ifdef CONFIG_FSL_BMAN_CONFIG +void __init bman_init_early(void); +#endif +#ifdef CONFIG_FSL_PME2_CTRL +void __init pme2_init_early(void); +#endif + +__init void corenet_ds_init_early(void) +{ +#ifdef CONFIG_FSL_QMAN_CONFIG + qman_init_early(); +#endif +#ifdef CONFIG_FSL_BMAN_CONFIG + bman_init_early(); +#endif +#ifdef CONFIG_FSL_PME2_CTRL + pme2_init_early(); +#endif +} + diff --git a/arch/powerpc/platforms/85xx/corenet_ds.h b/arch/powerpc/platforms/85xx/corenet_ds.h index ddd700b..7f2e9b1 100644 --- a/arch/powerpc/platforms/85xx/corenet_ds.h +++ b/arch/powerpc/platforms/85xx/corenet_ds.h @@ -1,7 +1,7 @@ /* * Corenet based SoC DS Setup * - * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2009-2010 Freescale Semiconductor Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -15,5 +15,7 @@ extern void __init corenet_ds_pic_init(void); extern void __init corenet_ds_setup_arch(void); extern int __init corenet_ds_publish_devices(void); +extern int __init declare_of_platform_devices(void); +extern void __init corenet_ds_init_early(void); #endif diff --git a/arch/powerpc/platforms/85xx/p4080_ds.c b/arch/powerpc/platforms/85xx/p4080_ds.c index c92417d..ad112ca 100644 --- a/arch/powerpc/platforms/85xx/p4080_ds.c +++ b/arch/powerpc/platforms/85xx/p4080_ds.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,18 @@ static int __init p4080_ds_probe(void) return 0; } +#if defined(CONFIG_PHYLIB) && defined(CONFIG_VITESSE_PHY) +int vsc824x_add_skew(struct phy_device *phydev); +#define PHY_ID_VSC8244 0x000fc6c0 +static int __init board_fixups(void) +{ + phy_register_fixup_for_uid(PHY_ID_VSC8244, 0xfffff, vsc824x_add_skew); + + return 0; +} +machine_device_initcall(p4080_ds, board_fixups); +#endif + define_machine(p4080_ds) { .name = "P4080 DS", .probe = p4080_ds_probe, @@ -79,9 +92,11 @@ define_machine(p4080_ds) { .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, .power_save = e500_idle, + .init_early = corenet_ds_init_early, }; -machine_device_initcall(p4080_ds, corenet_ds_publish_devices); +machine_device_initcall(p4080_ds, declare_of_platform_devices); + #ifdef CONFIG_SWIOTLB machine_arch_initcall(p4080_ds, swiotlb_setup_bus_notifier); #endif diff --git a/arch/powerpc/platforms/85xx/p4080_ds_mdio.c b/arch/powerpc/platforms/85xx/p4080_ds_mdio.c new file mode 100644 index 0000000..1c08620 --- /dev/null +++ b/arch/powerpc/platforms/85xx/p4080_ds_mdio.c @@ -0,0 +1,333 @@ +/* + * Provides proper gpio muxing for the MDIO buses on the corenet DS boards + * + * Author: Andy Fleming + * + * Copyright (c) 2009-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +struct p4080ds_mdio { + struct mii_bus *real_bus; + unsigned int num_gpios; + unsigned int *gpios; + int *gpio_values; +}; + +/* Set the GPIO mux, and then write the MDIO regs */ +int p4080ds_mdio_write(struct mii_bus *bus, int port_addr, int dev_addr, + int regnum, u16 value) +{ + struct p4080ds_mdio *priv = bus->priv; + int i; + + /* Write the GPIO regs to select this bus */ + for (i = 0; i < priv->num_gpios; i++) + gpio_set_value(priv->gpios[i], priv->gpio_values[i]); + + /* Write through to the attached MDIO bus */ + return priv->real_bus->write(priv->real_bus, port_addr, dev_addr, + regnum, value); +} + +/* Set the GPIO muxing, and then read from the MDIO bus */ +int p4080ds_mdio_read(struct mii_bus *bus, int port_addr, int dev_addr, + int regnum) +{ + struct p4080ds_mdio *priv = bus->priv; + int i; + + /* Write the GPIO regs to select this bus */ + for (i = 0; i < priv->num_gpios; i++) + gpio_set_value(priv->gpios[i], priv->gpio_values[i]); + + return priv->real_bus->read(priv->real_bus, port_addr, dev_addr, + regnum); +} + + +/* Reset the MIIM registers, and wait for the bus to free */ +static int p4080ds_mdio_reset(struct mii_bus *bus) +{ + struct p4080ds_mdio *priv = bus->priv; + + mutex_lock(&bus->mdio_lock); + priv->real_bus->reset(priv->real_bus); + mutex_unlock(&bus->mdio_lock); + + return 0; +} + + +static int p4080ds_mdio_probe(struct platform_device *ofdev) +{ + struct device_node *np = ofdev->dev.of_node; + struct mii_bus *new_bus; + struct p4080ds_mdio *priv; + struct device_node *mdio; + struct platform_device *ofmdiodev; + int i; + const u32 *val; + u32 gpio_mask; + int gpio; + int err = 0; + + new_bus = mdiobus_alloc(); + if (NULL == new_bus) + return -ENOMEM; + + new_bus->name = "Freescale P4080DS MDIO Bus", + new_bus->read = &p4080ds_mdio_read, + new_bus->write = &p4080ds_mdio_write, + new_bus->reset = &p4080ds_mdio_reset, + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + err = -ENOMEM; + goto err_priv_alloc; + } + + new_bus->priv = priv; + + mdio = of_parse_phandle(np, "fsl,mdio-handle", 0); + + if (mdio == NULL) { + printk(KERN_ERR "Could not find real MDIO bus for %s\n", + new_bus->id); + err = -ENODEV; + goto err_no_mdio_node; + } + + ofmdiodev = of_find_device_by_node(mdio); + + if (!ofmdiodev) { + printk(KERN_ERR "No of_device for MDIO node %s\n", mdio->name); + err = -ENODEV; + goto err_no_mdio_dev; + } + + of_node_put(mdio); + + priv->real_bus = dev_get_drvdata(&ofmdiodev->dev); + + if (!priv->real_bus) { + printk(KERN_ERR "The MDIO bus has no ofdev!\n"); + err = -ENODEV; + goto err_no_ofdev; + } + + new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); + + if (NULL == new_bus->irq) { + err = -ENOMEM; + goto err_irq_alloc; + } + + for (i = 0; i < PHY_MAX_ADDR; i++) + new_bus->irq[i] = PHY_POLL; + + new_bus->parent = &ofdev->dev; + dev_set_drvdata(&ofdev->dev, new_bus); + + /* Get the number of GPIO pins specified for this MDIO node */ + priv->num_gpios = of_gpio_count(mdio); + if (priv->num_gpios == 0) { + printk(KERN_ERR "No GPIO pins specified for MDIO node %s\n", + mdio->name); + err = -ENODEV; + goto err_no_gpios; + } + + priv->gpios = kzalloc(sizeof(unsigned int) * priv->num_gpios, + GFP_KERNEL); + if (!priv->gpios) { + err = -ENOMEM; + goto err_gpios_alloc; + } + + priv->gpio_values = kzalloc(sizeof(int) * priv->num_gpios, GFP_KERNEL); + if (!priv->gpio_values) { + err = -ENOMEM; + goto err_gpio_values_alloc; + } + + /* Grab the value to write to the GPIO */ + val = of_get_property(np, "fsl,muxval", NULL); + + if (!val) { + printk(KERN_ERR "No mux value found for %s\n", np->full_name); + err = -ENODEV; + goto err_get_muxval; + } + if (*val >= (1 << priv->num_gpios)) { + printk(KERN_ERR "Mux value for %s is out of range: [0 - %d]\n", + np->full_name, (1 << priv->num_gpios) - 1); + err = -EINVAL; + goto err_get_muxval; + } + + for (i = 0; i < priv->num_gpios; i++) { + /* Based on GPIO pin specified in DT, get a pin number relative + * to the GPIO controller's dynamically assigned base */ + gpio = of_get_gpio_flags(mdio, i, NULL); + if (gpio < 0) { + printk(KERN_ERR "Failed to get GPIO pin value\n"); + err = gpio; + goto err_gpio_get; + } + priv->gpios[i] = gpio; + if (!gpio_is_valid(priv->gpios[i])) { + printk(KERN_ERR "Invalid GPIO pin value: %d\n", + priv->gpios[i]); + err = -EINVAL; + goto err_gpio_get; + } + + /* Set the value to be written to the GPIO pin + * in order to select this mdio bus */ + gpio_mask = 1 << (priv->num_gpios - i - 1); + priv->gpio_values[i] = !!(*val & gpio_mask); + + /* Request the pin (check that pin number is valid & in range). + * More than one P4080 MDIO bus will use these pins; if already + * requested, continue without error */ + err = gpio_request(priv->gpios[i], NULL); + if ((err < 0) && (err != -EBUSY)) { + printk(KERN_ERR "Failed to reserve GPIO pin %d\n", + priv->gpios[i]); + goto err_gpio_req; + } + + /* Set the direction to output (we will write to this pin). + * Should be already set from u-boot, but make sure + * it's correct nonetheless */ + err = gpio_direction_output(priv->gpios[i], 0); + if (err < 0) { + printk(KERN_ERR "Failed to configure direction for " + "GPIO pin %d\n", priv->gpios[i]); + goto err_gpio_dir; + } + } + + sprintf(new_bus->id, "%s@%d", np->name, *val); + + err = of_mdiobus_register(new_bus, np); + + if (err) { + printk(KERN_ERR "%s: Cannot register as MDIO bus\n", + new_bus->name); + goto err_registration; + } + + return 0; + +err_registration: +err_gpio_dir: + for (i = 0; i < priv->num_gpios; i++) + gpio_free(priv->gpios[i]); +err_gpio_req: +err_gpio_get: +err_get_muxval: + kfree(priv->gpio_values); +err_gpio_values_alloc: + kfree(priv->gpios); +err_gpios_alloc: +err_no_gpios: + kfree(new_bus->irq); +err_irq_alloc: +err_no_ofdev: +err_no_mdio_dev: +err_no_mdio_node: + kfree(priv); +err_priv_alloc: + kfree(new_bus); + + return err; +} + +static int p4080ds_mdio_remove(struct platform_device *ofdev) +{ + struct device *device = &ofdev->dev; + struct mii_bus *bus = dev_get_drvdata(device); + struct p4080ds_mdio *priv = bus->priv; + int i; + + for (i = 0; i < priv->num_gpios; i++) + gpio_free(priv->gpios[i]); + kfree(priv->gpios); + kfree(priv->gpio_values); + + mdiobus_unregister(bus); + + dev_set_drvdata(device, NULL); + + bus->priv = NULL; + mdiobus_free(bus); + + return 0; +} + +static struct of_device_id p4080ds_mdio_match[] = { + { + .compatible = "fsl,p4080ds-mdio", + }, + { + .compatible = "fsl,p4080ds-xmdio", + }, + {} +}; + +static struct platform_driver p4080ds_mdio_driver = { + .driver = { + .name = "p4080ds_mdio", + .of_match_table = p4080ds_mdio_match, + }, + .probe = p4080ds_mdio_probe, + .remove = p4080ds_mdio_remove, +}; + +int __init p4080ds_mdio_init(void) +{ + return platform_driver_register(&p4080ds_mdio_driver); +} + +void p4080ds_mdio_exit(void) +{ + platform_driver_unregister(&p4080ds_mdio_driver); +} +subsys_initcall_sync(p4080ds_mdio_init); +module_exit(p4080ds_mdio_exit);