11643accdaad4625c2877f7ceefa39c1cb3e90117David Daney/* 21643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * EHCI HCD glue for Cavium Octeon II SOCs. 31643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * 41643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * Loosely based on ehci-au1xxx.c 51643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * 61643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * This file is subject to the terms and conditions of the GNU General Public 71643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * License. See the file "COPYING" in the main directory of this archive 81643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * for more details. 91643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * 101643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * Copyright (C) 2010 Cavium Networks 111643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * 121643accdaad4625c2877f7ceefa39c1cb3e90117David Daney */ 131643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 141643accdaad4625c2877f7ceefa39c1cb3e90117David Daney#include <linux/platform_device.h> 151643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 161643accdaad4625c2877f7ceefa39c1cb3e90117David Daney#include <asm/octeon/octeon.h> 171643accdaad4625c2877f7ceefa39c1cb3e90117David Daney#include <asm/octeon/cvmx-uctlx-defs.h> 181643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 191643accdaad4625c2877f7ceefa39c1cb3e90117David Daney#define OCTEON_OHCI_HCD_NAME "octeon-ohci" 201643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 211643accdaad4625c2877f7ceefa39c1cb3e90117David Daney/* Common clock init code. */ 221643accdaad4625c2877f7ceefa39c1cb3e90117David Daneyvoid octeon2_usb_clocks_start(void); 231643accdaad4625c2877f7ceefa39c1cb3e90117David Daneyvoid octeon2_usb_clocks_stop(void); 241643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 251643accdaad4625c2877f7ceefa39c1cb3e90117David Daneystatic void ohci_octeon_hw_start(void) 261643accdaad4625c2877f7ceefa39c1cb3e90117David Daney{ 271643accdaad4625c2877f7ceefa39c1cb3e90117David Daney union cvmx_uctlx_ohci_ctl ohci_ctl; 281643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 291643accdaad4625c2877f7ceefa39c1cb3e90117David Daney octeon2_usb_clocks_start(); 301643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 311643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); 321643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_ctl.s.l2c_addr_msb = 0; 331643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ 341643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ 351643accdaad4625c2877f7ceefa39c1cb3e90117David Daney cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); 361643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 371643accdaad4625c2877f7ceefa39c1cb3e90117David Daney} 381643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 391643accdaad4625c2877f7ceefa39c1cb3e90117David Daneystatic void ohci_octeon_hw_stop(void) 401643accdaad4625c2877f7ceefa39c1cb3e90117David Daney{ 411643accdaad4625c2877f7ceefa39c1cb3e90117David Daney /* Undo ohci_octeon_start() */ 421643accdaad4625c2877f7ceefa39c1cb3e90117David Daney octeon2_usb_clocks_stop(); 431643accdaad4625c2877f7ceefa39c1cb3e90117David Daney} 441643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 4541ac7b3ab7fe1d6175839947a877fdf95cbd2211Bill Pembertonstatic int ohci_octeon_start(struct usb_hcd *hcd) 461643accdaad4625c2877f7ceefa39c1cb3e90117David Daney{ 471643accdaad4625c2877f7ceefa39c1cb3e90117David Daney struct ohci_hcd *ohci = hcd_to_ohci(hcd); 481643accdaad4625c2877f7ceefa39c1cb3e90117David Daney int ret; 491643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 501643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ret = ohci_init(ohci); 511643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 521643accdaad4625c2877f7ceefa39c1cb3e90117David Daney if (ret < 0) 531643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return ret; 541643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 551643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ret = ohci_run(ohci); 561643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 571643accdaad4625c2877f7ceefa39c1cb3e90117David Daney if (ret < 0) { 581643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_err(ohci, "can't start %s", hcd->self.bus_name); 591643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_stop(hcd); 601643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return ret; 611643accdaad4625c2877f7ceefa39c1cb3e90117David Daney } 621643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 631643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return 0; 641643accdaad4625c2877f7ceefa39c1cb3e90117David Daney} 651643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 661643accdaad4625c2877f7ceefa39c1cb3e90117David Daneystatic const struct hc_driver ohci_octeon_hc_driver = { 671643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .description = hcd_name, 681643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .product_desc = "Octeon OHCI", 691643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .hcd_priv_size = sizeof(struct ohci_hcd), 701643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 711643accdaad4625c2877f7ceefa39c1cb3e90117David Daney /* 721643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * generic hardware linkage 731643accdaad4625c2877f7ceefa39c1cb3e90117David Daney */ 741643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .irq = ohci_irq, 751643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .flags = HCD_USB11 | HCD_MEMORY, 761643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 771643accdaad4625c2877f7ceefa39c1cb3e90117David Daney /* 781643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * basic lifecycle operations 791643accdaad4625c2877f7ceefa39c1cb3e90117David Daney */ 801643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .start = ohci_octeon_start, 811643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .stop = ohci_stop, 821643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .shutdown = ohci_shutdown, 831643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 841643accdaad4625c2877f7ceefa39c1cb3e90117David Daney /* 851643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * managing i/o requests and associated device resources 861643accdaad4625c2877f7ceefa39c1cb3e90117David Daney */ 871643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .urb_enqueue = ohci_urb_enqueue, 881643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .urb_dequeue = ohci_urb_dequeue, 891643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .endpoint_disable = ohci_endpoint_disable, 901643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 911643accdaad4625c2877f7ceefa39c1cb3e90117David Daney /* 921643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * scheduling support 931643accdaad4625c2877f7ceefa39c1cb3e90117David Daney */ 941643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .get_frame_number = ohci_get_frame, 951643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 961643accdaad4625c2877f7ceefa39c1cb3e90117David Daney /* 971643accdaad4625c2877f7ceefa39c1cb3e90117David Daney * root hub support 981643accdaad4625c2877f7ceefa39c1cb3e90117David Daney */ 991643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .hub_status_data = ohci_hub_status_data, 1001643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .hub_control = ohci_hub_control, 1011643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1021643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .start_port_reset = ohci_start_port_reset, 1031643accdaad4625c2877f7ceefa39c1cb3e90117David Daney}; 1041643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1051643accdaad4625c2877f7ceefa39c1cb3e90117David Daneystatic int ohci_octeon_drv_probe(struct platform_device *pdev) 1061643accdaad4625c2877f7ceefa39c1cb3e90117David Daney{ 1071643accdaad4625c2877f7ceefa39c1cb3e90117David Daney struct usb_hcd *hcd; 1081643accdaad4625c2877f7ceefa39c1cb3e90117David Daney struct ohci_hcd *ohci; 1091643accdaad4625c2877f7ceefa39c1cb3e90117David Daney void *reg_base; 1101643accdaad4625c2877f7ceefa39c1cb3e90117David Daney struct resource *res_mem; 1111643accdaad4625c2877f7ceefa39c1cb3e90117David Daney int irq; 1121643accdaad4625c2877f7ceefa39c1cb3e90117David Daney int ret; 1131643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1141643accdaad4625c2877f7ceefa39c1cb3e90117David Daney if (usb_disabled()) 1151643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return -ENODEV; 1161643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1171643accdaad4625c2877f7ceefa39c1cb3e90117David Daney irq = platform_get_irq(pdev, 0); 1181643accdaad4625c2877f7ceefa39c1cb3e90117David Daney if (irq < 0) { 1191643accdaad4625c2877f7ceefa39c1cb3e90117David Daney dev_err(&pdev->dev, "No irq assigned\n"); 1201643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return -ENODEV; 1211643accdaad4625c2877f7ceefa39c1cb3e90117David Daney } 1221643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1231643accdaad4625c2877f7ceefa39c1cb3e90117David Daney res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1241643accdaad4625c2877f7ceefa39c1cb3e90117David Daney if (res_mem == NULL) { 1251643accdaad4625c2877f7ceefa39c1cb3e90117David Daney dev_err(&pdev->dev, "No register space assigned\n"); 1261643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return -ENODEV; 1271643accdaad4625c2877f7ceefa39c1cb3e90117David Daney } 1281643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1291643accdaad4625c2877f7ceefa39c1cb3e90117David Daney /* Ohci is a 32-bit device. */ 130e1fd7341837238c6c5380c5073887d238f706cf0Russell King ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 13122d9d8e8316d7f69046c8805ce9aa8d9c43d4e5bRussell King if (ret) 13222d9d8e8316d7f69046c8805ce9aa8d9c43d4e5bRussell King return ret; 1331643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1341643accdaad4625c2877f7ceefa39c1cb3e90117David Daney hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon"); 1351643accdaad4625c2877f7ceefa39c1cb3e90117David Daney if (!hcd) 1361643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return -ENOMEM; 1371643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1381643accdaad4625c2877f7ceefa39c1cb3e90117David Daney hcd->rsrc_start = res_mem->start; 13928f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches hcd->rsrc_len = resource_size(res_mem); 1401643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 14181574fc65f67ca5948ee80af0ec030a20a802dd3Jingoo Han reg_base = devm_ioremap_resource(&pdev->dev, res_mem); 14281574fc65f67ca5948ee80af0ec030a20a802dd3Jingoo Han if (IS_ERR(reg_base)) { 14381574fc65f67ca5948ee80af0ec030a20a802dd3Jingoo Han ret = PTR_ERR(reg_base); 1441643accdaad4625c2877f7ceefa39c1cb3e90117David Daney goto err1; 1451643accdaad4625c2877f7ceefa39c1cb3e90117David Daney } 1461643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1471643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_octeon_hw_start(); 1481643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1491643accdaad4625c2877f7ceefa39c1cb3e90117David Daney hcd->regs = reg_base; 1501643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1511643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci = hcd_to_ohci(hcd); 1521643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1531643accdaad4625c2877f7ceefa39c1cb3e90117David Daney /* Octeon OHCI matches CPU endianness. */ 1541643accdaad4625c2877f7ceefa39c1cb3e90117David Daney#ifdef __BIG_ENDIAN 1551643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci->flags |= OHCI_QUIRK_BE_MMIO; 1561643accdaad4625c2877f7ceefa39c1cb3e90117David Daney#endif 1571643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1581643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_hcd_init(ohci); 1591643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 160b5dd18d8747010e3f3eb1cc76a49f94291938559Yong Zhang ret = usb_add_hcd(hcd, irq, IRQF_SHARED); 1611643accdaad4625c2877f7ceefa39c1cb3e90117David Daney if (ret) { 1621643accdaad4625c2877f7ceefa39c1cb3e90117David Daney dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); 16381574fc65f67ca5948ee80af0ec030a20a802dd3Jingoo Han goto err2; 1641643accdaad4625c2877f7ceefa39c1cb3e90117David Daney } 1651643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1663c9740a117d40a74412775b5d3fe2b88a7635a0ePeter Chen device_wakeup_enable(hcd->self.controller); 1673c9740a117d40a74412775b5d3fe2b88a7635a0ePeter Chen 1681643accdaad4625c2877f7ceefa39c1cb3e90117David Daney platform_set_drvdata(pdev, hcd); 1691643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1701643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return 0; 1711643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 17281574fc65f67ca5948ee80af0ec030a20a802dd3Jingoo Hanerr2: 1731643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_octeon_hw_stop(); 1741643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1751643accdaad4625c2877f7ceefa39c1cb3e90117David Daneyerr1: 1761643accdaad4625c2877f7ceefa39c1cb3e90117David Daney usb_put_hcd(hcd); 1771643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return ret; 1781643accdaad4625c2877f7ceefa39c1cb3e90117David Daney} 1791643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1801643accdaad4625c2877f7ceefa39c1cb3e90117David Daneystatic int ohci_octeon_drv_remove(struct platform_device *pdev) 1811643accdaad4625c2877f7ceefa39c1cb3e90117David Daney{ 1821643accdaad4625c2877f7ceefa39c1cb3e90117David Daney struct usb_hcd *hcd = platform_get_drvdata(pdev); 1831643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1841643accdaad4625c2877f7ceefa39c1cb3e90117David Daney usb_remove_hcd(hcd); 1851643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1861643accdaad4625c2877f7ceefa39c1cb3e90117David Daney ohci_octeon_hw_stop(); 1871643accdaad4625c2877f7ceefa39c1cb3e90117David Daney usb_put_hcd(hcd); 1881643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1891643accdaad4625c2877f7ceefa39c1cb3e90117David Daney return 0; 1901643accdaad4625c2877f7ceefa39c1cb3e90117David Daney} 1911643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 1921643accdaad4625c2877f7ceefa39c1cb3e90117David Daneystatic struct platform_driver ohci_octeon_driver = { 1931643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .probe = ohci_octeon_drv_probe, 1941643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .remove = ohci_octeon_drv_remove, 1951643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .shutdown = usb_hcd_platform_shutdown, 1961643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .driver = { 1971643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .name = OCTEON_OHCI_HCD_NAME, 1981643accdaad4625c2877f7ceefa39c1cb3e90117David Daney .owner = THIS_MODULE, 1991643accdaad4625c2877f7ceefa39c1cb3e90117David Daney } 2001643accdaad4625c2877f7ceefa39c1cb3e90117David Daney}; 2011643accdaad4625c2877f7ceefa39c1cb3e90117David Daney 2021643accdaad4625c2877f7ceefa39c1cb3e90117David DaneyMODULE_ALIAS("platform:" OCTEON_OHCI_HCD_NAME); 203