qe_lib: Add QE SoC support
PATCH 7/11 qe_lib: Add QE SoC support
Signed-off-by Li Yang <[email protected]>
Signed-off-by Kim Phillips <[email protected]>
---arch/powerpc/sysdev/qe_lib/qe.c | 176 +++++++++++++++++++++++++++++++++++++++
1 files changed, 176 insertions(+), 0 deletions(-)
arch/powerpc/sysdev/qe_lib/qe.c new file +172 -0
@@ -0,0 +1,176 @@ +/* +* Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. +* +* Author: Li Yang <[email protected]> +* +* Description: +* FSL QE SOC setup. +* +* 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/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/major.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> + +#include <asm/system.h> +#include <asm/atomic.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/prom.h> +#include <sysdev/fsl_soc.h> +#include <mm/mmu_decl.h> + +static phys_addr_t qebase =-1 ; + +phys_addr_t get_qe_base (void ) +{ +struct device_node *qe; + +if (qebase !=-1 ) +return qebase; + + qe =of_find_node_by_type (NULL ,"qe" ); +if (qe) { +unsigned int size; +void *prop =get_property (qe,"reg" , &size); + qebase =of_translate_address (qe, prop); +of_node_put (qe); + }; + +return qebase; +} + +EXPORT_SYMBOL (get_qe_base); + +static int __init ucc_geth_of_init (void ) +{ +struct device_node *np; +unsigned int i, ucc_num; +struct platform_device *ugeth_dev; +struct resource res; +int ret; + +for (np =NULL , i =0 ; + (np =of_find_compatible_node (np,"network" ,"ucc_geth" )) !=NULL ; + i++) { +struct resource r[2 ]; +struct device_node *phy, *mdio; +struct ucc_geth_platform_data ugeth_data; +unsigned int *id; +char *model; +void *mac_addr; +phandle *ph; + +memset (r,0 ,sizeof (r)); +memset (&ugeth_data,0 ,sizeof (ugeth_data)); + + ret =of_address_to_resource (np,0 , &r[0 ]); +if (ret) + goto err; + + ugeth_data.phy_reg_addr = r[0 ].start; + r[1 ].start = r[1 ].end =irq_of_parse_and_map (np,0 ); + r[1 ].flags =IORESOURCE_IRQ ; + + model =get_property (np,"model" ,NULL ); + ucc_num = *((u32 *)get_property (np,"device-id" ,NULL )); +if ((strstr (model,"UCC" ) ==NULL ) || + (ucc_num <1 ) || (ucc_num >8 )) { + ret = -ENODEV ; + goto err; + } + + ugeth_dev = +platform_device_register_simple ("ucc_geth" , ucc_num -1 , + &r[0 ],2 ); + +if (IS_ERR (ugeth_dev)) { + ret =PTR_ERR (ugeth_dev); + goto err; + } + + mac_addr =get_property (np,"mac-address" ,NULL ); + +memcpy (ugeth_data.mac_addr, mac_addr,6 ); + + ugeth_data.rx_clock = *((u32 *)get_property (np,"rx-clock" , +NULL )); + ugeth_data.tx_clock = *((u32 *)get_property (np,"tx-clock" , +NULL )); + + ph = (phandle *)get_property (np,"phy-handle" ,NULL ); + phy =of_find_node_by_phandle (*ph); + +if (phy ==NULL ) { + ret = -ENODEV ; + goto unreg; + } + + mdio =of_get_parent (phy); + + id = (u32 *)get_property (phy,"reg" ,NULL ); + ret =of_address_to_resource (mdio,0 , &res); +if (ret) { +of_node_put (phy); +of_node_put (mdio); + goto unreg; + } + + ugeth_data.phy_id = *id; + + ugeth_data.phy_interrupt =irq_of_parse_and_map (phy,0 );; + ugeth_data.phy_interface = *((u32 *)get_property (phy, +"interface" ,NULL )); + +/* FIXME: Work around for early chip rev. */ +/* There's a bug in initial chip rev(s) in the RGMII ac */ +/* timing. */ +/* The following compensates by writing to the reserved */ +/* QE Port Output Hold Registers (CPOH1?). */ +if ((ugeth_data.phy_interface ==ENET_1000_RGMII ) || + (ugeth_data.phy_interface ==ENET_100_RGMII ) || + (ugeth_data.phy_interface ==ENET_10_RGMII )) { +u32 *tmp_reg = (u32 *)ioremap (get_immrbase () + +0x14A8 ,0x4 ); +u32 tmp_val =in_be32 (tmp_reg); +if (ucc_num ==1 ) +out_be32 (tmp_reg, tmp_val |0x00003000 ); +else if (ucc_num ==2 ) +out_be32 (tmp_reg, tmp_val |0x0c000000 ); +iounmap (tmp_reg); + } + +if (ugeth_data.phy_interrupt !=0 ) + ugeth_data.board_flags |=FSL_UGETH_BRD_HAS_PHY_INTR ; + +of_node_put (phy); +of_node_put (mdio); + + ret =platform_device_add_data (ugeth_dev, &ugeth_data, +sizeof (struct ucc_geth_platform_data )); +if (ret) + goto unreg; + } + +return 0 ; + +unreg: +platform_device_unregister (ugeth_dev); +err: +return ret; +} + +arch_initcall (ucc_geth_of_init);