mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
Merge git://git.denx.de/u-boot-usb
- MediaTek USB host support
This commit is contained in:
commit
1259567ae3
25 changed files with 1135 additions and 188 deletions
|
@ -244,9 +244,12 @@ S: Maintained
|
|||
F: arch/arm/mach-mediatek/
|
||||
F: arch/arm/include/asm/arch-mediatek/
|
||||
F: board/mediatek/
|
||||
F: doc/device-tree-bindings/phy/phy-mtk-*
|
||||
F: doc/device-tree-bindings/usb/mediatek,*
|
||||
F: doc/README.mediatek
|
||||
F: drivers/clk/mediatek/
|
||||
F: drivers/mmc/mtk-sd.c
|
||||
F: drivers/phy/phy-mtk-*
|
||||
F: drivers/pinctrl/mediatek/
|
||||
F: drivers/power/domain/mtk-power-domain.c
|
||||
F: drivers/ram/mediatek/
|
||||
|
|
|
@ -82,6 +82,14 @@
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
&xhci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&u3phy {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&watchdog {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&watchdog_pins>;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/mt7629-power.h>
|
||||
#include <dt-bindings/reset/mt7629-reset.h>
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include "skeleton.dtsi"
|
||||
|
||||
/ {
|
||||
|
@ -222,6 +223,46 @@
|
|||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
ssusbsys: ssusbsys@1a000000 {
|
||||
compatible = "mediatek,mt7629-ssusbsys", "syscon";
|
||||
reg = <0x1a000000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
xhci: usb@1a0c0000 {
|
||||
compatible = "mediatek,mt7629-xhci", "mediatek,mtk-xhci";
|
||||
reg = <0x1a0c0000 0x1000>, <0x1a0c3e00 0x0100>;
|
||||
reg-names = "mac", "ippc";
|
||||
power-domains = <&scpsys MT7629_POWER_DOMAIN_HIF1>;
|
||||
clocks = <&ssusbsys CLK_SSUSB_SYS_EN>,
|
||||
<&ssusbsys CLK_SSUSB_REF_EN>,
|
||||
<&ssusbsys CLK_SSUSB_MCU_EN>,
|
||||
<&ssusbsys CLK_SSUSB_DMA_EN>;
|
||||
clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck";
|
||||
phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
u3phy: usb-phy@1a0c4000 {
|
||||
compatible = "mediatek,mt7629-tphy", "mediatek,generic-tphy-v2";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0x1a0c4000 0x1000>;
|
||||
status = "disabled";
|
||||
|
||||
u2port0: usb-phy@0 {
|
||||
reg = <0x0 0x0700>;
|
||||
#phy-cells = <1>;
|
||||
clocks = <&ssusbsys CLK_SSUSB_U2_PHY_EN>;
|
||||
clock-names = "ref";
|
||||
};
|
||||
|
||||
u3port0: usb-phy@700 {
|
||||
reg = <0x0700 0x0700>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
ethsys: syscon@1b000000 {
|
||||
compatible = "mediatek,mt7629-ethsys", "syscon";
|
||||
reg = <0x1b000000 0x1000>;
|
||||
|
|
|
@ -159,12 +159,23 @@
|
|||
broken;
|
||||
};
|
||||
|
||||
phy_provider2: gen_phy@2 {
|
||||
compatible = "sandbox,phy";
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
gen_phy_user: gen_phy_user {
|
||||
compatible = "simple-bus";
|
||||
phys = <&phy_provider0 0>, <&phy_provider0 1>, <&phy_provider1>;
|
||||
phy-names = "phy1", "phy2", "phy3";
|
||||
};
|
||||
|
||||
gen_phy_user1: gen_phy_user1 {
|
||||
compatible = "simple-bus";
|
||||
phys = <&phy_provider0 0>, <&phy_provider2>;
|
||||
phy-names = "phy1", "phy2";
|
||||
};
|
||||
|
||||
some-bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -218,6 +229,24 @@
|
|||
compatible = "denx,u-boot-fdt-test1";
|
||||
};
|
||||
|
||||
i-test {
|
||||
compatible = "mediatek,u-boot-fdt-test";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
subnode@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
subnode@1 {
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
subnode@2 {
|
||||
reg = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
devres-test {
|
||||
compatible = "denx,u-boot-devres-test";
|
||||
};
|
||||
|
|
|
@ -7,10 +7,17 @@ controllers on MediaTek SoCs, such as, USB2.0, USB3.0, PCIe, and SATA.
|
|||
Required properties (controller (parent) node):
|
||||
- compatible : should be one of
|
||||
"mediatek,generic-tphy-v1"
|
||||
- clocks : (deprecated, use port's clocks instead) a list of phandle +
|
||||
clock-specifier pairs, one for each entry in clock-names
|
||||
- clock-names : (deprecated, use port's one instead) must contain
|
||||
"u3phya_ref": for reference clock of usb3.0 analog phy.
|
||||
"mediatek,generic-tphy-v2"
|
||||
|
||||
- #address-cells: the number of cells used to represent physical
|
||||
base addresses.
|
||||
- #size-cells: the number of cells used to represent the size of an address.
|
||||
- ranges: the address mapping relationship to the parent, defined with
|
||||
- empty value: if optional 'reg' is used.
|
||||
- non-empty value: if optional 'reg' is not used. should set
|
||||
the child's base address to 0, the physical address
|
||||
within parent's address space, and the length of
|
||||
the address map.
|
||||
|
||||
Required nodes : a sub-node is required for each port the controller
|
||||
provides. Address range information including the usual
|
||||
|
@ -27,12 +34,6 @@ Optional properties (controller (parent) node):
|
|||
|
||||
Required properties (port (child) node):
|
||||
- reg : address and length of the register set for the port.
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock-names
|
||||
- clock-names : must contain
|
||||
"ref": 48M reference clock for HighSpeed analog phy; and 26M
|
||||
reference clock for SuperSpeed analog phy, sometimes is
|
||||
24M, 25M or 27M, depended on platform.
|
||||
- #phy-cells : should be 1 (See second example)
|
||||
cell after port phandle is phy type from:
|
||||
- PHY_TYPE_USB2
|
||||
|
@ -40,6 +41,17 @@ Required properties (port (child) node):
|
|||
- PHY_TYPE_PCIE
|
||||
- PHY_TYPE_SATA
|
||||
|
||||
Optional properties (port (child) node):
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock-names
|
||||
- clock-names : may contain
|
||||
"ref": 48M reference clock for HighSpeed (digital) phy; and 26M
|
||||
reference clock for SuperSpeed (digital) phy, sometimes is
|
||||
24M, 25M or 27M, depended on platform.
|
||||
"da_ref": the reference clock of analog phy, used if the clocks
|
||||
of analog and digital phys are separated, otherwise uses
|
||||
"ref" clock only if needed.
|
||||
|
||||
Example:
|
||||
|
||||
u3phy2: usb-phy@1a244000 {
|
||||
|
@ -84,3 +96,49 @@ usb30: usb@11270000 {
|
|||
phy-names = "usb2-0", "usb3-0";
|
||||
...
|
||||
};
|
||||
|
||||
Layout differences of banks between TPHY V1 and V2
|
||||
-------------------------------------------------------------
|
||||
IP V1:
|
||||
port offset bank
|
||||
shared 0x0000 SPLLC
|
||||
0x0100 FMREG
|
||||
u2 port0 0x0800 U2PHY_COM
|
||||
u3 port0 0x0900 U3PHYD
|
||||
0x0a00 U3PHYD_BANK2
|
||||
0x0b00 U3PHYA
|
||||
0x0c00 U3PHYA_DA
|
||||
u2 port1 0x1000 U2PHY_COM
|
||||
u3 port1 0x1100 U3PHYD
|
||||
0x1200 U3PHYD_BANK2
|
||||
0x1300 U3PHYA
|
||||
0x1400 U3PHYA_DA
|
||||
u2 port2 0x1800 U2PHY_COM
|
||||
...
|
||||
|
||||
IP V2:
|
||||
port offset bank
|
||||
u2 port0 0x0000 MISC
|
||||
0x0100 FMREG
|
||||
0x0300 U2PHY_COM
|
||||
u3 port0 0x0700 SPLLC
|
||||
0x0800 CHIP
|
||||
0x0900 U3PHYD
|
||||
0x0a00 U3PHYD_BANK2
|
||||
0x0b00 U3PHYA
|
||||
0x0c00 U3PHYA_DA
|
||||
u2 port1 0x1000 MISC
|
||||
0x1100 FMREG
|
||||
0x1300 U2PHY_COM
|
||||
u3 port1 0x1700 SPLLC
|
||||
0x1800 CHIP
|
||||
0x1900 U3PHYD
|
||||
0x1a00 U3PHYD_BANK2
|
||||
0x1b00 U3PHYA
|
||||
0x1c00 U3PHYA_DA
|
||||
u2 port2 0x2000 MISC
|
||||
...
|
||||
|
||||
SPLLC shared by u3 ports and FMREG shared by u2 ports on
|
||||
TPHY V1 are put back into each port; a new bank MISC for
|
||||
u2 ports and CHIP for u3 ports are added on TPHY V2.
|
||||
|
|
40
doc/device-tree-bindings/usb/mediatek,mtk-xhci.txt
Normal file
40
doc/device-tree-bindings/usb/mediatek,mtk-xhci.txt
Normal file
|
@ -0,0 +1,40 @@
|
|||
MediaTek xHCI
|
||||
|
||||
The device node for USB3 host controller on MediaTek SoCs.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "mediatek,mtk-xhci"
|
||||
- reg : specifies physical base address and size of the registers
|
||||
- reg-names: should be "mac" for xHCI MAC and "ippc" for IP port control
|
||||
- power-domains : a phandle to USB power domain node to control USB's
|
||||
MTCMOS
|
||||
- vusb33-supply : regulator of USB avdd3.3v
|
||||
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock-names
|
||||
- clock-names : must contain
|
||||
"sys_ck": controller clock used by normal mode,
|
||||
the following ones are optional:
|
||||
"ref_ck": reference clock used by low power mode etc,
|
||||
"mcu_ck": mcu_bus clock for register access,
|
||||
"dma_ck": dma_bus clock for data transfer by DMA,
|
||||
"xhci_ck": controller clock
|
||||
|
||||
- phys : list of all the USB PHYs on this HCD
|
||||
- phy-names: name specifier for the USB PHY
|
||||
|
||||
Optional properties:
|
||||
- vbus-supply : reference to the VBUS regulator;
|
||||
|
||||
Example:
|
||||
xhci: usb@1a0c0000 {
|
||||
compatible = "mediatek,mt7629-xhci", "mediatek,mtk-xhci";
|
||||
reg = <0x1a0c0000 0x1000>, <0x1a0c3e00 0x0100>;
|
||||
reg-names = "mac", "ippc";
|
||||
power-domains = <&scpsys MT7629_POWER_DOMAIN_HIF1>;
|
||||
clocks = <&ssusbsys CLK_SSUSB_SYS_EN>, <&ssusbsys CLK_SSUSB_REF_EN>,
|
||||
<&ssusbsys CLK_SSUSB_MCU_EN>, <&ssusbsys CLK_SSUSB_DMA_EN>;
|
||||
clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck";
|
||||
phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>;
|
||||
status = "disabled";
|
||||
};
|
|
@ -474,6 +474,17 @@ ofnode ofnode_get_chosen_node(const char *name)
|
|||
return ofnode_path(prop);
|
||||
}
|
||||
|
||||
int ofnode_get_child_count(ofnode parent)
|
||||
{
|
||||
ofnode child;
|
||||
int num = 0;
|
||||
|
||||
ofnode_for_each_subnode(child, parent)
|
||||
num++;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static int decode_timing_property(ofnode node, const char *name,
|
||||
struct timing_entry *result)
|
||||
{
|
||||
|
|
|
@ -352,3 +352,8 @@ fdt_addr_t dev_read_addr_pci(const struct udevice *dev)
|
|||
|
||||
return addr;
|
||||
}
|
||||
|
||||
int dev_get_child_count(const struct udevice *dev)
|
||||
{
|
||||
return ofnode_get_child_count(dev_ofnode(dev));
|
||||
}
|
||||
|
|
|
@ -20,11 +20,77 @@
|
|||
/* version V1 sub-banks offset base address */
|
||||
/* banks shared by multiple phys */
|
||||
#define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */
|
||||
#define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */
|
||||
#define SSUSB_SIFSLV_V1_CHIP 0x300 /* shared by u3 phys */
|
||||
/* u2 phy bank */
|
||||
#define SSUSB_SIFSLV_V1_U2PHY_COM 0x000
|
||||
/* u3/pcie/sata phy banks */
|
||||
#define SSUSB_SIFSLV_V1_U3PHYD 0x000
|
||||
#define SSUSB_SIFSLV_V1_U3PHYA 0x200
|
||||
|
||||
/* version V2 sub-banks offset base address */
|
||||
/* u2 phy banks */
|
||||
#define SSUSB_SIFSLV_V2_MISC 0x000
|
||||
#define SSUSB_SIFSLV_V2_U2FREQ 0x100
|
||||
#define SSUSB_SIFSLV_V2_U2PHY_COM 0x300
|
||||
/* u3/pcie/sata phy banks */
|
||||
#define SSUSB_SIFSLV_V2_SPLLC 0x000
|
||||
#define SSUSB_SIFSLV_V2_CHIP 0x100
|
||||
#define SSUSB_SIFSLV_V2_U3PHYD 0x200
|
||||
#define SSUSB_SIFSLV_V2_U3PHYA 0x400
|
||||
|
||||
#define U3P_USBPHYACR0 0x000
|
||||
#define PA0_RG_U2PLL_FORCE_ON BIT(15)
|
||||
#define PA0_RG_USB20_INTR_EN BIT(5)
|
||||
|
||||
#define U3P_USBPHYACR5 0x014
|
||||
#define PA5_RG_U2_HSTX_SRCAL_EN BIT(15)
|
||||
#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
|
||||
#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
|
||||
#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
|
||||
|
||||
#define U3P_USBPHYACR6 0x018
|
||||
#define PA6_RG_U2_BC11_SW_EN BIT(23)
|
||||
#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
|
||||
#define PA6_RG_U2_SQTH GENMASK(3, 0)
|
||||
#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
|
||||
|
||||
#define U3P_U2PHYACR4 0x020
|
||||
#define P2C_RG_USB20_GPIO_CTL BIT(9)
|
||||
#define P2C_USB20_GPIO_MODE BIT(8)
|
||||
#define P2C_U2_GPIO_CTR_MSK \
|
||||
(P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
|
||||
|
||||
#define U3P_U2PHYDTM0 0x068
|
||||
#define P2C_FORCE_UART_EN BIT(26)
|
||||
#define P2C_FORCE_DATAIN BIT(23)
|
||||
#define P2C_FORCE_DM_PULLDOWN BIT(21)
|
||||
#define P2C_FORCE_DP_PULLDOWN BIT(20)
|
||||
#define P2C_FORCE_XCVRSEL BIT(19)
|
||||
#define P2C_FORCE_SUSPENDM BIT(18)
|
||||
#define P2C_FORCE_TERMSEL BIT(17)
|
||||
#define P2C_RG_DATAIN GENMASK(13, 10)
|
||||
#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10)
|
||||
#define P2C_RG_DMPULLDOWN BIT(7)
|
||||
#define P2C_RG_DPPULLDOWN BIT(6)
|
||||
#define P2C_RG_XCVRSEL GENMASK(5, 4)
|
||||
#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4)
|
||||
#define P2C_RG_SUSPENDM BIT(3)
|
||||
#define P2C_RG_TERMSEL BIT(2)
|
||||
#define P2C_DTM0_PART_MASK \
|
||||
(P2C_FORCE_DATAIN | P2C_FORCE_DM_PULLDOWN | \
|
||||
P2C_FORCE_DP_PULLDOWN | P2C_FORCE_XCVRSEL | \
|
||||
P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
|
||||
P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
|
||||
|
||||
#define U3P_U2PHYDTM1 0x06C
|
||||
#define P2C_RG_UART_EN BIT(16)
|
||||
#define P2C_FORCE_IDDIG BIT(9)
|
||||
#define P2C_RG_VBUSVALID BIT(5)
|
||||
#define P2C_RG_SESSEND BIT(4)
|
||||
#define P2C_RG_AVALID BIT(2)
|
||||
#define P2C_RG_IDDIG BIT(1)
|
||||
|
||||
#define U3P_U3_CHIP_GPIO_CTLD 0x0c
|
||||
#define P3C_REG_IP_SW_RST BIT(31)
|
||||
#define P3C_MCU_BUS_CK_GATE_EN BIT(30)
|
||||
|
@ -42,6 +108,14 @@
|
|||
#define P3A_RG_CLKDRV_AMP GENMASK(31, 29)
|
||||
#define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29)
|
||||
|
||||
#define U3P_U3_PHYA_REG6 0x018
|
||||
#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
|
||||
#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28)
|
||||
|
||||
#define U3P_U3_PHYA_REG9 0x024
|
||||
#define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
|
||||
#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
|
||||
|
||||
#define U3P_U3_PHYA_DA_REG0 0x100
|
||||
#define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16)
|
||||
#define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16)
|
||||
|
@ -77,6 +151,16 @@
|
|||
#define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0)
|
||||
#define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x))
|
||||
|
||||
#define U3P_U3_PHYD_LFPS1 0x00c
|
||||
#define P3D_RG_FWAKE_TH GENMASK(21, 16)
|
||||
#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
|
||||
|
||||
#define U3P_U3_PHYD_CDR1 0x05c
|
||||
#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
|
||||
#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
|
||||
#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
|
||||
#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
|
||||
|
||||
#define U3P_U3_PHYD_RXDET1 0x128
|
||||
#define P3D_RG_RXDET_STB2_SET GENMASK(17, 9)
|
||||
#define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9)
|
||||
|
@ -85,6 +169,21 @@
|
|||
#define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0)
|
||||
#define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x))
|
||||
|
||||
#define U3P_SPLLC_XTALCTL3 0x018
|
||||
#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
|
||||
#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
|
||||
|
||||
enum mtk_phy_version {
|
||||
MTK_TPHY_V1 = 1,
|
||||
MTK_TPHY_V2,
|
||||
};
|
||||
|
||||
struct u2phy_banks {
|
||||
void __iomem *misc;
|
||||
void __iomem *fmreg;
|
||||
void __iomem *com;
|
||||
};
|
||||
|
||||
struct u3phy_banks {
|
||||
void __iomem *spllc;
|
||||
void __iomem *chip;
|
||||
|
@ -95,26 +194,136 @@ struct u3phy_banks {
|
|||
struct mtk_phy_instance {
|
||||
void __iomem *port_base;
|
||||
const struct device_node *np;
|
||||
union {
|
||||
struct u2phy_banks u2_banks;
|
||||
struct u3phy_banks u3_banks;
|
||||
};
|
||||
|
||||
struct u3phy_banks u3_banks;
|
||||
|
||||
/* reference clock of anolog phy */
|
||||
struct clk ref_clk;
|
||||
struct clk ref_clk; /* reference clock of (digital) phy */
|
||||
struct clk da_ref_clk; /* reference clock of analog phy */
|
||||
u32 index;
|
||||
u8 type;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
struct mtk_tphy {
|
||||
struct udevice *dev;
|
||||
void __iomem *sif_base;
|
||||
enum mtk_phy_version version;
|
||||
struct mtk_phy_instance **phys;
|
||||
int nphys;
|
||||
};
|
||||
|
||||
static void u2_phy_instance_init(struct mtk_tphy *tphy,
|
||||
struct mtk_phy_instance *instance)
|
||||
{
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
|
||||
/* switch to USB function, and enable usb pll */
|
||||
clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM0,
|
||||
P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM,
|
||||
P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0));
|
||||
|
||||
clrbits_le32(u2_banks->com + U3P_U2PHYDTM1, P2C_RG_UART_EN);
|
||||
setbits_le32(u2_banks->com + U3P_USBPHYACR0, PA0_RG_USB20_INTR_EN);
|
||||
|
||||
/* disable switch 100uA current to SSUSB */
|
||||
clrbits_le32(u2_banks->com + U3P_USBPHYACR5, PA5_RG_U2_HS_100U_U3_EN);
|
||||
|
||||
clrbits_le32(u2_banks->com + U3P_U2PHYACR4, P2C_U2_GPIO_CTR_MSK);
|
||||
|
||||
/* DP/DM BC1.1 path Disable */
|
||||
clrsetbits_le32(u2_banks->com + U3P_USBPHYACR6,
|
||||
PA6_RG_U2_BC11_SW_EN | PA6_RG_U2_SQTH,
|
||||
PA6_RG_U2_SQTH_VAL(2));
|
||||
|
||||
/* set HS slew rate */
|
||||
clrsetbits_le32(u2_banks->com + U3P_USBPHYACR5,
|
||||
PA5_RG_U2_HSTX_SRCTRL, PA5_RG_U2_HSTX_SRCTRL_VAL(4));
|
||||
|
||||
dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
|
||||
}
|
||||
|
||||
static void u2_phy_instance_power_on(struct mtk_tphy *tphy,
|
||||
struct mtk_phy_instance *instance)
|
||||
{
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
|
||||
clrbits_le32(u2_banks->com + U3P_U2PHYDTM0,
|
||||
P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
|
||||
|
||||
/* OTG Enable */
|
||||
setbits_le32(u2_banks->com + U3P_USBPHYACR6,
|
||||
PA6_RG_U2_OTG_VBUSCMP_EN);
|
||||
|
||||
clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM1,
|
||||
P2C_RG_SESSEND, P2C_RG_VBUSVALID | P2C_RG_AVALID);
|
||||
|
||||
dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
|
||||
}
|
||||
|
||||
static void u2_phy_instance_power_off(struct mtk_tphy *tphy,
|
||||
struct mtk_phy_instance *instance)
|
||||
{
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
|
||||
clrbits_le32(u2_banks->com + U3P_U2PHYDTM0,
|
||||
P2C_RG_XCVRSEL | P2C_RG_DATAIN);
|
||||
|
||||
/* OTG Disable */
|
||||
clrbits_le32(u2_banks->com + U3P_USBPHYACR6,
|
||||
PA6_RG_U2_OTG_VBUSCMP_EN);
|
||||
|
||||
clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM1,
|
||||
P2C_RG_VBUSVALID | P2C_RG_AVALID, P2C_RG_SESSEND);
|
||||
|
||||
dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
|
||||
}
|
||||
|
||||
static void u3_phy_instance_init(struct mtk_tphy *tphy,
|
||||
struct mtk_phy_instance *instance)
|
||||
{
|
||||
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||
|
||||
/* gating PCIe Analog XTAL clock */
|
||||
setbits_le32(u3_banks->spllc + U3P_SPLLC_XTALCTL3,
|
||||
XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD);
|
||||
|
||||
/* gating XSQ */
|
||||
clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG0,
|
||||
P3A_RG_XTAL_EXT_EN_U3, P3A_RG_XTAL_EXT_EN_U3_VAL(2));
|
||||
|
||||
clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG9,
|
||||
P3A_RG_RX_DAC_MUX, P3A_RG_RX_DAC_MUX_VAL(4));
|
||||
|
||||
clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG6,
|
||||
P3A_RG_TX_EIDLE_CM, P3A_RG_TX_EIDLE_CM_VAL(0xe));
|
||||
|
||||
clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_CDR1,
|
||||
P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1,
|
||||
P3D_RG_CDR_BIR_LTD0_VAL(0xc) |
|
||||
P3D_RG_CDR_BIR_LTD1_VAL(0x3));
|
||||
|
||||
clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_LFPS1,
|
||||
P3D_RG_FWAKE_TH, P3D_RG_FWAKE_TH_VAL(0x34));
|
||||
|
||||
clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET1,
|
||||
P3D_RG_RXDET_STB2_SET, P3D_RG_RXDET_STB2_SET_VAL(0x10));
|
||||
|
||||
clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET2,
|
||||
P3D_RG_RXDET_STB2_SET_P3,
|
||||
P3D_RG_RXDET_STB2_SET_P3_VAL(0x10));
|
||||
|
||||
dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
|
||||
}
|
||||
|
||||
static void pcie_phy_instance_init(struct mtk_tphy *tphy,
|
||||
struct mtk_phy_instance *instance)
|
||||
{
|
||||
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||
|
||||
if (tphy->version != MTK_TPHY_V1)
|
||||
return;
|
||||
|
||||
clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG0,
|
||||
P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H,
|
||||
P3A_RG_XTAL_EXT_PE1H_VAL(0x2) |
|
||||
|
@ -187,9 +396,16 @@ static void pcie_phy_instance_power_off(struct mtk_tphy *tphy,
|
|||
static void phy_v1_banks_init(struct mtk_tphy *tphy,
|
||||
struct mtk_phy_instance *instance)
|
||||
{
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||
|
||||
switch (instance->type) {
|
||||
case PHY_TYPE_USB2:
|
||||
u2_banks->misc = NULL;
|
||||
u2_banks->fmreg = tphy->sif_base + SSUSB_SIFSLV_V1_U2FREQ;
|
||||
u2_banks->com = instance->port_base + SSUSB_SIFSLV_V1_U2PHY_COM;
|
||||
break;
|
||||
case PHY_TYPE_USB3:
|
||||
case PHY_TYPE_PCIE:
|
||||
u3_banks->spllc = tphy->sif_base + SSUSB_SIFSLV_V1_SPLLC;
|
||||
u3_banks->chip = tphy->sif_base + SSUSB_SIFSLV_V1_CHIP;
|
||||
|
@ -197,6 +413,32 @@ static void phy_v1_banks_init(struct mtk_tphy *tphy,
|
|||
u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA;
|
||||
break;
|
||||
default:
|
||||
dev_err(tphy->dev, "incompatible PHY type\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void phy_v2_banks_init(struct mtk_tphy *tphy,
|
||||
struct mtk_phy_instance *instance)
|
||||
{
|
||||
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||
|
||||
switch (instance->type) {
|
||||
case PHY_TYPE_USB2:
|
||||
u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC;
|
||||
u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ;
|
||||
u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM;
|
||||
break;
|
||||
case PHY_TYPE_USB3:
|
||||
case PHY_TYPE_PCIE:
|
||||
u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC;
|
||||
u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP;
|
||||
u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD;
|
||||
u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA;
|
||||
break;
|
||||
default:
|
||||
dev_err(tphy->dev, "incompatible PHY type\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -208,14 +450,30 @@ static int mtk_phy_init(struct phy *phy)
|
|||
int ret;
|
||||
|
||||
ret = clk_enable(&instance->ref_clk);
|
||||
if (ret)
|
||||
if (ret < 0) {
|
||||
dev_err(tphy->dev, "failed to enable ref_clk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_enable(&instance->da_ref_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(tphy->dev, "failed to enable da_ref_clk %d\n", ret);
|
||||
clk_disable(&instance->ref_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (instance->type) {
|
||||
case PHY_TYPE_USB2:
|
||||
u2_phy_instance_init(tphy, instance);
|
||||
break;
|
||||
case PHY_TYPE_USB3:
|
||||
u3_phy_instance_init(tphy, instance);
|
||||
break;
|
||||
case PHY_TYPE_PCIE:
|
||||
pcie_phy_instance_init(tphy, instance);
|
||||
break;
|
||||
default:
|
||||
dev_err(tphy->dev, "incompatible PHY type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -227,7 +485,10 @@ static int mtk_phy_power_on(struct phy *phy)
|
|||
struct mtk_tphy *tphy = dev_get_priv(phy->dev);
|
||||
struct mtk_phy_instance *instance = tphy->phys[phy->id];
|
||||
|
||||
pcie_phy_instance_power_on(tphy, instance);
|
||||
if (instance->type == PHY_TYPE_USB2)
|
||||
u2_phy_instance_power_on(tphy, instance);
|
||||
else if (instance->type == PHY_TYPE_PCIE)
|
||||
pcie_phy_instance_power_on(tphy, instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -237,7 +498,10 @@ static int mtk_phy_power_off(struct phy *phy)
|
|||
struct mtk_tphy *tphy = dev_get_priv(phy->dev);
|
||||
struct mtk_phy_instance *instance = tphy->phys[phy->id];
|
||||
|
||||
pcie_phy_instance_power_off(tphy, instance);
|
||||
if (instance->type == PHY_TYPE_USB2)
|
||||
u2_phy_instance_power_off(tphy, instance);
|
||||
else if (instance->type == PHY_TYPE_PCIE)
|
||||
pcie_phy_instance_power_off(tphy, instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -247,6 +511,7 @@ static int mtk_phy_exit(struct phy *phy)
|
|||
struct mtk_tphy *tphy = dev_get_priv(phy->dev);
|
||||
struct mtk_phy_instance *instance = tphy->phys[phy->id];
|
||||
|
||||
clk_disable(&instance->da_ref_clk);
|
||||
clk_disable(&instance->ref_clk);
|
||||
|
||||
return 0;
|
||||
|
@ -285,13 +550,19 @@ static int mtk_phy_xlate(struct phy *phy,
|
|||
instance->type = args->args[1];
|
||||
if (!(instance->type == PHY_TYPE_USB2 ||
|
||||
instance->type == PHY_TYPE_USB3 ||
|
||||
instance->type == PHY_TYPE_PCIE ||
|
||||
instance->type == PHY_TYPE_SATA)) {
|
||||
instance->type == PHY_TYPE_PCIE)) {
|
||||
dev_err(phy->dev, "unsupported device type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
phy_v1_banks_init(tphy, instance);
|
||||
if (tphy->version == MTK_TPHY_V1) {
|
||||
phy_v1_banks_init(tphy, instance);
|
||||
} else if (tphy->version == MTK_TPHY_V2) {
|
||||
phy_v2_banks_init(tphy, instance);
|
||||
} else {
|
||||
dev_err(phy->dev, "phy version is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -310,17 +581,22 @@ static int mtk_tphy_probe(struct udevice *dev)
|
|||
ofnode subnode;
|
||||
int index = 0;
|
||||
|
||||
dev_for_each_subnode(subnode, dev)
|
||||
tphy->nphys++;
|
||||
tphy->nphys = dev_get_child_count(dev);
|
||||
|
||||
tphy->phys = devm_kcalloc(dev, tphy->nphys, sizeof(*tphy->phys),
|
||||
GFP_KERNEL);
|
||||
if (!tphy->phys)
|
||||
return -ENOMEM;
|
||||
|
||||
tphy->sif_base = dev_read_addr_ptr(dev);
|
||||
if (!tphy->sif_base)
|
||||
return -ENOENT;
|
||||
tphy->dev = dev;
|
||||
tphy->version = dev_get_driver_data(dev);
|
||||
|
||||
/* v1 has shared banks */
|
||||
if (tphy->version == MTK_TPHY_V1) {
|
||||
tphy->sif_base = dev_read_addr_ptr(dev);
|
||||
if (!tphy->sif_base)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
dev_for_each_subnode(subnode, dev) {
|
||||
struct mtk_phy_instance *instance;
|
||||
|
@ -345,13 +621,19 @@ static int mtk_tphy_probe(struct udevice *dev)
|
|||
&instance->ref_clk);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = clk_get_optional_nodev(subnode, "da_ref",
|
||||
&instance->da_ref_clk);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id mtk_tphy_id_table[] = {
|
||||
{ .compatible = "mediatek,generic-tphy-v1", },
|
||||
{ .compatible = "mediatek,generic-tphy-v1", .data = MTK_TPHY_V1, },
|
||||
{ .compatible = "mediatek,generic-tphy-v2", .data = MTK_TPHY_V2, },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/devres.h>
|
||||
#include <generic-phy.h>
|
||||
|
||||
static inline struct phy_ops *phy_dev_ops(struct udevice *dev)
|
||||
|
@ -167,6 +168,102 @@ int generic_phy_power_off(struct phy *phy)
|
|||
return ops->power_off ? ops->power_off(phy) : 0;
|
||||
}
|
||||
|
||||
int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk)
|
||||
{
|
||||
int i, ret, count;
|
||||
|
||||
bulk->count = 0;
|
||||
|
||||
/* Return if no phy declared */
|
||||
if (!dev_read_prop(dev, "phys", NULL))
|
||||
return 0;
|
||||
|
||||
count = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
|
||||
if (count < 1)
|
||||
return count;
|
||||
|
||||
bulk->phys = devm_kcalloc(dev, count, sizeof(struct phy), GFP_KERNEL);
|
||||
if (!bulk->phys)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = generic_phy_get_by_index(dev, i, &bulk->phys[i]);
|
||||
if (ret) {
|
||||
pr_err("Failed to get PHY%d for %s\n", i, dev->name);
|
||||
return ret;
|
||||
}
|
||||
bulk->count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generic_phy_init_bulk(struct phy_bulk *bulk)
|
||||
{
|
||||
struct phy *phys = bulk->phys;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < bulk->count; i++) {
|
||||
ret = generic_phy_init(&phys[i]);
|
||||
if (ret) {
|
||||
pr_err("Can't init PHY%d\n", i);
|
||||
goto phys_init_err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
phys_init_err:
|
||||
for (; i > 0; i--)
|
||||
generic_phy_exit(&phys[i - 1]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int generic_phy_exit_bulk(struct phy_bulk *bulk)
|
||||
{
|
||||
struct phy *phys = bulk->phys;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < bulk->count; i++)
|
||||
ret |= generic_phy_exit(&phys[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int generic_phy_power_on_bulk(struct phy_bulk *bulk)
|
||||
{
|
||||
struct phy *phys = bulk->phys;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < bulk->count; i++) {
|
||||
ret = generic_phy_power_on(&phys[i]);
|
||||
if (ret) {
|
||||
pr_err("Can't power on PHY%d\n", i);
|
||||
goto phys_poweron_err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
phys_poweron_err:
|
||||
for (; i > 0; i--)
|
||||
generic_phy_power_off(&phys[i - 1]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int generic_phy_power_off_bulk(struct phy_bulk *bulk)
|
||||
{
|
||||
struct phy *phys = bulk->phys;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < bulk->count; i++)
|
||||
ret |= generic_phy_power_off(&phys[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(phy) = {
|
||||
.id = UCLASS_PHY,
|
||||
.name = "phy",
|
||||
|
|
|
@ -838,87 +838,32 @@ MODULE_LICENSE("GPL v2");
|
|||
MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
|
||||
|
||||
#if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB)
|
||||
int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys)
|
||||
int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys)
|
||||
{
|
||||
int i, ret, count;
|
||||
struct phy *usb_phys;
|
||||
int ret;
|
||||
|
||||
/* Return if no phy declared */
|
||||
if (!dev_read_prop(dev, "phys", NULL))
|
||||
return 0;
|
||||
count = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
|
||||
if (count <= 0)
|
||||
return count;
|
||||
ret = generic_phy_get_bulk(dev, phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usb_phys = devm_kcalloc(dev, count, sizeof(struct phy),
|
||||
GFP_KERNEL);
|
||||
if (!usb_phys)
|
||||
return -ENOMEM;
|
||||
ret = generic_phy_init_bulk(phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = generic_phy_get_by_index(dev, i, &usb_phys[i]);
|
||||
if (ret && ret != -ENOENT) {
|
||||
pr_err("Failed to get USB PHY%d for %s\n",
|
||||
i, dev->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = generic_phy_init(&usb_phys[i]);
|
||||
if (ret) {
|
||||
pr_err("Can't init USB PHY%d for %s\n",
|
||||
i, dev->name);
|
||||
goto phys_init_err;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = generic_phy_power_on(&usb_phys[i]);
|
||||
if (ret) {
|
||||
pr_err("Can't power USB PHY%d for %s\n",
|
||||
i, dev->name);
|
||||
goto phys_poweron_err;
|
||||
}
|
||||
}
|
||||
|
||||
*array = usb_phys;
|
||||
*num_phys = count;
|
||||
return 0;
|
||||
|
||||
phys_poweron_err:
|
||||
for (i = count - 1; i >= 0; i--)
|
||||
generic_phy_power_off(&usb_phys[i]);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
generic_phy_exit(&usb_phys[i]);
|
||||
|
||||
return ret;
|
||||
|
||||
phys_init_err:
|
||||
for (; i >= 0; i--)
|
||||
generic_phy_exit(&usb_phys[i]);
|
||||
ret = generic_phy_power_on_bulk(phys);
|
||||
if (ret)
|
||||
generic_phy_exit_bulk(phys);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys)
|
||||
int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys)
|
||||
{
|
||||
int i, ret;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < num_phys; i++) {
|
||||
if (!generic_phy_valid(&usb_phys[i]))
|
||||
continue;
|
||||
|
||||
ret = generic_phy_power_off(&usb_phys[i]);
|
||||
ret |= generic_phy_exit(&usb_phys[i]);
|
||||
if (ret) {
|
||||
pr_err("Can't shutdown USB PHY%d for %s\n",
|
||||
i, dev->name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = generic_phy_power_off_bulk(phys);
|
||||
ret |= generic_phy_exit_bulk(phys);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -33,8 +33,7 @@ struct dwc3_generic_plat {
|
|||
struct dwc3_generic_priv {
|
||||
void *base;
|
||||
struct dwc3 dwc3;
|
||||
struct phy *phys;
|
||||
int num_phys;
|
||||
struct phy_bulk phys;
|
||||
};
|
||||
|
||||
struct dwc3_generic_host_priv {
|
||||
|
@ -56,7 +55,7 @@ static int dwc3_generic_probe(struct udevice *dev,
|
|||
dwc3_of_parse(dwc3);
|
||||
#endif
|
||||
|
||||
rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys);
|
||||
rc = dwc3_setup_phy(dev, &priv->phys);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -79,7 +78,7 @@ static int dwc3_generic_remove(struct udevice *dev,
|
|||
struct dwc3 *dwc3 = &priv->dwc3;
|
||||
|
||||
dwc3_remove(dwc3);
|
||||
dwc3_shutdown_phy(dev, priv->phys, priv->num_phys);
|
||||
dwc3_shutdown_phy(dev, &priv->phys);
|
||||
unmap_physmem(dwc3->regs, MAP_NOCACHE);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -943,8 +943,7 @@ int usb_gadget_handle_interrupts(int index)
|
|||
struct dwc2_priv_data {
|
||||
struct clk_bulk clks;
|
||||
struct reset_ctl_bulk resets;
|
||||
struct phy *phys;
|
||||
int num_phys;
|
||||
struct phy_bulk phys;
|
||||
struct udevice *usb33d_supply;
|
||||
};
|
||||
|
||||
|
@ -953,87 +952,29 @@ int dm_usb_gadget_handle_interrupts(struct udevice *dev)
|
|||
return dwc2_udc_handle_interrupt();
|
||||
}
|
||||
|
||||
int dwc2_phy_setup(struct udevice *dev, struct phy **array, int *num_phys)
|
||||
static int dwc2_phy_setup(struct udevice *dev, struct phy_bulk *phys)
|
||||
{
|
||||
int i, ret, count;
|
||||
struct phy *usb_phys;
|
||||
int ret;
|
||||
|
||||
/* Return if no phy declared */
|
||||
if (!dev_read_prop(dev, "phys", NULL))
|
||||
return 0;
|
||||
ret = generic_phy_get_bulk(dev, phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
count = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
|
||||
if (count <= 0)
|
||||
return count;
|
||||
ret = generic_phy_init_bulk(phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usb_phys = devm_kcalloc(dev, count, sizeof(struct phy),
|
||||
GFP_KERNEL);
|
||||
if (!usb_phys)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = generic_phy_get_by_index(dev, i, &usb_phys[i]);
|
||||
if (ret && ret != -ENOENT) {
|
||||
dev_err(dev, "Failed to get USB PHY%d for %s\n",
|
||||
i, dev->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = generic_phy_init(&usb_phys[i]);
|
||||
if (ret) {
|
||||
dev_err(dev, "Can't init USB PHY%d for %s\n",
|
||||
i, dev->name);
|
||||
goto phys_init_err;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = generic_phy_power_on(&usb_phys[i]);
|
||||
if (ret) {
|
||||
dev_err(dev, "Can't power USB PHY%d for %s\n",
|
||||
i, dev->name);
|
||||
goto phys_poweron_err;
|
||||
}
|
||||
}
|
||||
|
||||
*array = usb_phys;
|
||||
*num_phys = count;
|
||||
|
||||
return 0;
|
||||
|
||||
phys_poweron_err:
|
||||
for (i = count - 1; i >= 0; i--)
|
||||
generic_phy_power_off(&usb_phys[i]);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
generic_phy_exit(&usb_phys[i]);
|
||||
|
||||
return ret;
|
||||
|
||||
phys_init_err:
|
||||
for (; i >= 0; i--)
|
||||
generic_phy_exit(&usb_phys[i]);
|
||||
ret = generic_phy_power_on_bulk(phys);
|
||||
if (ret)
|
||||
generic_phy_exit_bulk(phys);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dwc2_phy_shutdown(struct udevice *dev, struct phy *usb_phys, int num_phys)
|
||||
static void dwc2_phy_shutdown(struct udevice *dev, struct phy_bulk *phys)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < num_phys; i++) {
|
||||
if (!generic_phy_valid(&usb_phys[i]))
|
||||
continue;
|
||||
|
||||
ret = generic_phy_power_off(&usb_phys[i]);
|
||||
ret |= generic_phy_exit(&usb_phys[i]);
|
||||
if (ret) {
|
||||
dev_err(dev, "Can't shutdown USB PHY%d for %s\n",
|
||||
i, dev->name);
|
||||
}
|
||||
}
|
||||
generic_phy_power_off_bulk(phys);
|
||||
generic_phy_exit_bulk(phys);
|
||||
}
|
||||
|
||||
static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev)
|
||||
|
@ -1158,7 +1099,7 @@ static int dwc2_udc_otg_probe(struct udevice *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dwc2_phy_setup(dev, &priv->phys, &priv->num_phys);
|
||||
ret = dwc2_phy_setup(dev, &priv->phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1208,7 +1149,7 @@ static int dwc2_udc_otg_remove(struct udevice *dev)
|
|||
|
||||
clk_release_bulk(&priv->clks);
|
||||
|
||||
dwc2_phy_shutdown(dev, priv->phys, priv->num_phys);
|
||||
dwc2_phy_shutdown(dev, &priv->phys);
|
||||
|
||||
return dm_scan_fdt_dev(dev);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,12 @@ config USB_XHCI_DWC3_OF_SIMPLE
|
|||
Support USB2/3 functionality in simple SoC integrations with
|
||||
USB controller based on the DesignWare USB3 IP Core.
|
||||
|
||||
config USB_XHCI_MTK
|
||||
bool "Support for MediaTek on-chip xHCI USB controller"
|
||||
depends on ARCH_MEDIATEK
|
||||
help
|
||||
Enables support for the on-chip xHCI controller on MediaTek SoCs.
|
||||
|
||||
config USB_XHCI_MVEBU
|
||||
bool "MVEBU USB 3.0 support"
|
||||
default y
|
||||
|
|
|
@ -51,6 +51,7 @@ obj-$(CONFIG_USB_XHCI_DWC3_OF_SIMPLE) += dwc3-of-simple.o
|
|||
obj-$(CONFIG_USB_XHCI_ROCKCHIP) += xhci-rockchip.o
|
||||
obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o
|
||||
obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o
|
||||
obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o
|
||||
obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o
|
||||
obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o
|
||||
obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
#include <linux/usb/otg.h>
|
||||
|
||||
struct xhci_dwc3_platdata {
|
||||
struct phy *usb_phys;
|
||||
int num_phys;
|
||||
struct phy_bulk *usb_phys;
|
||||
};
|
||||
|
||||
void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode)
|
||||
|
@ -125,7 +124,7 @@ static int xhci_dwc3_probe(struct udevice *dev)
|
|||
hcor = (struct xhci_hcor *)((uintptr_t)hccr +
|
||||
HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
|
||||
|
||||
ret = dwc3_setup_phy(dev, &plat->usb_phys, &plat->num_phys);
|
||||
ret = dwc3_setup_phy(dev, plat->usb_phys);
|
||||
if (ret && (ret != -ENOTSUPP))
|
||||
return ret;
|
||||
|
||||
|
@ -168,7 +167,7 @@ static int xhci_dwc3_remove(struct udevice *dev)
|
|||
{
|
||||
struct xhci_dwc3_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
dwc3_shutdown_phy(dev, plat->usb_phys, plat->num_phys);
|
||||
dwc3_shutdown_phy(dev, plat->usb_phys);
|
||||
|
||||
return xhci_deregister(dev);
|
||||
}
|
||||
|
|
303
drivers/usb/host/xhci-mtk.c
Normal file
303
drivers/usb/host/xhci-mtk.c
Normal file
|
@ -0,0 +1,303 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2019 MediaTek, Inc.
|
||||
* Authors: Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <clk.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/devres.h>
|
||||
#include <generic-phy.h>
|
||||
#include <malloc.h>
|
||||
#include <usb.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/compat.h>
|
||||
#include <power/regulator.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <usb/xhci.h>
|
||||
|
||||
/* IPPC (IP Port Control) registers */
|
||||
#define IPPC_IP_PW_CTRL0 0x00
|
||||
#define CTRL0_IP_SW_RST BIT(0)
|
||||
|
||||
#define IPPC_IP_PW_CTRL1 0x04
|
||||
#define CTRL1_IP_HOST_PDN BIT(0)
|
||||
|
||||
#define IPPC_IP_PW_STS1 0x10
|
||||
#define STS1_IP_SLEEP_STS BIT(30)
|
||||
#define STS1_U3_MAC_RST BIT(16)
|
||||
#define STS1_XHCI_RST BIT(11)
|
||||
#define STS1_SYS125_RST BIT(10)
|
||||
#define STS1_REF_RST BIT(8)
|
||||
#define STS1_SYSPLL_STABLE BIT(0)
|
||||
|
||||
#define IPPC_IP_XHCI_CAP 0x24
|
||||
#define CAP_U3_PORT_NUM(p) ((p) & 0xff)
|
||||
#define CAP_U2_PORT_NUM(p) (((p) >> 8) & 0xff)
|
||||
|
||||
#define IPPC_U3_CTRL_0P 0x30
|
||||
#define CTRL_U3_PORT_HOST_SEL BIT(2)
|
||||
#define CTRL_U3_PORT_PDN BIT(1)
|
||||
#define CTRL_U3_PORT_DIS BIT(0)
|
||||
|
||||
#define IPPC_U2_CTRL_0P 0x50
|
||||
#define CTRL_U2_PORT_HOST_SEL BIT(2)
|
||||
#define CTRL_U2_PORT_PDN BIT(1)
|
||||
#define CTRL_U2_PORT_DIS BIT(0)
|
||||
|
||||
#define IPPC_U3_CTRL(p) (IPPC_U3_CTRL_0P + ((p) * 0x08))
|
||||
#define IPPC_U2_CTRL(p) (IPPC_U2_CTRL_0P + ((p) * 0x08))
|
||||
|
||||
struct mtk_xhci {
|
||||
struct xhci_ctrl ctrl; /* Needs to come first in this struct! */
|
||||
struct xhci_hccr *hcd;
|
||||
void __iomem *ippc;
|
||||
struct udevice *dev;
|
||||
struct udevice *vusb33_supply;
|
||||
struct udevice *vbus_supply;
|
||||
struct clk_bulk clks;
|
||||
struct phy_bulk phys;
|
||||
int num_u2ports;
|
||||
int num_u3ports;
|
||||
};
|
||||
|
||||
static int xhci_mtk_host_enable(struct mtk_xhci *mtk)
|
||||
{
|
||||
u32 value;
|
||||
u32 check_val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* power on host ip */
|
||||
clrbits_le32(mtk->ippc + IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN);
|
||||
|
||||
/* power on and enable all u3 ports */
|
||||
for (i = 0; i < mtk->num_u3ports; i++) {
|
||||
clrsetbits_le32(mtk->ippc + IPPC_U3_CTRL(i),
|
||||
CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS,
|
||||
CTRL_U3_PORT_HOST_SEL);
|
||||
}
|
||||
|
||||
/* power on and enable all u2 ports */
|
||||
for (i = 0; i < mtk->num_u2ports; i++) {
|
||||
clrsetbits_le32(mtk->ippc + IPPC_U2_CTRL(i),
|
||||
CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS,
|
||||
CTRL_U2_PORT_HOST_SEL);
|
||||
}
|
||||
|
||||
/*
|
||||
* wait for clocks to be stable, and clock domains reset to
|
||||
* be inactive after power on and enable ports
|
||||
*/
|
||||
check_val = STS1_SYSPLL_STABLE | STS1_REF_RST |
|
||||
STS1_SYS125_RST | STS1_XHCI_RST;
|
||||
|
||||
if (mtk->num_u3ports)
|
||||
check_val |= STS1_U3_MAC_RST;
|
||||
|
||||
ret = readl_poll_timeout(mtk->ippc + IPPC_IP_PW_STS1, value,
|
||||
(check_val == (value & check_val)), 20000);
|
||||
if (ret)
|
||||
dev_err(mtk->dev, "clocks are not stable 0x%x!\n", value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xhci_mtk_host_disable(struct mtk_xhci *mtk)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* power down all u3 ports */
|
||||
for (i = 0; i < mtk->num_u3ports; i++)
|
||||
setbits_le32(mtk->ippc + IPPC_U3_CTRL(i), CTRL_U3_PORT_PDN);
|
||||
|
||||
/* power down all u2 ports */
|
||||
for (i = 0; i < mtk->num_u2ports; i++)
|
||||
setbits_le32(mtk->ippc + IPPC_U2_CTRL(i), CTRL_U2_PORT_PDN);
|
||||
|
||||
/* power down host ip */
|
||||
setbits_le32(mtk->ippc + IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xhci_mtk_ssusb_init(struct mtk_xhci *mtk)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
/* reset whole ip */
|
||||
setbits_le32(mtk->ippc + IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST);
|
||||
udelay(1);
|
||||
clrbits_le32(mtk->ippc + IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST);
|
||||
|
||||
value = readl(mtk->ippc + IPPC_IP_XHCI_CAP);
|
||||
mtk->num_u3ports = CAP_U3_PORT_NUM(value);
|
||||
mtk->num_u2ports = CAP_U2_PORT_NUM(value);
|
||||
dev_info(mtk->dev, "u2p:%d, u3p:%d\n",
|
||||
mtk->num_u2ports, mtk->num_u3ports);
|
||||
|
||||
return xhci_mtk_host_enable(mtk);
|
||||
}
|
||||
|
||||
static int xhci_mtk_ofdata_get(struct mtk_xhci *mtk)
|
||||
{
|
||||
struct udevice *dev = mtk->dev;
|
||||
int ret = 0;
|
||||
|
||||
mtk->hcd = devfdt_remap_addr_name(dev, "mac");
|
||||
if (!mtk->hcd) {
|
||||
dev_err(dev, "failed to get xHCI base address\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
mtk->ippc = devfdt_remap_addr_name(dev, "ippc");
|
||||
if (!mtk->ippc) {
|
||||
dev_err(dev, "failed to get IPPC base address\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
dev_info(dev, "hcd: 0x%p, ippc: 0x%p\n", mtk->hcd, mtk->ippc);
|
||||
|
||||
ret = clk_get_bulk(dev, &mtk->clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get clocks %d!\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_get_supply_regulator(dev, "vusb33-supply",
|
||||
&mtk->vusb33_supply);
|
||||
if (ret)
|
||||
debug("can't get vusb33 regulator %d!\n", ret);
|
||||
|
||||
ret = device_get_supply_regulator(dev, "vbus-supply",
|
||||
&mtk->vbus_supply);
|
||||
if (ret)
|
||||
debug("can't get vbus regulator %d!\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xhci_mtk_ldos_enable(struct mtk_xhci *mtk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regulator_set_enable(mtk->vusb33_supply, true);
|
||||
if (ret < 0 && ret != -ENOSYS) {
|
||||
dev_err(mtk->dev, "failed to enable vusb33 %d!\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_set_enable(mtk->vbus_supply, true);
|
||||
if (ret < 0 && ret != -ENOSYS) {
|
||||
dev_err(mtk->dev, "failed to enable vbus %d!\n", ret);
|
||||
regulator_set_enable(mtk->vusb33_supply, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xhci_mtk_ldos_disable(struct mtk_xhci *mtk)
|
||||
{
|
||||
regulator_set_enable(mtk->vbus_supply, false);
|
||||
regulator_set_enable(mtk->vusb33_supply, false);
|
||||
}
|
||||
|
||||
static int xhci_mtk_phy_setup(struct mtk_xhci *mtk)
|
||||
{
|
||||
struct udevice *dev = mtk->dev;
|
||||
struct phy_bulk *phys = &mtk->phys;
|
||||
int ret;
|
||||
|
||||
ret = generic_phy_get_bulk(dev, phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = generic_phy_init_bulk(phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = generic_phy_power_on_bulk(phys);
|
||||
if (ret)
|
||||
generic_phy_exit_bulk(phys);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xhci_mtk_phy_shutdown(struct mtk_xhci *mtk)
|
||||
{
|
||||
generic_phy_power_off_bulk(&mtk->phys);
|
||||
generic_phy_exit_bulk(&mtk->phys);
|
||||
}
|
||||
|
||||
static int xhci_mtk_probe(struct udevice *dev)
|
||||
{
|
||||
struct mtk_xhci *mtk = dev_get_priv(dev);
|
||||
struct xhci_hcor *hcor;
|
||||
int ret;
|
||||
|
||||
mtk->dev = dev;
|
||||
ret = xhci_mtk_ofdata_get(mtk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xhci_mtk_ldos_enable(mtk);
|
||||
if (ret)
|
||||
goto ldos_err;
|
||||
|
||||
ret = clk_enable_bulk(&mtk->clks);
|
||||
if (ret)
|
||||
goto clks_err;
|
||||
|
||||
ret = xhci_mtk_phy_setup(mtk);
|
||||
if (ret)
|
||||
goto phys_err;
|
||||
|
||||
ret = xhci_mtk_ssusb_init(mtk);
|
||||
if (ret)
|
||||
goto ssusb_init_err;
|
||||
|
||||
hcor = (struct xhci_hcor *)((uintptr_t)mtk->hcd +
|
||||
HC_LENGTH(xhci_readl(&mtk->hcd->cr_capbase)));
|
||||
|
||||
return xhci_register(dev, mtk->hcd, hcor);
|
||||
|
||||
ssusb_init_err:
|
||||
xhci_mtk_phy_shutdown(mtk);
|
||||
phys_err:
|
||||
clk_disable_bulk(&mtk->clks);
|
||||
clks_err:
|
||||
xhci_mtk_ldos_disable(mtk);
|
||||
ldos_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xhci_mtk_remove(struct udevice *dev)
|
||||
{
|
||||
struct mtk_xhci *mtk = dev_get_priv(dev);
|
||||
|
||||
xhci_deregister(dev);
|
||||
xhci_mtk_host_disable(mtk);
|
||||
xhci_mtk_ldos_disable(mtk);
|
||||
clk_disable_bulk(&mtk->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id xhci_mtk_ids[] = {
|
||||
{ .compatible = "mediatek,mtk-xhci" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(usb_xhci) = {
|
||||
.name = "xhci-mtk",
|
||||
.id = UCLASS_USB,
|
||||
.of_match = xhci_mtk_ids,
|
||||
.probe = xhci_mtk_probe,
|
||||
.remove = xhci_mtk_remove,
|
||||
.ops = &xhci_usb_ops,
|
||||
.bind = dm_scan_fdt_dev,
|
||||
.priv_auto_alloc_size = sizeof(struct mtk_xhci),
|
||||
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
||||
};
|
|
@ -610,6 +610,16 @@ static int xhci_set_configuration(struct usb_device *udev)
|
|||
ep_ctx[ep_index]->tx_info =
|
||||
cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
|
||||
EP_AVG_TRB_LENGTH(avg_trb_len));
|
||||
|
||||
/*
|
||||
* The MediaTek xHCI defines some extra SW parameters which
|
||||
* are put into reserved DWs in Slot and Endpoint Contexts
|
||||
* for synchronous endpoints.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_USB_XHCI_MTK)) {
|
||||
ep_ctx[ep_index]->reserved[0] =
|
||||
cpu_to_le32(EP_BPKTS(1) | EP_BBM(1));
|
||||
}
|
||||
}
|
||||
|
||||
return xhci_configure_endpoints(udev, false);
|
||||
|
|
|
@ -879,6 +879,14 @@ ofnode ofnode_by_prop_value(ofnode from, const char *propname,
|
|||
ofnode_valid(node); \
|
||||
node = ofnode_next_subnode(node))
|
||||
|
||||
/**
|
||||
* ofnode_get_child_count() - get the child count of a ofnode
|
||||
*
|
||||
* @node: valid node to get its child count
|
||||
* @return the number of subnodes
|
||||
*/
|
||||
int ofnode_get_child_count(ofnode parent);
|
||||
|
||||
/**
|
||||
* ofnode_translate_address() - Translate a device-tree address
|
||||
*
|
||||
|
|
|
@ -669,6 +669,14 @@ u64 dev_translate_dma_address(const struct udevice *dev,
|
|||
*/
|
||||
int dev_read_alias_highest_id(const char *stem);
|
||||
|
||||
/**
|
||||
* dev_get_child_count() - get the child count of a device
|
||||
*
|
||||
* @dev: device to use for interation (struct udevice *)
|
||||
* @return the count of child subnode
|
||||
*/
|
||||
int dev_get_child_count(const struct udevice *dev);
|
||||
|
||||
#else /* CONFIG_DM_DEV_READ_INLINE is enabled */
|
||||
|
||||
static inline int dev_read_u32(const struct udevice *dev,
|
||||
|
@ -978,6 +986,11 @@ static inline int dev_read_alias_highest_id(const char *stem)
|
|||
return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
|
||||
}
|
||||
|
||||
static inline int dev_get_child_count(const struct udevice *dev)
|
||||
{
|
||||
return ofnode_get_child_count(dev_ofnode(dev));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DM_DEV_READ_INLINE */
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef __DWC3_UBOOT_H_
|
||||
#define __DWC3_UBOOT_H_
|
||||
|
||||
#include <generic-phy.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/phy.h>
|
||||
|
||||
|
@ -43,17 +44,15 @@ void dwc3_uboot_handle_interrupt(int index);
|
|||
|
||||
struct phy;
|
||||
#if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB)
|
||||
int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys);
|
||||
int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys);
|
||||
int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys);
|
||||
int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys);
|
||||
#else
|
||||
static inline int dwc3_setup_phy(struct udevice *dev, struct phy **array,
|
||||
int *num_phys)
|
||||
static inline int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys,
|
||||
int num_phys)
|
||||
static inline int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
|
|
@ -124,6 +124,23 @@ struct phy_ops {
|
|||
int (*power_off)(struct phy *phy);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct phy_bulk - A handle to (allowing control of) a bulk of phys.
|
||||
*
|
||||
* Consumers provide storage for the phy bulk. The content of the structure is
|
||||
* managed solely by the phy API. A phy bulk struct is initialized
|
||||
* by "get"ing the phy bulk struct.
|
||||
* The phy bulk struct is passed to all other bulk phy APIs to apply
|
||||
* the API to all the phy in the bulk struct.
|
||||
*
|
||||
* @phys: An array of phy handles.
|
||||
* @count: The number of phy handles in the phys array.
|
||||
*/
|
||||
struct phy_bulk {
|
||||
struct phy *phys;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PHY
|
||||
|
||||
/**
|
||||
|
@ -250,6 +267,55 @@ int generic_phy_get_by_node(ofnode node, int index, struct phy *phy);
|
|||
int generic_phy_get_by_name(struct udevice *user, const char *phy_name,
|
||||
struct phy *phy);
|
||||
|
||||
/**
|
||||
* generic_phy_get_bulk - Get all phys of a device.
|
||||
*
|
||||
* This looks up and gets all phys of the consumer device; each device is
|
||||
* assumed to have n phys associated with it somehow, and this function finds
|
||||
* and gets all of them in a separate structure.
|
||||
*
|
||||
* @dev: The consumer device.
|
||||
* @bulk A pointer to a phy bulk struct to initialize.
|
||||
* @return 0 if OK, or a negative error code.
|
||||
*/
|
||||
int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk);
|
||||
|
||||
/**
|
||||
* generic_phy_init_bulk() - Initialize all phys in a phy bulk struct.
|
||||
*
|
||||
* @bulk: A phy bulk struct that was previously successfully requested
|
||||
* by generic_phy_get_bulk().
|
||||
* @return 0 if OK, or negative error code.
|
||||
*/
|
||||
int generic_phy_init_bulk(struct phy_bulk *bulk);
|
||||
|
||||
/**
|
||||
* generic_phy_exit_bulk() - de-initialize all phys in a phy bulk struct.
|
||||
*
|
||||
* @bulk: A phy bulk struct that was previously successfully requested
|
||||
* by generic_phy_get_bulk().
|
||||
* @return 0 if OK, or negative error code.
|
||||
*/
|
||||
int generic_phy_exit_bulk(struct phy_bulk *bulk);
|
||||
|
||||
/**
|
||||
* generic_phy_power_on_bulk() - Power on all phys in a phy bulk struct.
|
||||
*
|
||||
* @bulk: A phy bulk struct that was previously successfully requested
|
||||
* by generic_phy_get_bulk().
|
||||
* @return 0 if OK, or negative error code.
|
||||
*/
|
||||
int generic_phy_power_on_bulk(struct phy_bulk *bulk);
|
||||
|
||||
/**
|
||||
* generic_phy_power_off_bulk() - Power off all phys in a phy bulk struct.
|
||||
*
|
||||
* @bulk: A phy bulk struct that was previously successfully requested
|
||||
* by generic_phy_get_bulk().
|
||||
* @return 0 if OK, or negative error code.
|
||||
*/
|
||||
int generic_phy_power_off_bulk(struct phy_bulk *bulk);
|
||||
|
||||
#else /* CONFIG_PHY */
|
||||
|
||||
static inline int generic_phy_init(struct phy *phy)
|
||||
|
@ -289,6 +355,32 @@ static inline int generic_phy_get_by_name(struct udevice *user, const char *phy_
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int generic_phy_init_bulk(struct phy_bulk *bulk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int generic_phy_exit_bulk(struct phy_bulk *bulk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int generic_phy_power_on_bulk(struct phy_bulk *bulk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int generic_phy_power_off_bulk(struct phy_bulk *bulk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PHY */
|
||||
|
||||
/**
|
||||
|
|
|
@ -670,6 +670,9 @@ struct xhci_ep_ctx {
|
|||
/* deq bitmasks */
|
||||
#define EP_CTX_CYCLE_MASK (1 << 0)
|
||||
|
||||
/* reserved[0] bitmasks, MediaTek xHCI used */
|
||||
#define EP_BPKTS(p) (((p) & 0x7f) << 0)
|
||||
#define EP_BBM(p) (((p) & 0x1) << 11)
|
||||
|
||||
/**
|
||||
* struct xhci_input_control_context
|
||||
|
|
|
@ -113,3 +113,24 @@ static int dm_test_ofnode_read_chosen(struct unit_test_state *uts)
|
|||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_ofnode_read_chosen, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
||||
static int dm_test_ofnode_get_child_count(struct unit_test_state *uts)
|
||||
{
|
||||
ofnode node, child_node;
|
||||
u32 val;
|
||||
|
||||
node = ofnode_path("/i-test");
|
||||
ut_assert(ofnode_valid(node));
|
||||
|
||||
val = ofnode_get_child_count(node);
|
||||
ut_asserteq(3, val);
|
||||
|
||||
child_node = ofnode_first_subnode(node);
|
||||
ut_assert(ofnode_valid(child_node));
|
||||
val = ofnode_get_child_count(child_node);
|
||||
ut_asserteq(0, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_ofnode_get_child_count,
|
||||
DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
|
|
@ -110,3 +110,36 @@ static int dm_test_phy_ops(struct unit_test_state *uts)
|
|||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_phy_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
||||
static int dm_test_phy_bulk(struct unit_test_state *uts)
|
||||
{
|
||||
struct phy_bulk phys;
|
||||
struct udevice *parent;
|
||||
|
||||
/* test normal operations */
|
||||
ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS,
|
||||
"gen_phy_user1", &parent));
|
||||
|
||||
ut_assertok(generic_phy_get_bulk(parent, &phys));
|
||||
ut_asserteq(2, phys.count);
|
||||
|
||||
ut_asserteq(0, generic_phy_init_bulk(&phys));
|
||||
ut_asserteq(0, generic_phy_power_on_bulk(&phys));
|
||||
ut_asserteq(0, generic_phy_power_off_bulk(&phys));
|
||||
ut_asserteq(0, generic_phy_exit_bulk(&phys));
|
||||
|
||||
/* has a known problem phy */
|
||||
ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS,
|
||||
"gen_phy_user", &parent));
|
||||
|
||||
ut_assertok(generic_phy_get_bulk(parent, &phys));
|
||||
ut_asserteq(3, phys.count);
|
||||
|
||||
ut_asserteq(0, generic_phy_init_bulk(&phys));
|
||||
ut_asserteq(-EIO, generic_phy_power_on_bulk(&phys));
|
||||
ut_asserteq(-EIO, generic_phy_power_off_bulk(&phys));
|
||||
ut_asserteq(0, generic_phy_exit_bulk(&phys));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_phy_bulk, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
|
Loading…
Reference in a new issue