* [PATCH 0/3] usb: Add OCTEON II USB support.
@ 2010-10-08 21:47 David Daney
2010-10-08 21:47 ` [PATCH 1/3] MIPS: Octeon: Add register definitions for ehci/ohci USB glue logic David Daney
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: David Daney @ 2010-10-08 21:47 UTC (permalink / raw)
To: ralf, linux-mips, linux-usb, gregkh, dbrownell; +Cc: David Daney
The OCTEON II (CN63XX) is a new member of Cavium Networks' family of
mips64 based SOCs. These parts have an integrated EHCI/OHCI USB host
controller. As implied in the subject, this patch set adds the
necessary glue code to connect this hardware to the standard EHCI and
OHCI drivers.
There are two sets of prerequisite patches that are pending that
should be merged via Ralf's linux-mips.org tree. If these are OK, it
might make sense to either merge via Ralf's tree, or coordinate with
him as to maintain the dependencies between the various patches.
See:
http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=1285964854-28659-1-git-send-email-ddaney%40caviumnetworks.com
http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=1286492633-26885-1-git-send-email-ddaney%40caviumnetworks.com
David Daney (3):
MIPS: Octeon: Add register definitions for ehci/ohci USB glue logic.
usb: Add EHCI and OHCH glue for OCTEON II SOCs.
MIPS: Add platform device and Kconfig for Octeon USB EHCI/OHCI
arch/mips/Kconfig | 2 +
arch/mips/cavium-octeon/octeon-platform.c | 105 ++++++++++-
arch/mips/include/asm/octeon/cvmx-uctlx-defs.h | 261 ++++++++++++++++++++++++
drivers/usb/host/Kconfig | 27 +++-
drivers/usb/host/Makefile | 1 +
drivers/usb/host/ehci-hcd.c | 5 +
drivers/usb/host/ehci-octeon.c | 207 +++++++++++++++++++
drivers/usb/host/octeon2-common.c | 185 +++++++++++++++++
drivers/usb/host/ohci-hcd.c | 5 +
drivers/usb/host/ohci-octeon.c | 214 +++++++++++++++++++
10 files changed, 1010 insertions(+), 2 deletions(-)
create mode 100644 arch/mips/include/asm/octeon/cvmx-uctlx-defs.h
create mode 100644 drivers/usb/host/ehci-octeon.c
create mode 100644 drivers/usb/host/octeon2-common.c
create mode 100644 drivers/usb/host/ohci-octeon.c
--
1.7.2.3
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH 1/3] MIPS: Octeon: Add register definitions for ehci/ohci USB glue logic. 2010-10-08 21:47 [PATCH 0/3] usb: Add OCTEON II USB support David Daney @ 2010-10-08 21:47 ` David Daney 2010-10-11 16:08 ` Ralf Baechle 2010-10-08 21:47 ` [PATCH 2/3] usb: Add EHCI and OHCH glue for OCTEON II SOCs David Daney ` (2 subsequent siblings) 3 siblings, 1 reply; 9+ messages in thread From: David Daney @ 2010-10-08 21:47 UTC (permalink / raw) To: ralf, linux-mips, linux-usb, gregkh, dbrownell; +Cc: David Daney The EHCI and OHCI blocks connection to the I/O bus is controlled by these registers. Signed-off-by: David Daney <ddaney@caviumnetworks.com> --- arch/mips/include/asm/octeon/cvmx-uctlx-defs.h | 261 ++++++++++++++++++++++++ 1 files changed, 261 insertions(+), 0 deletions(-) create mode 100644 arch/mips/include/asm/octeon/cvmx-uctlx-defs.h diff --git a/arch/mips/include/asm/octeon/cvmx-uctlx-defs.h b/arch/mips/include/asm/octeon/cvmx-uctlx-defs.h new file mode 100644 index 0000000..594f1b6 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-uctlx-defs.h @@ -0,0 +1,261 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2010 Cavium Networks + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, Version 2, as + * published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_UCTLX_TYPEDEFS_H__ +#define __CVMX_UCTLX_TYPEDEFS_H__ + +#define CVMX_UCTLX_BIST_STATUS(block_id) (CVMX_ADD_IO_SEG(0x000118006F0000A0ull)) +#define CVMX_UCTLX_CLK_RST_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000000ull)) +#define CVMX_UCTLX_EHCI_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000080ull)) +#define CVMX_UCTLX_EHCI_FLA(block_id) (CVMX_ADD_IO_SEG(0x000118006F0000A8ull)) +#define CVMX_UCTLX_ERTO_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000090ull)) +#define CVMX_UCTLX_IF_ENA(block_id) (CVMX_ADD_IO_SEG(0x000118006F000030ull)) +#define CVMX_UCTLX_INT_ENA(block_id) (CVMX_ADD_IO_SEG(0x000118006F000028ull)) +#define CVMX_UCTLX_INT_REG(block_id) (CVMX_ADD_IO_SEG(0x000118006F000020ull)) +#define CVMX_UCTLX_OHCI_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000088ull)) +#define CVMX_UCTLX_ORTO_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000098ull)) +#define CVMX_UCTLX_PPAF_WM(block_id) (CVMX_ADD_IO_SEG(0x000118006F000038ull)) +#define CVMX_UCTLX_UPHY_CTL_STATUS(block_id) (CVMX_ADD_IO_SEG(0x000118006F000008ull)) +#define CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(offset, block_id) (CVMX_ADD_IO_SEG(0x000118006F000010ull) + (((offset) & 1) + ((block_id) & 0) * 0x0ull) * 8) + +union cvmx_uctlx_bist_status { + uint64_t u64; + struct cvmx_uctlx_bist_status_s { + uint64_t reserved_6_63:58; + uint64_t data_bis:1; + uint64_t desc_bis:1; + uint64_t erbm_bis:1; + uint64_t orbm_bis:1; + uint64_t wrbm_bis:1; + uint64_t ppaf_bis:1; + } s; + struct cvmx_uctlx_bist_status_s cn63xx; + struct cvmx_uctlx_bist_status_s cn63xxp1; +}; + +union cvmx_uctlx_clk_rst_ctl { + uint64_t u64; + struct cvmx_uctlx_clk_rst_ctl_s { + uint64_t reserved_25_63:39; + uint64_t clear_bist:1; + uint64_t start_bist:1; + uint64_t ehci_sm:1; + uint64_t ohci_clkcktrst:1; + uint64_t ohci_sm:1; + uint64_t ohci_susp_lgcy:1; + uint64_t app_start_clk:1; + uint64_t o_clkdiv_rst:1; + uint64_t h_clkdiv_byp:1; + uint64_t h_clkdiv_rst:1; + uint64_t h_clkdiv_en:1; + uint64_t o_clkdiv_en:1; + uint64_t h_div:4; + uint64_t p_refclk_sel:2; + uint64_t p_refclk_div:2; + uint64_t reserved_4_4:1; + uint64_t p_com_on:1; + uint64_t p_por:1; + uint64_t p_prst:1; + uint64_t hrst:1; + } s; + struct cvmx_uctlx_clk_rst_ctl_s cn63xx; + struct cvmx_uctlx_clk_rst_ctl_s cn63xxp1; +}; + +union cvmx_uctlx_ehci_ctl { + uint64_t u64; + struct cvmx_uctlx_ehci_ctl_s { + uint64_t reserved_20_63:44; + uint64_t desc_rbm:1; + uint64_t reg_nb:1; + uint64_t l2c_dc:1; + uint64_t l2c_bc:1; + uint64_t l2c_0pag:1; + uint64_t l2c_stt:1; + uint64_t l2c_buff_emod:2; + uint64_t l2c_desc_emod:2; + uint64_t inv_reg_a2:1; + uint64_t ehci_64b_addr_en:1; + uint64_t l2c_addr_msb:8; + } s; + struct cvmx_uctlx_ehci_ctl_s cn63xx; + struct cvmx_uctlx_ehci_ctl_s cn63xxp1; +}; + +union cvmx_uctlx_ehci_fla { + uint64_t u64; + struct cvmx_uctlx_ehci_fla_s { + uint64_t reserved_6_63:58; + uint64_t fla:6; + } s; + struct cvmx_uctlx_ehci_fla_s cn63xx; + struct cvmx_uctlx_ehci_fla_s cn63xxp1; +}; + +union cvmx_uctlx_erto_ctl { + uint64_t u64; + struct cvmx_uctlx_erto_ctl_s { + uint64_t reserved_32_63:32; + uint64_t to_val:27; + uint64_t reserved_0_4:5; + } s; + struct cvmx_uctlx_erto_ctl_s cn63xx; + struct cvmx_uctlx_erto_ctl_s cn63xxp1; +}; + +union cvmx_uctlx_if_ena { + uint64_t u64; + struct cvmx_uctlx_if_ena_s { + uint64_t reserved_1_63:63; + uint64_t en:1; + } s; + struct cvmx_uctlx_if_ena_s cn63xx; + struct cvmx_uctlx_if_ena_s cn63xxp1; +}; + +union cvmx_uctlx_int_ena { + uint64_t u64; + struct cvmx_uctlx_int_ena_s { + uint64_t reserved_8_63:56; + uint64_t ec_ovf_e:1; + uint64_t oc_ovf_e:1; + uint64_t wb_pop_e:1; + uint64_t wb_psh_f:1; + uint64_t cf_psh_f:1; + uint64_t or_psh_f:1; + uint64_t er_psh_f:1; + uint64_t pp_psh_f:1; + } s; + struct cvmx_uctlx_int_ena_s cn63xx; + struct cvmx_uctlx_int_ena_s cn63xxp1; +}; + +union cvmx_uctlx_int_reg { + uint64_t u64; + struct cvmx_uctlx_int_reg_s { + uint64_t reserved_8_63:56; + uint64_t ec_ovf_e:1; + uint64_t oc_ovf_e:1; + uint64_t wb_pop_e:1; + uint64_t wb_psh_f:1; + uint64_t cf_psh_f:1; + uint64_t or_psh_f:1; + uint64_t er_psh_f:1; + uint64_t pp_psh_f:1; + } s; + struct cvmx_uctlx_int_reg_s cn63xx; + struct cvmx_uctlx_int_reg_s cn63xxp1; +}; + +union cvmx_uctlx_ohci_ctl { + uint64_t u64; + struct cvmx_uctlx_ohci_ctl_s { + uint64_t reserved_19_63:45; + uint64_t reg_nb:1; + uint64_t l2c_dc:1; + uint64_t l2c_bc:1; + uint64_t l2c_0pag:1; + uint64_t l2c_stt:1; + uint64_t l2c_buff_emod:2; + uint64_t l2c_desc_emod:2; + uint64_t inv_reg_a2:1; + uint64_t reserved_8_8:1; + uint64_t l2c_addr_msb:8; + } s; + struct cvmx_uctlx_ohci_ctl_s cn63xx; + struct cvmx_uctlx_ohci_ctl_s cn63xxp1; +}; + +union cvmx_uctlx_orto_ctl { + uint64_t u64; + struct cvmx_uctlx_orto_ctl_s { + uint64_t reserved_32_63:32; + uint64_t to_val:24; + uint64_t reserved_0_7:8; + } s; + struct cvmx_uctlx_orto_ctl_s cn63xx; + struct cvmx_uctlx_orto_ctl_s cn63xxp1; +}; + +union cvmx_uctlx_ppaf_wm { + uint64_t u64; + struct cvmx_uctlx_ppaf_wm_s { + uint64_t reserved_5_63:59; + uint64_t wm:5; + } s; + struct cvmx_uctlx_ppaf_wm_s cn63xx; + struct cvmx_uctlx_ppaf_wm_s cn63xxp1; +}; + +union cvmx_uctlx_uphy_ctl_status { + uint64_t u64; + struct cvmx_uctlx_uphy_ctl_status_s { + uint64_t reserved_10_63:54; + uint64_t bist_done:1; + uint64_t bist_err:1; + uint64_t hsbist:1; + uint64_t fsbist:1; + uint64_t lsbist:1; + uint64_t siddq:1; + uint64_t vtest_en:1; + uint64_t uphy_bist:1; + uint64_t bist_en:1; + uint64_t ate_reset:1; + } s; + struct cvmx_uctlx_uphy_ctl_status_s cn63xx; + struct cvmx_uctlx_uphy_ctl_status_s cn63xxp1; +}; + +union cvmx_uctlx_uphy_portx_ctl_status { + uint64_t u64; + struct cvmx_uctlx_uphy_portx_ctl_status_s { + uint64_t reserved_43_63:21; + uint64_t tdata_out:4; + uint64_t txbiststuffenh:1; + uint64_t txbiststuffen:1; + uint64_t dmpulldown:1; + uint64_t dppulldown:1; + uint64_t vbusvldext:1; + uint64_t portreset:1; + uint64_t txhsvxtune:2; + uint64_t txvreftune:4; + uint64_t txrisetune:1; + uint64_t txpreemphasistune:1; + uint64_t txfslstune:4; + uint64_t sqrxtune:3; + uint64_t compdistune:3; + uint64_t loop_en:1; + uint64_t tclk:1; + uint64_t tdata_sel:1; + uint64_t taddr_in:4; + uint64_t tdata_in:8; + } s; + struct cvmx_uctlx_uphy_portx_ctl_status_s cn63xx; + struct cvmx_uctlx_uphy_portx_ctl_status_s cn63xxp1; +}; + +#endif -- 1.7.2.3 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/3] MIPS: Octeon: Add register definitions for ehci/ohci USB glue logic. 2010-10-08 21:47 ` [PATCH 1/3] MIPS: Octeon: Add register definitions for ehci/ohci USB glue logic David Daney @ 2010-10-11 16:08 ` Ralf Baechle 0 siblings, 0 replies; 9+ messages in thread From: Ralf Baechle @ 2010-10-11 16:08 UTC (permalink / raw) To: David Daney; +Cc: linux-mips, linux-usb, gregkh, dbrownell Thanks, queued for 2.6.37. Ralf ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/3] usb: Add EHCI and OHCH glue for OCTEON II SOCs. 2010-10-08 21:47 [PATCH 0/3] usb: Add OCTEON II USB support David Daney 2010-10-08 21:47 ` [PATCH 1/3] MIPS: Octeon: Add register definitions for ehci/ohci USB glue logic David Daney @ 2010-10-08 21:47 ` David Daney 2010-10-11 16:08 ` Ralf Baechle 2010-10-12 7:23 ` Maulik Mankad 2010-10-08 21:47 ` [PATCH 3/3] MIPS: Add platform device and Kconfig for Octeon USB EHCI/OHCI David Daney 2010-10-08 22:00 ` [PATCH 0/3] usb: Add OCTEON II USB support Greg KH 3 siblings, 2 replies; 9+ messages in thread From: David Daney @ 2010-10-08 21:47 UTC (permalink / raw) To: ralf, linux-mips, linux-usb, gregkh, dbrownell; +Cc: David Daney The OCTEON II SOC has USB EHCI and OHCI controllers connected directly to the internal I/O bus. This patch adds the necessary 'glue' logic to allow ehci-hcd and ohci-hcd drivers to work on OCTEON II. The OCTEON normally runs big-endian, and the ehci/ohci internal registers have host endianness, so we need to select USB_EHCI_BIG_ENDIAN_MMIO. The ehci and ohci blocks share a common clocking and PHY infrastructure. Initialization of the host controller and PHY clocks is common between the two and is factored out into the octeon2-common.c file. Setting of USB_ARCH_HAS_OHCI and USB_ARCH_HAS_EHCI is done in arch/mips/Kconfig in a following patch. Signed-off-by: David Daney <ddaney@caviumnetworks.com> --- drivers/usb/host/Kconfig | 27 +++++- drivers/usb/host/Makefile | 1 + drivers/usb/host/ehci-hcd.c | 5 + drivers/usb/host/ehci-octeon.c | 207 +++++++++++++++++++++++++++++++++++ drivers/usb/host/octeon2-common.c | 185 ++++++++++++++++++++++++++++++++ drivers/usb/host/ohci-hcd.c | 5 + drivers/usb/host/ohci-octeon.c | 214 +++++++++++++++++++++++++++++++++++++ 7 files changed, 643 insertions(+), 1 deletions(-) create mode 100644 drivers/usb/host/ehci-octeon.c create mode 100644 drivers/usb/host/octeon2-common.c create mode 100644 drivers/usb/host/ohci-octeon.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 2d926ce..a03d688 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -93,7 +93,7 @@ config USB_EHCI_TT_NEWSCHED config USB_EHCI_BIG_ENDIAN_MMIO bool - depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX) + depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || CPU_CAVIUM_OCTEON) default y config USB_EHCI_BIG_ENDIAN_DESC @@ -428,3 +428,28 @@ config USB_IMX21_HCD To compile this driver as a module, choose M here: the module will be called "imx21-hcd". +config USB_OCTEON_EHCI + bool "Octeon on-chip EHCI support" + depends on USB && USB_EHCI_HCD && CPU_CAVIUM_OCTEON + default n + select USB_EHCI_BIG_ENDIAN_MMIO + help + Enable support for the Octeon II SOC's on-chip EHCI + controller. It is needed for high-speed (480Mbit/sec) + USB 2.0 device support. All CN6XXX based chips with USB are + supported. + +config USB_OCTEON_OHCI + bool "Octeon on-chip OHCI support" + depends on USB && USB_OHCI_HCD && CPU_CAVIUM_OCTEON + default USB_OCTEON_EHCI + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_OHCI_LITTLE_ENDIAN + help + Enable support for the Octeon II SOC's on-chip OHCI + controller. It is needed for low-speed USB 1.0 device + support. All CN6XXX based chips with USB are supported. + +config USB_OCTEON2_COMMON + bool + default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index b6315aa..36099ce 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -33,4 +33,5 @@ obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o +obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 34a928d..158a520 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1197,6 +1197,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_atmel_driver #endif +#ifdef CONFIG_USB_OCTEON_EHCI +#include "ehci-octeon.c" +#define PLATFORM_DRIVER ehci_octeon_driver +#endif + #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ !defined(XILINX_OF_PLATFORM_DRIVER) diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c new file mode 100644 index 0000000..a31a031 --- /dev/null +++ b/drivers/usb/host/ehci-octeon.c @@ -0,0 +1,207 @@ +/* + * EHCI HCD glue for Cavium Octeon II SOCs. + * + * Loosely based on ehci-au1xxx.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2010 Cavium Networks + * + */ + +#include <linux/platform_device.h> + +#include <asm/octeon/octeon.h> +#include <asm/octeon/cvmx-uctlx-defs.h> + +#define OCTEON_EHCI_HCD_NAME "octeon-ehci" + +/* Common clock init code. */ +void octeon2_usb_clocks_start(void); +void octeon2_usb_clocks_stop(void); + +static void ehci_octeon_start(void) +{ + union cvmx_uctlx_ehci_ctl ehci_ctl; + + octeon2_usb_clocks_start(); + + ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); + /* Use 64-bit addressing. */ + ehci_ctl.s.ehci_64b_addr_en = 1; + ehci_ctl.s.l2c_addr_msb = 0; + ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ + ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ + cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); +} + +static void ehci_octeon_stop(void) +{ + octeon2_usb_clocks_stop(); +} + +static const struct hc_driver ehci_octeon_hc_driver = { + .description = hcd_name, + .product_desc = "Octeon EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_init, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +}; + +static u64 ehci_octeon_dma_mask = DMA_BIT_MASK(64); + +static int ehci_octeon_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct resource *res_mem; + int irq; + int ret; + + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No irq assigned\n"); + return -ENODEV; + } + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem == NULL) { + dev_err(&pdev->dev, "No register space assigned\n"); + return -ENODEV; + } + + /* + * We can DMA from anywhere. But the descriptors must be in + * the lower 4GB. + */ + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &ehci_octeon_dma_mask; + + hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = res_mem->end - res_mem->start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + OCTEON_EHCI_HCD_NAME)) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + ret = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err2; + } + + ehci_octeon_start(); + + ehci = hcd_to_ehci(hcd); + + /* Octeon EHCI matches CPU endianness. */ +#ifdef __BIG_ENDIAN + ehci->big_endian_mmio = 1; +#endif + + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + if (ret) { + dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); + goto err3; + } + + platform_set_drvdata(pdev, hcd); + + /* root ports should always stay powered */ + ehci_port_power(ehci, 1); + + return 0; +err3: + ehci_octeon_stop(); + + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + return ret; +} + +static int ehci_octeon_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + + ehci_octeon_stop(); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ehci_octeon_driver = { + .probe = ehci_octeon_drv_probe, + .remove = ehci_octeon_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = OCTEON_EHCI_HCD_NAME, + .owner = THIS_MODULE, + } +}; + +MODULE_ALIAS("platform:" OCTEON_EHCI_HCD_NAME); diff --git a/drivers/usb/host/octeon2-common.c b/drivers/usb/host/octeon2-common.c new file mode 100644 index 0000000..72d672c --- /dev/null +++ b/drivers/usb/host/octeon2-common.c @@ -0,0 +1,185 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2010 Cavium Networks + */ + +#include <linux/module.h> +#include <linux/delay.h> + +#include <asm/atomic.h> + +#include <asm/octeon/octeon.h> +#include <asm/octeon/cvmx-uctlx-defs.h> + +static atomic_t octeon2_usb_clock_start_cnt = ATOMIC_INIT(0); + +void octeon2_usb_clocks_start(void) +{ + u64 div; + union cvmx_uctlx_if_ena if_ena; + union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; + union cvmx_uctlx_uphy_ctl_status uphy_ctl_status; + union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status; + int i; + unsigned long io_clk_64_to_ns; + + if (atomic_inc_return(&octeon2_usb_clock_start_cnt) != 1) + return; + + io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); + + /* + * Step 1: Wait for voltages stable. That surely happened + * before starting the kernel. + * + * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1 + */ + if_ena.u64 = 0; + if_ena.s.en = 1; + cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); + + /* Step 3: Configure the reference clock, PHY, and HCLK */ + clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); + /* 3a */ + clk_rst_ctl.s.p_por = 1; + clk_rst_ctl.s.hrst = 0; + clk_rst_ctl.s.p_prst = 0; + clk_rst_ctl.s.h_clkdiv_rst = 0; + clk_rst_ctl.s.o_clkdiv_rst = 0; + clk_rst_ctl.s.h_clkdiv_en = 0; + clk_rst_ctl.s.o_clkdiv_en = 0; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 3b */ + /* 12MHz crystal. */ + clk_rst_ctl.s.p_refclk_sel = 0; + clk_rst_ctl.s.p_refclk_div = 0; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 3c */ + div = octeon_get_io_clock_rate() / 130000000ull; + + switch (div) { + case 0: + div = 1; + break; + case 1: + case 2: + case 3: + case 4: + break; + case 5: + div = 4; + break; + case 6: + case 7: + div = 6; + break; + case 8: + case 9: + case 10: + case 11: + div = 8; + break; + default: + div = 12; + break; + } + clk_rst_ctl.s.h_div = div; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + /* Read it back, */ + clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); + clk_rst_ctl.s.h_clkdiv_en = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + /* 3d */ + clk_rst_ctl.s.h_clkdiv_rst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 3e: delay 64 io clocks */ + ndelay(io_clk_64_to_ns); + + /* + * Step 4: Program the power-on reset field in the UCTL + * clock-reset-control register. + */ + clk_rst_ctl.s.p_por = 0; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* Step 5: Wait 1 ms for the PHY clock to start. */ + mdelay(1); + + /* + * Step 6: Program the reset input from automatic test + * equipment field in the UPHY CSR + */ + uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0)); + uphy_ctl_status.s.ate_reset = 1; + cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); + + /* Step 7: Wait for at least 10ns. */ + ndelay(10); + + /* Step 8: Clear the ATE_RESET field in the UPHY CSR. */ + uphy_ctl_status.s.ate_reset = 0; + cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); + + /* + * Step 9: Wait for at least 20ns for UPHY to output PHY clock + * signals and OHCI_CLK48 + */ + ndelay(20); + + /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */ + /* 10a */ + clk_rst_ctl.s.o_clkdiv_rst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 10b */ + clk_rst_ctl.s.o_clkdiv_en = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* 10c */ + ndelay(io_clk_64_to_ns); + + /* + * Step 11: Program the PHY reset field: + * UCTL0_CLK_RST_CTL[P_PRST] = 1 + */ + clk_rst_ctl.s.p_prst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* Step 12: Wait 1 uS. */ + udelay(1); + + /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */ + clk_rst_ctl.s.hrst = 1; + cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); + + /* Now we can set some other registers. */ + + for (i = 0; i <= 1; i++) { + port_ctl_status.u64 = + cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); + /* Set txvreftune to 15 to obtain complient 'eye' diagram. */ + port_ctl_status.s.txvreftune = 15; + cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), + port_ctl_status.u64); + } +} +EXPORT_SYMBOL(octeon2_usb_clocks_start); + +void octeon2_usb_clocks_stop(void) +{ + union cvmx_uctlx_if_ena if_ena; + + if (atomic_dec_return(&octeon2_usb_clock_start_cnt) != 0) + return; + + if_ena.u64 = 0; + if_ena.s.en = 0; + cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); +} +EXPORT_SYMBOL(octeon2_usb_clocks_stop); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c3b4ccc..dc3c675 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1100,6 +1100,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_jz4740_driver #endif +#ifdef CONFIG_USB_OCTEON_OHCI +#include "ohci-octeon.c" +#define PLATFORM_DRIVER ohci_octeon_driver +#endif + #if !defined(PCI_DRIVER) && \ !defined(PLATFORM_DRIVER) && \ !defined(OMAP1_PLATFORM_DRIVER) && \ diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c new file mode 100644 index 0000000..e4ddfaf --- /dev/null +++ b/drivers/usb/host/ohci-octeon.c @@ -0,0 +1,214 @@ +/* + * EHCI HCD glue for Cavium Octeon II SOCs. + * + * Loosely based on ehci-au1xxx.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2010 Cavium Networks + * + */ + +#include <linux/platform_device.h> + +#include <asm/octeon/octeon.h> +#include <asm/octeon/cvmx-uctlx-defs.h> + +#define OCTEON_OHCI_HCD_NAME "octeon-ohci" + +/* Common clock init code. */ +void octeon2_usb_clocks_start(void); +void octeon2_usb_clocks_stop(void); + +static void ohci_octeon_hw_start(void) +{ + union cvmx_uctlx_ohci_ctl ohci_ctl; + + octeon2_usb_clocks_start(); + + ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); + ohci_ctl.s.l2c_addr_msb = 0; + ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ + ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ + cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); + +} + +static void ohci_octeon_hw_stop(void) +{ + /* Undo ohci_octeon_start() */ + octeon2_usb_clocks_stop(); +} + +static int __devinit ohci_octeon_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + ret = ohci_init(ohci); + + if (ret < 0) + return ret; + + ret = ohci_run(ohci); + + if (ret < 0) { + ohci_err(ohci, "can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static const struct hc_driver ohci_octeon_hc_driver = { + .description = hcd_name, + .product_desc = "Octeon OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_octeon_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + + .start_port_reset = ohci_start_port_reset, +}; + +static int ohci_octeon_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct ohci_hcd *ohci; + void *reg_base; + struct resource *res_mem; + int irq; + int ret; + + if (usb_disabled()) + return -ENODEV; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No irq assigned\n"); + return -ENODEV; + } + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem == NULL) { + dev_err(&pdev->dev, "No register space assigned\n"); + return -ENODEV; + } + + /* Ohci is a 32-bit device. */ + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + + hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res_mem->start; + hcd->rsrc_len = res_mem->end - res_mem->start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + OCTEON_OHCI_HCD_NAME)) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + ret = -EBUSY; + goto err1; + } + + reg_base = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!reg_base) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err2; + } + + ohci_octeon_hw_start(); + + hcd->regs = reg_base; + + ohci = hcd_to_ohci(hcd); + + /* Octeon OHCI matches CPU endianness. */ +#ifdef __BIG_ENDIAN + ohci->flags |= OHCI_QUIRK_BE_MMIO; +#endif + + ohci_hcd_init(ohci); + + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); + if (ret) { + dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); + goto err3; + } + + platform_set_drvdata(pdev, hcd); + + return 0; + +err3: + ohci_octeon_hw_stop(); + + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + return ret; +} + +static int ohci_octeon_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + + ohci_octeon_hw_stop(); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ohci_octeon_driver = { + .probe = ohci_octeon_drv_probe, + .remove = ohci_octeon_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = OCTEON_OHCI_HCD_NAME, + .owner = THIS_MODULE, + } +}; + +MODULE_ALIAS("platform:" OCTEON_OHCI_HCD_NAME); -- 1.7.2.3 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 2/3] usb: Add EHCI and OHCH glue for OCTEON II SOCs. 2010-10-08 21:47 ` [PATCH 2/3] usb: Add EHCI and OHCH glue for OCTEON II SOCs David Daney @ 2010-10-11 16:08 ` Ralf Baechle 2010-10-12 7:23 ` Maulik Mankad 1 sibling, 0 replies; 9+ messages in thread From: Ralf Baechle @ 2010-10-11 16:08 UTC (permalink / raw) To: David Daney; +Cc: linux-mips, linux-usb, gregkh, dbrownell Thanks, queued for 2.6.37. Ralf ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/3] usb: Add EHCI and OHCH glue for OCTEON II SOCs. 2010-10-08 21:47 ` [PATCH 2/3] usb: Add EHCI and OHCH glue for OCTEON II SOCs David Daney 2010-10-11 16:08 ` Ralf Baechle @ 2010-10-12 7:23 ` Maulik Mankad 1 sibling, 0 replies; 9+ messages in thread From: Maulik Mankad @ 2010-10-12 7:23 UTC (permalink / raw) To: David Daney; +Cc: ralf, linux-mips, linux-usb, gregkh, dbrownell Hi, On Sat, Oct 9, 2010 at 3:17 AM, David Daney <ddaney@caviumnetworks.com> wrote: > The OCTEON II SOC has USB EHCI and OHCI controllers connected directly > to the internal I/O bus. This patch adds the necessary 'glue' logic > to allow ehci-hcd and ohci-hcd drivers to work on OCTEON II. > > The OCTEON normally runs big-endian, and the ehci/ohci internal > registers have host endianness, so we need to select > USB_EHCI_BIG_ENDIAN_MMIO. > > The ehci and ohci blocks share a common clocking and PHY > infrastructure. Initialization of the host controller and PHY clocks > is common between the two and is factored out into the > octeon2-common.c file. > > Setting of USB_ARCH_HAS_OHCI and USB_ARCH_HAS_EHCI is done in > arch/mips/Kconfig in a following patch. > > Signed-off-by: David Daney <ddaney@caviumnetworks.com> > --- > drivers/usb/host/Kconfig | 27 +++++- > drivers/usb/host/Makefile | 1 + > drivers/usb/host/ehci-hcd.c | 5 + > drivers/usb/host/ehci-octeon.c | 207 +++++++++++++++++++++++++++++++++++ > drivers/usb/host/octeon2-common.c | 185 ++++++++++++++++++++++++++++++++ > drivers/usb/host/ohci-hcd.c | 5 + > drivers/usb/host/ohci-octeon.c | 214 +++++++++++++++++++++++++++++++++++++ > 7 files changed, 643 insertions(+), 1 deletions(-) > create mode 100644 drivers/usb/host/ehci-octeon.c > create mode 100644 drivers/usb/host/octeon2-common.c > create mode 100644 drivers/usb/host/ohci-octeon.c > It would be good to have EHCI and OHCI support in separate patches. > diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig > index 2d926ce..a03d688 100644 > --- a/drivers/usb/host/Kconfig > +++ b/drivers/usb/host/Kconfig > @@ -93,7 +93,7 @@ config USB_EHCI_TT_NEWSCHED > > config USB_EHCI_BIG_ENDIAN_MMIO > bool > - depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX) > + depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || CPU_CAVIUM_OCTEON) > default y > > config USB_EHCI_BIG_ENDIAN_DESC > @@ -428,3 +428,28 @@ config USB_IMX21_HCD > To compile this driver as a module, choose M here: the > module will be called "imx21-hcd". > > +config USB_OCTEON_EHCI > + bool "Octeon on-chip EHCI support" > + depends on USB && USB_EHCI_HCD && CPU_CAVIUM_OCTEON > + default n > + select USB_EHCI_BIG_ENDIAN_MMIO > + help > + Enable support for the Octeon II SOC's on-chip EHCI > + controller. It is needed for high-speed (480Mbit/sec) > + USB 2.0 device support. All CN6XXX based chips with USB are > + supported. > + > +config USB_OCTEON_OHCI > + bool "Octeon on-chip OHCI support" > + depends on USB && USB_OHCI_HCD && CPU_CAVIUM_OCTEON > + default USB_OCTEON_EHCI > + select USB_OHCI_BIG_ENDIAN_MMIO > + select USB_OHCI_LITTLE_ENDIAN > + help > + Enable support for the Octeon II SOC's on-chip OHCI > + controller. It is needed for low-speed USB 1.0 device > + support. All CN6XXX based chips with USB are supported. > + > +config USB_OCTEON2_COMMON > + bool > + default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI > diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile > index b6315aa..36099ce 100644 > --- a/drivers/usb/host/Makefile > +++ b/drivers/usb/host/Makefile > @@ -33,4 +33,5 @@ obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o > obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o > obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o > obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o > +obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o > > diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c > index 34a928d..158a520 100644 > --- a/drivers/usb/host/ehci-hcd.c > +++ b/drivers/usb/host/ehci-hcd.c > @@ -1197,6 +1197,11 @@ MODULE_LICENSE ("GPL"); > #define PLATFORM_DRIVER ehci_atmel_driver > #endif > > +#ifdef CONFIG_USB_OCTEON_EHCI > +#include "ehci-octeon.c" > +#define PLATFORM_DRIVER ehci_octeon_driver > +#endif > + > #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ > !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ > !defined(XILINX_OF_PLATFORM_DRIVER) > diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c > new file mode 100644 > index 0000000..a31a031 > --- /dev/null > +++ b/drivers/usb/host/ehci-octeon.c > @@ -0,0 +1,207 @@ > +/* > + * EHCI HCD glue for Cavium Octeon II SOCs. > + * > + * Loosely based on ehci-au1xxx.c > + * > + * This file is subject to the terms and conditions of the GNU General Public > + * License. See the file "COPYING" in the main directory of this archive > + * for more details. > + * > + * Copyright (C) 2010 Cavium Networks > + * > + */ > + > +#include <linux/platform_device.h> > + > +#include <asm/octeon/octeon.h> > +#include <asm/octeon/cvmx-uctlx-defs.h> > + > +#define OCTEON_EHCI_HCD_NAME "octeon-ehci" > + > +/* Common clock init code. */ > +void octeon2_usb_clocks_start(void); > +void octeon2_usb_clocks_stop(void); > + > +static void ehci_octeon_start(void) > +{ > + union cvmx_uctlx_ehci_ctl ehci_ctl; > + > + octeon2_usb_clocks_start(); > + > + ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); > + /* Use 64-bit addressing. */ > + ehci_ctl.s.ehci_64b_addr_en = 1; > + ehci_ctl.s.l2c_addr_msb = 0; > + ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ > + ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ > + cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); > +} > + > +static void ehci_octeon_stop(void) > +{ > + octeon2_usb_clocks_stop(); > +} > + > +static const struct hc_driver ehci_octeon_hc_driver = { > + .description = hcd_name, > + .product_desc = "Octeon EHCI", > + .hcd_priv_size = sizeof(struct ehci_hcd), > + > + /* > + * generic hardware linkage > + */ > + .irq = ehci_irq, > + .flags = HCD_MEMORY | HCD_USB2, > + > + /* > + * basic lifecycle operations > + */ > + .reset = ehci_init, > + .start = ehci_run, > + .stop = ehci_stop, > + .shutdown = ehci_shutdown, > + > + /* > + * managing i/o requests and associated device resources > + */ > + .urb_enqueue = ehci_urb_enqueue, > + .urb_dequeue = ehci_urb_dequeue, > + .endpoint_disable = ehci_endpoint_disable, > + .endpoint_reset = ehci_endpoint_reset, > + > + /* > + * scheduling support > + */ > + .get_frame_number = ehci_get_frame, > + > + /* > + * root hub support > + */ > + .hub_status_data = ehci_hub_status_data, > + .hub_control = ehci_hub_control, > + .bus_suspend = ehci_bus_suspend, > + .bus_resume = ehci_bus_resume, > + .relinquish_port = ehci_relinquish_port, > + .port_handed_over = ehci_port_handed_over, > + > + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, > +}; > + > +static u64 ehci_octeon_dma_mask = DMA_BIT_MASK(64); > + > +static int ehci_octeon_drv_probe(struct platform_device *pdev) > +{ > + struct usb_hcd *hcd; > + struct ehci_hcd *ehci; > + struct resource *res_mem; > + int irq; > + int ret; > + > + if (usb_disabled()) > + return -ENODEV; > + > + irq = platform_get_irq(pdev, 0); > + if (irq < 0) { > + dev_err(&pdev->dev, "No irq assigned\n"); > + return -ENODEV; > + } > + > + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (res_mem == NULL) { > + dev_err(&pdev->dev, "No register space assigned\n"); > + return -ENODEV; > + } > + > + /* > + * We can DMA from anywhere. But the descriptors must be in > + * the lower 4GB. > + */ > + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); > + pdev->dev.dma_mask = &ehci_octeon_dma_mask; > + > + hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon"); > + if (!hcd) > + return -ENOMEM; > + > + hcd->rsrc_start = res_mem->start; > + hcd->rsrc_len = res_mem->end - res_mem->start + 1; You can use resource_size() to compute the length of the resource. > + > + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, > + OCTEON_EHCI_HCD_NAME)) { > + dev_err(&pdev->dev, "request_mem_region failed\n"); > + ret = -EBUSY; > + goto err1; > + } > + > + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); > + if (!hcd->regs) { > + dev_err(&pdev->dev, "ioremap failed\n"); > + ret = -ENOMEM; > + goto err2; > + } > + > + ehci_octeon_start(); > + > + ehci = hcd_to_ehci(hcd); > + > + /* Octeon EHCI matches CPU endianness. */ > +#ifdef __BIG_ENDIAN > + ehci->big_endian_mmio = 1; > +#endif > + > + ehci->caps = hcd->regs; > + ehci->regs = hcd->regs + > + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); > + /* cache this readonly data; minimize chip reads */ > + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); > + > + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); > + if (ret) { > + dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); > + goto err3; > + } > + > + platform_set_drvdata(pdev, hcd); > + > + /* root ports should always stay powered */ > + ehci_port_power(ehci, 1); > + > + return 0; > +err3: > + ehci_octeon_stop(); > + > + iounmap(hcd->regs); > +err2: > + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); > +err1: > + usb_put_hcd(hcd); > + return ret; > +} [...] > +static int ohci_octeon_drv_probe(struct platform_device *pdev) > +{ > + struct usb_hcd *hcd; > + struct ohci_hcd *ohci; > + void *reg_base; > + struct resource *res_mem; > + int irq; > + int ret; > + > + if (usb_disabled()) > + return -ENODEV; > + > + irq = platform_get_irq(pdev, 0); > + if (irq < 0) { > + dev_err(&pdev->dev, "No irq assigned\n"); > + return -ENODEV; > + } > + > + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (res_mem == NULL) { > + dev_err(&pdev->dev, "No register space assigned\n"); > + return -ENODEV; > + } > + > + /* Ohci is a 32-bit device. */ > + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); > + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; > + > + hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon"); > + if (!hcd) > + return -ENOMEM; > + > + hcd->rsrc_start = res_mem->start; > + hcd->rsrc_len = res_mem->end - res_mem->start + 1; > + Same here. > + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, > + OCTEON_OHCI_HCD_NAME)) { > + dev_err(&pdev->dev, "request_mem_region failed\n"); > + ret = -EBUSY; > + goto err1; > + } > + > + reg_base = ioremap(hcd->rsrc_start, hcd->rsrc_len); > + if (!reg_base) { > + dev_err(&pdev->dev, "ioremap failed\n"); > + ret = -ENOMEM; > + goto err2; > + } > + > + ohci_octeon_hw_start(); > + > + hcd->regs = reg_base; > + > + ohci = hcd_to_ohci(hcd); > + > + /* Octeon OHCI matches CPU endianness. */ > +#ifdef __BIG_ENDIAN > + ohci->flags |= OHCI_QUIRK_BE_MMIO; > +#endif > + > + ohci_hcd_init(ohci); > + > + ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); > + if (ret) { > + dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); > + goto err3; > + } > + > + platform_set_drvdata(pdev, hcd); > + > + return 0; > + > +err3: > + ohci_octeon_hw_stop(); > + > + iounmap(hcd->regs); > +err2: > + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); > +err1: > + usb_put_hcd(hcd); > + return ret; > +} > + Regards, Maulik ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/3] MIPS: Add platform device and Kconfig for Octeon USB EHCI/OHCI 2010-10-08 21:47 [PATCH 0/3] usb: Add OCTEON II USB support David Daney 2010-10-08 21:47 ` [PATCH 1/3] MIPS: Octeon: Add register definitions for ehci/ohci USB glue logic David Daney 2010-10-08 21:47 ` [PATCH 2/3] usb: Add EHCI and OHCH glue for OCTEON II SOCs David Daney @ 2010-10-08 21:47 ` David Daney 2010-10-11 16:08 ` Ralf Baechle 2010-10-08 22:00 ` [PATCH 0/3] usb: Add OCTEON II USB support Greg KH 3 siblings, 1 reply; 9+ messages in thread From: David Daney @ 2010-10-08 21:47 UTC (permalink / raw) To: ralf, linux-mips, linux-usb, gregkh, dbrownell; +Cc: David Daney Declare that OCTEON reference boards have both OHCI and EHCI. Add platform devices for the corresponding hardware. Signed-off-by: David Daney <ddaney@caviumnetworks.com> --- arch/mips/Kconfig | 2 + arch/mips/cavium-octeon/octeon-platform.c | 105 ++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index e68b89f..fbaf08e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -696,6 +696,8 @@ config CAVIUM_OCTEON_REFERENCE_BOARD select HW_HAS_PCI select ARCH_SUPPORTS_MSI select ZONE_DMA32 + select USB_ARCH_HAS_OHCI + select USB_ARCH_HAS_EHCI help This option supports all of the Octeon reference boards from Cavium Networks. It builds a kernel that dynamically determines the Octeon diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 49c3320..cecaf62 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -3,13 +3,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2004-2009 Cavium Networks + * Copyright (C) 2004-2010 Cavium Networks * Copyright (C) 2008 Wind River Systems */ #include <linux/init.h> #include <linux/irq.h> #include <linux/i2c.h> +#include <linux/usb.h> #include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -337,6 +338,108 @@ out: } device_initcall(octeon_mgmt_device_init); +#ifdef CONFIG_USB + +static int __init octeon_ehci_device_init(void) +{ + struct platform_device *pd; + int ret = 0; + + struct resource usb_resources[] = { + { + .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ, + } + }; + + /* Only Octeon2 has ehci/ohci */ + if (!OCTEON_IS_MODEL(OCTEON_CN63XX)) + return 0; + + if (octeon_is_simulation() || usb_disabled()) + return 0; /* No USB in the simulator. */ + + pd = platform_device_alloc("octeon-ehci", 0); + if (!pd) { + ret = -ENOMEM; + goto out; + } + + usb_resources[0].start = 0x00016F0000000000ULL; + usb_resources[0].end = usb_resources[0].start + 0x100; + + usb_resources[1].start = OCTEON_IRQ_USB0; + usb_resources[1].end = OCTEON_IRQ_USB0; + + ret = platform_device_add_resources(pd, usb_resources, + ARRAY_SIZE(usb_resources)); + if (ret) + goto fail; + + ret = platform_device_add(pd); + if (ret) + goto fail; + + return ret; +fail: + platform_device_put(pd); +out: + return ret; +} +device_initcall(octeon_ehci_device_init); + +static int __init octeon_ohci_device_init(void) +{ + struct platform_device *pd; + int ret = 0; + + struct resource usb_resources[] = { + { + .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ, + } + }; + + /* Only Octeon2 has ehci/ohci */ + if (!OCTEON_IS_MODEL(OCTEON_CN63XX)) + return 0; + + if (octeon_is_simulation() || usb_disabled()) + return 0; /* No USB in the simulator. */ + + pd = platform_device_alloc("octeon-ohci", 0); + if (!pd) { + ret = -ENOMEM; + goto out; + } + + usb_resources[0].start = 0x00016F0000000400ULL; + usb_resources[0].end = usb_resources[0].start + 0x100; + + usb_resources[1].start = OCTEON_IRQ_USB0; + usb_resources[1].end = OCTEON_IRQ_USB0; + + ret = platform_device_add_resources(pd, usb_resources, + ARRAY_SIZE(usb_resources)); + if (ret) + goto fail; + + ret = platform_device_add(pd); + if (ret) + goto fail; + + return ret; +fail: + platform_device_put(pd); +out: + return ret; +} +device_initcall(octeon_ohci_device_init); + +#endif /* CONFIG_USB */ + MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Platform driver for Octeon SOC"); -- 1.7.2.3 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 3/3] MIPS: Add platform device and Kconfig for Octeon USB EHCI/OHCI 2010-10-08 21:47 ` [PATCH 3/3] MIPS: Add platform device and Kconfig for Octeon USB EHCI/OHCI David Daney @ 2010-10-11 16:08 ` Ralf Baechle 0 siblings, 0 replies; 9+ messages in thread From: Ralf Baechle @ 2010-10-11 16:08 UTC (permalink / raw) To: David Daney; +Cc: linux-mips, linux-usb, gregkh, dbrownell Thanks, queued for 2.6.37. Ralf ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/3] usb: Add OCTEON II USB support. 2010-10-08 21:47 [PATCH 0/3] usb: Add OCTEON II USB support David Daney ` (2 preceding siblings ...) 2010-10-08 21:47 ` [PATCH 3/3] MIPS: Add platform device and Kconfig for Octeon USB EHCI/OHCI David Daney @ 2010-10-08 22:00 ` Greg KH 3 siblings, 0 replies; 9+ messages in thread From: Greg KH @ 2010-10-08 22:00 UTC (permalink / raw) To: David Daney; +Cc: ralf, linux-mips, linux-usb, dbrownell On Fri, Oct 08, 2010 at 02:47:50PM -0700, David Daney wrote: > The OCTEON II (CN63XX) is a new member of Cavium Networks' family of > mips64 based SOCs. These parts have an integrated EHCI/OHCI USB host > controller. As implied in the subject, this patch set adds the > necessary glue code to connect this hardware to the standard EHCI and > OHCI drivers. > > There are two sets of prerequisite patches that are pending that > should be merged via Ralf's linux-mips.org tree. If these are OK, it > might make sense to either merge via Ralf's tree, or coordinate with > him as to maintain the dependencies between the various patches. No objection from me to take this through Ralf's tree, feel free to add: Acked-by: Greg Kroah-Hartman <gregkh@suse.de> to these patches. thanks, greg k-h ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2010-10-12 7:23 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-10-08 21:47 [PATCH 0/3] usb: Add OCTEON II USB support David Daney 2010-10-08 21:47 ` [PATCH 1/3] MIPS: Octeon: Add register definitions for ehci/ohci USB glue logic David Daney 2010-10-11 16:08 ` Ralf Baechle 2010-10-08 21:47 ` [PATCH 2/3] usb: Add EHCI and OHCH glue for OCTEON II SOCs David Daney 2010-10-11 16:08 ` Ralf Baechle 2010-10-12 7:23 ` Maulik Mankad 2010-10-08 21:47 ` [PATCH 3/3] MIPS: Add platform device and Kconfig for Octeon USB EHCI/OHCI David Daney 2010-10-11 16:08 ` Ralf Baechle 2010-10-08 22:00 ` [PATCH 0/3] usb: Add OCTEON II USB support Greg KH
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.