Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: add USB EHCI support for MPC5121 SoC

Extends FSL EHCI platform driver glue layer to support
MPC5121 USB controllers. MPC5121 Rev 2.0 silicon EHCI
registers are in big endian format. The appropriate flags
are set using the information in the platform data structure.
MPC83xx system interface registers are not available on
MPC512x, so the access to these registers is isolated in
MPC512x case. Furthermore the USB controller clocks
must be enabled before 512x register accesses which is
done by providing platform specific init callback.

The MPC512x internal USB PHY doesn't provide supply voltage.
For boards using different power switches allow specifying
DRVVBUS and PWR_FAULT signal polarity of the MPC5121 internal
PHY using "fsl,invert-drvvbus" and "fsl,invert-pwr-fault"
properties in the device tree USB nodes. Adds documentation
for this new device tree bindings.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Anatolij Gustschin and committed by
Greg Kroah-Hartman
230f7ede 126512e3

+215 -32
+22
Documentation/powerpc/dts-bindings/fsl/usb.txt
··· 8 8 Required properties : 9 9 - compatible : Should be "fsl-usb2-mph" for multi port host USB 10 10 controllers, or "fsl-usb2-dr" for dual role USB controllers 11 + or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121 11 12 - phy_type : For multi port host USB controllers, should be one of 12 13 "ulpi", or "serial". For dual role USB controllers, should be 13 14 one of "ulpi", "utmi", "utmi_wide", or "serial". ··· 34 33 - interrupt-parent : the phandle for the interrupt controller that 35 34 services interrupts for this device. 36 35 36 + Optional properties : 37 + - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the 38 + port power polarity of internal PHY signal DRVVBUS is inverted. 39 + - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates 40 + the PWR_FAULT signal polarity is inverted. 41 + 37 42 Example multi port host USB controller device node : 38 43 usb@22000 { 39 44 compatible = "fsl-usb2-mph"; ··· 63 56 interrupts = <26 1>; 64 57 dr_mode = "otg"; 65 58 phy = "ulpi"; 59 + }; 60 + 61 + Example dual role USB controller device node for MPC5121ADS: 62 + 63 + usb@4000 { 64 + compatible = "fsl,mpc5121-usb2-dr"; 65 + reg = <0x4000 0x1000>; 66 + #address-cells = <1>; 67 + #size-cells = <0>; 68 + interrupt-parent = < &ipic >; 69 + interrupts = <44 0x8>; 70 + dr_mode = "otg"; 71 + phy_type = "utmi_wide"; 72 + fsl,invert-drvvbus; 73 + fsl,invert-pwr-fault; 66 74 };
+1
drivers/usb/Kconfig
··· 59 59 config USB_ARCH_HAS_EHCI 60 60 boolean 61 61 default y if PPC_83xx 62 + default y if PPC_MPC512x 62 63 default y if SOC_AU1200 63 64 default y if ARCH_IXP4XX 64 65 default y if ARCH_W90X900
+4 -2
drivers/usb/host/Kconfig
··· 93 93 94 94 config USB_EHCI_BIG_ENDIAN_MMIO 95 95 bool 96 - depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX) 96 + depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || \ 97 + XPS_USB_HCD_XILINX || PPC_MPC512x) 97 98 default y 98 99 99 100 config USB_EHCI_BIG_ENDIAN_DESC 100 101 bool 101 - depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX) 102 + depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ 103 + PPC_MPC512x) 102 104 default y 103 105 104 106 config XPS_USB_HCD_XILINX
+71 -28
drivers/usb/host/ehci-fsl.c
··· 116 116 goto err3; 117 117 } 118 118 119 - /* Enable USB controller */ 120 - temp = in_be32(hcd->regs + 0x500); 121 - out_be32(hcd->regs + 0x500, temp | 0x4); 119 + pdata->regs = hcd->regs; 122 120 123 - /* Set to Host mode */ 124 - temp = in_le32(hcd->regs + 0x1a8); 125 - out_le32(hcd->regs + 0x1a8, temp | 0x3); 121 + /* 122 + * do platform specific init: check the clock, grab/config pins, etc. 123 + */ 124 + if (pdata->init && pdata->init(pdev)) { 125 + retval = -ENODEV; 126 + goto err3; 127 + } 128 + 129 + /* 130 + * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs 131 + * flag for 83xx or 8536 system interface registers. 132 + */ 133 + if (pdata->big_endian_mmio) 134 + temp = in_be32(hcd->regs + FSL_SOC_USB_ID); 135 + else 136 + temp = in_le32(hcd->regs + FSL_SOC_USB_ID); 137 + 138 + if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK)) 139 + pdata->have_sysif_regs = 1; 140 + 141 + /* Enable USB controller, 83xx or 8536 */ 142 + if (pdata->have_sysif_regs) 143 + setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); 144 + 145 + /* Don't need to set host mode here. It will be done by tdi_reset() */ 126 146 127 147 retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); 128 148 if (retval != 0) ··· 157 137 usb_put_hcd(hcd); 158 138 err1: 159 139 dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); 140 + if (pdata->exit) 141 + pdata->exit(pdev); 160 142 return retval; 161 143 } 162 144 ··· 176 154 static void usb_hcd_fsl_remove(struct usb_hcd *hcd, 177 155 struct platform_device *pdev) 178 156 { 157 + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; 158 + 179 159 usb_remove_hcd(hcd); 160 + 161 + /* 162 + * do platform specific un-initialization: 163 + * release iomux pins, disable clock, etc. 164 + */ 165 + if (pdata->exit) 166 + pdata->exit(pdev); 180 167 iounmap(hcd->regs); 181 168 release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 182 169 usb_put_hcd(hcd); 183 170 } 184 171 185 - static void mpc83xx_setup_phy(struct ehci_hcd *ehci, 186 - enum fsl_usb2_phy_modes phy_mode, 187 - unsigned int port_offset) 172 + static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, 173 + enum fsl_usb2_phy_modes phy_mode, 174 + unsigned int port_offset) 188 175 { 189 - u32 portsc = 0; 176 + u32 portsc; 177 + 178 + portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]); 179 + portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW); 180 + 190 181 switch (phy_mode) { 191 182 case FSL_USB2_PHY_ULPI: 192 183 portsc |= PORT_PTS_ULPI; ··· 219 184 ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); 220 185 } 221 186 222 - static void mpc83xx_usb_setup(struct usb_hcd *hcd) 187 + static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) 223 188 { 224 - struct ehci_hcd *ehci = hcd_to_ehci(hcd); 189 + struct usb_hcd *hcd = ehci_to_hcd(ehci); 225 190 struct fsl_usb2_platform_data *pdata; 226 191 void __iomem *non_ehci = hcd->regs; 227 192 u32 temp; 228 193 229 - pdata = 230 - (struct fsl_usb2_platform_data *)hcd->self.controller-> 231 - platform_data; 194 + pdata = hcd->self.controller->platform_data; 195 + 232 196 /* Enable PHY interface in the control reg. */ 233 - temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); 234 - out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004); 235 - out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b); 197 + if (pdata->have_sysif_regs) { 198 + temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); 199 + out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004); 200 + out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b); 201 + } 236 202 237 203 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) 238 204 /* ··· 250 214 251 215 if ((pdata->operating_mode == FSL_USB2_DR_HOST) || 252 216 (pdata->operating_mode == FSL_USB2_DR_OTG)) 253 - mpc83xx_setup_phy(ehci, pdata->phy_mode, 0); 217 + ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); 254 218 255 219 if (pdata->operating_mode == FSL_USB2_MPH_HOST) { 256 220 unsigned int chip, rev, svr; ··· 264 228 ehci->has_fsl_port_bug = 1; 265 229 266 230 if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) 267 - mpc83xx_setup_phy(ehci, pdata->phy_mode, 0); 231 + ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); 268 232 if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) 269 - mpc83xx_setup_phy(ehci, pdata->phy_mode, 1); 233 + ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1); 270 234 } 271 235 236 + if (pdata->have_sysif_regs) { 272 237 #ifdef CONFIG_PPC_85xx 273 - out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008); 274 - out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080); 238 + out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008); 239 + out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080); 275 240 #else 276 - out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c); 277 - out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040); 241 + out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c); 242 + out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040); 278 243 #endif 279 - out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); 244 + out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); 245 + } 280 246 } 281 247 282 248 /* called after powerup, by probe or system-pm "wakeup" */ 283 249 static int ehci_fsl_reinit(struct ehci_hcd *ehci) 284 250 { 285 - mpc83xx_usb_setup(ehci_to_hcd(ehci)); 251 + ehci_fsl_usb_setup(ehci); 286 252 ehci_port_power(ehci, 0); 287 253 288 254 return 0; ··· 295 257 { 296 258 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 297 259 int retval; 260 + struct fsl_usb2_platform_data *pdata; 261 + 262 + pdata = hcd->self.controller->platform_data; 263 + ehci->big_endian_desc = pdata->big_endian_desc; 264 + ehci->big_endian_mmio = pdata->big_endian_mmio; 298 265 299 266 /* EHCI registers start at offset 0x100 */ 300 267 ehci->caps = hcd->regs + 0x100; ··· 413 370 * generic hardware linkage 414 371 */ 415 372 .irq = ehci_irq, 416 - .flags = HCD_USB2, 373 + .flags = HCD_USB2 | HCD_MEMORY, 417 374 418 375 /* 419 376 * basic lifecycle operations
+12 -1
drivers/usb/host/ehci-fsl.h
··· 1 - /* Copyright (c) 2005 freescale semiconductor 1 + /* Copyright (C) 2005-2010 Freescale Semiconductor, Inc. 2 2 * Copyright (c) 2005 MontaVista Software 3 3 * 4 4 * This program is free software; you can redistribute it and/or modify it ··· 19 19 #define _EHCI_FSL_H 20 20 21 21 /* offsets for the non-ehci registers in the FSL SOC USB controller */ 22 + #define FSL_SOC_USB_ID 0x0 23 + #define ID_MSK 0x3f 24 + #define NID_MSK 0x3f00 22 25 #define FSL_SOC_USB_ULPIVP 0x170 23 26 #define FSL_SOC_USB_PORTSC1 0x184 24 27 #define PORT_PTS_MSK (3<<30) ··· 30 27 #define PORT_PTS_SERIAL (3<<30) 31 28 #define PORT_PTS_PTW (1<<28) 32 29 #define FSL_SOC_USB_PORTSC2 0x188 30 + 31 + #define FSL_SOC_USB_USBGENCTRL 0x200 32 + #define USBGENCTRL_PPP (1 << 3) 33 + #define USBGENCTRL_PFP (1 << 2) 34 + #define FSL_SOC_USB_ISIPHYCTRL 0x204 35 + #define ISIPHYCTRL_PXE (1) 36 + #define ISIPHYCTRL_PHYE (1 << 4) 37 + 33 38 #define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */ 34 39 #define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */ 35 40 #define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */
+1 -1
drivers/usb/host/ehci-mem.c
··· 40 40 { 41 41 memset (qtd, 0, sizeof *qtd); 42 42 qtd->qtd_dma = dma; 43 - qtd->hw_token = cpu_to_le32 (QTD_STS_HALT); 43 + qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT); 44 44 qtd->hw_next = EHCI_LIST_END(ehci); 45 45 qtd->hw_alt_next = EHCI_LIST_END(ehci); 46 46 INIT_LIST_HEAD (&qtd->qtd_list);
+89
drivers/usb/host/fsl-mph-dr-of.c
··· 15 15 #include <linux/err.h> 16 16 #include <linux/io.h> 17 17 #include <linux/of_platform.h> 18 + #include <linux/clk.h> 18 19 19 20 struct fsl_usb2_dev_data { 20 21 char *dr_mode; /* controller mode */ ··· 154 153 155 154 pdata->operating_mode = FSL_USB2_MPH_HOST; 156 155 } else { 156 + if (of_get_property(np, "fsl,invert-drvvbus", NULL)) 157 + pdata->invert_drvvbus = 1; 158 + 159 + if (of_get_property(np, "fsl,invert-pwr-fault", NULL)) 160 + pdata->invert_pwr_fault = 1; 161 + 157 162 /* setup mode selected in the device tree */ 158 163 pdata->operating_mode = dev_data->op_mode; 159 164 } ··· 193 186 return 0; 194 187 } 195 188 189 + #ifdef CONFIG_PPC_MPC512x 190 + 191 + #define USBGENCTRL 0x200 /* NOTE: big endian */ 192 + #define GC_WU_INT_CLR (1 << 5) /* Wakeup int clear */ 193 + #define GC_ULPI_SEL (1 << 4) /* ULPI i/f select (usb0 only)*/ 194 + #define GC_PPP (1 << 3) /* Inv. Port Power Polarity */ 195 + #define GC_PFP (1 << 2) /* Inv. Power Fault Polarity */ 196 + #define GC_WU_ULPI_EN (1 << 1) /* Wakeup on ULPI event */ 197 + #define GC_WU_IE (1 << 1) /* Wakeup interrupt enable */ 198 + 199 + #define ISIPHYCTRL 0x204 /* NOTE: big endian */ 200 + #define PHYCTRL_PHYE (1 << 4) /* On-chip UTMI PHY enable */ 201 + #define PHYCTRL_BSENH (1 << 3) /* Bit Stuff Enable High */ 202 + #define PHYCTRL_BSEN (1 << 2) /* Bit Stuff Enable */ 203 + #define PHYCTRL_LSFE (1 << 1) /* Line State Filter Enable */ 204 + #define PHYCTRL_PXE (1 << 0) /* PHY oscillator enable */ 205 + 206 + int fsl_usb2_mpc5121_init(struct platform_device *pdev) 207 + { 208 + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; 209 + struct clk *clk; 210 + char clk_name[10]; 211 + int base, clk_num; 212 + 213 + base = pdev->resource->start & 0xf000; 214 + if (base == 0x3000) 215 + clk_num = 1; 216 + else if (base == 0x4000) 217 + clk_num = 2; 218 + else 219 + return -ENODEV; 220 + 221 + snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num); 222 + clk = clk_get(&pdev->dev, clk_name); 223 + if (IS_ERR(clk)) { 224 + dev_err(&pdev->dev, "failed to get clk\n"); 225 + return PTR_ERR(clk); 226 + } 227 + 228 + clk_enable(clk); 229 + pdata->clk = clk; 230 + 231 + if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) { 232 + u32 reg = 0; 233 + 234 + if (pdata->invert_drvvbus) 235 + reg |= GC_PPP; 236 + 237 + if (pdata->invert_pwr_fault) 238 + reg |= GC_PFP; 239 + 240 + out_be32(pdata->regs + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE); 241 + out_be32(pdata->regs + USBGENCTRL, reg); 242 + } 243 + return 0; 244 + } 245 + 246 + static void fsl_usb2_mpc5121_exit(struct platform_device *pdev) 247 + { 248 + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; 249 + 250 + pdata->regs = NULL; 251 + 252 + if (pdata->clk) { 253 + clk_disable(pdata->clk); 254 + clk_put(pdata->clk); 255 + } 256 + } 257 + 258 + struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = { 259 + .big_endian_desc = 1, 260 + .big_endian_mmio = 1, 261 + .es = 1, 262 + .le_setup_buf = 1, 263 + .init = fsl_usb2_mpc5121_init, 264 + .exit = fsl_usb2_mpc5121_exit, 265 + }; 266 + #endif /* CONFIG_PPC_MPC512x */ 267 + 196 268 static const struct of_device_id fsl_usb2_mph_dr_of_match[] = { 197 269 { .compatible = "fsl-usb2-mph", }, 198 270 { .compatible = "fsl-usb2-dr", }, 271 + #ifdef CONFIG_PPC_MPC512x 272 + { .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, }, 273 + #endif 199 274 {}, 200 275 }; 201 276
+15
include/linux/fsl_devices.h
··· 58 58 FSL_USB2_PHY_SERIAL, 59 59 }; 60 60 61 + struct clk; 62 + struct platform_device; 63 + 61 64 struct fsl_usb2_platform_data { 62 65 /* board specific information */ 63 66 enum fsl_usb2_operating_modes operating_mode; 64 67 enum fsl_usb2_phy_modes phy_mode; 65 68 unsigned int port_enables; 69 + 70 + int (*init)(struct platform_device *); 71 + void (*exit)(struct platform_device *); 72 + void __iomem *regs; /* ioremap'd register base */ 73 + struct clk *clk; 74 + unsigned big_endian_mmio:1; 75 + unsigned big_endian_desc:1; 76 + unsigned es:1; /* need USBMODE:ES */ 77 + unsigned le_setup_buf:1; 78 + unsigned have_sysif_regs:1; 79 + unsigned invert_drvvbus:1; 80 + unsigned invert_pwr_fault:1; 66 81 }; 67 82 68 83 /* Flags in fsl_usb2_mph_platform_data */