2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2016-11-04 03:55:50 +03:00
/*
* Copyright ( C ) 2004 - 2016 Synopsys , Inc .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions , and the following disclaimer ,
* without modification .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The names of the above - listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission .
*
* ALTERNATIVELY , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) as published by the Free Software
* Foundation ; either version 2 of the License , or ( at your option ) any
* later version .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS
* IS " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
* PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_device.h>
# include "core.h"
2017-01-24 01:57:04 +03:00
static void dwc2_set_bcm_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
2016-11-04 03:55:50 +03:00
2017-01-24 01:57:04 +03:00
p - > host_rx_fifo_size = 774 ;
p - > max_transfer_size = 65535 ;
p - > max_packet_count = 511 ;
p - > ahbcfg = 0x10 ;
}
2016-11-04 03:55:50 +03:00
2017-01-24 01:57:04 +03:00
static void dwc2_set_his_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
2016-11-04 03:55:50 +03:00
2017-01-24 01:57:04 +03:00
p - > otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE ;
p - > speed = DWC2_SPEED_PARAM_HIGH ;
p - > host_rx_fifo_size = 512 ;
p - > host_nperio_tx_fifo_size = 512 ;
p - > host_perio_tx_fifo_size = 512 ;
p - > max_transfer_size = 65535 ;
p - > max_packet_count = 511 ;
p - > host_channels = 16 ;
p - > phy_type = DWC2_PHY_TYPE_PARAM_UTMI ;
p - > phy_utmi_width = 8 ;
p - > i2c_enable = false ;
p - > reload_ctl = false ;
p - > ahbcfg = GAHBCFG_HBSTLEN_INCR16 < <
GAHBCFG_HBSTLEN_SHIFT ;
2017-01-24 02:00:18 +03:00
p - > change_speed_quirk = true ;
2020-06-16 11:26:17 +03:00
p - > power_down = DWC2_POWER_DOWN_PARAM_NONE ;
2017-01-24 01:57:04 +03:00
}
2016-11-04 03:55:50 +03:00
2018-11-20 18:38:15 +03:00
static void dwc2_set_s3c6400_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
2020-06-16 11:26:17 +03:00
p - > power_down = DWC2_POWER_DOWN_PARAM_NONE ;
2019-06-14 09:52:53 +03:00
p - > phy_utmi_width = 8 ;
2018-11-20 18:38:15 +03:00
}
2017-01-24 01:57:04 +03:00
static void dwc2_set_rk_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE ;
p - > host_rx_fifo_size = 525 ;
p - > host_nperio_tx_fifo_size = 128 ;
p - > host_perio_tx_fifo_size = 256 ;
p - > ahbcfg = GAHBCFG_HBSTLEN_INCR16 < <
GAHBCFG_HBSTLEN_SHIFT ;
2020-06-16 11:26:17 +03:00
p - > power_down = DWC2_POWER_DOWN_PARAM_NONE ;
2017-01-24 01:57:04 +03:00
}
static void dwc2_set_ltq_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > otg_cap = 2 ;
p - > host_rx_fifo_size = 288 ;
p - > host_nperio_tx_fifo_size = 128 ;
p - > host_perio_tx_fifo_size = 96 ;
p - > max_transfer_size = 65535 ;
p - > max_packet_count = 511 ;
p - > ahbcfg = GAHBCFG_HBSTLEN_INCR16 < <
GAHBCFG_HBSTLEN_SHIFT ;
}
static void dwc2_set_amlogic_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE ;
p - > speed = DWC2_SPEED_PARAM_HIGH ;
p - > host_rx_fifo_size = 512 ;
p - > host_nperio_tx_fifo_size = 500 ;
p - > host_perio_tx_fifo_size = 500 ;
p - > host_channels = 16 ;
p - > phy_type = DWC2_PHY_TYPE_PARAM_UTMI ;
p - > ahbcfg = GAHBCFG_HBSTLEN_INCR8 < <
GAHBCFG_HBSTLEN_SHIFT ;
2018-12-09 22:01:29 +03:00
p - > power_down = DWC2_POWER_DOWN_PARAM_NONE ;
2017-01-24 01:57:04 +03:00
}
2019-04-23 11:51:26 +03:00
static void dwc2_set_amlogic_g12a_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > lpm = false ;
p - > lpm_clock_gating = false ;
p - > besl = false ;
p - > hird_threshold_en = false ;
}
2017-01-24 01:57:04 +03:00
static void dwc2_set_amcc_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > ahbcfg = GAHBCFG_HBSTLEN_INCR16 < < GAHBCFG_HBSTLEN_SHIFT ;
}
2016-11-04 03:55:50 +03:00
2017-02-01 04:25:43 +03:00
static void dwc2_set_stm32f4x9_fsotg_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE ;
p - > speed = DWC2_SPEED_PARAM_FULL ;
p - > host_rx_fifo_size = 128 ;
p - > host_nperio_tx_fifo_size = 96 ;
p - > host_perio_tx_fifo_size = 96 ;
p - > max_packet_count = 256 ;
p - > phy_type = DWC2_PHY_TYPE_PARAM_FS ;
p - > i2c_enable = false ;
p - > activate_stm_fs_transceiver = true ;
}
2018-03-01 13:05:35 +03:00
static void dwc2_set_stm32f7_hsotg_params ( struct dwc2_hsotg * hsotg )
2017-08-17 12:33:01 +03:00
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > host_rx_fifo_size = 622 ;
p - > host_nperio_tx_fifo_size = 128 ;
p - > host_perio_tx_fifo_size = 256 ;
}
2020-01-24 11:41:31 +03:00
static void dwc2_set_stm32mp15_fsotg_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE ;
p - > speed = DWC2_SPEED_PARAM_FULL ;
p - > host_rx_fifo_size = 128 ;
p - > host_nperio_tx_fifo_size = 96 ;
p - > host_perio_tx_fifo_size = 96 ;
p - > max_packet_count = 256 ;
p - > phy_type = DWC2_PHY_TYPE_PARAM_FS ;
p - > i2c_enable = false ;
p - > activate_stm_fs_transceiver = true ;
p - > activate_stm_id_vb_detection = true ;
p - > power_down = DWC2_POWER_DOWN_PARAM_NONE ;
}
static void dwc2_set_stm32mp15_hsotg_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE ;
2020-09-09 12:35:11 +03:00
p - > activate_stm_id_vb_detection = ! device_property_read_bool ( hsotg - > dev , " usb-role-switch " ) ;
2020-01-24 11:41:31 +03:00
p - > host_rx_fifo_size = 440 ;
p - > host_nperio_tx_fifo_size = 256 ;
p - > host_perio_tx_fifo_size = 256 ;
p - > power_down = DWC2_POWER_DOWN_PARAM_NONE ;
}
2016-11-04 03:55:50 +03:00
const struct of_device_id dwc2_of_match_table [ ] = {
2017-01-24 01:57:04 +03:00
{ . compatible = " brcm,bcm2835-usb " , . data = dwc2_set_bcm_params } ,
{ . compatible = " hisilicon,hi6220-usb " , . data = dwc2_set_his_params } ,
{ . compatible = " rockchip,rk3066-usb " , . data = dwc2_set_rk_params } ,
{ . compatible = " lantiq,arx100-usb " , . data = dwc2_set_ltq_params } ,
{ . compatible = " lantiq,xrx200-usb " , . data = dwc2_set_ltq_params } ,
{ . compatible = " snps,dwc2 " } ,
2018-11-20 18:38:15 +03:00
{ . compatible = " samsung,s3c6400-hsotg " ,
. data = dwc2_set_s3c6400_params } ,
2017-05-06 20:37:45 +03:00
{ . compatible = " amlogic,meson8-usb " ,
. data = dwc2_set_amlogic_params } ,
2017-01-24 01:57:04 +03:00
{ . compatible = " amlogic,meson8b-usb " ,
. data = dwc2_set_amlogic_params } ,
{ . compatible = " amlogic,meson-gxbb-usb " ,
. data = dwc2_set_amlogic_params } ,
2019-04-23 11:51:26 +03:00
{ . compatible = " amlogic,meson-g12a-usb " ,
. data = dwc2_set_amlogic_g12a_params } ,
2017-01-24 01:57:04 +03:00
{ . compatible = " amcc,dwc-otg " , . data = dwc2_set_amcc_params } ,
2020-09-20 03:18:50 +03:00
{ . compatible = " apm,apm82181-dwc-otg " , . data = dwc2_set_amcc_params } ,
2017-02-01 04:25:43 +03:00
{ . compatible = " st,stm32f4x9-fsotg " ,
. data = dwc2_set_stm32f4x9_fsotg_params } ,
{ . compatible = " st,stm32f4x9-hsotg " } ,
2018-03-01 13:05:35 +03:00
{ . compatible = " st,stm32f7-hsotg " ,
. data = dwc2_set_stm32f7_hsotg_params } ,
2020-01-24 11:41:31 +03:00
{ . compatible = " st,stm32mp15-fsotg " ,
. data = dwc2_set_stm32mp15_fsotg_params } ,
{ . compatible = " st,stm32mp15-hsotg " ,
. data = dwc2_set_stm32mp15_hsotg_params } ,
2016-11-04 03:55:50 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , dwc2_of_match_table ) ;
2017-01-24 01:55:14 +03:00
static void dwc2_set_param_otg_cap ( struct dwc2_hsotg * hsotg )
2016-11-04 03:56:05 +03:00
{
2017-01-24 01:55:14 +03:00
u8 val ;
2016-11-04 03:56:05 +03:00
2017-01-24 01:55:14 +03:00
switch ( hsotg - > hw_params . op_mode ) {
case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE :
val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE ;
2016-11-04 03:56:05 +03:00
break ;
2017-01-24 01:55:14 +03:00
case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE :
case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE :
case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST :
val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE ;
2016-11-04 03:56:05 +03:00
break ;
default :
2017-01-24 01:55:14 +03:00
val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE ;
2016-11-04 03:56:05 +03:00
break ;
2016-11-04 03:55:50 +03:00
}
2016-11-04 03:55:53 +03:00
hsotg - > params . otg_cap = val ;
2016-11-04 03:55:50 +03:00
}
2017-01-24 01:55:14 +03:00
static void dwc2_set_param_phy_type ( struct dwc2_hsotg * hsotg )
2016-11-04 03:55:50 +03:00
{
2017-01-24 01:55:14 +03:00
int val ;
u32 hs_phy_type = hsotg - > hw_params . hs_phy_type ;
2016-11-04 03:55:50 +03:00
2017-01-24 01:55:14 +03:00
val = DWC2_PHY_TYPE_PARAM_FS ;
if ( hs_phy_type ! = GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED ) {
if ( hs_phy_type = = GHWCFG2_HS_PHY_TYPE_UTMI | |
hs_phy_type = = GHWCFG2_HS_PHY_TYPE_UTMI_ULPI )
val = DWC2_PHY_TYPE_PARAM_UTMI ;
else
val = DWC2_PHY_TYPE_PARAM_ULPI ;
2016-11-04 03:55:50 +03:00
}
2017-01-24 01:55:14 +03:00
if ( dwc2_is_fs_iot ( hsotg ) )
hsotg - > params . phy_type = DWC2_PHY_TYPE_PARAM_FS ;
2016-11-04 03:55:50 +03:00
2016-11-04 03:55:53 +03:00
hsotg - > params . phy_type = val ;
2016-11-04 03:55:50 +03:00
}
2017-01-24 01:55:14 +03:00
static void dwc2_set_param_speed ( struct dwc2_hsotg * hsotg )
2016-11-04 03:55:50 +03:00
{
2017-01-24 01:55:14 +03:00
int val ;
2016-11-04 03:55:50 +03:00
2017-01-24 01:55:14 +03:00
val = hsotg - > params . phy_type = = DWC2_PHY_TYPE_PARAM_FS ?
DWC2_SPEED_PARAM_FULL : DWC2_SPEED_PARAM_HIGH ;
2016-11-04 03:55:50 +03:00
2017-01-24 01:55:14 +03:00
if ( dwc2_is_fs_iot ( hsotg ) )
val = DWC2_SPEED_PARAM_FULL ;
2016-11-15 06:17:03 +03:00
2017-01-24 01:55:14 +03:00
if ( dwc2_is_hs_iot ( hsotg ) )
val = DWC2_SPEED_PARAM_HIGH ;
2016-11-04 03:55:50 +03:00
2016-11-04 03:55:53 +03:00
hsotg - > params . speed = val ;
2016-11-04 03:55:50 +03:00
}
2017-01-24 01:55:14 +03:00
static void dwc2_set_param_phy_utmi_width ( struct dwc2_hsotg * hsotg )
2016-11-04 03:55:50 +03:00
{
2017-01-24 01:55:14 +03:00
int val ;
2016-11-04 03:55:50 +03:00
2017-01-24 01:55:14 +03:00
val = ( hsotg - > hw_params . utmi_phy_data_width = =
GHWCFG4_UTMI_PHY_DATA_WIDTH_8 ) ? 8 : 16 ;
2016-11-04 03:55:50 +03:00
2019-05-09 12:15:28 +03:00
if ( hsotg - > phy ) {
/*
* If using the generic PHY framework , check if the PHY bus
* width is 8 - bit and set the phyif appropriately .
*/
if ( phy_get_bus_width ( hsotg - > phy ) = = 8 )
val = 8 ;
}
2016-11-04 03:55:53 +03:00
hsotg - > params . phy_utmi_width = val ;
2016-11-04 03:55:50 +03:00
}
2016-11-04 03:56:05 +03:00
static void dwc2_set_param_tx_fifo_sizes ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
2017-01-24 02:01:23 +03:00
int depth_average ;
int fifo_count ;
int i ;
fifo_count = dwc2_hsotg_tx_fifo_count ( hsotg ) ;
2016-11-04 03:56:05 +03:00
memset ( p - > g_tx_fifo_size , 0 , sizeof ( p - > g_tx_fifo_size ) ) ;
2017-01-24 02:01:23 +03:00
depth_average = dwc2_hsotg_tx_fifo_average_depth ( hsotg ) ;
for ( i = 1 ; i < = fifo_count ; i + + )
p - > g_tx_fifo_size [ i ] = depth_average ;
2016-11-10 06:27:40 +03:00
}
2018-02-16 13:12:28 +03:00
static void dwc2_set_param_power_down ( struct dwc2_hsotg * hsotg )
{
int val ;
if ( hsotg - > hw_params . hibernation )
2020-06-16 11:26:17 +03:00
val = DWC2_POWER_DOWN_PARAM_HIBERNATION ;
2018-02-16 13:12:28 +03:00
else if ( hsotg - > hw_params . power_optimized )
2020-06-16 11:26:17 +03:00
val = DWC2_POWER_DOWN_PARAM_PARTIAL ;
2018-02-16 13:12:28 +03:00
else
2020-06-16 11:26:17 +03:00
val = DWC2_POWER_DOWN_PARAM_NONE ;
2018-02-16 13:12:28 +03:00
hsotg - > params . power_down = val ;
}
2019-03-04 16:08:07 +03:00
static void dwc2_set_param_lpm ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
p - > lpm = hsotg - > hw_params . lpm_mode ;
if ( p - > lpm ) {
p - > lpm_clock_gating = true ;
p - > besl = true ;
p - > hird_threshold_en = true ;
p - > hird_threshold = 4 ;
} else {
p - > lpm_clock_gating = false ;
p - > besl = false ;
p - > hird_threshold_en = false ;
}
}
2016-11-04 03:56:05 +03:00
/**
2017-01-24 01:55:14 +03:00
* dwc2_set_default_params ( ) - Set all core parameters to their
* auto - detected default values .
2018-05-16 11:04:24 +03:00
*
* @ hsotg : Programming view of the DWC_otg controller
*
2016-11-04 03:55:50 +03:00
*/
2017-01-24 01:55:14 +03:00
static void dwc2_set_default_params ( struct dwc2_hsotg * hsotg )
2016-11-04 03:55:50 +03:00
{
2016-11-04 03:56:05 +03:00
struct dwc2_hw_params * hw = & hsotg - > hw_params ;
struct dwc2_core_params * p = & hsotg - > params ;
2016-11-04 03:56:12 +03:00
bool dma_capable = ! ( hw - > arch = = GHWCFG2_SLAVE_ONLY_ARCH ) ;
2016-11-04 03:55:50 +03:00
2017-01-24 01:55:14 +03:00
dwc2_set_param_otg_cap ( hsotg ) ;
dwc2_set_param_phy_type ( hsotg ) ;
dwc2_set_param_speed ( hsotg ) ;
dwc2_set_param_phy_utmi_width ( hsotg ) ;
2018-02-16 13:12:28 +03:00
dwc2_set_param_power_down ( hsotg ) ;
2019-03-04 16:08:07 +03:00
dwc2_set_param_lpm ( hsotg ) ;
2017-01-24 01:55:14 +03:00
p - > phy_ulpi_ddr = false ;
p - > phy_ulpi_ext_vbus = false ;
p - > enable_dynamic_fifo = hw - > enable_dynamic_fifo ;
p - > en_multiple_tx_fifo = hw - > en_multiple_tx_fifo ;
p - > i2c_enable = hw - > i2c_enable ;
2018-01-24 16:40:29 +03:00
p - > acg_enable = hw - > acg_enable ;
2017-01-24 01:55:14 +03:00
p - > ulpi_fs_ls = false ;
p - > ts_dline = false ;
p - > reload_ctl = ( hw - > snpsid > = DWC2_CORE_REV_2_92a ) ;
p - > uframe_sched = true ;
p - > external_id_pin_ctl = false ;
2018-05-05 11:17:58 +03:00
p - > ipg_isoc_en = false ;
2018-08-29 19:59:34 +03:00
p - > service_interval = false ;
2017-01-24 01:55:14 +03:00
p - > max_packet_count = hw - > max_packet_count ;
p - > max_transfer_size = hw - > max_transfer_size ;
2018-01-19 13:40:23 +03:00
p - > ahbcfg = GAHBCFG_HBSTLEN_INCR < < GAHBCFG_HBSTLEN_SHIFT ;
2018-08-29 20:01:31 +03:00
p - > ref_clk_per = 33333 ;
p - > sof_cnt_wkup_alert = 100 ;
2017-01-24 01:55:14 +03:00
2016-11-04 03:56:12 +03:00
if ( ( hsotg - > dr_mode = = USB_DR_MODE_HOST ) | |
( hsotg - > dr_mode = = USB_DR_MODE_OTG ) ) {
2017-01-24 01:55:14 +03:00
p - > host_dma = dma_capable ;
p - > dma_desc_enable = false ;
p - > dma_desc_fs_enable = false ;
p - > host_support_fs_ls_low_power = false ;
p - > host_ls_low_power_phy_clk = false ;
p - > host_channels = hw - > host_channels ;
p - > host_rx_fifo_size = hw - > rx_fifo_size ;
p - > host_nperio_tx_fifo_size = hw - > host_nperio_tx_fifo_size ;
p - > host_perio_tx_fifo_size = hw - > host_perio_tx_fifo_size ;
2016-11-04 03:56:12 +03:00
}
2016-11-04 03:56:05 +03:00
if ( ( hsotg - > dr_mode = = USB_DR_MODE_PERIPHERAL ) | |
( hsotg - > dr_mode = = USB_DR_MODE_OTG ) ) {
2017-01-24 01:55:14 +03:00
p - > g_dma = dma_capable ;
p - > g_dma_desc = hw - > dma_desc_enable ;
2016-11-04 03:56:05 +03:00
/*
* The values for g_rx_fifo_size ( 2048 ) and
* g_np_tx_fifo_size ( 1024 ) come from the legacy s3c
* gadget driver . These defaults have been hard - coded
* for some time so many platforms depend on these
* values . Leave them as defaults for now and only
* auto - detect if the hardware does not support the
* default .
*/
2017-01-24 01:55:14 +03:00
p - > g_rx_fifo_size = 2048 ;
p - > g_np_tx_fifo_size = 1024 ;
2016-11-04 03:56:05 +03:00
dwc2_set_param_tx_fifo_sizes ( hsotg ) ;
}
2016-11-04 03:55:50 +03:00
}
2017-01-24 01:55:35 +03:00
/**
* dwc2_get_device_properties ( ) - Read in device properties .
*
2018-05-16 11:04:24 +03:00
* @ hsotg : Programming view of the DWC_otg controller
*
2017-01-24 01:55:35 +03:00
* Read in the device properties and adjust core parameters if needed .
*/
static void dwc2_get_device_properties ( struct dwc2_hsotg * hsotg )
{
struct dwc2_core_params * p = & hsotg - > params ;
int num ;
if ( ( hsotg - > dr_mode = = USB_DR_MODE_PERIPHERAL ) | |
( hsotg - > dr_mode = = USB_DR_MODE_OTG ) ) {
device_property_read_u32 ( hsotg - > dev , " g-rx-fifo-size " ,
& p - > g_rx_fifo_size ) ;
device_property_read_u32 ( hsotg - > dev , " g-np-tx-fifo-size " ,
& p - > g_np_tx_fifo_size ) ;
2019-07-23 22:16:39 +03:00
num = device_property_count_u32 ( hsotg - > dev , " g-tx-fifo-size " ) ;
2017-01-24 01:55:35 +03:00
if ( num > 0 ) {
num = min ( num , 15 ) ;
memset ( p - > g_tx_fifo_size , 0 ,
sizeof ( p - > g_tx_fifo_size ) ) ;
device_property_read_u32_array ( hsotg - > dev ,
" g-tx-fifo-size " ,
& p - > g_tx_fifo_size [ 1 ] ,
num ) ;
}
}
2017-10-16 16:57:18 +03:00
if ( of_find_property ( hsotg - > dev - > of_node , " disable-over-current " , NULL ) )
p - > oc_disable = true ;
2017-01-24 01:55:35 +03:00
}
2017-01-24 01:56:43 +03:00
static void dwc2_check_param_otg_cap ( struct dwc2_hsotg * hsotg )
{
int valid = 1 ;
switch ( hsotg - > params . otg_cap ) {
case DWC2_CAP_PARAM_HNP_SRP_CAPABLE :
if ( hsotg - > hw_params . op_mode ! = GHWCFG2_OP_MODE_HNP_SRP_CAPABLE )
valid = 0 ;
break ;
case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE :
switch ( hsotg - > hw_params . op_mode ) {
case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE :
case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE :
case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE :
case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST :
break ;
default :
valid = 0 ;
break ;
}
break ;
case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE :
/* always valid */
break ;
default :
valid = 0 ;
break ;
}
if ( ! valid )
dwc2_set_param_otg_cap ( hsotg ) ;
}
static void dwc2_check_param_phy_type ( struct dwc2_hsotg * hsotg )
{
int valid = 0 ;
u32 hs_phy_type ;
u32 fs_phy_type ;
hs_phy_type = hsotg - > hw_params . hs_phy_type ;
fs_phy_type = hsotg - > hw_params . fs_phy_type ;
switch ( hsotg - > params . phy_type ) {
case DWC2_PHY_TYPE_PARAM_FS :
if ( fs_phy_type = = GHWCFG2_FS_PHY_TYPE_DEDICATED )
valid = 1 ;
break ;
case DWC2_PHY_TYPE_PARAM_UTMI :
if ( ( hs_phy_type = = GHWCFG2_HS_PHY_TYPE_UTMI ) | |
( hs_phy_type = = GHWCFG2_HS_PHY_TYPE_UTMI_ULPI ) )
valid = 1 ;
break ;
case DWC2_PHY_TYPE_PARAM_ULPI :
if ( ( hs_phy_type = = GHWCFG2_HS_PHY_TYPE_UTMI ) | |
( hs_phy_type = = GHWCFG2_HS_PHY_TYPE_UTMI_ULPI ) )
valid = 1 ;
break ;
default :
break ;
}
if ( ! valid )
dwc2_set_param_phy_type ( hsotg ) ;
}
static void dwc2_check_param_speed ( struct dwc2_hsotg * hsotg )
{
int valid = 1 ;
int phy_type = hsotg - > params . phy_type ;
int speed = hsotg - > params . speed ;
switch ( speed ) {
case DWC2_SPEED_PARAM_HIGH :
if ( ( hsotg - > params . speed = = DWC2_SPEED_PARAM_HIGH ) & &
( phy_type = = DWC2_PHY_TYPE_PARAM_FS ) )
valid = 0 ;
break ;
case DWC2_SPEED_PARAM_FULL :
case DWC2_SPEED_PARAM_LOW :
break ;
default :
valid = 0 ;
break ;
}
if ( ! valid )
dwc2_set_param_speed ( hsotg ) ;
}
static void dwc2_check_param_phy_utmi_width ( struct dwc2_hsotg * hsotg )
{
int valid = 0 ;
int param = hsotg - > params . phy_utmi_width ;
int width = hsotg - > hw_params . utmi_phy_data_width ;
switch ( width ) {
case GHWCFG4_UTMI_PHY_DATA_WIDTH_8 :
valid = ( param = = 8 ) ;
break ;
case GHWCFG4_UTMI_PHY_DATA_WIDTH_16 :
valid = ( param = = 16 ) ;
break ;
case GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 :
valid = ( param = = 8 | | param = = 16 ) ;
break ;
}
if ( ! valid )
dwc2_set_param_phy_utmi_width ( hsotg ) ;
}
2018-02-16 13:07:05 +03:00
static void dwc2_check_param_power_down ( struct dwc2_hsotg * hsotg )
{
int param = hsotg - > params . power_down ;
switch ( param ) {
case DWC2_POWER_DOWN_PARAM_NONE :
break ;
case DWC2_POWER_DOWN_PARAM_PARTIAL :
if ( hsotg - > hw_params . power_optimized )
break ;
dev_dbg ( hsotg - > dev ,
" Partial power down isn't supported by HW \n " ) ;
param = DWC2_POWER_DOWN_PARAM_NONE ;
break ;
case DWC2_POWER_DOWN_PARAM_HIBERNATION :
if ( hsotg - > hw_params . hibernation )
break ;
dev_dbg ( hsotg - > dev ,
" Hibernation isn't supported by HW \n " ) ;
param = DWC2_POWER_DOWN_PARAM_NONE ;
break ;
default :
dev_err ( hsotg - > dev ,
" %s: Invalid parameter power_down=%d \n " ,
__func__ , param ) ;
param = DWC2_POWER_DOWN_PARAM_NONE ;
break ;
}
hsotg - > params . power_down = param ;
}
2017-01-24 02:01:45 +03:00
static void dwc2_check_param_tx_fifo_sizes ( struct dwc2_hsotg * hsotg )
{
int fifo_count ;
int fifo ;
int min ;
u32 total = 0 ;
u32 dptxfszn ;
fifo_count = dwc2_hsotg_tx_fifo_count ( hsotg ) ;
min = hsotg - > hw_params . en_multiple_tx_fifo ? 16 : 4 ;
for ( fifo = 1 ; fifo < = fifo_count ; fifo + + )
total + = hsotg - > params . g_tx_fifo_size [ fifo ] ;
if ( total > dwc2_hsotg_tx_fifo_total_depth ( hsotg ) | | ! total ) {
dev_warn ( hsotg - > dev , " %s: Invalid parameter g-tx-fifo-size, setting to default average \n " ,
__func__ ) ;
dwc2_set_param_tx_fifo_sizes ( hsotg ) ;
}
for ( fifo = 1 ; fifo < = fifo_count ; fifo + + ) {
2017-11-30 11:16:37 +03:00
dptxfszn = hsotg - > hw_params . g_tx_fifo_size [ fifo ] ;
2017-01-24 02:01:45 +03:00
if ( hsotg - > params . g_tx_fifo_size [ fifo ] < min | |
hsotg - > params . g_tx_fifo_size [ fifo ] > dptxfszn ) {
dev_warn ( hsotg - > dev , " %s: Invalid parameter g_tx_fifo_size[%d]=%d \n " ,
__func__ , fifo ,
hsotg - > params . g_tx_fifo_size [ fifo ] ) ;
hsotg - > params . g_tx_fifo_size [ fifo ] = dptxfszn ;
}
}
}
2017-01-24 01:56:43 +03:00
# define CHECK_RANGE(_param, _min, _max, _def) do { \
2018-04-03 14:22:25 +03:00
if ( ( int ) ( hsotg - > params . _param ) < ( _min ) | | \
2017-01-24 01:56:43 +03:00
( hsotg - > params . _param ) > ( _max ) ) { \
dev_warn ( hsotg - > dev , " %s: Invalid parameter %s=%d \n " , \
__func__ , # _param , hsotg - > params . _param ) ; \
hsotg - > params . _param = ( _def ) ; \
} \
} while ( 0 )
# define CHECK_BOOL(_param, _check) do { \
if ( hsotg - > params . _param & & ! ( _check ) ) { \
dev_warn ( hsotg - > dev , " %s: Invalid parameter %s=%d \n " , \
__func__ , # _param , hsotg - > params . _param ) ; \
hsotg - > params . _param = false ; \
} \
} while ( 0 )
static void dwc2_check_params ( struct dwc2_hsotg * hsotg )
{
struct dwc2_hw_params * hw = & hsotg - > hw_params ;
struct dwc2_core_params * p = & hsotg - > params ;
bool dma_capable = ! ( hw - > arch = = GHWCFG2_SLAVE_ONLY_ARCH ) ;
dwc2_check_param_otg_cap ( hsotg ) ;
dwc2_check_param_phy_type ( hsotg ) ;
dwc2_check_param_speed ( hsotg ) ;
dwc2_check_param_phy_utmi_width ( hsotg ) ;
2018-02-16 13:07:05 +03:00
dwc2_check_param_power_down ( hsotg ) ;
2017-01-24 01:56:43 +03:00
CHECK_BOOL ( enable_dynamic_fifo , hw - > enable_dynamic_fifo ) ;
CHECK_BOOL ( en_multiple_tx_fifo , hw - > en_multiple_tx_fifo ) ;
CHECK_BOOL ( i2c_enable , hw - > i2c_enable ) ;
2018-05-05 11:17:58 +03:00
CHECK_BOOL ( ipg_isoc_en , hw - > ipg_isoc_en ) ;
2018-01-24 16:40:29 +03:00
CHECK_BOOL ( acg_enable , hw - > acg_enable ) ;
2017-01-24 01:56:43 +03:00
CHECK_BOOL ( reload_ctl , ( hsotg - > hw_params . snpsid > DWC2_CORE_REV_2_92a ) ) ;
2018-01-24 16:41:48 +03:00
CHECK_BOOL ( lpm , ( hsotg - > hw_params . snpsid > = DWC2_CORE_REV_2_80a ) ) ;
CHECK_BOOL ( lpm , hw - > lpm_mode ) ;
CHECK_BOOL ( lpm_clock_gating , hsotg - > params . lpm ) ;
CHECK_BOOL ( besl , hsotg - > params . lpm ) ;
CHECK_BOOL ( besl , ( hsotg - > hw_params . snpsid > = DWC2_CORE_REV_3_00a ) ) ;
CHECK_BOOL ( hird_threshold_en , hsotg - > params . lpm ) ;
CHECK_RANGE ( hird_threshold , 0 , hsotg - > params . besl ? 12 : 7 , 0 ) ;
2018-08-29 19:59:34 +03:00
CHECK_BOOL ( service_interval , hw - > service_interval_mode ) ;
2017-01-24 01:56:43 +03:00
CHECK_RANGE ( max_packet_count ,
15 , hw - > max_packet_count ,
hw - > max_packet_count ) ;
CHECK_RANGE ( max_transfer_size ,
2047 , hw - > max_transfer_size ,
hw - > max_transfer_size ) ;
if ( ( hsotg - > dr_mode = = USB_DR_MODE_HOST ) | |
( hsotg - > dr_mode = = USB_DR_MODE_OTG ) ) {
CHECK_BOOL ( host_dma , dma_capable ) ;
CHECK_BOOL ( dma_desc_enable , p - > host_dma ) ;
CHECK_BOOL ( dma_desc_fs_enable , p - > dma_desc_enable ) ;
CHECK_BOOL ( host_ls_low_power_phy_clk ,
p - > phy_type = = DWC2_PHY_TYPE_PARAM_FS ) ;
CHECK_RANGE ( host_channels ,
1 , hw - > host_channels ,
hw - > host_channels ) ;
CHECK_RANGE ( host_rx_fifo_size ,
16 , hw - > rx_fifo_size ,
hw - > rx_fifo_size ) ;
CHECK_RANGE ( host_nperio_tx_fifo_size ,
16 , hw - > host_nperio_tx_fifo_size ,
hw - > host_nperio_tx_fifo_size ) ;
CHECK_RANGE ( host_perio_tx_fifo_size ,
16 , hw - > host_perio_tx_fifo_size ,
hw - > host_perio_tx_fifo_size ) ;
}
if ( ( hsotg - > dr_mode = = USB_DR_MODE_PERIPHERAL ) | |
( hsotg - > dr_mode = = USB_DR_MODE_OTG ) ) {
CHECK_BOOL ( g_dma , dma_capable ) ;
CHECK_BOOL ( g_dma_desc , ( p - > g_dma & & hw - > dma_desc_enable ) ) ;
CHECK_RANGE ( g_rx_fifo_size ,
16 , hw - > rx_fifo_size ,
hw - > rx_fifo_size ) ;
CHECK_RANGE ( g_np_tx_fifo_size ,
16 , hw - > dev_nperio_tx_fifo_size ,
hw - > dev_nperio_tx_fifo_size ) ;
2017-01-24 02:01:45 +03:00
dwc2_check_param_tx_fifo_sizes ( hsotg ) ;
2017-01-24 01:56:43 +03:00
}
}
2016-11-04 03:55:50 +03:00
/*
* Gets host hardware parameters . Forces host mode if not currently in
* host mode . Should be called immediately after a core soft reset in
* order to get the reset values .
*/
static void dwc2_get_host_hwparams ( struct dwc2_hsotg * hsotg )
{
struct dwc2_hw_params * hw = & hsotg - > hw_params ;
u32 gnptxfsiz ;
u32 hptxfsiz ;
if ( hsotg - > dr_mode = = USB_DR_MODE_PERIPHERAL )
return ;
2018-02-16 11:56:03 +03:00
dwc2_force_mode ( hsotg , true ) ;
2016-11-04 03:55:50 +03:00
2018-07-26 17:00:13 +03:00
gnptxfsiz = dwc2_readl ( hsotg , GNPTXFSIZ ) ;
hptxfsiz = dwc2_readl ( hsotg , HPTXFSIZ ) ;
2016-11-04 03:55:50 +03:00
hw - > host_nperio_tx_fifo_size = ( gnptxfsiz & FIFOSIZE_DEPTH_MASK ) > >
FIFOSIZE_DEPTH_SHIFT ;
hw - > host_perio_tx_fifo_size = ( hptxfsiz & FIFOSIZE_DEPTH_MASK ) > >
FIFOSIZE_DEPTH_SHIFT ;
}
/*
* Gets device hardware parameters . Forces device mode if not
* currently in device mode . Should be called immediately after a core
* soft reset in order to get the reset values .
*/
static void dwc2_get_dev_hwparams ( struct dwc2_hsotg * hsotg )
{
struct dwc2_hw_params * hw = & hsotg - > hw_params ;
u32 gnptxfsiz ;
2017-11-30 11:16:37 +03:00
int fifo , fifo_count ;
2016-11-04 03:55:50 +03:00
if ( hsotg - > dr_mode = = USB_DR_MODE_HOST )
return ;
2018-02-16 11:56:03 +03:00
dwc2_force_mode ( hsotg , false ) ;
2016-11-04 03:55:50 +03:00
2018-07-26 17:00:13 +03:00
gnptxfsiz = dwc2_readl ( hsotg , GNPTXFSIZ ) ;
2016-11-04 03:55:50 +03:00
2017-11-30 11:16:37 +03:00
fifo_count = dwc2_hsotg_tx_fifo_count ( hsotg ) ;
for ( fifo = 1 ; fifo < = fifo_count ; fifo + + ) {
hw - > g_tx_fifo_size [ fifo ] =
2018-07-26 17:00:13 +03:00
( dwc2_readl ( hsotg , DPTXFSIZN ( fifo ) ) &
2017-11-30 11:16:37 +03:00
FIFOSIZE_DEPTH_MASK ) > > FIFOSIZE_DEPTH_SHIFT ;
}
2016-11-04 03:55:50 +03:00
hw - > dev_nperio_tx_fifo_size = ( gnptxfsiz & FIFOSIZE_DEPTH_MASK ) > >
FIFOSIZE_DEPTH_SHIFT ;
}
/**
* During device initialization , read various hardware configuration
* registers and interpret the contents .
2018-05-16 11:04:24 +03:00
*
* @ hsotg : Programming view of the DWC_otg controller
*
2016-11-04 03:55:50 +03:00
*/
int dwc2_get_hwparams ( struct dwc2_hsotg * hsotg )
{
struct dwc2_hw_params * hw = & hsotg - > hw_params ;
unsigned int width ;
u32 hwcfg1 , hwcfg2 , hwcfg3 , hwcfg4 ;
u32 grxfsiz ;
2018-07-26 17:00:13 +03:00
hwcfg1 = dwc2_readl ( hsotg , GHWCFG1 ) ;
hwcfg2 = dwc2_readl ( hsotg , GHWCFG2 ) ;
hwcfg3 = dwc2_readl ( hsotg , GHWCFG3 ) ;
hwcfg4 = dwc2_readl ( hsotg , GHWCFG4 ) ;
grxfsiz = dwc2_readl ( hsotg , GRXFSIZ ) ;
2016-11-04 03:55:50 +03:00
/* hwcfg1 */
hw - > dev_ep_dirs = hwcfg1 ;
/* hwcfg2 */
hw - > op_mode = ( hwcfg2 & GHWCFG2_OP_MODE_MASK ) > >
GHWCFG2_OP_MODE_SHIFT ;
hw - > arch = ( hwcfg2 & GHWCFG2_ARCHITECTURE_MASK ) > >
GHWCFG2_ARCHITECTURE_SHIFT ;
hw - > enable_dynamic_fifo = ! ! ( hwcfg2 & GHWCFG2_DYNAMIC_FIFO ) ;
hw - > host_channels = 1 + ( ( hwcfg2 & GHWCFG2_NUM_HOST_CHAN_MASK ) > >
GHWCFG2_NUM_HOST_CHAN_SHIFT ) ;
hw - > hs_phy_type = ( hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK ) > >
GHWCFG2_HS_PHY_TYPE_SHIFT ;
hw - > fs_phy_type = ( hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK ) > >
GHWCFG2_FS_PHY_TYPE_SHIFT ;
hw - > num_dev_ep = ( hwcfg2 & GHWCFG2_NUM_DEV_EP_MASK ) > >
GHWCFG2_NUM_DEV_EP_SHIFT ;
hw - > nperio_tx_q_depth =
( hwcfg2 & GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK ) > >
GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT < < 1 ;
hw - > host_perio_tx_q_depth =
( hwcfg2 & GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK ) > >
GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT < < 1 ;
hw - > dev_token_q_depth =
( hwcfg2 & GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK ) > >
GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT ;
/* hwcfg3 */
width = ( hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK ) > >
GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT ;
hw - > max_transfer_size = ( 1 < < ( width + 11 ) ) - 1 ;
width = ( hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK ) > >
GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT ;
hw - > max_packet_count = ( 1 < < ( width + 4 ) ) - 1 ;
hw - > i2c_enable = ! ! ( hwcfg3 & GHWCFG3_I2C ) ;
hw - > total_fifo_size = ( hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK ) > >
GHWCFG3_DFIFO_DEPTH_SHIFT ;
2018-01-24 16:41:48 +03:00
hw - > lpm_mode = ! ! ( hwcfg3 & GHWCFG3_OTG_LPM_EN ) ;
2016-11-04 03:55:50 +03:00
/* hwcfg4 */
hw - > en_multiple_tx_fifo = ! ! ( hwcfg4 & GHWCFG4_DED_FIFO_EN ) ;
hw - > num_dev_perio_in_ep = ( hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK ) > >
GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT ;
2017-11-30 11:16:37 +03:00
hw - > num_dev_in_eps = ( hwcfg4 & GHWCFG4_NUM_IN_EPS_MASK ) > >
GHWCFG4_NUM_IN_EPS_SHIFT ;
2016-11-04 03:55:50 +03:00
hw - > dma_desc_enable = ! ! ( hwcfg4 & GHWCFG4_DESC_DMA ) ;
hw - > power_optimized = ! ! ( hwcfg4 & GHWCFG4_POWER_OPTIMIZ ) ;
2018-02-16 13:07:05 +03:00
hw - > hibernation = ! ! ( hwcfg4 & GHWCFG4_HIBER ) ;
2016-11-04 03:55:50 +03:00
hw - > utmi_phy_data_width = ( hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK ) > >
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT ;
2018-01-24 16:40:29 +03:00
hw - > acg_enable = ! ! ( hwcfg4 & GHWCFG4_ACG_SUPPORTED ) ;
2018-05-05 11:17:58 +03:00
hw - > ipg_isoc_en = ! ! ( hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED ) ;
2018-08-29 19:59:34 +03:00
hw - > service_interval_mode = ! ! ( hwcfg4 &
GHWCFG4_SERVICE_INTERVAL_SUPPORTED ) ;
2016-11-04 03:55:50 +03:00
/* fifo sizes */
2016-11-04 03:56:02 +03:00
hw - > rx_fifo_size = ( grxfsiz & GRXFSIZ_DEPTH_MASK ) > >
2016-11-04 03:55:50 +03:00
GRXFSIZ_DEPTH_SHIFT ;
2017-11-30 11:16:37 +03:00
/*
* Host specific hardware parameters . Reading these parameters
* requires the controller to be in host mode . The mode will
* be forced , if necessary , to read these values .
*/
dwc2_get_host_hwparams ( hsotg ) ;
dwc2_get_dev_hwparams ( hsotg ) ;
2016-11-04 03:55:50 +03:00
return 0 ;
}
2016-11-04 03:55:55 +03:00
int dwc2_init_params ( struct dwc2_hsotg * hsotg )
{
2017-01-24 01:57:04 +03:00
const struct of_device_id * match ;
2020-07-25 09:03:54 +03:00
void ( * set_params ) ( struct dwc2_hsotg * data ) ;
2017-01-24 01:57:04 +03:00
2017-01-24 01:55:14 +03:00
dwc2_set_default_params ( hsotg ) ;
2017-01-24 01:55:35 +03:00
dwc2_get_device_properties ( hsotg ) ;
2016-11-04 03:55:55 +03:00
2017-01-24 01:57:04 +03:00
match = of_match_device ( dwc2_of_match_table , hsotg - > dev ) ;
if ( match & & match - > data ) {
set_params = match - > data ;
set_params ( hsotg ) ;
}
2017-01-24 01:56:43 +03:00
dwc2_check_params ( hsotg ) ;
2016-11-04 03:55:55 +03:00
return 0 ;
}