firmware/br-ext-chip-goke/board/gk7205v200/kernel/patches/00_drivers-usb-dwc3-dwc3-go...

363 lines
8.1 KiB
Diff

--- linux-4.9.37/drivers/usb/dwc3/dwc3-goke.c 1970-01-01 03:00:00.000000000 +0300
+++ linux-4.9.y/drivers/usb/dwc3/dwc3-goke.c 2021-06-07 13:01:34.000000000 +0300
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) Hunan Goke,Chengdu Goke,Shandong Goke. 2021. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/usb/ch9.h>
+
+#include "dwc3-goke.h"
+
+#define USB3_CTRL 0x190
+#define REG_SYS_STAT 0x8c
+#define PCIE_USB3_MODE_MASK (0x3 << 12)
+#define USB3_PCLK_OCC_SEL (0x1 << 30)
+
+#define PERI_USB3_GTXTHRCFG 0x2310000
+
+#define REG_GUSB3PIPECTL0 0xc2c0
+#define GTXTHRCFG 0xc108
+
+#define PCS_SSP_SOFT_RESET (0x1 << 31)
+#define SUSPEND_USB3_SS_PHY (0x1 << 17)
+
+#define GUSB2PHYCFG_OFFSET 0xc200
+#define GCTL_OFFSET 0xc110
+#define GUCTL_OFFSET 0xc12C
+#define GFLADJ_OFFSET 0xc630
+
+#define U2_FREECLK_EXISTS (0x1 << 30)
+#define SOFITPSYNC (0x1 << 10)
+#define REFCLKPER_MASK 0xffc00000
+#define REFCLKPER_VAL 0x29
+#define set_refclkper(a) (((a) << 22) & REFCLKPER_MASK)
+
+#define PLS1 (0x1 << 31)
+#define DECR_MASK 0x7f000000
+#define DECR_VAL 0xa
+#define set_decr(a) (((a) << 24) & DECR_MASK)
+
+#define LPM_SEL (0x1 << 23)
+#define FLADJ_MASK 0x003fff00
+#define FLADJ_VAL 0x7f0
+#define set_fladj(a) (((a) << 8) & FLADJ_MASK)
+
+#define DOUBLE_PCIE_MODE 0x0
+#define P0_PCIE_ADD_P1_USB3 (0x1 << 12)
+#define DOUBLE_USB3 (0x2 << 12)
+
+#define PCIE_X1_MODE (0x0 << 12)
+#define USB3_MODE (0x1 << 12)
+
+static struct bsp_priv *usb_priv = NULL;
+
+
+
+int usb_get_max_speed(struct device *dev)
+{
+ unsigned int ret;
+ struct device_node *np = dev->of_node;
+
+ if (np == NULL)
+ return -EINVAL;
+
+ usb_priv = kzalloc(sizeof(*usb_priv), GFP_KERNEL);
+ if (usb_priv == NULL)
+ return -ENOMEM;
+
+ usb_priv->peri_crg = of_iomap(np, DEV_NODE_FLAG1);
+ if (IS_ERR(usb_priv->peri_crg)) {
+ kfree(usb_priv);
+ usb_priv = NULL;
+ return -ENOMEM;
+ }
+
+ usb_priv->sys_ctrl = of_iomap(np, DEV_NODE_FLAG2);
+ if (IS_ERR(usb_priv->sys_ctrl)) {
+ iounmap(usb_priv->peri_crg);
+
+ kfree(usb_priv);
+ usb_priv = NULL;
+ return -ENOMEM;
+ }
+
+ ret = usb_get_maximum_speed(dev);
+
+ iounmap(usb_priv->sys_ctrl);
+ iounmap(usb_priv->peri_crg);
+
+ return ret;
+}
+EXPORT_SYMBOL(usb_get_max_speed);
+
+void bsp_dwc3_exited(void)
+{
+ kfree(usb_priv);
+ usb_priv = NULL;
+}
+EXPORT_SYMBOL(bsp_dwc3_exited);
+
+static int set_ctrl_crg_val(struct device_node *np, struct dwc3_host *host)
+{
+ unsigned int ret;
+ unsigned int reg;
+
+ if ((np == NULL) || (host == NULL))
+ return -EINVAL;
+
+ /* get usb ctrl crg para */
+ ret = of_property_read_u32(np, "crg_offset", &host->crg_offset);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "crg_ctrl_def_mask", &host->crg_ctrl_def_mask);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "crg_ctrl_def_val", &host->crg_ctrl_def_val);
+ if (ret)
+ return ret;
+
+ /* write usb ctrl crg default value */
+ reg = readl(host->crg_base + host->crg_offset);
+ reg &= ~host->crg_ctrl_def_mask;
+ reg |= host->crg_ctrl_def_val;
+ writel(reg, host->crg_base + host->crg_offset);
+
+ return 0;
+}
+
+static int dwc3_bsp_clk_init(struct dwc3_host *host, int count)
+{
+ struct device *dev = host->dev;
+ struct device_node *np = dev->of_node;
+ int i, ret;
+
+ if (!count)
+ return -EINVAL;
+
+ if (np == NULL)
+ return -EINVAL;
+
+ host->num_clocks = count;
+
+ host->clks = devm_kcalloc(dev, host->num_clocks, sizeof(struct clk *), GFP_KERNEL);
+ if (host->clks == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < host->num_clocks; i++) {
+ struct clk *clk;
+
+ clk = of_clk_get(np, i);
+ if (IS_ERR(clk)) {
+ while (--i >= 0)
+ clk_put(host->clks[i]);
+
+ ret = PTR_ERR(clk);
+ goto clk_free;
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret < 0) {
+ while (--i >= 0) {
+ clk_disable_unprepare(host->clks[i]);
+ clk_put(host->clks[i]);
+ }
+ clk_put(clk);
+
+ goto clk_free;
+ }
+
+ host->clks[i] = clk;
+ }
+
+ return 0;
+clk_free:
+ devm_kfree(dev, host->clks);
+ host->clks = NULL;
+
+ return ret;
+}
+
+static void control_free_clk_config(struct dwc3_host *host)
+{
+ unsigned int reg;
+
+ if (host == NULL)
+ return;
+
+ reg = readl(host->ctrl_base + GUSB2PHYCFG_OFFSET);
+ reg &= ~U2_FREECLK_EXISTS;
+ writel(reg, host->ctrl_base + GUSB2PHYCFG_OFFSET);
+
+ reg = readl(host->ctrl_base + GCTL_OFFSET);
+ reg &= ~SOFITPSYNC;
+ writel(reg, host->ctrl_base + GCTL_OFFSET);
+
+ reg = readl(host->ctrl_base + GUCTL_OFFSET);
+ reg &= ~REFCLKPER_MASK;
+ reg |= set_refclkper(REFCLKPER_VAL);
+ writel(reg, host->ctrl_base + GUCTL_OFFSET);
+
+ reg = readl(host->ctrl_base + GFLADJ_OFFSET);
+ reg &= ~PLS1;
+ writel(reg, host->ctrl_base + GFLADJ_OFFSET);
+
+ reg = readl(host->ctrl_base + GFLADJ_OFFSET);
+ reg &= ~DECR_MASK;
+ reg |= set_decr(DECR_VAL);
+ writel(reg, host->ctrl_base + GFLADJ_OFFSET);
+
+ reg = readl(host->ctrl_base + GFLADJ_OFFSET);
+ reg |= LPM_SEL;
+ writel(reg, host->ctrl_base + GFLADJ_OFFSET);
+
+ reg = readl(host->ctrl_base + GFLADJ_OFFSET);
+ reg &= ~FLADJ_MASK;
+ reg |= set_fladj(FLADJ_VAL);
+ writel(reg, host->ctrl_base + GFLADJ_OFFSET);
+}
+
+static int dwc3_bsp_iomap(struct device_node *np, struct dwc3_host *host)
+{
+ if ((np == NULL) || (host == NULL))
+ return -EINVAL;
+
+ host->ctrl_base = of_iomap(np, DEV_NODE_FLAG0);
+ if (IS_ERR(host->ctrl_base))
+ return -ENOMEM;
+
+ host->crg_base = of_iomap(np, DEV_NODE_FLAG1);
+ if (IS_ERR(host->crg_base)) {
+ iounmap(host->ctrl_base);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int dwc3_bsp_probe(struct platform_device *pdev)
+{
+ struct dwc3_host *host = NULL;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ int ret, i;
+
+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+ if (host == NULL)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, host);
+ host->dev = dev;
+
+ ret = dwc3_bsp_iomap(np, host);
+ if (ret) {
+ devm_kfree(dev, host);
+ host = NULL;
+
+ return -ENOMEM;
+ }
+
+ host->port_rst = devm_reset_control_get(dev, "vcc_reset");
+ if (IS_ERR_OR_NULL(host->port_rst)) {
+ ret = PTR_ERR(host->port_rst);
+ goto dwc3_unmap;
+ }
+
+ ret = set_ctrl_crg_val(np, host);
+ if (ret)
+ goto dwc3_unmap;
+
+ reset_control_assert(host->port_rst);
+
+ ret = dwc3_bsp_clk_init(host, of_clk_get_parent_count(np));
+ if (ret)
+ goto dwc3_unmap;
+
+ reset_control_deassert(host->port_rst);
+
+ control_free_clk_config(host);
+
+ udelay(U_LEVEL2);
+
+ ret = of_platform_populate(np, NULL, NULL, dev);
+ if (ret) {
+ for (i = 0; i < host->num_clocks; i++) {
+ clk_disable_unprepare(host->clks[i]);
+ clk_put(host->clks[i]);
+ }
+ goto dwc3_unmap;
+ }
+
+ return 0;
+dwc3_unmap:
+ iounmap(host->ctrl_base);
+ iounmap(host->crg_base);
+
+ devm_kfree(dev, host);
+ host = NULL;
+
+ return ret;
+}
+
+static int dwc3_bsp_remove(struct platform_device *pdev)
+{
+ struct dwc3_host *host = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+ int i;
+
+ for (i = 0; i < host->num_clocks; i++) {
+ clk_disable_unprepare(host->clks[i]);
+ clk_put(host->clks[i]);
+ }
+
+ reset_control_assert(host->port_rst);
+
+ of_platform_depopulate(dev);
+
+ iounmap(host->ctrl_base);
+ iounmap(host->crg_base);
+
+ devm_kfree(dev, host);
+ host = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id bsp_dwc3_match[] = {
+ { .compatible = "goke,dwusb2" },
+ { .compatible = "goke,dwusb3" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bsp_dwc3_match);
+
+static struct platform_driver dwc3_bsp_driver = {
+ .probe = dwc3_bsp_probe,
+ .remove = dwc3_bsp_remove,
+ .driver = {
+ .name = "goke-dwc3",
+ .of_match_table = bsp_dwc3_match,
+ },
+};
+module_platform_driver(dwc3_bsp_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare USB3 of Goke");
+MODULE_AUTHOR("Goke Technologies Co., Ltd..>");