summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc2
diff options
context:
space:
mode:
authorJohn Youn <John.Youn@synopsys.com>2017-01-23 14:56:43 -0800
committerFelipe Balbi <felipe.balbi@linux.intel.com>2017-01-24 16:19:06 +0200
commitd936e666aea157a6c552334cce30bce2ae4576b3 (patch)
treec05c778b5d33d63990de4e395a48040db0261e7e /drivers/usb/dwc2
parent57b8e23511408e45e8948616cc3345dc3e08d20b (diff)
usb: dwc2: Check core parameters
Check that core parameters have valid values and adjust them if they aren't. Signed-off-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb/dwc2')
-rw-r--r--drivers/usb/dwc2/params.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 4416eae09647..6ea9d2dafd74 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -377,6 +377,189 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg)
}
}
+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);
+}
+
+#define CHECK_RANGE(_param, _min, _max, _def) do { \
+ if ((hsotg->params._param) < (_min) || \
+ (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);
+ 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);
+ CHECK_BOOL(reload_ctl, (hsotg->hw_params.snpsid > DWC2_CORE_REV_2_92a));
+ 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);
+ }
+}
+
/*
* Gets host hardware parameters. Forces host mode if not currently in
* host mode. Should be called immediately after a core soft reset in
@@ -591,5 +774,7 @@ int dwc2_init_params(struct dwc2_hsotg *hsotg)
dwc2_set_default_params(hsotg);
dwc2_get_device_properties(hsotg);
+ dwc2_check_params(hsotg);
+
return 0;
}