usb: dwc2: Check core parameters
authorJohn Youn <John.Youn@synopsys.com>
Mon, 23 Jan 2017 22:56:43 +0000 (14:56 -0800)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Tue, 24 Jan 2017 14:19:06 +0000 (16:19 +0200)
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>
drivers/usb/dwc2/params.c

index 4416eae096478dfbe37b2472d9aaea340ad13d60..6ea9d2dafd74de47eb62c6a4b382a148e08c08a6 100644 (file)
@@ -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;
 }