Add support for ULPI and UTMI PHYs based on usb controller version info read from device-tree Example of USB Controller versioning info: Version 1.2 and below : MPC8536, MPC8315, etc Version 1.6 : P1020, P1010, P2020, P5020, etc Version 2.2 : PSC9131, PSC9132, P3060, etc No changes for non-DT users Signed-off-by: Ramneek Mehresh <ramneek.mehresh@xxxxxxxxxxxxx> --- v6 is tested and acked by Peter Chen Changes for v7: - moved usb_get_ver_info() from include/linux/fsl_devices.h to drivers/usb/host/fsl-mph-dr-of.c - made usb_get_ver_info() non-static and non-inline funcion drivers/usb/gadget/fsl_udc_core.c | 37 ++++++++++++++++++++++++++++++++----- drivers/usb/gadget/fsl_usb2_udc.h | 11 +++++++++++ drivers/usb/host/ehci-fsl.c | 35 ++++++++++++++++++++++++++++------- drivers/usb/host/ehci-fsl.h | 13 ++++++++++++- drivers/usb/host/fsl-mph-dr-of.c | 36 ++++++++++++++++++++++++++++++++++++ include/linux/fsl_devices.h | 10 +++++++++- 6 files changed, 128 insertions(+), 14 deletions(-) diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index b30e21f..ff2a99e 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc. + * Copyright (C) 2004-2007,2011-2012 Freescale Semiconductor, Inc. * All rights reserved. * * Author: Li Yang <leoli@xxxxxxxxxxxxx> @@ -59,9 +59,8 @@ static const char driver_name[] = "fsl-usb2-udc"; static const char driver_desc[] = DRIVER_DESC; static struct usb_dr_device *dr_regs; -#ifndef CONFIG_ARCH_MXC + static struct usb_sys_interface *usb_sys_regs; -#endif /* it is initialized in probe() */ static struct fsl_udc *udc_controller = NULL; @@ -245,23 +244,51 @@ static int dr_controller_setup(struct fsl_udc *udc) { unsigned int tmp, portctrl, ep_num; unsigned int max_no_of_ep; -#ifndef CONFIG_ARCH_MXC unsigned int ctrl; -#endif unsigned long timeout; + int contr_ver = usb_get_ver_info(); + #define FSL_UDC_RESET_TIMEOUT 1000 + if (udc->pdata->have_sysif_regs) { + if (contr_ver < 0) { + pr_warn("fsl-usb2-udc: Could not get" + " controller version\n"); + return -ENODEV; + } + } + /* Config PHY interface */ portctrl = fsl_readl(&dr_regs->portsc1); portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH); switch (udc->phy_mode) { case FSL_USB2_PHY_ULPI: + if (udc->pdata->have_sysif_regs) { + if (contr_ver) { + /* controller version 1.6 or above */ + ctrl = __raw_readl(&usb_sys_regs->control); + ctrl &= ~USB_CTRL_UTMI_PHY_EN; + ctrl |= USB_CTRL_USB_EN; + __raw_writel(ctrl, &usb_sys_regs->control); + } + } portctrl |= PORTSCX_PTS_ULPI; break; case FSL_USB2_PHY_UTMI_WIDE: portctrl |= PORTSCX_PTW_16BIT; /* fall through */ case FSL_USB2_PHY_UTMI: + if (udc->pdata->have_sysif_regs) { + if (contr_ver) { + /* controller version 1.6 or above */ + ctrl = __raw_readl(&usb_sys_regs->control); + ctrl |= (USB_CTRL_UTMI_PHY_EN | + USB_CTRL_USB_EN); + __raw_writel(ctrl, &usb_sys_regs->control); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI + PHY CLK to become stable - 10ms*/ + } + } portctrl |= PORTSCX_PTS_UTMI; break; case FSL_USB2_PHY_SERIAL: diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index e651469..1212646 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -1,4 +1,12 @@ /* + * Copyright (C) 2004,2012 Freescale Semiconductor, Inc + * All rights reserved. + * + * 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. + * * Freescale USB device/endpoint management registers */ #ifndef __FSL_USB2_UDC_H @@ -348,6 +356,9 @@ struct usb_sys_interface { /* control Register Bit Masks */ #define USB_CTRL_IOENB 0x00000004 #define USB_CTRL_ULPI_INT0EN 0x00000001 +#define USB_CTRL_UTMI_PHY_EN 0x00000200 +#define USB_CTRL_USB_EN 0x00000004 +#define USB_CTRL_ULPI_PHY_CLK_SEL 0x00000400 /* Endpoint Queue Head data struct * Rem: all the variables of qh are LittleEndian Mode diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index cf56667..6c2c2ce 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -1,6 +1,6 @@ /* * Copyright 2005-2009 MontaVista Software, Inc. - * Copyright 2008 Freescale Semiconductor, Inc. + * Copyright 2008,2012 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 @@ -211,19 +211,32 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, usb_put_hcd(hcd); } -static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, +static void ehci_fsl_setup_phy(struct usb_hcd *hcd, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) { - u32 portsc; - struct usb_hcd *hcd = ehci_to_hcd(ehci); + u32 portsc, temp; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; + int contr_ver = usb_get_ver_info(); + + if (contr_ver < 0) { + dev_warn(hcd->self.controller, "fsl_usb: Could not get" + " controller version\n"); + return; + } portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]); portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW); switch (phy_mode) { case FSL_USB2_PHY_ULPI: + if (contr_ver) { + /* controller version 1.6 or above */ + temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); + out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | + USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL); + } portsc |= PORT_PTS_ULPI; break; case FSL_USB2_PHY_SERIAL: @@ -233,6 +246,14 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, portsc |= PORT_PTS_PTW; /* fall through */ case FSL_USB2_PHY_UTMI: + if (contr_ver) { + /* controller version 1.6 or above */ + temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); + out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | + UTMI_PHY_EN | USB_CTRL_USB_EN); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to + become stable - 10ms*/ + } /* enable UTMI PHY */ setbits32(non_ehci + FSL_SOC_USB_CTRL, CTRL_UTMI_PHY_EN); portsc |= PORT_PTS_UTMI; @@ -271,7 +292,7 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) if ((pdata->operating_mode == FSL_USB2_DR_HOST) || (pdata->operating_mode == FSL_USB2_DR_OTG)) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); + ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); if (pdata->operating_mode == FSL_USB2_MPH_HOST) { unsigned int chip, rev, svr; @@ -285,9 +306,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) ehci->has_fsl_port_bug = 1; if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); + ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1); + ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1); } if (pdata->have_sysif_regs) { diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index 863fb0c..8840368 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc. +/* Copyright (C) 2005-2010,2012 Freescale Semiconductor, Inc. * Copyright (c) 2005 MontaVista Software * * This program is free software; you can redistribute it and/or modify it @@ -50,4 +50,15 @@ #define CTRL_UTMI_PHY_EN (1<<9) #define CTRL_PHY_CLK_VALID (1 << 17) #define SNOOP_SIZE_2GB 0x1e + +/* control Register Bit Masks */ +#define ULPI_INT_EN (1<<0) +#define WU_INT_EN (1<<1) +#define USB_CTRL_USB_EN (1<<2) +#define LINE_STATE_FILTER__EN (1<<3) +#define KEEP_OTG_ON (1<<4) +#define OTG_PORT (1<<5) +#define PLL_RESET (1<<8) +#define UTMI_PHY_EN (1<<9) +#define ULPI_PHY_CLK_SEL (1<<10) #endif /* _EHCI_FSL_H */ diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index ab333ac..89e83e8 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -193,6 +193,42 @@ static int __devexit fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev) return 0; } +#ifdef CONFIG_USB_FSL_MPH_DR_OF +int usb_get_ver_info(void) +{ + struct device_node *np; + int ver = -1; + + /* + * returns 1 for usb controller version 1.6 + * returns 2 for usb controller version 2.2 + * returns 0 otherwise + */ + for_each_compatible_node(np, NULL, "fsl-usb2-dr") { + if (of_device_is_compatible(np, "fsl-usb2-dr-v1.6")) + ver = 1; + else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2")) + ver = 2; + else /* for previous controller versions */ + ver = 0; + } + + if (ver > -1) + return ver; + + for_each_compatible_node(np, NULL, "fsl-usb2-mph") { + if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6")) + ver = 1; + else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2")) + ver = 2; + else /* for previous controller versions */ + ver = 0; + } + + return ver; +} +#endif /* CONFIG_USB_FSL_MPH_DR_OF */ + #ifdef CONFIG_PPC_MPC512x #define USBGENCTRL 0x200 /* NOTE: big endian */ diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index fffdf00..d7276df 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -6,7 +6,7 @@ * * Maintainer: Kumar Gala <galak@xxxxxxxxxxxxxxxxxxx> * - * Copyright 2004 Freescale Semiconductor, Inc + * Copyright 2004,2012 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 @@ -17,6 +17,8 @@ #ifndef _FSL_DEVICE_H_ #define _FSL_DEVICE_H_ +#define FSL_UTMI_PHY_DLY 10 /*As per P1010RM, delay for UTMI + PHY CLK to become stable - 10ms*/ #include <linux/types.h> /* @@ -135,4 +137,10 @@ int fsl_deep_sleep(void); static inline int fsl_deep_sleep(void) { return 0; } #endif +#ifdef CONFIG_USB_FSL_MPH_DR_OF +extern int usb_get_ver_info(void); +#else +static inline usb_get_ver_info(void) { return 0; } +#endif + #endif /* _FSL_DEVICE_H_ */ -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html