Release develop 260109
This commit is contained in:
@@ -990,11 +990,6 @@
|
||||
&rp3x1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pcie_x1_pins>;
|
||||
minipcie-1v5-pwren-gpios = <&aw9535_0 6 GPIO_ACTIVE_HIGH>;
|
||||
minipcie-3v3-pwren-gpios = <&aw9535_0 7 GPIO_ACTIVE_HIGH>;
|
||||
minipcie-perst-gpios = <&aw9535_0 15 GPIO_ACTIVE_HIGH>;
|
||||
pcie-clk-en-gpios = <&aw9535_0 12 GPIO_ACTIVE_HIGH>;
|
||||
pcie-clk-pwren-gpios = <&aw9535_1 13 GPIO_ACTIVE_HIGH>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -1066,9 +1061,12 @@
|
||||
wakeup-source;
|
||||
};
|
||||
|
||||
&usb20_zhihe {
|
||||
usb21-pwren-gpios = <&aw9535_1 8 GPIO_ACTIVE_HIGH>;
|
||||
usb20-pwren-gpios = <&aw9535_1 9 GPIO_ACTIVE_HIGH>;
|
||||
&usb2phy0 {
|
||||
pwren-gpios = <&aw9535_1 8 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
&usb2phy1 {
|
||||
pwren-gpios = <&aw9535_1 9 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
&usb3 {
|
||||
@@ -1078,11 +1076,18 @@
|
||||
};
|
||||
|
||||
&sata {
|
||||
m2-sata-3v3-pwren-gpios = <&aw9535_0 14 GPIO_ACTIVE_HIGH>;
|
||||
m2-sata-en-gpios = <&aw9535_0 9 GPIO_ACTIVE_HIGH>;
|
||||
sata-clk-en-gpios = <&aw9535_0 12 GPIO_ACTIVE_HIGH>;
|
||||
sata-clk-pwren-gpios = <&aw9535_1 13 GPIO_ACTIVE_HIGH>;
|
||||
status = "disabled";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&e16phy {
|
||||
init-seq-select = "pcie_dmx1_rpx1_satax2";
|
||||
base-en-gpios = <&aw9535_0 12 GPIO_ACTIVE_HIGH>, // pcie-clk, sata-clk
|
||||
<&aw9535_1 13 GPIO_ACTIVE_HIGH>; // pcie-clk-pwren, sata-clk-pwren
|
||||
sata-en-gpios = <&aw9535_0 14 GPIO_ACTIVE_HIGH>, // m2-sata-3v3-pwren
|
||||
<&aw9535_0 9 GPIO_ACTIVE_HIGH>; // m2-sata-en
|
||||
pcie-en-gpios = <&aw9535_0 6 GPIO_ACTIVE_HIGH>, // minipcie-1v5-pwren
|
||||
<&aw9535_0 7 GPIO_ACTIVE_HIGH>, // minipcie-3v3-pwren
|
||||
<&aw9535_0 15 GPIO_ACTIVE_HIGH>; // minipcie-perst
|
||||
};
|
||||
|
||||
&mipi0_csi0 {
|
||||
|
||||
@@ -1305,13 +1305,6 @@
|
||||
clock-frequency = <400000>;
|
||||
};
|
||||
|
||||
&dm3x4 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pcie_x4_pins>;
|
||||
num-lanes = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart2 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart2_pins>;
|
||||
@@ -1468,9 +1461,20 @@
|
||||
&rp3x1 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pcie_x1_pins>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&dm3x4 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pcie_x4_pins>;
|
||||
num-lanes = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&e16phy {
|
||||
init-seq-select = "pcie_dmx1_rpx1_satax2";
|
||||
};
|
||||
|
||||
/*
|
||||
expansion IO: i2c2-0
|
||||
Conflict with: sata_p0
|
||||
|
||||
@@ -78,10 +78,6 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&i2c1 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -1414,44 +1414,66 @@
|
||||
};
|
||||
};
|
||||
|
||||
usb20_zhihe: usb20_zhihe@08300000 {
|
||||
compatible = "zhihe,usb20";
|
||||
reg = <0x00 0x8300000 0x0 0x2000>;
|
||||
reg-names = "usb20-blk-sysreg";
|
||||
resets = <&rst USB_USB20_BLK_USB0_PHY_PON_RESET>,
|
||||
<&rst USB_USB20_BLK_USB1_PHY_PON_RESET>;
|
||||
reset-names = "usb0-phy-rst", "usb1-phy-rst";
|
||||
usb2phy0: phy@08300000 {
|
||||
compatible = "zhihe,a210-usb2-phy";
|
||||
reg = <0x00 0x8300000 0x0 0x001000>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
reg-names = "usb20-blk-sysreg";
|
||||
resets = <&rst USB_USB20_BLK_USB0_PHY_PON_RESET>;
|
||||
reset-names = "usb-phy-rst";
|
||||
#phy-cells = <0>;
|
||||
power-domains = <&power_usb>;
|
||||
};
|
||||
|
||||
usb2_0: dwc2@8200000 {
|
||||
compatible = "zhihe,p100-usb";
|
||||
reg = <0x00 0x8200000 0x0 0x40000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <181>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
maximum-speed = "high-speed";
|
||||
dr_mode = "host";
|
||||
power-domains = <&power_usb>;
|
||||
// iommus = <&iommu DEVID_DIE0_USB2_0>;
|
||||
snps,need-phy-for-wake;
|
||||
};
|
||||
usb2phy1: phy@08301000 {
|
||||
compatible = "zhihe,a210-usb2-phy";
|
||||
reg = <0x00 0x8301000 0x0 0x001000>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
reg-names = "usb20-blk-sysreg";
|
||||
resets = <&rst USB_USB20_BLK_USB1_PHY_PON_RESET>;
|
||||
reset-names = "usb-phy-rst";
|
||||
#phy-cells = <0>;
|
||||
power-domains = <&power_usb>;
|
||||
};
|
||||
|
||||
usb2_1: dwc2@8240000 {
|
||||
compatible = "zhihe,p100-usb";
|
||||
reg = <0x00 0x8240000 0x0 0x40000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <182>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
maximum-speed = "high-speed";
|
||||
dr_mode = "host";
|
||||
power-domains = <&power_usb>;
|
||||
// iommus = <&iommu DEVID_DIE0_USB2_1>;
|
||||
snps,need-phy-for-wake;
|
||||
};
|
||||
usb2_0: dwc2@8200000 {
|
||||
compatible = "zhihe,a210-usb", "snps,dwc2";
|
||||
reg = <0x00 0x8200000 0x0 0x40000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <181>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
g-np-tx-fifo-size = <16>;
|
||||
g-rx-fifo-size = <275>;
|
||||
g-tx-fifo-size = <256 128 128 64 64 32>;
|
||||
maximum-speed = "high-speed";
|
||||
dr_mode = "host";
|
||||
power-domains = <&power_usb>;
|
||||
// iommus = <&iommu DEVID_DIE0_USB2_0>;
|
||||
snps,need-phy-for-wake;
|
||||
phys = <&usb2phy0>;
|
||||
phy-names = "usb";
|
||||
};
|
||||
|
||||
usb2_1: dwc2@8240000 {
|
||||
compatible = "zhihe,a210-usb", "snps,dwc2";
|
||||
reg = <0x00 0x8240000 0x0 0x40000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <182>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
g-np-tx-fifo-size = <16>;
|
||||
g-rx-fifo-size = <275>;
|
||||
g-tx-fifo-size = <256 128 128 64 64 32>;
|
||||
maximum-speed = "high-speed";
|
||||
dr_mode = "host";
|
||||
power-domains = <&power_usb>;
|
||||
// iommus = <&iommu DEVID_DIE0_USB2_1>;
|
||||
snps,need-phy-for-wake;
|
||||
phys = <&usb2phy1>;
|
||||
phy-names = "usb";
|
||||
};
|
||||
|
||||
audio_pdm0: audio_pdm0@0002008000 {
|
||||
@@ -1603,22 +1625,22 @@
|
||||
<0x108 0x00000011>,
|
||||
<0x048 0x00010001>;
|
||||
/* PCIE_DMx2,SATA_x2 */
|
||||
init-seq-pcie_dmx2_sata_x2 = /bits/ 32 <0x000 0x00110001>,
|
||||
init-seq-pcie_dmx2_satax2 = /bits/ 32 <0x000 0x00110001>,
|
||||
<0x004 0x00001100>,
|
||||
<0x008 0x00002200>,
|
||||
<0x108 0x00000011>,
|
||||
<0x048 0x00010001>;
|
||||
/* PCIE_DMx1,PCIE_RPx1,SATA_x2 */
|
||||
init-seq-pcie_dmx1_rpx1_sata_x2 = /bits/ 32 <0x000 0x00110101>,
|
||||
init-seq-pcie_dmx1_rpx1_satax2 = /bits/ 32 <0x000 0x00110101>,
|
||||
<0x004 0x00001100>,
|
||||
<0x008 0x00002200>,
|
||||
<0x108 0x00000011>,
|
||||
<0x048 0x00010001>;
|
||||
init-seq-select = "pcie_dmx1_rpx1_sata_x2";
|
||||
init-seq-select = "pcie_dmx4";
|
||||
};
|
||||
|
||||
dm3x4: pcie@b000000 {
|
||||
compatible = "zh,p100-pcie";
|
||||
compatible = "zhihe,a210-pcie";
|
||||
reg = <0x00 0x0b000000 0x0 0x800000>,
|
||||
<0x18 0x00000000 0x0 0x200000>,
|
||||
<0x00 0x0A004000 0x0 0x001000>;
|
||||
@@ -1631,7 +1653,6 @@
|
||||
ranges = <0x81000000 0x18 0x00200000 0x18 0x00200000 0x0 0x600000>,
|
||||
<0x82000000 0x00 0x40100000 0x00 0x40100000 0x0 0x800000>,
|
||||
<0xc3000000 0x18 0x00300000 0x18 0x00300000 0x0 0x800000>;
|
||||
num-lanes = <4>;
|
||||
interrupts = <139>,<140>,<141>,<142>,<143>;
|
||||
interrupt-names = "msi","inta","intb","intc","intd";
|
||||
interrupt-parent = <&intc>;
|
||||
@@ -1640,7 +1661,6 @@
|
||||
<0x0 0x0 0x0 0x2 &intc 141>,
|
||||
<0x0 0x0 0x0 0x3 &intc 142>,
|
||||
<0x0 0x0 0x0 0x4 &intc 143>;
|
||||
zh,max-link-speed = <3>;
|
||||
clocks = <&clk_pcie PCIE_DM_GEN3X4_AUX_CLK_EN>,
|
||||
<&clk_pcie PCIE_DM_GEN3X4_SLV_ACLK_EN>,
|
||||
<&clk_pcie PCIE_DM_GEN3X4_MST_ACLK_EN>,
|
||||
@@ -1650,15 +1670,16 @@
|
||||
//iommus = <&iommu DEVID_DIE0_PCIE_0>;
|
||||
phys = <&e16phy>;
|
||||
phy-names = "pcie-phy";
|
||||
num-lanes = <4>;
|
||||
max-link-speed = <3>;
|
||||
};
|
||||
|
||||
rp3x1: pcie@b800000 {
|
||||
compatible = "zh,p100-pcie";
|
||||
compatible = "zhihe,a210-pcie";
|
||||
reg = <0x00 0x0b800000 0x0 0x800000>,
|
||||
<0x1E 0x00000000 0x0 0x20000>,
|
||||
<0x00 0x0A005000 0x0 0x001000>,
|
||||
<0x00 0x0A180000 0x0 0x001000>;
|
||||
reg-names = "dbi","config","pcie_sysreg","phy_sysreg";
|
||||
<0x00 0x0A005000 0x0 0x001000>;
|
||||
reg-names = "dbi","config","pcie_sysreg";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
@@ -1667,7 +1688,6 @@
|
||||
ranges = <0x81000000 0x1E 0x00200000 0x1E 0x00200000 0x0 0x600000>,
|
||||
<0x82000000 0x00 0x50100000 0x00 0x50100000 0x0 0x800000>,
|
||||
<0xc3000000 0x1E 0x00300000 0x1E 0x00300000 0x0 0x800000>;
|
||||
num-lanes = <1>;
|
||||
interrupts = <158>,<159>,<160>,<161>,<162>;
|
||||
interrupt-names = "msi","inta","intb","intc","intd";
|
||||
interrupt-parent = <&intc>;
|
||||
@@ -1676,7 +1696,6 @@
|
||||
<0x0 0x0 0x0 0x2 &intc 160>,
|
||||
<0x0 0x0 0x0 0x3 &intc 161>,
|
||||
<0x0 0x0 0x0 0x4 &intc 162>;
|
||||
zh,max-link-speed = <3>;
|
||||
clocks = <&clk_pcie PCIE_RP_GEN3X1_AUX_CLK_EN>,
|
||||
<&clk_pcie PCIE_RP_GEN3X1_SLV_ACLK_EN>,
|
||||
<&clk_pcie PCIE_RP_GEN3X1_MST_ACLK_EN>,
|
||||
@@ -1686,6 +1705,8 @@
|
||||
//iommus = <&iommu DEVID_DIE0_PCIE_1>;
|
||||
phys = <&e16phy>;
|
||||
phy-names = "pcie-phy";
|
||||
num-lanes = <1>;
|
||||
max-link-speed = <3>;
|
||||
};
|
||||
|
||||
mbox_920: mbox@0000310000 {
|
||||
@@ -2059,7 +2080,7 @@
|
||||
};
|
||||
|
||||
bmu4: usb-bmu@0008024000 {
|
||||
compatible = "zhihe,p100-usb-bmu";
|
||||
compatible = "zhihe,a210-usb-bmu";
|
||||
reg = <0x00 0x08024000 0x0 0x400>;
|
||||
zhihe,bm-num = <1>;
|
||||
zhihe,bm-name ="bmu_usb";
|
||||
|
||||
@@ -339,26 +339,13 @@ CONFIG_V4L_MEM2MEM_DRIVERS=y
|
||||
# CONFIG_MEDIA_TUNER_XC4000 is not set
|
||||
# CONFIG_MEDIA_TUNER_XC5000 is not set
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_MIPI_DSI=y
|
||||
CONFIG_DRM_KMS_HELPER=y
|
||||
CONFIG_DRM_FBDEV_EMULATION=y
|
||||
CONFIG_DRM_FBDEV_OVERALLOC=100
|
||||
CONFIG_DRM_LOAD_EDID_FIRMWARE=y
|
||||
CONFIG_DRM_DISPLAY_HELPER=m
|
||||
CONFIG_DRM_DISPLAY_DP_HELPER=y
|
||||
CONFIG_DRM_DISPLAY_HDCP_HELPER=y
|
||||
CONFIG_DRM_DISPLAY_HDMI_HELPER=y
|
||||
CONFIG_DRM_DP_AUX_CHARDEV=y
|
||||
CONFIG_DRM_PANEL=y
|
||||
CONFIG_DRM_PANEL_SIMPLE=m
|
||||
CONFIG_DRM_PANEL_ILITEK_ILI9881C=m
|
||||
CONFIG_DRM_PANEL_JADARD_JD9365DA_H3=y
|
||||
CONFIG_DRM_PANEL_LT8911=y
|
||||
CONFIG_DRM_BRIDGE=y
|
||||
CONFIG_DRM_PANEL_BRIDGE=y
|
||||
CONFIG_DRM_DW_HDMI=m
|
||||
CONFIG_DRM_VERISILICON=m
|
||||
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y
|
||||
CONFIG_VERISILICON_DW_DP_P100=y
|
||||
CONFIG_ZHIHE_AUXDISP=y
|
||||
CONFIG_FB=y
|
||||
@@ -463,6 +450,7 @@ CONFIG_PWM=y
|
||||
CONFIG_PWM_THEAD=y
|
||||
CONFIG_PHY_DW_DPHY=y
|
||||
CONFIG_PHY_ZHIHE_SNPS_PCIE3=m
|
||||
CONFIG_PHY_ZHIHE_SNPS_USB2=m
|
||||
CONFIG_NVMEM_XUANTIE_TH1520_EFUSE=y
|
||||
CONFIG_NVMEM_ZH_EFUSE=y
|
||||
CONFIG_TEE=m
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe RC driver for zh P100
|
||||
* PCIe RC driver for A210
|
||||
*
|
||||
* Copyright (C) 2025 zh computing, Inc.
|
||||
* Copyright (C) 2025 zhihe computing, Inc.
|
||||
*
|
||||
* Author: Ya.Huang
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
@@ -19,12 +17,23 @@
|
||||
#include <linux/resource.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include "pcie-designware.h"
|
||||
|
||||
#define PCIE_GEN3X4_CTRL_REG 0x00000000
|
||||
#define PCIE_GEN3X4_DBG_INFO_REG0 0x00000430
|
||||
#define APP_PCIE_GEN3X4_CTRL_REG 0x000
|
||||
#define DEVICE_TYPE_EP 0
|
||||
#define DEVICE_TYPE_RP BIT(2)
|
||||
#define DEVICE_TYPE_SYSREG BIT(4)
|
||||
#define APP_LTSSM_ENABLE BIT(8)
|
||||
#define APP_DEVICE_TYPE_MASK GENMASK(3, 0)
|
||||
|
||||
#define APP_PCIE_GEN3X4_LINK_STS_REG 0x034
|
||||
#define RDLH_LINK_UP BIT(0)
|
||||
#define SMLH_LINK_UP BIT(4)
|
||||
#define SMLH_LTSM_STATE_MASK GENMASK(25, 20)
|
||||
#define SMLH_LTSM_S_L0 BIT(20) | BIT(24)
|
||||
|
||||
#define APP_PCIE_GEN3X4_DBG_INFO_REG0 0x430
|
||||
|
||||
#define PCIE_EXTENDED_REG0 0x00000154
|
||||
#define PCIE_EXTENDED_REG1 0x00000158
|
||||
@@ -43,21 +52,12 @@
|
||||
#define DEVICE_CONTROL_DEVICE_STATUS 0x00000078
|
||||
#define LINK_CONTROL2_LINK_STATUS2_REG 0x000000a0
|
||||
|
||||
#define LINK_UP_IS_OK 0x11
|
||||
|
||||
struct zhihe_pcie {
|
||||
struct dw_pcie pci;
|
||||
enum dw_pcie_device_mode mode;
|
||||
void __iomem *cfg_base;
|
||||
struct gpio_desc *pcie_bat_en;
|
||||
struct gpio_desc *pcie_3v3_en;
|
||||
struct gpio_desc *pcie_12v_en;
|
||||
struct gpio_desc *pcie_clk_en;
|
||||
struct gpio_desc *minipcie_1v5_pwren;
|
||||
struct gpio_desc *minipcie_3v3_pwren;
|
||||
struct gpio_desc *minipcie_perst;
|
||||
struct gpio_desc *pcie_clk_pwren;
|
||||
struct phy *phy;
|
||||
struct dw_pcie pci;
|
||||
enum dw_pcie_device_mode mode;
|
||||
void __iomem *app_base;
|
||||
struct phy *phy;
|
||||
u32 cap_base;
|
||||
};
|
||||
|
||||
#define to_zhihe_pcie(x) (struct zhihe_pcie*)dev_get_drvdata((x)->dev)
|
||||
@@ -66,51 +66,88 @@ struct zhihe_pcie_of_data {
|
||||
enum dw_pcie_device_mode mode;
|
||||
};
|
||||
|
||||
static inline int zhihe_pcie_cfg_readl(struct zhihe_pcie *pcie, u32 reg)
|
||||
static void pcie_update_bits(void __iomem *base, u32 ofs, u32 mask, u32 val)
|
||||
{
|
||||
return readl(pcie->cfg_base + reg);
|
||||
u32 old;
|
||||
|
||||
old = readl(base + ofs);
|
||||
val = (old & ~mask) | (val & mask);
|
||||
|
||||
if (val != old)
|
||||
writel(val, base + ofs);
|
||||
}
|
||||
|
||||
static inline void zhihe_pcie_cfg_writel(struct zhihe_pcie *pcie,
|
||||
u32 reg, u32 val)
|
||||
static inline int pcie_app_rd(struct zhihe_pcie *pcie, u32 reg)
|
||||
{
|
||||
writel(val, pcie->cfg_base + reg);
|
||||
return readl(pcie->app_base + reg);
|
||||
}
|
||||
|
||||
static void __maybe_unused zhihe_pcie_ltssm_enable(struct dw_pcie *pci)
|
||||
static inline void pcie_app_wr(struct zhihe_pcie *pcie, u32 reg, u32 val)
|
||||
{
|
||||
struct zhihe_pcie *pcie = to_zhihe_pcie(pci);
|
||||
writel(0x1114, pcie->cfg_base + PCIE_GEN3X4_CTRL_REG);
|
||||
writel(val, pcie->app_base + reg);
|
||||
}
|
||||
|
||||
static void __maybe_unused zhihe_pcie_ltssm_disable(struct dw_pcie *pci)
|
||||
static void pcie_app_wr_mask(struct zhihe_pcie *pcie, u32 ofs,
|
||||
u32 mask, u32 val)
|
||||
{
|
||||
struct zhihe_pcie *pcie = to_zhihe_pcie(pci);
|
||||
writel(0x1014, pcie->cfg_base + PCIE_GEN3X4_CTRL_REG);
|
||||
pcie_update_bits(pcie->app_base, ofs, mask, val);
|
||||
}
|
||||
|
||||
static void zhihe_pcie_wait_linkup(struct zhihe_pcie *pcie)
|
||||
static void __maybe_unused pcie_dump_mmio(struct device *dev, void __iomem *start,
|
||||
unsigned int bytes)
|
||||
{
|
||||
u32 ltssm_stat = 0;
|
||||
unsigned long cnt = 0;
|
||||
unsigned int TIME_OUT_CNT = 20;
|
||||
unsigned int DELAY_MS = 50;
|
||||
unsigned int b, w, o, offset = 0;
|
||||
unsigned char linebuf[38];
|
||||
|
||||
for (b = 0; b < bytes;) {
|
||||
for (w = 0, o = 0; b < bytes && w < 4; w++) {
|
||||
o += scnprintf(linebuf + o, sizeof(linebuf) - o,
|
||||
"%08x ", readl(start + b));
|
||||
b += sizeof(u32);
|
||||
}
|
||||
dev_info(dev, "%03x: %s\n", offset, linebuf);
|
||||
offset += w * sizeof(u32);
|
||||
}
|
||||
}
|
||||
|
||||
static void zhihe_pcie_set_device_type(struct zhihe_pcie *pcie, u32 type)
|
||||
{
|
||||
pcie_app_wr_mask(pcie, APP_PCIE_GEN3X4_CTRL_REG,
|
||||
DEVICE_TYPE_SYSREG | APP_DEVICE_TYPE_MASK,
|
||||
DEVICE_TYPE_SYSREG | type);
|
||||
}
|
||||
|
||||
static void zhihe_pcie_ltssm_enable(struct zhihe_pcie *pcie)
|
||||
{
|
||||
pcie_app_wr_mask(pcie, APP_PCIE_GEN3X4_CTRL_REG, APP_LTSSM_ENABLE, APP_LTSSM_ENABLE);
|
||||
}
|
||||
|
||||
static void zhihe_pcie_ltssm_disable(struct zhihe_pcie *pcie)
|
||||
{
|
||||
pcie_app_wr_mask(pcie, APP_PCIE_GEN3X4_CTRL_REG, APP_LTSSM_ENABLE, 0);
|
||||
}
|
||||
|
||||
static int zhihe_pcie_wait_linkup(struct zhihe_pcie *pcie)
|
||||
{
|
||||
u32 ltssm_stat;
|
||||
int count = 20;
|
||||
|
||||
do {
|
||||
mdelay(DELAY_MS);
|
||||
ltssm_stat = zhihe_pcie_cfg_readl(pcie, \
|
||||
PCIE_GEN3X4_DBG_INFO_REG0);
|
||||
ltssm_stat &= 0x3f;
|
||||
if (ltssm_stat == LINK_UP_IS_OK) {
|
||||
ltssm_stat = pcie_app_rd(pcie, APP_PCIE_GEN3X4_LINK_STS_REG);
|
||||
if (ltssm_stat && (SMLH_LTSM_S_L0 | SMLH_LINK_UP | RDLH_LINK_UP)) {
|
||||
dev_info(pcie->pci.dev, "ltssm:link up ok!\n");
|
||||
break;
|
||||
}
|
||||
if (cnt > TIME_OUT_CNT) {
|
||||
dev_err(pcie->pci.dev, "ltssm_stat = 0x%x,link up fail!\n",ltssm_stat);
|
||||
break;
|
||||
}
|
||||
cnt++;
|
||||
} while (ltssm_stat != LINK_UP_IS_OK);
|
||||
mdelay(50);
|
||||
} while (count--);
|
||||
|
||||
if (count < 0) {
|
||||
dev_err(pcie->pci.dev, "ltssm_stat = 0x%x,link up fail!\n",ltssm_stat);
|
||||
pcie_dump_mmio(pcie->pci.dev, pcie->app_base, 0x490);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,60 +163,11 @@ static int zhihe_pcie_get_resources(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie_sysreg");
|
||||
pcie->cfg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(pcie->cfg_base))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->cfg_base),
|
||||
pcie->app_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(pcie->app_base))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->app_base),
|
||||
"Failed to get pcie_sysreg resource");
|
||||
|
||||
/* Get GPIO descriptors for PCIe power control */
|
||||
pcie->pcie_bat_en = devm_gpiod_get_optional(&pdev->dev,
|
||||
"pcie-bat-en", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pcie->pcie_bat_en))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->pcie_bat_en),
|
||||
"Failed to get pcie-bat-en GPIO");
|
||||
|
||||
pcie->pcie_3v3_en = devm_gpiod_get_optional(&pdev->dev,
|
||||
"pcie-3v3-en", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pcie->pcie_3v3_en))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->pcie_3v3_en),
|
||||
"Failed to get pcie-3v3-en GPIO");
|
||||
|
||||
pcie->pcie_12v_en = devm_gpiod_get_optional(&pdev->dev,
|
||||
"pcie-12v-en", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pcie->pcie_12v_en))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->pcie_12v_en),
|
||||
"Failed to get pcie-12v-en GPIO");
|
||||
|
||||
pcie->pcie_clk_en = devm_gpiod_get_optional(&pdev->dev,
|
||||
"pcie-clk-en", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pcie->pcie_clk_en))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->pcie_clk_en),
|
||||
"Failed to get pcie-clk-en GPIO");
|
||||
|
||||
pcie->minipcie_1v5_pwren = devm_gpiod_get_optional(&pdev->dev,
|
||||
"minipcie-1v5-pwren", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pcie->minipcie_1v5_pwren))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->minipcie_1v5_pwren),
|
||||
"Failed to get minipcie-1v5-pwren GPIO");
|
||||
|
||||
pcie->minipcie_3v3_pwren = devm_gpiod_get_optional(&pdev->dev,
|
||||
"minipcie-3v3-pwren", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pcie->minipcie_3v3_pwren))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->minipcie_3v3_pwren),
|
||||
"Failed to get minipcie-3v3-pwren GPIO");
|
||||
|
||||
pcie->minipcie_perst = devm_gpiod_get_optional(&pdev->dev,
|
||||
"minipcie-perst", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pcie->minipcie_perst))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->minipcie_perst),
|
||||
"Failed to get minipcie-perst GPIO");
|
||||
|
||||
pcie->pcie_clk_pwren = devm_gpiod_get_optional(&pdev->dev,
|
||||
"pcie-clk-pwren", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pcie->pcie_clk_pwren))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pcie->pcie_clk_pwren),
|
||||
"Failed to get pcie-clk-pwren GPIO");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -194,9 +182,15 @@ static int __maybe_unused zhihe_pcie_phy_init(struct zhihe_pcie *pcie)
|
||||
"missing PHY\n");
|
||||
|
||||
ret = phy_init(pcie->phy);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = phy_set_mode_ext(pcie->phy, PHY_MODE_PCIE, pcie->mode);
|
||||
if (ret) {
|
||||
phy_exit(pcie->phy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = phy_power_on(pcie->phy);
|
||||
if (ret)
|
||||
phy_exit(pcie->phy);
|
||||
@@ -210,102 +204,79 @@ static void __maybe_unused zhihe_pcie_phy_deinit(struct zhihe_pcie *pcie)
|
||||
phy_power_off(pcie->phy);
|
||||
}
|
||||
|
||||
static int zhihe_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct zhihe_pcie *pcie = to_zhihe_pcie(pci);
|
||||
zhihe_pcie_ltssm_enable(pcie);
|
||||
return zhihe_pcie_wait_linkup(pcie);
|
||||
}
|
||||
|
||||
static void zhihe_pcie_stop_link(struct dw_pcie *pci)
|
||||
{
|
||||
zhihe_pcie_ltssm_disable(pci);
|
||||
struct zhihe_pcie *pcie = to_zhihe_pcie(pci);
|
||||
zhihe_pcie_ltssm_disable(pcie);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.start_link = zhihe_pcie_start_link,
|
||||
.stop_link = zhihe_pcie_stop_link,
|
||||
};
|
||||
|
||||
static int zhihe_pcie_ipctrl_init(struct dw_pcie_rp *pp)
|
||||
static int zhihe_pcie_host_init(struct dw_pcie_rp *pp)
|
||||
{
|
||||
u32 val;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct zhihe_pcie *pcie = to_zhihe_pcie(pci);
|
||||
|
||||
int ret = zhihe_pcie_phy_init(pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*disable ltssm*/
|
||||
zhihe_pcie_ltssm_disable(pci);
|
||||
zhihe_pcie_ltssm_disable(pcie);
|
||||
/* Set RP mode */
|
||||
zhihe_pcie_set_device_type(pcie, DEVICE_TYPE_RP);
|
||||
|
||||
if (!pcie->cap_base)
|
||||
pcie->cap_base = dw_pcie_find_capability(&pcie->pci, PCI_CAP_ID_EXP);
|
||||
|
||||
/* Disable BARs for inbound access */
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0);
|
||||
|
||||
/* Configure Max lane width from DT */
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
val = dw_pcie_readl_dbi(pci, pcie->cap_base + PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_MLW;
|
||||
val |= (pci->num_lanes << PCI_EXP_LNKSTA_NLW_SHIFT);
|
||||
dw_pcie_writel_dbi(pci, pcie->cap_base + PCI_EXP_LNKCAP, val);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_LANE_SKEW);
|
||||
val &= ~PORT_LANE_SKEW_INSERT_MASK;
|
||||
if(pci->num_lanes == 4) {
|
||||
val |= BIT(27) | BIT(28);
|
||||
}
|
||||
if (pci->num_lanes < 4)
|
||||
val |= BIT(6);
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LANE_SKEW, val);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
|
||||
val |= GEN3_RELATED_OFF_EQ_PHASE_2_3;
|
||||
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
|
||||
dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, 0xc020071);
|
||||
/*ip ctrl cfg*/
|
||||
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, GEN3_RELATED_OFF_RXEQ_RGRDLESS_RXTS); // 0x2000
|
||||
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, GEN3_RELATED_OFF_EQ_PHASE_2_3 | BIT(11) | GEN3_RELATED_OFF_RXEQ_RGRDLESS_RXTS); //0x2a00
|
||||
dw_pcie_writel_dbi(pci, PCIE_EXTENDED_REG0, 0x21614536);
|
||||
dw_pcie_writel_dbi(pci, PCIE_EXTENDED_REG1, 0x6337451);
|
||||
dw_pcie_writel_dbi(pci, PCIE_EXTENDED_REG2, 0x8553824);
|
||||
dw_pcie_writel_dbi(pci, PCIE_EXTENDED_REG3, 0x47373650);
|
||||
dw_pcie_writel_dbi(pci, GEN3_EQ_FB_MODE_DIR_CHANGE_OFF, 0x0);
|
||||
dw_pcie_writel_dbi(pci, DEVICE_CONTROL_DEVICE_STATUS, 0x2130);
|
||||
/*cfg Gen3*/
|
||||
val = dw_pcie_readl_dbi(pci, LINK_CONTROL2_LINK_STATUS2_REG);
|
||||
val &= 0xfffffff0;
|
||||
val |= 0x3;
|
||||
dw_pcie_writel_dbi(pci, LINK_CONTROL2_LINK_STATUS2_REG, val);
|
||||
|
||||
/*config space setup*/
|
||||
dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, 0);
|
||||
dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_1, 0);
|
||||
|
||||
dw_pcie_writel_dbi(pci, TRGT_MAP_CTRL_OFF, 0x40);
|
||||
dw_pcie_writel_dbi(pci, SEC_STAT_IO_LIMIT_IO_BASE_REG, 0x4f40);
|
||||
dw_pcie_writel_dbi(pci, IO_LIMIT_UPPER_IO_BASE_UPPER_REG, 0x0);
|
||||
dw_pcie_writel_dbi(pci, MEM_LIMIT_MEM_BASE_REG, 0xc91fc800);
|
||||
dw_pcie_writel_dbi(pci, PREF_MEM_LIMIT_PREF_MEM_BASE_REG, 0xfff0);
|
||||
dw_pcie_writel_dbi(pci, PREF_BASE_UPPER_REG, 0x0);
|
||||
dw_pcie_writel_dbi(pci, PREF_LIMIT_UPPER_REG, 0x0);
|
||||
dw_pcie_writel_dbi(pci, TYPE1_STATUS_COMMAND_REG, 0x100007);
|
||||
/*enable ltssm*/
|
||||
zhihe_pcie_ltssm_enable(pci);
|
||||
zhihe_pcie_wait_linkup(pcie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops zhihe_pcie_host_ops = {
|
||||
.host_init = zhihe_pcie_ipctrl_init,
|
||||
.host_init = zhihe_pcie_host_init,
|
||||
};
|
||||
|
||||
static int zhihe_add_pcie_port(struct zhihe_pcie *pcie,
|
||||
struct platform_device *pdev)
|
||||
static int zhihe_add_pcie_port(struct zhihe_pcie *pcie, struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = &pcie->pci;
|
||||
struct dw_pcie_rp *pp = &pci->pp;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
if (pcie->pcie_bat_en)
|
||||
gpiod_set_value(pcie->pcie_bat_en, 1);
|
||||
|
||||
if (pcie->pcie_3v3_en)
|
||||
gpiod_set_value(pcie->pcie_3v3_en, 1);
|
||||
|
||||
if (pcie->pcie_12v_en)
|
||||
gpiod_set_value(pcie->pcie_12v_en, 1);
|
||||
|
||||
if (pcie->pcie_clk_en)
|
||||
gpiod_set_value(pcie->pcie_clk_en, 1);
|
||||
|
||||
if (pcie->minipcie_1v5_pwren)
|
||||
gpiod_set_value(pcie->minipcie_1v5_pwren, 1);
|
||||
|
||||
if (pcie->minipcie_3v3_pwren)
|
||||
gpiod_set_value(pcie->minipcie_3v3_pwren, 1);
|
||||
|
||||
if (pcie->minipcie_perst)
|
||||
gpiod_set_value(pcie->minipcie_perst, 1);
|
||||
|
||||
if (pcie->pcie_clk_pwren)
|
||||
gpiod_set_value(pcie->pcie_clk_pwren, 1);
|
||||
|
||||
pp->irq = platform_get_irq(pdev, 0);
|
||||
if (pp->irq < 0)
|
||||
return pp->irq;
|
||||
@@ -353,10 +324,6 @@ static int zhihe_pcie_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = zhihe_pcie_phy_init(pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (pcie->mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
ret = zhihe_add_pcie_port(pcie, pdev);
|
||||
@@ -380,7 +347,6 @@ static int zhihe_pcie_remove(struct platform_device *pdev)
|
||||
|
||||
dw_pcie_host_deinit(&pcie->pci.pp);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -390,7 +356,7 @@ static const struct zhihe_pcie_of_data zhihe_pcie_rc_of_data = {
|
||||
|
||||
static const struct of_device_id zhihe_pcie_of_match[] = {
|
||||
{
|
||||
.compatible = "zh,p100-pcie",
|
||||
.compatible = "zhihe,a210-pcie",
|
||||
.data = &zhihe_pcie_rc_of_data,
|
||||
},
|
||||
{},
|
||||
@@ -406,4 +372,6 @@ static struct platform_driver zhihe_pcie_driver = {
|
||||
.remove = zhihe_pcie_remove,
|
||||
};
|
||||
module_platform_driver(zhihe_pcie_driver);
|
||||
|
||||
MODULE_DEVICE_TABLE(of, zhihe_pcie_of_match);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -99,6 +99,6 @@ source "drivers/phy/tegra/Kconfig"
|
||||
source "drivers/phy/ti/Kconfig"
|
||||
source "drivers/phy/intel/Kconfig"
|
||||
source "drivers/phy/xilinx/Kconfig"
|
||||
source "drivers/phy/synopsys/Kconfig"
|
||||
source "drivers/phy/zhihe/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -37,4 +37,4 @@ obj-y += allwinner/ \
|
||||
tegra/ \
|
||||
ti/ \
|
||||
xilinx/ \
|
||||
synopsys/
|
||||
zhihe/
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-$(CONFIG_PHY_DW_DPHY) += phy-dw-mipi-dphy.o
|
||||
obj-$(CONFIG_PHY_ZHIHE_SNPS_PCIE3) += phy-dw-e16.o
|
||||
@@ -17,3 +17,13 @@ config PHY_ZHIHE_SNPS_PCIE3
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Enable this to support the ZHIHE snps PCIe3 PHY.
|
||||
|
||||
config PHY_ZHIHE_SNPS_USB2
|
||||
tristate "Zhihe Snps USB2.0 PHY Driver"
|
||||
depends on (ARCH_ZHIHE && OF) || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the ZHIHE Snps USB 2.0 PHY.
|
||||
This driver provides PHY support for the USB 2.0 controllers
|
||||
on ZHIHE platforms.
|
||||
5
drivers/phy/zhihe/Makefile
Normal file
5
drivers/phy/zhihe/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-$(CONFIG_PHY_DW_DPHY) += phy-zhihe-snps-mipidsi.o
|
||||
obj-$(CONFIG_PHY_ZHIHE_SNPS_PCIE3) += phy-zhihe-snps-e16phy.o
|
||||
obj-$(CONFIG_PHY_ZHIHE_SNPS_USB2) += phy-zhihe-snps-usb2.o
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
/* Registers definition for ZHIHE A210 */
|
||||
#define E16PHY_GLB_CTRL_REG 0x00000000
|
||||
@@ -75,14 +76,16 @@ struct zhihe_e16phy_priv {
|
||||
int num_clks;
|
||||
struct e16phy_seq *init_seq;
|
||||
int num_init_seq;
|
||||
struct gpio_descs *base_en;
|
||||
struct gpio_descs *sata_en;
|
||||
struct gpio_descs *pcie_en;
|
||||
};
|
||||
|
||||
static void e16phy_dump_mmio(struct device *dev, void __iomem *start,
|
||||
unsigned int bytes)
|
||||
{
|
||||
unsigned int b, w, o;
|
||||
unsigned int b, w, o, offset = 0;
|
||||
unsigned char linebuf[38];
|
||||
int offset = 0;
|
||||
|
||||
for (b = 0; b < bytes;) {
|
||||
for (w = 0, o = 0; b < bytes && w < 4; w++) {
|
||||
@@ -91,7 +94,7 @@ static void e16phy_dump_mmio(struct device *dev, void __iomem *start,
|
||||
b += sizeof(u32);
|
||||
}
|
||||
dev_info(dev, "%03x: %s\n", offset, linebuf);
|
||||
offset += b;
|
||||
offset += w * sizeof(u32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,9 +161,42 @@ static int zhihe_e16phy_exit(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zhihe_e16phy_gpio_set_value(struct gpio_descs *gpios, int val)
|
||||
{
|
||||
if (!gpios)
|
||||
return;
|
||||
for (int i = 0; i < gpios->ndescs; i++)
|
||||
gpiod_set_value(gpios->desc[i], val);
|
||||
}
|
||||
|
||||
static int zhihe_e16phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
|
||||
{
|
||||
struct zhihe_e16phy_priv *priv = phy_get_drvdata(phy);
|
||||
|
||||
/* Actually We don't care EP/RC mode, but just record it */
|
||||
switch (mode) {
|
||||
case PHY_MODE_SATA:
|
||||
priv->mode = PHY_MODE_SATA;
|
||||
zhihe_e16phy_gpio_set_value(priv->base_en, 1);
|
||||
zhihe_e16phy_gpio_set_value(priv->sata_en, 1);
|
||||
break;
|
||||
case PHY_MODE_PCIE:
|
||||
priv->mode = PHY_MODE_PCIE;
|
||||
zhihe_e16phy_gpio_set_value(priv->base_en, 1);
|
||||
zhihe_e16phy_gpio_set_value(priv->pcie_en, 1);
|
||||
break;
|
||||
default:
|
||||
dev_err(&phy->dev, "%s, invalid mode\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops zhihe_e16phy_ops = {
|
||||
.init = zhihe_e16phy_init,
|
||||
.exit = zhihe_e16phy_exit,
|
||||
.set_mode = zhihe_e16phy_set_mode,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
@@ -230,8 +266,24 @@ static int zhihe_e16phy_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(dev, "using init sequence: %s (%d entries)\n",
|
||||
mode_name, priv->num_init_seq);
|
||||
/* Get base-en-gpios property */
|
||||
priv->base_en = devm_gpiod_get_array_optional(&pdev->dev,
|
||||
"base-en", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->base_en))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->base_en),
|
||||
"Failed to get base-en GPIO");
|
||||
|
||||
priv->pcie_en = devm_gpiod_get_array_optional(&pdev->dev,
|
||||
"pcie-en", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->pcie_en))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->pcie_en),
|
||||
"Failed to get pcie-en GPIO");
|
||||
|
||||
priv->sata_en = devm_gpiod_get_array_optional(&pdev->dev,
|
||||
"sata-en", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->sata_en))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->sata_en),
|
||||
"Failed to get sata-en GPIO");
|
||||
|
||||
dev_set_drvdata(dev, priv);
|
||||
phy_set_drvdata(priv->phy, priv);
|
||||
164
drivers/phy/zhihe/phy-zhihe-snps-usb2.c
Normal file
164
drivers/phy/zhihe/phy-zhihe-snps-usb2.c
Normal file
@@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* phy-zhihe-snps-femto-v2.c - ZHIHE USB 2.0 PHY driver
|
||||
*
|
||||
* Based on PHY operations from dwc2-zhihe.c
|
||||
*
|
||||
* Copyright (C) 2025, Anonymous <Anonymous@zhcomputing.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
/* USB20 BLK SYSREG registers */
|
||||
#define PHY_ANA_CFG 0x0
|
||||
#define PHY_CFG 0x4
|
||||
|
||||
/* Bit fields */
|
||||
#define PHY_DM_PULLDOWN BIT(1)
|
||||
#define PHY_DP_PULLDOWN BIT(0)
|
||||
|
||||
|
||||
/* USB2.0 PHY TxVRefTune Mask */
|
||||
#define USB20_PHY_TXVREFTUNE_MASK 0x1E0000
|
||||
#define HS_DV_VOLTAGE_LEVEL_POS_16_PER (0xB << 17)
|
||||
|
||||
struct zhihe_usb2_phy {
|
||||
struct device *dev;
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
struct reset_control *phy_rst;
|
||||
struct gpio_desc *pwren;
|
||||
};
|
||||
|
||||
static int zhihe_usb2_phy_init(struct phy *phy)
|
||||
{
|
||||
struct zhihe_usb2_phy *zhphy = phy_get_drvdata(phy);
|
||||
int val;
|
||||
|
||||
/* Set PHY power enable */
|
||||
if (zhphy->pwren)
|
||||
gpiod_set_value(zhphy->pwren, 1);
|
||||
|
||||
/* Deassert PHY reset */
|
||||
reset_control_assert(zhphy->phy_rst);
|
||||
|
||||
/* Pull-up the PHY reset */
|
||||
val = readl(zhphy->base + PHY_CFG);
|
||||
val |= PHY_DM_PULLDOWN | PHY_DP_PULLDOWN;
|
||||
writel(val, zhphy->base + PHY_CFG);
|
||||
|
||||
/* Configure PHY analog - Set TxVRefTune */
|
||||
val = readl(zhphy->base + PHY_ANA_CFG);
|
||||
val &= ~USB20_PHY_TXVREFTUNE_MASK;
|
||||
val |= HS_DV_VOLTAGE_LEVEL_POS_16_PER;
|
||||
writel(val, zhphy->base + PHY_ANA_CFG);
|
||||
|
||||
/* Assert PHY reset to complete initialization */
|
||||
reset_control_deassert(zhphy->phy_rst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zhihe_usb2_phy_exit(struct phy *phy)
|
||||
{
|
||||
struct zhihe_usb2_phy *zhphy = phy_get_drvdata(phy);
|
||||
|
||||
/* Assert reset to power down PHY */
|
||||
reset_control_assert(zhphy->phy_rst);
|
||||
/* Set PHY power disable */
|
||||
if (zhphy->pwren)
|
||||
gpiod_set_value(zhphy->pwren, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops zhihe_usb2_phy_ops = {
|
||||
.init = zhihe_usb2_phy_init,
|
||||
.exit = zhihe_usb2_phy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int zhihe_usb2_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct zhihe_usb2_phy *zhphy;
|
||||
struct phy_provider *phy_provider;
|
||||
struct phy *generic_phy;
|
||||
|
||||
zhphy = devm_kzalloc(dev, sizeof(*zhphy), GFP_KERNEL);
|
||||
if (!zhphy)
|
||||
return -ENOMEM;
|
||||
|
||||
zhphy->dev = dev;
|
||||
|
||||
/* Get USB20 BLK SYSREG base address */
|
||||
zhphy->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(zhphy->base))
|
||||
return PTR_ERR(zhphy->base);
|
||||
|
||||
/* Get PHY reset control */
|
||||
zhphy->phy_rst = devm_reset_control_get_shared(dev, "usb-phy-rst");
|
||||
if (IS_ERR(zhphy->phy_rst)) {
|
||||
dev_err(dev, "failed to get usb-phy-rst: %ld\n",
|
||||
PTR_ERR(zhphy->phy_rst));
|
||||
return PTR_ERR(zhphy->phy_rst);
|
||||
}
|
||||
zhphy->pwren = devm_gpiod_get_optional(&pdev->dev,
|
||||
"pwren", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(zhphy->pwren)) {
|
||||
dev_err(&pdev->dev, "Failed to get pwren GPIO\n");
|
||||
return PTR_ERR(zhphy->pwren);
|
||||
}
|
||||
|
||||
/* Create PHY */
|
||||
generic_phy = devm_phy_create(dev, NULL, &zhihe_usb2_phy_ops);
|
||||
if (IS_ERR(generic_phy)) {
|
||||
dev_err(dev, "failed to create phy: %ld\n", PTR_ERR(generic_phy));
|
||||
return PTR_ERR(generic_phy);
|
||||
}
|
||||
|
||||
zhphy->phy = generic_phy;
|
||||
dev_set_drvdata(dev, zhphy);
|
||||
phy_set_drvdata(generic_phy, zhphy);
|
||||
|
||||
/* Register PHY provider */
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider)) {
|
||||
dev_err(dev, "failed to register phy provider: %ld\n",
|
||||
PTR_ERR(phy_provider));
|
||||
return PTR_ERR(phy_provider);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id zhihe_usb2_phy_of_match[] = {
|
||||
{ .compatible = "zhihe,a210-usb2-phy", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zhihe_usb2_phy_of_match);
|
||||
|
||||
static struct platform_driver zhihe_usb2_phy_driver = {
|
||||
.probe = zhihe_usb2_phy_probe,
|
||||
.driver = {
|
||||
.name = "phy-zhihe-snps-femtophy",
|
||||
.of_match_table = zhihe_usb2_phy_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(zhihe_usb2_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ZHIHE USB 2.0 PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Zhu Guangzhao <zhuzg.zhu@zhcomputing.com>");
|
||||
@@ -990,7 +990,7 @@ static const struct of_device_id a210_bmu_dt_ids[] = {
|
||||
.data = &bmu3_para_data[BMU_PCIE],
|
||||
},
|
||||
{
|
||||
.compatible = "zhihe,p100-usb-bmu",
|
||||
.compatible = "zhihe,a210-usb-bmu",
|
||||
.data = &bmu3_para_data[BMU_USB],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config USB_DWC2_ZHIHE
|
||||
tristate "Zhihe DWC2 Platform"
|
||||
depends on ARCH_ZHIHE || COMPILE_TEST
|
||||
default USB_DWC2
|
||||
help
|
||||
Support Zhihe platform with DesignWare Core USB2 IP.
|
||||
Only the host mode is currently supported.
|
||||
Say 'Y' or 'M' here if you have one such device.
|
||||
|
||||
config USB_DWC2
|
||||
tristate "DesignWare USB2 DRD Core Support"
|
||||
depends on HAS_DMA
|
||||
|
||||
@@ -19,8 +19,6 @@ ifneq ($(CONFIG_DEBUG_FS),)
|
||||
dwc2-y += debugfs.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_USB_DWC2_ZHIHE) += dwc2-zhihe.o
|
||||
|
||||
# NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to
|
||||
# this location and renamed gadget.c. When building for dynamically linked
|
||||
# modules, dwc2.ko will get built for host mode, peripheral mode, and dual-role
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* dwc2-zhihe.c - ZHIHE platform specific glue layer for DWC2
|
||||
*
|
||||
* Inspired by dwc3-zhihe.c and dwc2-platform.c
|
||||
*
|
||||
* Copyright (C) 2025, Anonymous <Anonymous@zhcomputing.com>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/of.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "hcd.h"
|
||||
|
||||
/* USB20 BLK SYSREG registers */
|
||||
#define USB20_PHY_ANA_CFG 0x0
|
||||
#define USB20_PHY_CFG 0x4
|
||||
#define USB21_PHY_ANA_CFG 0x1000
|
||||
#define USB21_PHY_CFG 0x1004
|
||||
|
||||
/* Bit fields */
|
||||
/* USB20_PHY_CFG */
|
||||
#define USB0_PHY_DM_PULLDOWN BIT(1)
|
||||
#define USB0_PHY_DP_PULLDOWN BIT(0)
|
||||
|
||||
/* USB21_PHY_CFG */
|
||||
#define USB1_PHY_DM_PULLDOWN BIT(3)
|
||||
#define USB1_PHY_DP_PULLDOWN BIT(2)
|
||||
|
||||
/* USB2.0 PHY TxVRefTune Mask */
|
||||
#define USB20_PHY_TXVREFTUNE_MASK 0x1E0000
|
||||
#define HS_DV_VOLTAGE_LEVEL_POS_16_PER (0xB << 17)
|
||||
|
||||
struct dwc2_zhihe {
|
||||
struct device *dev;
|
||||
void __iomem *usb20_blk_sysreg;
|
||||
struct reset_control *usb0_phy_rst;
|
||||
struct reset_control *usb1_phy_rst;
|
||||
struct gpio_desc *usb20_pwren;
|
||||
struct gpio_desc *usb21_pwren;
|
||||
};
|
||||
|
||||
static int dwc2_zhihe_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct dwc2_zhihe *zhihe;
|
||||
int ret, val;
|
||||
|
||||
if (!np) {
|
||||
dev_err(dev, "device node not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
zhihe = devm_kzalloc(dev, sizeof(*zhihe), GFP_KERNEL);
|
||||
if (!zhihe)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, zhihe);
|
||||
zhihe->dev = dev;
|
||||
|
||||
/* Get USB20 system registers */
|
||||
struct resource *res = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, "usb20-blk-sysreg");
|
||||
if (!res) {
|
||||
dev_err(dev, "failed to get resource - %ld\n", PTR_ERR(res));
|
||||
return PTR_ERR(res);
|
||||
}
|
||||
|
||||
zhihe->usb20_blk_sysreg = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(zhihe->usb20_blk_sysreg)) {
|
||||
dev_err(dev, "failed to get iomem - %ld\n", PTR_ERR(zhihe->usb20_blk_sysreg));
|
||||
return PTR_ERR(zhihe->usb20_blk_sysreg);
|
||||
}
|
||||
|
||||
zhihe->usb0_phy_rst = devm_reset_control_get_shared(&pdev->dev, "usb0-phy-rst");
|
||||
if (IS_ERR(zhihe->usb0_phy_rst))
|
||||
return PTR_ERR(zhihe->usb0_phy_rst);
|
||||
|
||||
zhihe->usb1_phy_rst = devm_reset_control_get_shared(&pdev->dev, "usb1-phy-rst");
|
||||
if (IS_ERR(zhihe->usb1_phy_rst))
|
||||
return PTR_ERR(zhihe->usb1_phy_rst);
|
||||
|
||||
/* Pull-up the PHY reset */
|
||||
val = readl(zhihe->usb20_blk_sysreg + USB20_PHY_CFG);
|
||||
val |= USB0_PHY_DM_PULLDOWN | USB0_PHY_DP_PULLDOWN;
|
||||
writel(val, zhihe->usb20_blk_sysreg + USB20_PHY_CFG);
|
||||
|
||||
val = readl(zhihe->usb20_blk_sysreg + USB21_PHY_CFG);
|
||||
val |= USB1_PHY_DM_PULLDOWN | USB1_PHY_DP_PULLDOWN;
|
||||
writel(val, zhihe->usb20_blk_sysreg + USB21_PHY_CFG);
|
||||
|
||||
reset_control_deassert(zhihe->usb0_phy_rst);
|
||||
reset_control_deassert(zhihe->usb1_phy_rst);
|
||||
|
||||
val = readl(zhihe->usb20_blk_sysreg + USB20_PHY_ANA_CFG);
|
||||
val &= ~USB20_PHY_TXVREFTUNE_MASK;
|
||||
val |= HS_DV_VOLTAGE_LEVEL_POS_16_PER;
|
||||
writel(val, zhihe->usb20_blk_sysreg + USB20_PHY_ANA_CFG);
|
||||
|
||||
val = readl(zhihe->usb20_blk_sysreg + USB21_PHY_ANA_CFG);
|
||||
val &= ~USB20_PHY_TXVREFTUNE_MASK;
|
||||
val |= HS_DV_VOLTAGE_LEVEL_POS_16_PER;
|
||||
writel(val, zhihe->usb20_blk_sysreg + USB21_PHY_ANA_CFG);
|
||||
|
||||
reset_control_assert(zhihe->usb0_phy_rst);
|
||||
reset_control_assert(zhihe->usb1_phy_rst);
|
||||
|
||||
/* Populate child nodes (dwc2 controllers) */
|
||||
ret = of_platform_populate(np, NULL, NULL, dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to populate child nodes: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
zhihe->usb20_pwren = devm_gpiod_get_optional(&pdev->dev,
|
||||
"usb20-pwren",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(zhihe->usb20_pwren)) {
|
||||
dev_err(&pdev->dev, "Failed to get usb20-pwren GPIO\n");
|
||||
return PTR_ERR(zhihe->usb20_pwren);
|
||||
}
|
||||
|
||||
zhihe->usb21_pwren = devm_gpiod_get_optional(&pdev->dev,
|
||||
"usb21-pwren",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(zhihe->usb21_pwren)) {
|
||||
dev_err(&pdev->dev, "Failed to get usb21-pwren GPIO\n");
|
||||
return PTR_ERR(zhihe->usb21_pwren);
|
||||
}
|
||||
|
||||
if (zhihe->usb20_pwren)
|
||||
gpiod_set_value(zhihe->usb20_pwren, 1);
|
||||
|
||||
if (zhihe->usb21_pwren)
|
||||
gpiod_set_value(zhihe->usb21_pwren, 1);
|
||||
|
||||
dev_info(dev, "ZHIHE DWC2 glue layer initialized\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc2_zhihe_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc2_zhihe *zhihe = platform_get_drvdata(pdev);
|
||||
|
||||
of_platform_depopulate(zhihe->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id dwc2_zhihe_of_match[] = {
|
||||
{ .compatible = "zhihe,usb20" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dwc2_zhihe_of_match);
|
||||
|
||||
static struct platform_driver dwc2_zhihe_driver = {
|
||||
.probe = dwc2_zhihe_probe,
|
||||
.remove = dwc2_zhihe_remove,
|
||||
.driver = {
|
||||
.name = "dwc2-zhihe",
|
||||
.of_match_table = dwc2_zhihe_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(dwc2_zhihe_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("ZHIHE DWC2 Glue Layer");
|
||||
MODULE_AUTHOR("Anonymous <Anonymous@zhcomputing.com>");
|
||||
@@ -136,13 +136,18 @@ static void dwc2_set_zhihe_params(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *p = &hsotg->params;
|
||||
|
||||
p->phy_utmi_width = 8;
|
||||
/* Use INCR4 burst length to prevent AHB ERROR during long-term USB storage operations */
|
||||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT;
|
||||
/* Configure FIFO sizes for stable bulk transfers */
|
||||
p->host_rx_fifo_size = 1024;
|
||||
p->host_nperio_tx_fifo_size = 1024;
|
||||
p->host_perio_tx_fifo_size = 1024;
|
||||
p->otg_caps.hnp_support = false;
|
||||
p->otg_caps.srp_support = false;
|
||||
p->host_rx_fifo_size = 525;
|
||||
p->host_nperio_tx_fifo_size = 128;
|
||||
p->host_perio_tx_fifo_size = 256;
|
||||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
|
||||
GAHBCFG_HBSTLEN_SHIFT;
|
||||
p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
|
||||
p->lpm = false;
|
||||
p->lpm_clock_gating = false;
|
||||
p->besl = false;
|
||||
p->hird_threshold_en = false;
|
||||
}
|
||||
|
||||
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
|
||||
@@ -293,7 +298,7 @@ const struct of_device_id dwc2_of_match_table[] = {
|
||||
{ .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params },
|
||||
{ .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },
|
||||
{ .compatible = "snps,dwc2" },
|
||||
{ .compatible = "zhihe,p100-usb", .data = dwc2_set_zhihe_params },
|
||||
{ .compatible = "zhihe,a210-usb", .data = dwc2_set_zhihe_params },
|
||||
{ .compatible = "samsung,s3c6400-hsotg",
|
||||
.data = dwc2_set_s3c6400_params },
|
||||
{ .compatible = "amlogic,meson8-usb",
|
||||
|
||||
Reference in New Issue
Block a user