usb: add usb host & device driver support for g12a

PD#156734: usb: add usb host & device driver support for g12a

Change-Id: Ia12b63f85fb6d980a7c7906664ae2db7c4ddb86b
Signed-off-by: Yue Wang <yue.wang@amlogic.com>
This commit is contained in:
Yue Wang
2018-02-01 23:21:39 +08:00
committed by Yixun Lan
parent 05191cd937
commit 948c49455e
22 changed files with 1229 additions and 10 deletions

View File

@@ -13531,6 +13531,10 @@ F: drivers/usb/phy/phy-aml-new-usb.h
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
@@ -13541,6 +13545,7 @@ F: include/linux/amlogic/usb-gxbbtv.h
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>

View File

@@ -311,6 +311,69 @@
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";

View File

@@ -1472,6 +1472,12 @@ void dwc_otg_core_init(dwc_otg_core_if_t *core_if)
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

View File

@@ -1057,6 +1057,8 @@ struct dwc_otg_core_if {
uint8_t stop_adpprb;
int controller_type;
uint32_t phy_interface;
};
#ifdef DEBUG

View File

@@ -611,8 +611,12 @@ static void amlogic_device_detect_work(struct work_struct *work)
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)
@@ -952,6 +956,7 @@ static int dwc_otg_driver_probe(struct platform_device *pdev)
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;
@@ -1049,6 +1054,10 @@ static int dwc_otg_driver_probe(struct platform_device *pdev)
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);
@@ -1143,6 +1152,7 @@ static int dwc_otg_driver_probe(struct platform_device *pdev)
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
@@ -1387,8 +1397,12 @@ static int dwc_otg_driver_probe(struct platform_device *pdev)
#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;

View File

@@ -46,6 +46,7 @@
#ifdef CONFIG_AMLOGIC_USB3PHY
extern void aml_new_usb_init(void);
extern void aml_new_usb_v2_init(void);
#endif
/* Type declarations */

View File

@@ -1127,6 +1127,12 @@ int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t *pcd)
/* 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 */

View File

@@ -62,6 +62,7 @@
#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 {
@@ -1293,7 +1294,10 @@ int pcd_init(struct platform_device *pdev)
}
#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
@@ -1361,7 +1365,10 @@ void pcd_remove(struct platform_device *pdev)
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;
}

View File

@@ -5,3 +5,6 @@ obj-$(CONFIG_AMLOGIC_USB3PHY) += phy-aml-usb3.o
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

View File

@@ -0,0 +1,60 @@
/*
* 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);

View File

@@ -0,0 +1,26 @@
/*
* 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);

View File

@@ -0,0 +1,268 @@
/*
* 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");

View File

@@ -0,0 +1,420 @@
/*
* 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");

View File

@@ -33,6 +33,7 @@
#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>
@@ -69,6 +70,26 @@ int device_status(unsigned long usb_peri_reg)
}
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)
{
@@ -368,6 +389,49 @@ static void set_device_mode(struct platform_device *pdev,
}
}
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)
@@ -404,6 +468,23 @@ int clk_enable_usb_gxl(struct platform_device *pdev,
}
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)
@@ -432,6 +513,19 @@ void clk_disable_usb_gxl(struct platform_device *pdev,
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)
@@ -489,6 +583,33 @@ int clk_resume_usb_gxl(struct platform_device *pdev,
}
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)
@@ -510,6 +631,9 @@ int clk_enable_usb(struct platform_device *pdev, const char *s_clock_name,
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*/
@@ -536,6 +660,9 @@ int clk_disable_usb(struct platform_device *pdev, const char *s_clock_name,
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;
@@ -560,6 +687,9 @@ int clk_resume_usb(struct platform_device *pdev, const char *s_clock_name,
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*/
@@ -583,6 +713,9 @@ int clk_suspend_usb(struct platform_device *pdev, const char *s_clock_name,
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;

View File

@@ -1141,7 +1141,10 @@ static int dwc3_probe(struct platform_device *pdev)
&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;

View File

@@ -982,6 +982,7 @@ struct dwc3 {
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
};

View File

@@ -113,6 +113,11 @@ int dwc3_host_init(struct dwc3 *dwc)
}
}
#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",

View File

@@ -255,6 +255,7 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
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;
@@ -279,12 +280,22 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
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)

View File

@@ -237,6 +237,11 @@ static int xhci_plat_probe(struct platform_device *pdev)
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);

View File

@@ -1662,7 +1662,9 @@ struct xhci_hcd {
#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 */

View File

@@ -0,0 +1,176 @@
/*
* 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

View File

@@ -25,6 +25,7 @@
#define GXBABY "gxbaby"
#define GXBABYTV "gxtvbaby"
#define GXL "gxl"
#define V2 "v2"
#define USB_NORMAL 0
#define USB_HOST_ONLY 1
@@ -92,6 +93,7 @@ int clk_suspend_usb(struct platform_device *pdev, const char *s_clock_name,
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);