1/* 2 * Copyright 2012 Tilera Corporation. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, version 2. 7 * 8 * This program is distributed in the hope that it will be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 11 * NON INFRINGEMENT. See the GNU General Public License for 12 * more details. 13 */ 14 15/* 16 * Tilera TILE-Gx USB EHCI host controller driver. 17 */ 18 19#include <linux/irq.h> 20#include <linux/platform_device.h> 21#include <linux/usb/tilegx.h> 22#include <linux/usb.h> 23 24#include <asm/homecache.h> 25 26#include <gxio/iorpc_usb_host.h> 27#include <gxio/usb_host.h> 28 29static void tilegx_start_ehc(void) 30{ 31} 32 33static void tilegx_stop_ehc(void) 34{ 35} 36 37static int tilegx_ehci_setup(struct usb_hcd *hcd) 38{ 39 int ret = ehci_init(hcd); 40 41 /* 42 * Some drivers do: 43 * 44 * struct ehci_hcd *ehci = hcd_to_ehci(hcd); 45 * ehci->need_io_watchdog = 0; 46 * 47 * here, but since this is a new driver we're going to leave the 48 * watchdog enabled. Later we may try to turn it off and see 49 * whether we run into any problems. 50 */ 51 52 return ret; 53} 54 55static const struct hc_driver ehci_tilegx_hc_driver = { 56 .description = hcd_name, 57 .product_desc = "Tile-Gx EHCI", 58 .hcd_priv_size = sizeof(struct ehci_hcd), 59 60 /* 61 * Generic hardware linkage. 62 */ 63 .irq = ehci_irq, 64 .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, 65 66 /* 67 * Basic lifecycle operations. 68 */ 69 .reset = tilegx_ehci_setup, 70 .start = ehci_run, 71 .stop = ehci_stop, 72 .shutdown = ehci_shutdown, 73 74 /* 75 * Managing I/O requests and associated device resources. 76 */ 77 .urb_enqueue = ehci_urb_enqueue, 78 .urb_dequeue = ehci_urb_dequeue, 79 .endpoint_disable = ehci_endpoint_disable, 80 .endpoint_reset = ehci_endpoint_reset, 81 82 /* 83 * Scheduling support. 84 */ 85 .get_frame_number = ehci_get_frame, 86 87 /* 88 * Root hub support. 89 */ 90 .hub_status_data = ehci_hub_status_data, 91 .hub_control = ehci_hub_control, 92 .bus_suspend = ehci_bus_suspend, 93 .bus_resume = ehci_bus_resume, 94 .relinquish_port = ehci_relinquish_port, 95 .port_handed_over = ehci_port_handed_over, 96 97 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 98}; 99 100static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev) 101{ 102 struct usb_hcd *hcd; 103 struct ehci_hcd *ehci; 104 struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); 105 pte_t pte = { 0 }; 106 int my_cpu = smp_processor_id(); 107 int ret; 108 109 if (usb_disabled()) 110 return -ENODEV; 111 112 /* 113 * Try to initialize our GXIO context; if we can't, the device 114 * doesn't exist. 115 */ 116 if (gxio_usb_host_init(&pdata->usb_ctx, pdata->dev_index, 1) != 0) 117 return -ENXIO; 118 119 hcd = usb_create_hcd(&ehci_tilegx_hc_driver, &pdev->dev, 120 dev_name(&pdev->dev)); 121 if (!hcd) { 122 ret = -ENOMEM; 123 goto err_hcd; 124 } 125 126 /* 127 * We don't use rsrc_start to map in our registers, but seems like 128 * we ought to set it to something, so we use the register VA. 129 */ 130 hcd->rsrc_start = 131 (ulong) gxio_usb_host_get_reg_start(&pdata->usb_ctx); 132 hcd->rsrc_len = gxio_usb_host_get_reg_len(&pdata->usb_ctx); 133 hcd->regs = gxio_usb_host_get_reg_start(&pdata->usb_ctx); 134 135 tilegx_start_ehc(); 136 137 ehci = hcd_to_ehci(hcd); 138 ehci->caps = hcd->regs; 139 ehci->regs = 140 hcd->regs + HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); 141 /* cache this readonly data; minimize chip reads */ 142 ehci->hcs_params = readl(&ehci->caps->hcs_params); 143 144 /* Create our IRQs and register them. */ 145 pdata->irq = irq_alloc_hwirq(-1); 146 if (!pdata->irq) { 147 ret = -ENXIO; 148 goto err_no_irq; 149 } 150 151 tile_irq_activate(pdata->irq, TILE_IRQ_PERCPU); 152 153 /* Configure interrupts. */ 154 ret = gxio_usb_host_cfg_interrupt(&pdata->usb_ctx, 155 cpu_x(my_cpu), cpu_y(my_cpu), 156 KERNEL_PL, pdata->irq); 157 if (ret) { 158 ret = -ENXIO; 159 goto err_have_irq; 160 } 161 162 /* Register all of our memory. */ 163 pte = pte_set_home(pte, PAGE_HOME_HASH); 164 ret = gxio_usb_host_register_client_memory(&pdata->usb_ctx, pte, 0); 165 if (ret) { 166 ret = -ENXIO; 167 goto err_have_irq; 168 } 169 170 ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED); 171 if (ret == 0) { 172 platform_set_drvdata(pdev, hcd); 173 device_wakeup_enable(hcd->self.controller); 174 return ret; 175 } 176 177err_have_irq: 178 irq_free_hwirq(pdata->irq); 179err_no_irq: 180 tilegx_stop_ehc(); 181 usb_put_hcd(hcd); 182err_hcd: 183 gxio_usb_host_destroy(&pdata->usb_ctx); 184 return ret; 185} 186 187static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev) 188{ 189 struct usb_hcd *hcd = platform_get_drvdata(pdev); 190 struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); 191 192 usb_remove_hcd(hcd); 193 usb_put_hcd(hcd); 194 tilegx_stop_ehc(); 195 gxio_usb_host_destroy(&pdata->usb_ctx); 196 irq_free_hwirq(pdata->irq); 197 198 return 0; 199} 200 201static void ehci_hcd_tilegx_drv_shutdown(struct platform_device *pdev) 202{ 203 usb_hcd_platform_shutdown(pdev); 204 ehci_hcd_tilegx_drv_remove(pdev); 205} 206 207static struct platform_driver ehci_hcd_tilegx_driver = { 208 .probe = ehci_hcd_tilegx_drv_probe, 209 .remove = ehci_hcd_tilegx_drv_remove, 210 .shutdown = ehci_hcd_tilegx_drv_shutdown, 211 .driver = { 212 .name = "tilegx-ehci", 213 } 214}; 215 216MODULE_ALIAS("platform:tilegx-ehci"); 217