F: drivers/usb/phy/phy-aml-new-usb.c
F: drivers/usb/phy/phy-aml-new-usb2.c
F: drivers/usb/phy/phy-aml-new-usb3.c
+F: drivers/usb/phy/phy-aml-new-usb-v2.h
+F: drivers/usb/phy/phy-aml-new-usb-v2.c
+F: drivers/usb/phy/phy-aml-new-usb2-v2.c
+F: drivers/usb/phy/phy-aml-new-usb3-v2.c
F: drivers/usb/phy/phy-aml-usb.h
F: drivers/usb/phy/phy-aml-usb.c
F: drivers/usb/phy/phy-aml-usb2.c
F: include/linux/amlogic/usb-gxl.h
F: include/linux/amlogic/usb-gxbb.h
F: include/linux/amlogic/usbtype.h
+F: include/linux/amlogic/usb-v2.h
AMLOGIC scpi cpufreq
M: jianxin.pan <jianxin.pan@amlogic.com>
pinctrl-0 = <&c_uart_pins>;
};
+ dwc3: dwc3@ff500000 {
+ compatible = "synopsys, dwc3";
+ status = "okay";
+ reg = <0x0 0xff500000 0x0 0x100000>;
+ interrupts = <0 30 4>;
+ usb-phy = <&usb2_phy_v2>, <&usb3_phy_v2>;
+ cpu-type = "gxl";
+ clock-src = "usb3.0";
+ clocks = <&clkc CLKID_USB_GENERAL>;
+ clock-names = "dwc_general";
+ /*snps,super_speed_support;*/
+ };
+
+ usb2_phy_v2: usb2phy@ffe09000 {
+ compatible = "amlogic, amlogic-new-usb2-v2";
+ status = "okay";
+ portnum = <2>;
+ reg = <0x0 0xffe09000 0x0 0x80
+ 0x0 0xffd01008 0x0 0x4
+ 0x0 0xff636000 0x0 0x2000
+ 0x0 0xff63a000 0x0 0x2000>;
+ };
+
+ usb3_phy_v2: usb3phy@ffe09080 {
+ compatible = "amlogic, amlogic-new-usb3-v2";
+ status = "okay";
+ portnum = <1>;
+ reg = <0x0 0xffe09080 0x0 0x20>;
+ phy-reg = <0xff646000>;
+ phy-reg-size = <0x4>;
+ interrupts = <0 16 4>;
+ otg = <0>;
+ };
+
+ dwc2_a {
+ compatible = "amlogic, dwc2";
+ device_name = "dwc2_a";
+ reg = <0x0 0xff400000 0x0 0x40000>;
+ status = "okay";
+ interrupts = <0 31 4>;
+ pl-periph-id = <0>; /** lm name */
+ clock-src = "usb0"; /** clock src */
+ port-id = <0>; /** ref to mach/usb.h */
+ port-type = <2>; /** 0: otg, 1: host, 2: slave */
+ port-speed = <0>; /** 0: default, high, 1: full */
+ port-config = <0>; /** 0: default */
+ /*0:default,1:single,2:incr,3:incr4,4:incr8,5:incr16,6:disable*/
+ port-dma = <0>;
+ port-id-mode = <0>; /** 0: hardware, 1: sw_host, 2: sw_slave*/
+ usb-fifo = <728>;
+ cpu-type = "v2";
+ /** 0: normal, 1: otg+dwc3 host only, 2: otg+dwc3 device only*/
+ controller-type = <1>;
+ phy-reg = <0xffe09000>;
+ phy-reg-size = <0xa0>;
+ /** phy-interface: 0x0: amlogic phy, 0x1: synopsys phy **/
+ phy-interface = <0x0>;
+ clocks = <&clkc CLKID_USB_GENERAL
+ &clkc CLKID_USB1_TO_DDR>;
+ clock-names = "usb_general",
+ "usb1";
+ };
+
canvas{
compatible = "amlogic, meson, canvas";
dev_name = "amlogic-canvas";
break;
}
+ /* AMLOGIC USB PHY interface */
+ if (core_if->phy_interface == 1)
+ usbcfg.b.usbtrdtim = 9;
+ else
+ usbcfg.b.usbtrdtim = 5;
+
DWC_WRITE_REG32(&global_regs->gusbcfg, usbcfg.d32);
#ifdef CONFIG_USB_DWC_OTG_LPM
uint8_t stop_adpprb;
int controller_type;
+
+ uint32_t phy_interface;
};
#ifdef DEBUG
int ret;
if (USB_OTG == dwc_otg_device->core_if->controller_type) {
- ret = device_status((unsigned long)dwc_otg_device->
- core_if->usb_peri_reg);
+ if (dwc_otg_device->core_if->phy_interface == 1)
+ ret = device_status((unsigned long)dwc_otg_device->
+ core_if->usb_peri_reg);
+ else
+ ret = device_status_v2((unsigned long)dwc_otg_device->
+ core_if->usb_peri_reg);
if (!ret) {
DWC_PRINTF("usb device plug out, stop pcd!!!\n");
if (dwc_otg_device->pcd->core_if->pcd_cb->stop)
unsigned int p_phy_reg_addr = 0;
unsigned int p_ctrl_reg_addr = 0;
unsigned int phy_reg_addr_size = 0;
+ unsigned int phy_interface = 1;
const char *s_clock_name = NULL;
const char *cpu_type = NULL;
const char *gpio_name = NULL;
if (retval < 0)
return -EINVAL;
+ prop = of_get_property(of_node, "phy-interface", NULL);
+ if (prop)
+ phy_interface = of_read_ulong(prop, 1);
+
dwc_otg_module_params.host_rx_fifo_size = dwc_otg_module_params.data_fifo_size / 2;
DWC_PRINTF("dwc_otg: %s: type: %d speed: %d, ",
s_clock_name, port_type, port_speed);
dwc_otg_device->core_if->usb_peri_reg = (usb_peri_reg_t *)phy_reg_addr;
dwc_otg_device->core_if->controller_type = controller_type;
+ dwc_otg_device->core_if->phy_interface = phy_interface;
/*
* Attempt to ensure this device is really a DWC_otg Controller.
* Read and verify the SNPSID register contents. The value should be
#endif
#ifdef CONFIG_AMLOGIC_USB3PHY
- if (USB_OTG == dwc_otg_device->core_if->controller_type)
- aml_new_usb_init();
+ if (dwc_otg_device->core_if->controller_type == USB_OTG) {
+ if (dwc_otg_device->core_if->phy_interface == 1)
+ aml_new_usb_init();
+ else
+ aml_new_usb_v2_init();
+ }
#endif
return 0;
#ifdef CONFIG_AMLOGIC_USB3PHY
extern void aml_new_usb_init(void);
+extern void aml_new_usb_v2_init(void);
#endif
/* Type declarations */
/* Full or low speed */
gusbcfg.b.usbtrdtim = 9;
}
+
+ /* AMLOGIC USB PHY interface */
+ if (GET_CORE_IF(pcd)->phy_interface == 1)
+ gusbcfg.b.usbtrdtim = 9;
+ else
+ gusbcfg.b.usbtrdtim = 5;
DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32);
/* Clear interrupt */
#include <linux/platform_device.h>
#include <linux/usb/gadget.h>
#include <linux/amlogic/usb-gxl.h>
+#include <linux/amlogic/usb-v2.h>
#include <linux/of_device.h>
static struct gadget_wrapper {
}
#ifdef CONFIG_AMLOGIC_USB3PHY
- aml_new_usb_register_notifier(&otg_dev->nb);
+ if (otg_dev->core_if->phy_interface == 1)
+ aml_new_usb_register_notifier(&otg_dev->nb);
+ else
+ aml_new_usb_v2_register_notifier(&otg_dev->nb);
otg_dev->nb.notifier_call = dwc_usb_change;
#endif
free_wrapper(gadget_wrapper);
dwc_otg_pcd_remove(otg_dev->pcd);
#ifdef CONFIG_AMLOGIC_USB3PHY
- aml_new_usb_unregister_notifier(&otg_dev->nb);
+ if (otg_dev->core_if->phy_interface == 1)
+ aml_new_usb_unregister_notifier(&otg_dev->nb);
+ else
+ aml_new_usb_v2_unregister_notifier(&otg_dev->nb);
#endif
otg_dev->pcd = 0;
}
obj-$(CONFIG_AMLOGIC_USBPHY) += phy-aml-new-usb.o
obj-$(CONFIG_AMLOGIC_USB2PHY) += phy-aml-new-usb2.o
obj-$(CONFIG_AMLOGIC_USB3PHY) += phy-aml-new-usb3.o
+obj-$(CONFIG_AMLOGIC_USBPHY) += phy-aml-new-usb-v2.o
+obj-$(CONFIG_AMLOGIC_USB2PHY) += phy-aml-new-usb2-v2.o
+obj-$(CONFIG_AMLOGIC_USB3PHY) += phy-aml-new-usb3-v2.o
--- /dev/null
+/*
+ * drivers/amlogic/usb/phy/phy-aml-new-usb-v2.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/amlogic/usb-v2.h>
+#include <linux/amlogic/iomap.h>
+#include "phy-aml-new-usb-v2.h"
+
+int amlogic_new_usbphy_reset_v2(struct amlogic_usb_v2 *phy)
+{
+ static int init_count;
+ int i = 0;
+
+ if (!init_count) {
+ init_count++;
+ if (!phy->reset_regs)
+ aml_cbus_update_bits(0x1102, 0x1<<2, 0x1<<2);
+ else
+ writel((readl(phy->reset_regs) | (0x1 << 2)),
+ phy->reset_regs);
+ for (i = 0; i < 1000; i++)
+ udelay(500);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amlogic_new_usbphy_reset_v2);
+
+int amlogic_new_usbphy_reset_phycfg_v2(struct amlogic_usb_v2 *phy, int cnt)
+{
+ int i = 0;
+
+ if (phy->reset_regs)
+ writel((readl(phy->reset_regs) | (1 << (16 + i))),
+ phy->reset_regs);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amlogic_new_usbphy_reset_phycfg_v2);
--- /dev/null
+/*
+ * drivers/amlogic/usb/phy/phy-aml-new-usb-v2.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/usb/phy.h>
+#include <linux/amlogic/usb-v2.h>
+
+#define phy_to_amlusb(x) container_of((x), struct amlogic_usb_v2, phy)
+
+extern int amlogic_new_usbphy_reset_v2(struct amlogic_usb_v2 *phy);
+extern int amlogic_new_usbphy_reset_phycfg_v2
+ (struct amlogic_usb_v2 *phy, int cnt);
+
--- /dev/null
+/*
+ * drivers/amlogic/usb/phy/phy-aml-new-usb2-v2.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/usb/phy.h>
+#include <linux/amlogic/usb-v2.h>
+#include "phy-aml-new-usb-v2.h"
+
+void set_usb_pll(void __iomem *reg)
+{
+ /* TO DO set usb PLL */
+ writel(0x39400414, reg + 0x40);
+ writel(0x927E0000, reg + 0x44);
+ writel(0xAD5B29E9, reg + 0x48);
+ udelay(100);
+ writel(0x19400414, reg + 0x40);
+}
+
+static int amlogic_new_usb2_init(struct usb_phy *x)
+{
+ int i, j, cnt;
+
+ struct amlogic_usb_v2 *phy = phy_to_amlusb(x);
+ struct u2p_aml_regs_v2 u2p_aml_regs;
+ union u2p_r0_v2 reg0;
+ union u2p_r1_v2 reg1;
+ //u32 val;
+
+ if (phy->suspend_flag) {
+ phy->suspend_flag = 0;
+ for (i = 0; i < phy->portnum; i++) {
+ for (j = 0; j < 2; j++) {
+ u2p_aml_regs.u2p_r_v2[j] = (void __iomem *)
+ ((unsigned long)phy->regs + i*PHY_REGISTER_SIZE
+ + 4 * j);
+ }
+ }
+ /*TO DO: set usb phy to low power mode*/
+ return 0;
+ }
+
+ amlogic_new_usbphy_reset_v2(phy);
+
+ for (i = 0; i < phy->portnum; i++) {
+ for (j = 0; j < 2; j++) {
+ u2p_aml_regs.u2p_r_v2[j] = (void __iomem *)
+ ((unsigned long)phy->regs + i*PHY_REGISTER_SIZE
+ + 4 * j);
+ }
+
+ reg0.d32 = readl(u2p_aml_regs.u2p_r_v2[0]);
+ reg0.b.POR = 1;
+ reg0.b.host_device = 1;
+ if (i == 1)
+ reg0.b.IDPULLUP0 = 1;
+
+ writel(reg0.d32, u2p_aml_regs.u2p_r_v2[0]);
+
+ udelay(10);
+ amlogic_new_usbphy_reset_phycfg_v2(phy, i);
+ udelay(50);
+#if 0
+ /* ID DETECT: usb2_otg_aca_en set to 0 */
+ /* usb2_otg_iddet_en set to 1 */
+ writel(readl(phy->phy_cfg[i] + 0x54) & (~(1 << 2)),
+ (phy->phy_cfg[i] + 0x54));
+ if (i == 1) {
+ writel((readl(phy->phy_cfg[i] + 0x50) | (1 << 0)),
+ (phy->phy_cfg[i] + 0x50));
+ }
+#endif
+ reg1.d32 = readl(u2p_aml_regs.u2p_r_v2[1]);
+ cnt = 0;
+ while (reg1.b.phy_rdy != 1) {
+ reg1.d32 = readl(u2p_aml_regs.u2p_r_v2[1]);
+ /*we wait phy ready max 1ms, common is 100us*/
+ if (cnt > 200)
+ break;
+
+ cnt++;
+ udelay(5);
+ }
+
+ /* step 7: pll setting */
+ set_usb_pll(phy->phy_cfg[i]);
+ }
+
+ return 0;
+}
+
+static int amlogic_new_usb2_suspend(struct usb_phy *x, int suspend)
+{
+ return 0;
+}
+
+static void amlogic_new_usb2phy_shutdown(struct usb_phy *x)
+{
+ struct amlogic_usb_v2 *phy = phy_to_amlusb(x);
+ struct u2p_aml_regs_v2 u2p_aml_regs;
+ int i, j;
+
+ phy->suspend_flag = 1;
+ for (i = phy->portnum - 1; i >= 0; i--) {
+ for (j = 0; j < 2; j++) {
+ u2p_aml_regs.u2p_r_v2[j] = (void __iomem *)
+ ((unsigned long)phy->regs + i*PHY_REGISTER_SIZE
+ + 4 * j);
+ }
+
+ /*TO DO: set usb phy to low power mode*/
+ }
+}
+
+static int amlogic_new_usb2_probe(struct platform_device *pdev)
+{
+ struct amlogic_usb_v2 *phy;
+ struct device *dev = &pdev->dev;
+ struct resource *phy_mem;
+ struct resource *reset_mem;
+ struct resource *phy_cfg_mem[4];
+ void __iomem *phy_base;
+ void __iomem *reset_base = NULL;
+ void __iomem *phy_cfg_base[4];
+ int portnum = 0;
+ const void *prop;
+ int i = 0;
+
+ prop = of_get_property(dev->of_node, "portnum", NULL);
+ if (prop)
+ portnum = of_read_ulong(prop, 1);
+
+ if (!portnum) {
+ dev_err(&pdev->dev, "This phy has no usb port\n");
+ return -ENOMEM;
+ }
+
+ phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ phy_base = devm_ioremap_resource(dev, phy_mem);
+ if (IS_ERR(phy_base))
+ return PTR_ERR(phy_base);
+
+ reset_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (reset_mem) {
+ reset_base = ioremap(reset_mem->start,
+ resource_size(reset_mem));
+ if (IS_ERR(reset_base))
+ return PTR_ERR(reset_base);
+ }
+
+ for (i = 0; i < portnum; i++) {
+ phy_cfg_mem[i] = platform_get_resource
+ (pdev, IORESOURCE_MEM, 2 + i);
+ if (phy_cfg_mem[i]) {
+ phy_cfg_base[i] = ioremap(phy_cfg_mem[i]->start,
+ resource_size(phy_cfg_mem[i]));
+ if (IS_ERR(phy_cfg_base[i]))
+ return PTR_ERR(phy_cfg_base[i]);
+ }
+ }
+
+ phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ dev_info(&pdev->dev, "USB2 phy probe:phy_mem:0x%lx, iomap phy_base:0x%lx\n",
+ (unsigned long)phy_mem->start, (unsigned long)phy_base);
+
+ phy->dev = dev;
+ phy->regs = phy_base;
+ phy->reset_regs = reset_base;
+ phy->portnum = portnum;
+ phy->suspend_flag = 0;
+ phy->phy.dev = phy->dev;
+ phy->phy.label = "amlogic-usbphy2";
+ phy->phy.init = amlogic_new_usb2_init;
+ phy->phy.set_suspend = amlogic_new_usb2_suspend;
+ phy->phy.shutdown = amlogic_new_usb2phy_shutdown;
+ phy->phy.type = USB_PHY_TYPE_USB2;
+ for (i = 0; i < portnum; i++)
+ phy->phy_cfg[i] = phy_cfg_base[i];
+
+ usb_add_phy_dev(&phy->phy);
+
+ platform_set_drvdata(pdev, phy);
+
+ pm_runtime_enable(phy->dev);
+
+ return 0;
+}
+
+static int amlogic_new_usb2_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int amlogic_new_usb2_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int amlogic_new_usb2_runtime_resume(struct device *dev)
+{
+ unsigned int ret = 0;
+
+ return ret;
+}
+
+static const struct dev_pm_ops amlogic_new_usb2_pm_ops = {
+ SET_RUNTIME_PM_OPS(amlogic_new_usb2_runtime_suspend,
+ amlogic_new_usb2_runtime_resume,
+ NULL)
+};
+
+#define DEV_PM_OPS (&amlogic_new_usb2_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id amlogic_new_usb2_id_table[] = {
+ { .compatible = "amlogic, amlogic-new-usb2-v2" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, amlogic_new_usb2_id_table);
+#endif
+
+static struct platform_driver amlogic_new_usb2_v2_driver = {
+ .probe = amlogic_new_usb2_probe,
+ .remove = amlogic_new_usb2_remove,
+ .driver = {
+ .name = "amlogic-new-usb2-v2",
+ .owner = THIS_MODULE,
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_match_ptr(amlogic_new_usb2_id_table),
+ },
+};
+
+module_platform_driver(amlogic_new_usb2_v2_driver);
+
+MODULE_ALIAS("platform: amlogic_usb2_v2");
+MODULE_AUTHOR("Amlogic Inc.");
+MODULE_DESCRIPTION("amlogic USB2 v2 phy driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * drivers/amlogic/usb/phy/phy-aml-new-usb3-v2.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/usb/phy.h>
+#include <linux/amlogic/usb-v2.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/workqueue.h>
+#include <linux/notifier.h>
+#include "phy-aml-new-usb-v2.h"
+
+#define HOST_MODE 0
+#define DEVICE_MODE 1
+
+struct usb_aml_regs_v2 usb_new_aml_regs_v2;
+struct amlogic_usb_v2 *g_phy_v2;
+
+static void set_mode(unsigned long reg_addr, int mode);
+BLOCKING_NOTIFIER_HEAD(aml_new_usb_v2_notifier_list);
+
+int aml_new_usb_v2_register_notifier(struct notifier_block *nb)
+{
+ int ret;
+
+ ret = blocking_notifier_chain_register
+ (&aml_new_usb_v2_notifier_list, nb);
+
+ return ret;
+}
+EXPORT_SYMBOL(aml_new_usb_v2_register_notifier);
+
+int aml_new_usb_v2_unregister_notifier(struct notifier_block *nb)
+{
+ int ret;
+
+ ret = blocking_notifier_chain_unregister
+ (&aml_new_usb_v2_notifier_list, nb);
+
+ return ret;
+}
+EXPORT_SYMBOL(aml_new_usb_v2_unregister_notifier);
+
+static void aml_new_usb_notifier_call(unsigned long is_device_on)
+{
+ blocking_notifier_call_chain
+ (&aml_new_usb_v2_notifier_list, is_device_on, NULL);
+}
+//EXPORT_SYMBOL(aml_new_usb_notifier_call);
+
+static void set_usb_vbus_power
+ (struct gpio_desc *usb_gd, int pin, char is_power_on)
+{
+ if (is_power_on)
+ /*set vbus on by gpio*/
+ gpiod_direction_output(usb_gd, is_power_on);
+ else
+ /*set vbus off by gpio first*/
+ gpiod_direction_output(usb_gd, is_power_on);
+}
+
+static void amlogic_new_set_vbus_power
+ (struct amlogic_usb_v2 *phy, char is_power_on)
+{
+ if (phy->vbus_power_pin != -1)
+ set_usb_vbus_power(phy->usb_gpio_desc,
+ phy->vbus_power_pin, is_power_on);
+}
+
+static int amlogic_new_usb3_suspend(struct usb_phy *x, int suspend)
+{
+ return 0;
+}
+
+static void amlogic_new_usb3phy_shutdown(struct usb_phy *x)
+{
+ struct amlogic_usb_v2 *phy = phy_to_amlusb(x);
+
+ phy->suspend_flag = 1;
+}
+
+void aml_new_usb_v2_init(void)
+{
+ union usb_r5_v2 r5 = {.d32 = 0};
+ unsigned long reg_addr = ((unsigned long)
+ usb_new_aml_regs_v2.usb_r_v2[0] - 0x80);
+
+ r5.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[5]);
+ if (r5.b.iddig_curr == 0) {
+ amlogic_new_set_vbus_power(g_phy_v2, 1);
+ aml_new_usb_notifier_call(0);
+ set_mode(reg_addr, HOST_MODE);
+ }
+}
+EXPORT_SYMBOL(aml_new_usb_v2_init);
+
+static int amlogic_new_usb3_init(struct usb_phy *x)
+{
+ struct amlogic_usb_v2 *phy = phy_to_amlusb(x);
+ union usb_r1_v2 r1 = {.d32 = 0};
+ union usb_r2_v2 r2 = {.d32 = 0};
+ union usb_r3_v2 r3 = {.d32 = 0};
+ union usb_r5_v2 r5 = {.d32 = 0};
+ int i = 0;
+
+ if (phy->suspend_flag) {
+ phy->suspend_flag = 0;
+ return 0;
+ }
+
+ /* set the phy from pcie to usb3 */
+ if (phy->portnum > 0)
+ writel((readl(phy->phy3_cfg) | (3<<5)), phy->phy3_cfg);
+
+ for (i = 0; i < 6; i++) {
+ usb_new_aml_regs_v2.usb_r_v2[i] = (void __iomem *)
+ ((unsigned long)phy->regs + 4*i);
+ }
+
+ r1.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[1]);
+ r1.b.u3h_fladj_30mhz_reg = 0x20;
+ writel(r1.d32, usb_new_aml_regs_v2.usb_r_v2[1]);
+
+ r5.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[5]);
+ r5.b.iddig_en0 = 1;
+ r5.b.iddig_en1 = 1;
+ r5.b.iddig_th = 255;
+ writel(r5.d32, usb_new_aml_regs_v2.usb_r_v2[5]);
+
+ /* config usb3 phy */
+ if (phy->portnum > 0) {
+ r3.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[3]);
+ r3.b.p30_ssc_en = 1;
+ r3.b.p30_ref_ssp_en = 1;
+ writel(r3.d32, usb_new_aml_regs_v2.usb_r_v2[3]);
+ udelay(2);
+ r2.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[2]);
+ r2.b.p30_pcs_tx_deemph_3p5db = 0x15;
+ r2.b.p30_pcs_tx_deemph_6db = 0x20;
+ writel(r2.d32, usb_new_aml_regs_v2.usb_r_v2[2]);
+ udelay(2);
+ r1.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[1]);
+ r1.b.u3h_host_port_power_control_present = 1;
+ r1.b.u3h_fladj_30mhz_reg = 32;
+ writel(r1.d32, usb_new_aml_regs_v2.usb_r_v2[1]);
+ udelay(2);
+ }
+
+ return 0;
+}
+
+static void set_mode(unsigned long reg_addr, int mode)
+{
+ struct u2p_aml_regs_v2 u2p_aml_regs;
+ struct usb_aml_regs_v2 usb_gxl_aml_regs;
+ union u2p_r0_v2 reg0;
+ union usb_r0_v2 r0 = {.d32 = 0};
+ union usb_r4_v2 r4 = {.d32 = 0};
+
+ u2p_aml_regs.u2p_r_v2[0] = (void __iomem *)
+ ((unsigned long)reg_addr + PHY_REGISTER_SIZE);
+
+ usb_gxl_aml_regs.usb_r_v2[0] = (void __iomem *)
+ ((unsigned long)reg_addr + 4*PHY_REGISTER_SIZE
+ + 4*0);
+ usb_gxl_aml_regs.usb_r_v2[1] = (void __iomem *)
+ ((unsigned long)reg_addr + 4*PHY_REGISTER_SIZE
+ + 4*1);
+ usb_gxl_aml_regs.usb_r_v2[4] = (void __iomem *)
+ ((unsigned long)reg_addr + 4*PHY_REGISTER_SIZE
+ + 4*4);
+
+ r0.d32 = readl(usb_gxl_aml_regs.usb_r_v2[0]);
+ if (mode == DEVICE_MODE) {
+ r0.b.u2d_act = 1;
+ r0.b.u2d_ss_scaledown_mode = 0;
+ } else
+ r0.b.u2d_act = 0;
+ writel(r0.d32, usb_gxl_aml_regs.usb_r_v2[0]);
+
+ r4.d32 = readl(usb_gxl_aml_regs.usb_r_v2[4]);
+ if (mode == DEVICE_MODE)
+ r4.b.p21_SLEEPM0 = 0x1;
+ else
+ r4.b.p21_SLEEPM0 = 0x0;
+ writel(r4.d32, usb_gxl_aml_regs.usb_r_v2[4]);
+
+ reg0.d32 = readl(u2p_aml_regs.u2p_r_v2[0]);
+ if (mode == DEVICE_MODE) {
+ reg0.b.host_device = 0;
+ reg0.b.POR = 0;
+ } else {
+ reg0.b.host_device = 1;
+ reg0.b.POR = 0;
+ }
+ writel(reg0.d32, u2p_aml_regs.u2p_r_v2[0]);
+
+ udelay(500);
+}
+
+static void amlogic_gxl_work(struct work_struct *work)
+{
+ struct amlogic_usb_v2 *phy =
+ container_of(work, struct amlogic_usb_v2, work.work);
+ union usb_r5_v2 r5 = {.d32 = 0};
+ unsigned long reg_addr = ((unsigned long)phy->regs - 0x80);
+
+ r5.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[5]);
+ if (r5.b.iddig_curr == 0) {
+ amlogic_new_set_vbus_power(phy, 1);
+ aml_new_usb_notifier_call(0);
+ set_mode(reg_addr, HOST_MODE);
+ } else {
+ set_mode(reg_addr, DEVICE_MODE);
+ aml_new_usb_notifier_call(1);
+ amlogic_new_set_vbus_power(phy, 0);
+ }
+ r5.b.usb_iddig_irq = 0;
+ writel(r5.d32, usb_new_aml_regs_v2.usb_r_v2[5]);
+}
+
+static irqreturn_t amlogic_botg_detect_irq(int irq, void *dev)
+{
+ struct amlogic_usb_v2 *phy = (struct amlogic_usb_v2 *)dev;
+ union usb_r5_v2 r5 = {.d32 = 0};
+
+ r5.d32 = readl(usb_new_aml_regs_v2.usb_r_v2[5]);
+ r5.b.usb_iddig_irq = 0;
+ writel(r5.d32, usb_new_aml_regs_v2.usb_r_v2[5]);
+
+ schedule_delayed_work(&phy->work, msecs_to_jiffies(10));
+
+ return IRQ_HANDLED;
+}
+
+static int amlogic_new_usb3_v2_probe(struct platform_device *pdev)
+{
+ struct amlogic_usb_v2 *phy;
+ struct device *dev = &pdev->dev;
+ struct resource *phy_mem;
+ void __iomem *phy_base;
+ void __iomem *phy3_base;
+ unsigned int phy3_mem;
+ unsigned int phy3_mem_size = 0;
+ const char *gpio_name = NULL;
+ struct gpio_desc *usb_gd = NULL;
+ const void *prop;
+ int portnum = 0;
+ int irq;
+ int retval;
+ int gpio_vbus_power_pin = -1;
+ int otg = 0;
+
+ gpio_name = of_get_property(dev->of_node, "gpio-vbus-power", NULL);
+ if (gpio_name) {
+ gpio_vbus_power_pin = 1;
+ usb_gd = gpiod_get_index(&pdev->dev,
+ NULL, 0, GPIOD_OUT_LOW);
+ if (IS_ERR(usb_gd))
+ return -1;
+ }
+
+ prop = of_get_property(dev->of_node, "portnum", NULL);
+ if (prop)
+ portnum = of_read_ulong(prop, 1);
+
+ if (!portnum)
+ dev_err(&pdev->dev, "This phy has no usb port\n");
+
+ prop = of_get_property(dev->of_node, "otg", NULL);
+ if (prop)
+ otg = of_read_ulong(prop, 1);
+
+ phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ phy_base = devm_ioremap_resource(dev, phy_mem);
+ if (IS_ERR(phy_base))
+ return PTR_ERR(phy_base);
+
+ retval = of_property_read_u32(dev->of_node, "phy-reg", &phy3_mem);
+ if (retval < 0)
+ return -EINVAL;
+
+ retval = of_property_read_u32
+ (dev->of_node, "phy-reg-size", &phy3_mem_size);
+ if (retval < 0)
+ return -EINVAL;
+
+ phy3_base = devm_ioremap_nocache
+ (&(pdev->dev), (resource_size_t)phy3_mem,
+ (unsigned long)phy3_mem_size);
+ if (!phy3_base)
+ return -ENOMEM;
+
+ phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ if (otg) {
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENODEV;
+ retval = request_irq(irq, amlogic_botg_detect_irq,
+ IRQF_SHARED | IRQ_LEVEL,
+ "amlogic_botg_detect", phy);
+
+ if (retval) {
+ dev_err(&pdev->dev, "request of irq%d failed\n", irq);
+ retval = -EBUSY;
+ return retval;
+ }
+ }
+
+ dev_info(&pdev->dev, "USB3 phy probe:phy_mem:0x%lx, iomap phy_base:0x%lx\n",
+ (unsigned long)phy_mem->start, (unsigned long)phy_base);
+
+ phy->dev = dev;
+ phy->regs = phy_base;
+ phy->phy3_cfg = phy3_base;
+ phy->portnum = portnum;
+ phy->suspend_flag = 0;
+ phy->phy.dev = phy->dev;
+ phy->phy.label = "amlogic-usbphy3";
+ phy->phy.init = amlogic_new_usb3_init;
+ phy->phy.set_suspend = amlogic_new_usb3_suspend;
+ phy->phy.shutdown = amlogic_new_usb3phy_shutdown;
+ phy->phy.type = USB_PHY_TYPE_USB3;
+ phy->vbus_power_pin = gpio_vbus_power_pin;
+ phy->usb_gpio_desc = usb_gd;
+
+ INIT_DELAYED_WORK(&phy->work, amlogic_gxl_work);
+
+ usb_add_phy_dev(&phy->phy);
+
+ platform_set_drvdata(pdev, phy);
+
+ pm_runtime_enable(phy->dev);
+
+ g_phy_v2 = phy;
+
+ return 0;
+}
+
+static int amlogic_new_usb3_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int amlogic_new_usb3_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int amlogic_new_usb3_runtime_resume(struct device *dev)
+{
+ u32 ret = 0;
+
+ return ret;
+}
+
+static const struct dev_pm_ops amlogic_new_usb3_pm_ops = {
+ SET_RUNTIME_PM_OPS(amlogic_new_usb3_runtime_suspend,
+ amlogic_new_usb3_runtime_resume,
+ NULL)
+};
+
+#define DEV_PM_OPS (&amlogic_new_usb3_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id amlogic_new_usb3_v2_id_table[] = {
+ { .compatible = "amlogic, amlogic-new-usb3-v2" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, amlogic_new_usb3_v2_id_table);
+#endif
+
+static struct platform_driver amlogic_new_usb3_v2_driver = {
+ .probe = amlogic_new_usb3_v2_probe,
+ .remove = amlogic_new_usb3_remove,
+ .driver = {
+ .name = "amlogic-new-usb3-v2",
+ .owner = THIS_MODULE,
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_match_ptr(amlogic_new_usb3_v2_id_table),
+ },
+};
+
+module_platform_driver(amlogic_new_usb3_v2_driver);
+
+MODULE_ALIAS("platform: amlogic_usb3_v2");
+MODULE_AUTHOR("Amlogic Inc.");
+MODULE_DESCRIPTION("amlogic USB3 v2 phy driver");
+MODULE_LICENSE("GPL v2");
#include <linux/platform_device.h>
#include <linux/amlogic/usb-gxbb.h>
#include <linux/amlogic/usb-gxbbtv.h>
+#include <linux/amlogic/usb-v2.h>
#include <linux/amlogic/cpu_version.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
}
EXPORT_SYMBOL(device_status);
+/* ret 1: device plug in */
+/* ret 0: device plug out */
+int device_status_v2(unsigned long usb_peri_reg)
+{
+ struct u2p_aml_regs_v2 u2p_aml_regs;
+ union u2p_r1_v2 reg1;
+ int ret = 1;
+
+ u2p_aml_regs.u2p_r_v2[1] = (void __iomem *)
+ ((unsigned long)usb_peri_reg +
+ PHY_REGISTER_SIZE + 0x4);
+ reg1.d32 = readl(u2p_aml_regs.u2p_r_v2[1]);
+ if (!reg1.b.OTGSESSVLD0)
+ ret = 0;
+
+ return ret;
+}
+EXPORT_SYMBOL(device_status_v2);
+
+
int clk_enable_usb_meson8(struct platform_device *pdev,
const char *s_clock_name, unsigned long usb_peri_reg)
{
}
}
+static void set_device_mode_v2(struct platform_device *pdev,
+ unsigned long reg_addr, int controller_type)
+{
+ struct u2p_aml_regs_v2 u2p_aml_regs;
+ struct usb_aml_regs_v2 usb_aml_regs;
+ union u2p_r0_v2 reg0;
+ union usb_r0_v2 r0 = {.d32 = 0};
+ union usb_r1_v2 r1 = {.d32 = 0};
+ union usb_r4_v2 r4 = {.d32 = 0};
+
+ u2p_aml_regs.u2p_r_v2[0] = (void __iomem *)
+ ((unsigned long)reg_addr + PHY_REGISTER_SIZE);
+ usb_aml_regs.usb_r_v2[0] = (void __iomem *)
+ ((unsigned long)reg_addr + 4*PHY_REGISTER_SIZE
+ + 4*0);
+ usb_aml_regs.usb_r_v2[1] = (void __iomem *)
+ ((unsigned long)reg_addr + 4*PHY_REGISTER_SIZE
+ + 4*1);
+ usb_aml_regs.usb_r_v2[4] = (void __iomem *)
+ ((unsigned long)reg_addr + 4*PHY_REGISTER_SIZE
+ + 4*4);
+ r0.d32 = readl(usb_aml_regs.usb_r_v2[0]);
+ r0.b.u2d_act = 1;
+ r0.b.u2d_ss_scaledown_mode = 0;
+ writel(r0.d32, usb_aml_regs.usb_r_v2[0]);
+
+ r4.d32 = readl(usb_aml_regs.usb_r_v2[4]);
+ r4.b.p21_SLEEPM0 = 0x1;
+ writel(r4.d32, usb_aml_regs.usb_r_v2[4]);
+
+ if (controller_type != USB_OTG) {
+ r1.d32 = readl(usb_aml_regs.usb_r_v2[1]);
+ r1.b.u3h_host_u2_port_disable = 0x2;
+ writel(r1.d32, usb_aml_regs.usb_r_v2[1]);
+ }
+
+ reg0.d32 = readl(u2p_aml_regs.u2p_r_v2[0]);
+ reg0.b.host_device = 0;
+ reg0.b.POR = 0;
+ writel(reg0.d32, u2p_aml_regs.u2p_r_v2[0]);
+}
+
+
int clk_enable_usb_gxbabytv(struct platform_device *pdev,
const char *s_clock_name, unsigned long usb_peri_reg,
int controller_type)
}
+int clk_enable_usb_v2(struct platform_device *pdev,
+ const char *s_clock_name, unsigned long usb_peri_reg,
+ int controller_type)
+{
+ struct clk *usb_reset;
+
+ usb_reset = devm_clk_get(&pdev->dev, "usb_general");
+ clk_prepare_enable(usb_reset);
+ p_clk_reset[pdev->id].usb_reset_usb_general = usb_reset;
+ usb_reset = devm_clk_get(&pdev->dev, "usb1");
+ clk_prepare_enable(usb_reset);
+ p_clk_reset[pdev->id].usb_reset_usb_to_ddr = usb_reset;
+ set_device_mode_v2(pdev, usb_peri_reg, controller_type);
+ return 0;
+}
+
+
void clk_disable_usb_gxbabytv(struct platform_device *pdev,
const char *s_clock_name,
unsigned long usb_peri_reg)
return;
}
+void clk_disable_usb_v2(struct platform_device *pdev,
+ const char *s_clock_name,
+ unsigned long usb_peri_reg)
+{
+ struct clk *usb_reset;
+
+ usb_reset = p_clk_reset[pdev->id].usb_reset_usb_general;
+ clk_disable_unprepare(usb_reset);
+ usb_reset = p_clk_reset[pdev->id].usb_reset_usb_to_ddr;
+ clk_disable_unprepare(usb_reset);
+}
+
+
int clk_resume_usb_gxbaby(struct platform_device *pdev,
const char *s_clock_name,
unsigned long usb_peri_reg)
}
+int clk_resume_usb_v2(struct platform_device *pdev,
+ const char *s_clock_name,
+ unsigned long usb_peri_reg)
+{
+ struct clk *usb_reset;
+
+ if (pdev->id == 0) {
+ usb_reset = p_clk_reset[pdev->id].usb_reset_usb_general;
+ clk_prepare_enable(usb_reset);
+ usb_reset = p_clk_reset[pdev->id].usb_reset_usb_to_ddr;
+ clk_prepare_enable(usb_reset);
+ } else if (pdev->id == 1) {
+ usb_reset = p_clk_reset[pdev->id].usb_reset_usb_general;
+ clk_prepare_enable(usb_reset);
+ usb_reset = p_clk_reset[pdev->id].usb_reset_usb_to_ddr;
+ clk_prepare_enable(usb_reset);
+ } else {
+ dev_err(&pdev->dev, "bad usb clk name.\n");
+ return -1;
+ }
+
+ dmb(4);
+
+ return 0;
+}
+
+
int clk_enable_usb(struct platform_device *pdev, const char *s_clock_name,
unsigned long usb_peri_reg, const char *cpu_type,
int controller_type)
else if (!strcmp(cpu_type, GXL))
ret = clk_enable_usb_gxl(pdev,
s_clock_name, usb_peri_reg, controller_type);
+ else if (!strcmp(cpu_type, V2))
+ ret = clk_enable_usb_v2(pdev,
+ s_clock_name, usb_peri_reg, controller_type);
/*add other cpu type's usb clock enable*/
else if (!strcmp(cpu_type, GXL))
clk_disable_usb_gxl(pdev,
s_clock_name, usb_peri_reg);
+ else if (!strcmp(cpu_type, V2))
+ clk_disable_usb_v2(pdev,
+ s_clock_name, usb_peri_reg);
dmb(4);
return 0;
else if (!strcmp(cpu_type, GXL))
ret = clk_resume_usb_gxl(pdev,
s_clock_name, usb_peri_reg);
+ else if (!strcmp(cpu_type, V2))
+ ret = clk_resume_usb_v2(pdev,
+ s_clock_name, usb_peri_reg);
/*add other cpu type's usb clock enable*/
else if (!strcmp(cpu_type, GXL))
clk_disable_usb_gxl(pdev,
s_clock_name, usb_peri_reg);
+ else if (!strcmp(cpu_type, V2))
+ clk_disable_usb_v2(pdev,
+ s_clock_name, usb_peri_reg);
dmb(4);
return 0;
&dwc->hsphy_interface);
device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
&dwc->fladj);
-
+#ifdef CONFIG_AMLOGIC_USB
+ dwc->super_speed_support = device_property_read_bool(dev,
+ "snps,super_speed_support");
+#endif
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
dwc->tx_de_emphasis = tx_de_emphasis;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
#ifdef CONFIG_AMLOGIC_USB
+ unsigned super_speed_support:1;
struct clk *general_clk;
#endif
};
}
}
+#ifdef CONFIG_AMLOGIC_USB
+ if (dwc->super_speed_support)
+ props[prop_idx++].name = "usb3-support";
+#endif
+
phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy",
dev_name(&xhci->dev));
phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy",
unsigned int i;
ports = xhci->num_usb3_ports;
+
xhci_common_hub_descriptor(xhci, desc, ports);
desc->bDescriptorType = USB_DT_SS_HUB;
desc->bDescLength = USB_DT_SS_HUB_SIZE;
static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
struct usb_hub_descriptor *desc)
{
-
+#ifdef CONFIG_AMLOGIC_USB
+ if (xhci->quirks & XHCI_AML_SUPER_SPEED_SUPPORT) {
+ if (hcd->speed >= HCD_USB3)
+ xhci_usb3_hub_descriptor(hcd, xhci, desc);
+ else
+ xhci_usb2_hub_descriptor(hcd, xhci, desc);
+ } else {
+ if (hcd->speed < HCD_USB3)
+ xhci_usb2_hub_descriptor(hcd, xhci, desc);
+ }
+#else
if (hcd->speed >= HCD_USB3)
xhci_usb3_hub_descriptor(hcd, xhci, desc);
else
xhci_usb2_hub_descriptor(hcd, xhci, desc);
-
+#endif
}
static unsigned int xhci_port_speed(unsigned int port_status)
if (device_property_read_bool(&pdev->dev, "quirk-broken-port-ped"))
xhci->quirks |= XHCI_BROKEN_PORT_PED;
+#ifdef CONFIG_AMLOGIC_USB
+ if (device_property_read_bool(&pdev->dev, "usb3-support"))
+ xhci->quirks |= XHCI_AML_SUPER_SPEED_SUPPORT;
+#endif
+
hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
if (IS_ERR(hcd->usb_phy)) {
ret = PTR_ERR(hcd->usb_phy);
#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
/* Reserved. It was XHCI_U2_DISABLE_WAKE */
#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
-
+#ifdef CONFIG_AMLOGIC_USB
+#define XHCI_AML_SUPER_SPEED_SUPPORT (1 << 29)
+#endif
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
--- /dev/null
+/*
+ * include/linux/amlogic/usb-v2.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __USB_V2_HEADER_
+#define __USB_V2_HEADER_
+
+#include <linux/usb/phy.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/workqueue.h>
+#include <linux/notifier.h>
+
+#define PHY_REGISTER_SIZE 0x20
+/* Register definitions */
+
+int aml_new_usb_v2_register_notifier(struct notifier_block *nb);
+int aml_new_usb_v2_unregister_notifier(struct notifier_block *nb);
+
+struct u2p_aml_regs_v2 {
+ void __iomem *u2p_r_v2[2];
+};
+
+union u2p_r0_v2 {
+ /** raw register data */
+ uint32_t d32;
+ /** register bits */
+ struct {
+ unsigned host_device:1;
+ unsigned power_ok:1;
+ unsigned hast_mode:1;
+ unsigned POR:1;
+ unsigned IDPULLUP0:1;
+ unsigned DRVVBUS0:1;
+ unsigned reserved:26;
+ } b;
+};
+
+union u2p_r1_v2 {
+ /** raw register data */
+ uint32_t d32;
+ /** register bits */
+ struct {
+ unsigned phy_rdy:1;
+ unsigned IDDIG0:1;
+ unsigned OTGSESSVLD0:1;
+ unsigned VBUSVALID0:1;
+ unsigned reserved:28;
+ } b;
+};
+
+struct usb_aml_regs_v2 {
+ void __iomem *usb_r_v2[6];
+};
+
+union usb_r0_v2 {
+ /** raw register data */
+ uint32_t d32;
+ /** register bits */
+ struct {
+ unsigned reserved:17;
+ unsigned p30_lane0_tx2rx_loopback:1;
+ unsigned p30_lane0_ext_pclk_reg:1;
+ unsigned p30_pcs_rx_los_mask_val:10;
+ unsigned u2d_ss_scaledown_mode:2;
+ unsigned u2d_act:1;
+ } b;
+};
+
+union usb_r1_v2 {
+ /** raw register data */
+ uint32_t d32;
+ /** register bits */
+ struct {
+ unsigned u3h_bigendian_gs:1;
+ unsigned u3h_pme_en:1;
+ unsigned u3h_hub_port_overcurrent:3;
+ unsigned reserved_1:2;
+ unsigned u3h_hub_port_perm_attach:3;
+ unsigned reserved_2:2;
+ unsigned u3h_host_u2_port_disable:2;
+ unsigned reserved_3:2;
+ unsigned u3h_host_u3_port_disable:1;
+ unsigned u3h_host_port_power_control_present:1;
+ unsigned u3h_host_msi_enable:1;
+ unsigned u3h_fladj_30mhz_reg:6;
+ unsigned p30_pcs_tx_swing_full:7;
+ } b;
+};
+
+union usb_r2_v2 {
+ /** raw register data */
+ uint32_t d32;
+ /** register bits */
+ struct {
+ unsigned reserved:20;
+ unsigned p30_pcs_tx_deemph_3p5db:6;
+ unsigned p30_pcs_tx_deemph_6db:6;
+ } b;
+};
+
+union usb_r3_v2 {
+ /** raw register data */
+ uint32_t d32;
+ /** register bits */
+ struct {
+ unsigned p30_ssc_en:1;
+ unsigned p30_ssc_range:3;
+ unsigned p30_ssc_ref_clk_sel:9;
+ unsigned p30_ref_ssp_en:1;
+ unsigned reserved:18;
+ } b;
+};
+
+union usb_r4_v2 {
+ /** raw register data */
+ uint32_t d32;
+ /** register bits */
+ struct {
+ unsigned p21_PORTRESET0:1;
+ unsigned p21_SLEEPM0:1;
+ unsigned mem_pd:2;
+ unsigned p21_only:1;
+ unsigned reserved:27;
+ } b;
+};
+
+union usb_r5_v2 {
+ /** raw register data */
+ uint32_t d32;
+ /** register bits */
+ struct {
+ unsigned iddig_sync:1;
+ unsigned iddig_reg:1;
+ unsigned iddig_cfg:2;
+ unsigned iddig_en0:1;
+ unsigned iddig_en1:1;
+ unsigned iddig_curr:1;
+ unsigned usb_iddig_irq:1;
+ unsigned iddig_th:8;
+ unsigned iddig_cnt:8;
+ unsigned reserved:8;
+ } b;
+};
+
+struct amlogic_usb_v2 {
+ struct usb_phy phy;
+ struct device *dev;
+ void __iomem *regs;
+ void __iomem *reset_regs;
+ void __iomem *phy_cfg[4];
+ void __iomem *phy3_cfg;
+ /* Set VBus Power though GPIO */
+ int vbus_power_pin;
+ int vbus_power_pin_work_mask;
+ struct delayed_work work;
+ struct gpio_desc *usb_gpio_desc;
+
+ int portnum;
+ int suspend_flag;
+};
+
+#endif
#define GXBABY "gxbaby"
#define GXBABYTV "gxtvbaby"
#define GXL "gxl"
+#define V2 "v2"
#define USB_NORMAL 0
#define USB_HOST_ONLY 1
unsigned long usb_peri_reg, const char *cpu_type);
int device_status(unsigned long usb_peri_reg);
+int device_status_v2(unsigned long usb_peri_reg);
extern int dwc_otg_power_register_notifier(struct notifier_block *nb);
extern int dwc_otg_power_unregister_notifier(struct notifier_block *nb);