Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * dwc3-st.c Support for dwc3 platform devices on ST Microelectronics platforms
0004  *
0005  * This is a small driver for the dwc3 to provide the glue logic
0006  * to configure the controller. Tested on STi platforms.
0007  *
0008  * Copyright (C) 2014 Stmicroelectronics
0009  *
0010  * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
0011  * Contributors: Aymen Bouattay <aymen.bouattay@st.com>
0012  *               Peter Griffin <peter.griffin@linaro.org>
0013  *
0014  * Inspired by dwc3-omap.c and dwc3-exynos.c.
0015  */
0016 
0017 #include <linux/delay.h>
0018 #include <linux/interrupt.h>
0019 #include <linux/io.h>
0020 #include <linux/ioport.h>
0021 #include <linux/kernel.h>
0022 #include <linux/mfd/syscon.h>
0023 #include <linux/module.h>
0024 #include <linux/of.h>
0025 #include <linux/of_platform.h>
0026 #include <linux/platform_device.h>
0027 #include <linux/slab.h>
0028 #include <linux/regmap.h>
0029 #include <linux/reset.h>
0030 #include <linux/pinctrl/consumer.h>
0031 #include <linux/usb/of.h>
0032 
0033 #include "core.h"
0034 #include "io.h"
0035 
0036 /* glue registers */
0037 #define CLKRST_CTRL     0x00
0038 #define AUX_CLK_EN      BIT(0)
0039 #define SW_PIPEW_RESET_N    BIT(4)
0040 #define EXT_CFG_RESET_N     BIT(8)
0041 /*
0042  * 1'b0 : The host controller complies with the xHCI revision 0.96
0043  * 1'b1 : The host controller complies with the xHCI revision 1.0
0044  */
0045 #define XHCI_REVISION       BIT(12)
0046 
0047 #define USB2_VBUS_MNGMNT_SEL1   0x2C
0048 /*
0049  * For all fields in USB2_VBUS_MNGMNT_SEL1
0050  * 2’b00 : Override value from Reg 0x30 is selected
0051  * 2’b01 : utmiotg_<signal_name> from usb3_top is selected
0052  * 2’b10 : pipew_<signal_name> from PIPEW instance is selected
0053  * 2’b11 : value is 1'b0
0054  */
0055 #define USB2_VBUS_REG30     0x0
0056 #define USB2_VBUS_UTMIOTG   0x1
0057 #define USB2_VBUS_PIPEW     0x2
0058 #define USB2_VBUS_ZERO      0x3
0059 
0060 #define SEL_OVERRIDE_VBUSVALID(n)   (n << 0)
0061 #define SEL_OVERRIDE_POWERPRESENT(n)    (n << 4)
0062 #define SEL_OVERRIDE_BVALID(n)      (n << 8)
0063 
0064 /* Static DRD configuration */
0065 #define USB3_CONTROL_MASK       0xf77
0066 
0067 #define USB3_DEVICE_NOT_HOST        BIT(0)
0068 #define USB3_FORCE_VBUSVALID        BIT(1)
0069 #define USB3_DELAY_VBUSVALID        BIT(2)
0070 #define USB3_SEL_FORCE_OPMODE       BIT(4)
0071 #define USB3_FORCE_OPMODE(n)        (n << 5)
0072 #define USB3_SEL_FORCE_DPPULLDOWN2  BIT(8)
0073 #define USB3_FORCE_DPPULLDOWN2      BIT(9)
0074 #define USB3_SEL_FORCE_DMPULLDOWN2  BIT(10)
0075 #define USB3_FORCE_DMPULLDOWN2      BIT(11)
0076 
0077 /**
0078  * struct st_dwc3 - dwc3-st driver private structure
0079  * @dev:        device pointer
0080  * @glue_base:      ioaddr for the glue registers
0081  * @regmap:     regmap pointer for getting syscfg
0082  * @syscfg_reg_off: usb syscfg control offset
0083  * @dr_mode:        drd static host/device config
0084  * @rstc_pwrdn:     rest controller for powerdown signal
0085  * @rstc_rst:       reset controller for softreset signal
0086  */
0087 
0088 struct st_dwc3 {
0089     struct device *dev;
0090     void __iomem *glue_base;
0091     struct regmap *regmap;
0092     int syscfg_reg_off;
0093     enum usb_dr_mode dr_mode;
0094     struct reset_control *rstc_pwrdn;
0095     struct reset_control *rstc_rst;
0096 };
0097 
0098 static inline u32 st_dwc3_readl(void __iomem *base, u32 offset)
0099 {
0100     return readl_relaxed(base + offset);
0101 }
0102 
0103 static inline void st_dwc3_writel(void __iomem *base, u32 offset, u32 value)
0104 {
0105     writel_relaxed(value, base + offset);
0106 }
0107 
0108 /**
0109  * st_dwc3_drd_init: program the port
0110  * @dwc3_data: driver private structure
0111  * Description: this function is to program the port as either host or device
0112  * according to the static configuration passed from devicetree.
0113  * OTG and dual role are not yet supported!
0114  */
0115 static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data)
0116 {
0117     u32 val;
0118     int err;
0119 
0120     err = regmap_read(dwc3_data->regmap, dwc3_data->syscfg_reg_off, &val);
0121     if (err)
0122         return err;
0123 
0124     val &= USB3_CONTROL_MASK;
0125 
0126     switch (dwc3_data->dr_mode) {
0127     case USB_DR_MODE_PERIPHERAL:
0128 
0129         val &= ~(USB3_DELAY_VBUSVALID
0130             | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3)
0131             | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
0132             | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
0133 
0134         /*
0135          * USB3_PORT2_FORCE_VBUSVALID When '1' and when
0136          * USB3_PORT2_DEVICE_NOT_HOST = 1, forces VBUSVLDEXT2 input
0137          * of the pico PHY to 1.
0138          */
0139 
0140         val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID;
0141         break;
0142 
0143     case USB_DR_MODE_HOST:
0144 
0145         val &= ~(USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID
0146             | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3)
0147             | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
0148             | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
0149 
0150         /*
0151          * USB3_DELAY_VBUSVALID is ANDed with USB_C_VBUSVALID. Thus,
0152          * when set to ‘0‘, it can delay the arrival of VBUSVALID
0153          * information to VBUSVLDEXT2 input of the pico PHY.
0154          * We don't want to do that so we set the bit to '1'.
0155          */
0156 
0157         val |= USB3_DELAY_VBUSVALID;
0158         break;
0159 
0160     default:
0161         dev_err(dwc3_data->dev, "Unsupported mode of operation %d\n",
0162             dwc3_data->dr_mode);
0163         return -EINVAL;
0164     }
0165 
0166     return regmap_write(dwc3_data->regmap, dwc3_data->syscfg_reg_off, val);
0167 }
0168 
0169 /**
0170  * st_dwc3_init: init the controller via glue logic
0171  * @dwc3_data: driver private structure
0172  */
0173 static void st_dwc3_init(struct st_dwc3 *dwc3_data)
0174 {
0175     u32 reg = st_dwc3_readl(dwc3_data->glue_base, CLKRST_CTRL);
0176 
0177     reg |= AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION;
0178     reg &= ~SW_PIPEW_RESET_N;
0179     st_dwc3_writel(dwc3_data->glue_base, CLKRST_CTRL, reg);
0180 
0181     /* configure mux for vbus, powerpresent and bvalid signals */
0182     reg = st_dwc3_readl(dwc3_data->glue_base, USB2_VBUS_MNGMNT_SEL1);
0183 
0184     reg |= SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) |
0185         SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) |
0186         SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG);
0187 
0188     st_dwc3_writel(dwc3_data->glue_base, USB2_VBUS_MNGMNT_SEL1, reg);
0189 
0190     reg = st_dwc3_readl(dwc3_data->glue_base, CLKRST_CTRL);
0191     reg |= SW_PIPEW_RESET_N;
0192     st_dwc3_writel(dwc3_data->glue_base, CLKRST_CTRL, reg);
0193 }
0194 
0195 static int st_dwc3_probe(struct platform_device *pdev)
0196 {
0197     struct st_dwc3 *dwc3_data;
0198     struct resource *res;
0199     struct device *dev = &pdev->dev;
0200     struct device_node *node = dev->of_node, *child;
0201     struct platform_device *child_pdev;
0202     struct regmap *regmap;
0203     int ret;
0204 
0205     dwc3_data = devm_kzalloc(dev, sizeof(*dwc3_data), GFP_KERNEL);
0206     if (!dwc3_data)
0207         return -ENOMEM;
0208 
0209     dwc3_data->glue_base =
0210         devm_platform_ioremap_resource_byname(pdev, "reg-glue");
0211     if (IS_ERR(dwc3_data->glue_base))
0212         return PTR_ERR(dwc3_data->glue_base);
0213 
0214     regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg");
0215     if (IS_ERR(regmap))
0216         return PTR_ERR(regmap);
0217 
0218     dwc3_data->dev = dev;
0219     dwc3_data->regmap = regmap;
0220 
0221     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "syscfg-reg");
0222     if (!res) {
0223         ret = -ENXIO;
0224         goto undo_platform_dev_alloc;
0225     }
0226 
0227     dwc3_data->syscfg_reg_off = res->start;
0228 
0229     dev_vdbg(&pdev->dev, "glue-logic addr 0x%pK, syscfg-reg offset 0x%x\n",
0230          dwc3_data->glue_base, dwc3_data->syscfg_reg_off);
0231 
0232     dwc3_data->rstc_pwrdn =
0233         devm_reset_control_get_exclusive(dev, "powerdown");
0234     if (IS_ERR(dwc3_data->rstc_pwrdn)) {
0235         dev_err(&pdev->dev, "could not get power controller\n");
0236         ret = PTR_ERR(dwc3_data->rstc_pwrdn);
0237         goto undo_platform_dev_alloc;
0238     }
0239 
0240     /* Manage PowerDown */
0241     reset_control_deassert(dwc3_data->rstc_pwrdn);
0242 
0243     dwc3_data->rstc_rst =
0244         devm_reset_control_get_shared(dev, "softreset");
0245     if (IS_ERR(dwc3_data->rstc_rst)) {
0246         dev_err(&pdev->dev, "could not get reset controller\n");
0247         ret = PTR_ERR(dwc3_data->rstc_rst);
0248         goto undo_powerdown;
0249     }
0250 
0251     /* Manage SoftReset */
0252     reset_control_deassert(dwc3_data->rstc_rst);
0253 
0254     child = of_get_child_by_name(node, "usb");
0255     if (!child) {
0256         dev_err(&pdev->dev, "failed to find dwc3 core node\n");
0257         ret = -ENODEV;
0258         goto err_node_put;
0259     }
0260 
0261     /* Allocate and initialize the core */
0262     ret = of_platform_populate(node, NULL, NULL, dev);
0263     if (ret) {
0264         dev_err(dev, "failed to add dwc3 core\n");
0265         goto err_node_put;
0266     }
0267 
0268     child_pdev = of_find_device_by_node(child);
0269     if (!child_pdev) {
0270         dev_err(dev, "failed to find dwc3 core device\n");
0271         ret = -ENODEV;
0272         goto err_node_put;
0273     }
0274 
0275     dwc3_data->dr_mode = usb_get_dr_mode(&child_pdev->dev);
0276     of_node_put(child);
0277     platform_device_put(child_pdev);
0278 
0279     /*
0280      * Configure the USB port as device or host according to the static
0281      * configuration passed from DT.
0282      * DRD is the only mode currently supported so this will be enhanced
0283      * as soon as OTG is available.
0284      */
0285     ret = st_dwc3_drd_init(dwc3_data);
0286     if (ret) {
0287         dev_err(dev, "drd initialisation failed\n");
0288         goto undo_softreset;
0289     }
0290 
0291     /* ST glue logic init */
0292     st_dwc3_init(dwc3_data);
0293 
0294     platform_set_drvdata(pdev, dwc3_data);
0295     return 0;
0296 
0297 err_node_put:
0298     of_node_put(child);
0299 undo_softreset:
0300     reset_control_assert(dwc3_data->rstc_rst);
0301 undo_powerdown:
0302     reset_control_assert(dwc3_data->rstc_pwrdn);
0303 undo_platform_dev_alloc:
0304     platform_device_put(pdev);
0305     return ret;
0306 }
0307 
0308 static int st_dwc3_remove(struct platform_device *pdev)
0309 {
0310     struct st_dwc3 *dwc3_data = platform_get_drvdata(pdev);
0311 
0312     of_platform_depopulate(&pdev->dev);
0313 
0314     reset_control_assert(dwc3_data->rstc_pwrdn);
0315     reset_control_assert(dwc3_data->rstc_rst);
0316 
0317     return 0;
0318 }
0319 
0320 #ifdef CONFIG_PM_SLEEP
0321 static int st_dwc3_suspend(struct device *dev)
0322 {
0323     struct st_dwc3 *dwc3_data = dev_get_drvdata(dev);
0324 
0325     reset_control_assert(dwc3_data->rstc_pwrdn);
0326     reset_control_assert(dwc3_data->rstc_rst);
0327 
0328     pinctrl_pm_select_sleep_state(dev);
0329 
0330     return 0;
0331 }
0332 
0333 static int st_dwc3_resume(struct device *dev)
0334 {
0335     struct st_dwc3 *dwc3_data = dev_get_drvdata(dev);
0336     int ret;
0337 
0338     pinctrl_pm_select_default_state(dev);
0339 
0340     reset_control_deassert(dwc3_data->rstc_pwrdn);
0341     reset_control_deassert(dwc3_data->rstc_rst);
0342 
0343     ret = st_dwc3_drd_init(dwc3_data);
0344     if (ret) {
0345         dev_err(dev, "drd initialisation failed\n");
0346         return ret;
0347     }
0348 
0349     /* ST glue logic init */
0350     st_dwc3_init(dwc3_data);
0351 
0352     return 0;
0353 }
0354 #endif /* CONFIG_PM_SLEEP */
0355 
0356 static SIMPLE_DEV_PM_OPS(st_dwc3_dev_pm_ops, st_dwc3_suspend, st_dwc3_resume);
0357 
0358 static const struct of_device_id st_dwc3_match[] = {
0359     { .compatible = "st,stih407-dwc3" },
0360     { /* sentinel */ },
0361 };
0362 
0363 MODULE_DEVICE_TABLE(of, st_dwc3_match);
0364 
0365 static struct platform_driver st_dwc3_driver = {
0366     .probe = st_dwc3_probe,
0367     .remove = st_dwc3_remove,
0368     .driver = {
0369         .name = "usb-st-dwc3",
0370         .of_match_table = st_dwc3_match,
0371         .pm = &st_dwc3_dev_pm_ops,
0372     },
0373 };
0374 
0375 module_platform_driver(st_dwc3_driver);
0376 
0377 MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
0378 MODULE_DESCRIPTION("DesignWare USB3 STi Glue Layer");
0379 MODULE_LICENSE("GPL v2");