From de27d073f65ebc287f5545edc9472fb64f2aabee Mon Sep 17 00:00:00 2001 From: Frank Sae Date: Sat, 28 Jan 2023 14:35:57 +0800 Subject: [PATCH 01/16] net: phy: fix the spelling problem of Sentinel CHECK: 'sentinal' may be misspelled - perhaps 'sentinel'? Signed-off-by: Frank Sae Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230128063558.5850-1-Frank.Sae@motor-comm.com Signed-off-by: Jakub Kicinski Signed-off-by: Jaehoon Chung Change-Id: I1b526c10df1df49984224c1a2cd8d690918f0a72 --- drivers/net/phy/motorcomm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 685190d..b6968c7 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -1804,7 +1804,7 @@ static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, - { /* sentinal */ } + { /* sentinel */ } }; MODULE_DEVICE_TABLE(mdio, motorcomm_tbl); -- 2.7.4 From 9876760593277b10977b3f8337bb9ea50bf4f7ff Mon Sep 17 00:00:00 2001 From: Frank Sae Date: Sat, 28 Jan 2023 14:35:58 +0800 Subject: [PATCH 02/16] net: phy: motorcomm: change the phy id of yt8521 and yt8531s to lowercase The phy id is usually defined in lower case. Signed-off-by: Frank Sae Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230128063558.5850-2-Frank.Sae@motor-comm.com Signed-off-by: Jakub Kicinski Signed-off-by: Jaehoon Chung Change-Id: If5dba6dda0ac08f235f08bb333298b093d180853 --- drivers/net/phy/motorcomm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index b6968c7..aa02e72 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -12,8 +12,8 @@ #include #define PHY_ID_YT8511 0x0000010a -#define PHY_ID_YT8521 0x0000011A -#define PHY_ID_YT8531S 0x4F51E91A +#define PHY_ID_YT8521 0x0000011a +#define PHY_ID_YT8531S 0x4f51e91a /* YT8521/YT8531S Register Overview * UTP Register space | FIBER Register space -- 2.7.4 From e660d317a4550bd0d1370bf4ff013d65239c130f Mon Sep 17 00:00:00 2001 From: Frank Sae Date: Thu, 2 Feb 2023 11:00:34 +0800 Subject: [PATCH 03/16] net: phy: Add BIT macro for Motorcomm yt8521/yt8531 gigabit ethernet phy Add BIT macro for Motorcomm yt8521/yt8531 gigabit ethernet phy. This is a preparatory patch. Add BIT macro for 0xA012 reg, and supplement for 0xA001 and 0xA003 reg. These will be used to support dts. Signed-off-by: Frank Sae Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Jaehoon Chung Change-Id: Ia86f4b51b61329bcc4b585ec4cfa26fe80943d02 --- drivers/net/phy/motorcomm.c | 55 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index aa02e72..830f9d6 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -161,6 +161,11 @@ #define YT8521_CHIP_CONFIG_REG 0xA001 #define YT8521_CCR_SW_RST BIT(15) +/* 1b0 disable 1.9ns rxc clock delay *default* + * 1b1 enable 1.9ns rxc clock delay + */ +#define YT8521_CCR_RXC_DLY_EN BIT(8) +#define YT8521_CCR_RXC_DLY_1_900_NS 1900 #define YT8521_CCR_MODE_SEL_MASK (BIT(2) | BIT(1) | BIT(0)) #define YT8521_CCR_MODE_UTP_TO_RGMII 0 @@ -178,22 +183,41 @@ #define YT8521_MODE_POLL 0x3 #define YT8521_RGMII_CONFIG1_REG 0xA003 - +/* 1b0 use original tx_clk_rgmii *default* + * 1b1 use inverted tx_clk_rgmii. + */ +#define YT8521_RC1R_TX_CLK_SEL_INVERTED BIT(14) /* TX Gig-E Delay is bits 3:0, default 0x1 * TX Fast-E Delay is bits 7:4, default 0xf * RX Delay is bits 13:10, default 0x0 * Delay = 150ps * N * On = 2250ps, off = 0ps */ -#define YT8521_RC1R_RX_DELAY_MASK (0xF << 10) +#define YT8521_RC1R_RX_DELAY_MASK GENMASK(13, 10) #define YT8521_RC1R_RX_DELAY_EN (0xF << 10) #define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10) -#define YT8521_RC1R_FE_TX_DELAY_MASK (0xF << 4) +#define YT8521_RC1R_FE_TX_DELAY_MASK GENMASK(7, 4) #define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4) #define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4) -#define YT8521_RC1R_GE_TX_DELAY_MASK (0xF << 0) +#define YT8521_RC1R_GE_TX_DELAY_MASK GENMASK(3, 0) #define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0) #define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0) +#define YT8521_RC1R_RGMII_0_000_NS 0 +#define YT8521_RC1R_RGMII_0_150_NS 1 +#define YT8521_RC1R_RGMII_0_300_NS 2 +#define YT8521_RC1R_RGMII_0_450_NS 3 +#define YT8521_RC1R_RGMII_0_600_NS 4 +#define YT8521_RC1R_RGMII_0_750_NS 5 +#define YT8521_RC1R_RGMII_0_900_NS 6 +#define YT8521_RC1R_RGMII_1_050_NS 7 +#define YT8521_RC1R_RGMII_1_200_NS 8 +#define YT8521_RC1R_RGMII_1_350_NS 9 +#define YT8521_RC1R_RGMII_1_500_NS 10 +#define YT8521_RC1R_RGMII_1_650_NS 11 +#define YT8521_RC1R_RGMII_1_800_NS 12 +#define YT8521_RC1R_RGMII_1_950_NS 13 +#define YT8521_RC1R_RGMII_2_100_NS 14 +#define YT8521_RC1R_RGMII_2_250_NS 15 #define YTPHY_MISC_CONFIG_REG 0xA006 #define YTPHY_MCR_FIBER_SPEED_MASK BIT(0) @@ -222,6 +246,29 @@ */ #define YTPHY_WCR_TYPE_PULSE BIT(0) +#define YTPHY_SYNCE_CFG_REG 0xA012 +#define YT8521_SCR_SYNCE_ENABLE BIT(5) +/* 1b0 output 25m clock + * 1b1 output 125m clock *default* + */ +#define YT8521_SCR_CLK_FRE_SEL_125M BIT(3) +#define YT8521_SCR_CLK_SRC_MASK GENMASK(2, 1) +#define YT8521_SCR_CLK_SRC_PLL_125M 0 +#define YT8521_SCR_CLK_SRC_UTP_RX 1 +#define YT8521_SCR_CLK_SRC_SDS_RX 2 +#define YT8521_SCR_CLK_SRC_REF_25M 3 +#define YT8531_SCR_SYNCE_ENABLE BIT(6) +/* 1b0 output 25m clock *default* + * 1b1 output 125m clock + */ +#define YT8531_SCR_CLK_FRE_SEL_125M BIT(4) +#define YT8531_SCR_CLK_SRC_MASK GENMASK(3, 1) +#define YT8531_SCR_CLK_SRC_PLL_125M 0 +#define YT8531_SCR_CLK_SRC_UTP_RX 1 +#define YT8531_SCR_CLK_SRC_SDS_RX 2 +#define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3 +#define YT8531_SCR_CLK_SRC_REF_25M 4 +#define YT8531_SCR_CLK_SRC_SSC_25M 5 #define YT8531S_SYNCE_CFG_REG 0xA012 #define YT8531S_SCR_SYNCE_ENABLE BIT(6) -- 2.7.4 From 974c549cf7f1ef704ca8941a6c15646d372dd1e2 Mon Sep 17 00:00:00 2001 From: Frank Sae Date: Thu, 2 Feb 2023 11:00:35 +0800 Subject: [PATCH 04/16] net: phy: Add dts support for Motorcomm yt8521 gigabit ethernet phy Add dts support for Motorcomm yt8521 gigabit ethernet phy. Add ytphy_rgmii_clk_delay_config function to support dst config for the delay of rgmii clk. This funciont is common for yt8521, yt8531s and yt8531. This patch has been verified on AM335x platform. Signed-off-by: Frank Sae Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Jaehoon Chung Change-Id: I96c978c5b0ee9c6d227f771b35001e331882f33a --- drivers/net/phy/motorcomm.c | 253 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 199 insertions(+), 54 deletions(-) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 830f9d6..ee30e8a 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -10,6 +10,7 @@ #include #include #include +#include #define PHY_ID_YT8511 0x0000010a #define PHY_ID_YT8521 0x0000011a @@ -187,21 +188,9 @@ * 1b1 use inverted tx_clk_rgmii. */ #define YT8521_RC1R_TX_CLK_SEL_INVERTED BIT(14) -/* TX Gig-E Delay is bits 3:0, default 0x1 - * TX Fast-E Delay is bits 7:4, default 0xf - * RX Delay is bits 13:10, default 0x0 - * Delay = 150ps * N - * On = 2250ps, off = 0ps - */ #define YT8521_RC1R_RX_DELAY_MASK GENMASK(13, 10) -#define YT8521_RC1R_RX_DELAY_EN (0xF << 10) -#define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10) #define YT8521_RC1R_FE_TX_DELAY_MASK GENMASK(7, 4) -#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4) -#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4) #define YT8521_RC1R_GE_TX_DELAY_MASK GENMASK(3, 0) -#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0) -#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0) #define YT8521_RC1R_RGMII_0_000_NS 0 #define YT8521_RC1R_RGMII_0_150_NS 1 #define YT8521_RC1R_RGMII_0_300_NS 2 @@ -274,6 +263,10 @@ /* Extended Register end */ +#define YTPHY_DTS_OUTPUT_CLK_DIS 0 +#define YTPHY_DTS_OUTPUT_CLK_25M 25000000 +#define YTPHY_DTS_OUTPUT_CLK_125M 125000000 + struct yt8521_priv { /* combo_advertising is used for case of YT8521 in combo mode, * this means that yt8521 may work in utp or fiber mode which depends @@ -641,6 +634,142 @@ static int yt8521_write_page(struct phy_device *phydev, int page) }; /** + * struct ytphy_cfg_reg_map - map a config value to a register value + * @cfg: value in device configuration + * @reg: value in the register + */ +struct ytphy_cfg_reg_map { + u32 cfg; + u32 reg; +}; + +static const struct ytphy_cfg_reg_map ytphy_rgmii_delays[] = { + /* for tx delay / rx delay with YT8521_CCR_RXC_DLY_EN is not set. */ + { 0, YT8521_RC1R_RGMII_0_000_NS }, + { 150, YT8521_RC1R_RGMII_0_150_NS }, + { 300, YT8521_RC1R_RGMII_0_300_NS }, + { 450, YT8521_RC1R_RGMII_0_450_NS }, + { 600, YT8521_RC1R_RGMII_0_600_NS }, + { 750, YT8521_RC1R_RGMII_0_750_NS }, + { 900, YT8521_RC1R_RGMII_0_900_NS }, + { 1050, YT8521_RC1R_RGMII_1_050_NS }, + { 1200, YT8521_RC1R_RGMII_1_200_NS }, + { 1350, YT8521_RC1R_RGMII_1_350_NS }, + { 1500, YT8521_RC1R_RGMII_1_500_NS }, + { 1650, YT8521_RC1R_RGMII_1_650_NS }, + { 1800, YT8521_RC1R_RGMII_1_800_NS }, + { 1950, YT8521_RC1R_RGMII_1_950_NS }, /* default tx/rx delay */ + { 2100, YT8521_RC1R_RGMII_2_100_NS }, + { 2250, YT8521_RC1R_RGMII_2_250_NS }, + + /* only for rx delay with YT8521_CCR_RXC_DLY_EN is set. */ + { 0 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_000_NS }, + { 150 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_150_NS }, + { 300 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_300_NS }, + { 450 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_450_NS }, + { 600 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_600_NS }, + { 750 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_750_NS }, + { 900 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_900_NS }, + { 1050 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_050_NS }, + { 1200 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_200_NS }, + { 1350 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_350_NS }, + { 1500 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_500_NS }, + { 1650 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_650_NS }, + { 1800 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_800_NS }, + { 1950 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_950_NS }, + { 2100 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_2_100_NS }, + { 2250 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_2_250_NS } +}; + +static u32 ytphy_get_delay_reg_value(struct phy_device *phydev, + const char *prop_name, + const struct ytphy_cfg_reg_map *tbl, + int tb_size, + u16 *rxc_dly_en, + u32 dflt) +{ + struct device_node *node = phydev->mdio.dev.of_node; + int tb_size_half = tb_size / 2; + u32 val; + int i; + + if (of_property_read_u32(node, prop_name, &val)) + goto err_dts_val; + + /* when rxc_dly_en is NULL, it is get the delay for tx, only half of + * tb_size is valid. + */ + if (!rxc_dly_en) + tb_size = tb_size_half; + + for (i = 0; i < tb_size; i++) { + if (tbl[i].cfg == val) { + if (rxc_dly_en && i < tb_size_half) + *rxc_dly_en = 0; + return tbl[i].reg; + } + } + + phydev_warn(phydev, "Unsupported value %d for %s using default (%u)\n", + val, prop_name, dflt); + +err_dts_val: + /* when rxc_dly_en is not NULL, it is get the delay for rx. + * The rx default in dts and ytphy_rgmii_clk_delay_config is 1950 ps, + * so YT8521_CCR_RXC_DLY_EN should not be set. + */ + if (rxc_dly_en) + *rxc_dly_en = 0; + + return dflt; +} + +static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev) +{ + int tb_size = ARRAY_SIZE(ytphy_rgmii_delays); + u16 rxc_dly_en = YT8521_CCR_RXC_DLY_EN; + u32 rx_reg, tx_reg; + u16 mask, val = 0; + int ret; + + rx_reg = ytphy_get_delay_reg_value(phydev, "rx-internal-delay-ps", + ytphy_rgmii_delays, tb_size, + &rxc_dly_en, + YT8521_RC1R_RGMII_1_950_NS); + tx_reg = ytphy_get_delay_reg_value(phydev, "tx-internal-delay-ps", + ytphy_rgmii_delays, tb_size, NULL, + YT8521_RC1R_RGMII_1_950_NS); + + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: + rxc_dly_en = 0; + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg); + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + rxc_dly_en = 0; + val |= FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg); + break; + case PHY_INTERFACE_MODE_RGMII_ID: + val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg) | + FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg); + break; + default: /* do not support other modes */ + return -EOPNOTSUPP; + } + + ret = ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG, + YT8521_CCR_RXC_DLY_EN, rxc_dly_en); + if (ret < 0) + return ret; + + /* Generally, it is not necessary to adjust YT8521_RC1R_FE_TX_DELAY */ + mask = YT8521_RC1R_RX_DELAY_MASK | YT8521_RC1R_GE_TX_DELAY_MASK; + return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val); +} + +/** * yt8521_probe() - read chip config then set suitable polling_mode * @phydev: a pointer to a &struct phy_device * @@ -648,9 +777,12 @@ static int yt8521_write_page(struct phy_device *phydev, int page) */ static int yt8521_probe(struct phy_device *phydev) { + struct device_node *node = phydev->mdio.dev.of_node; struct device *dev = &phydev->mdio.dev; struct yt8521_priv *priv; int chip_config; + u16 mask, val; + u32 freq; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -695,7 +827,45 @@ static int yt8521_probe(struct phy_device *phydev) return ret; } - return 0; + if (of_property_read_u32(node, "motorcomm,clk-out-frequency-hz", &freq)) + freq = YTPHY_DTS_OUTPUT_CLK_DIS; + + if (phydev->drv->phy_id == PHY_ID_YT8521) { + switch (freq) { + case YTPHY_DTS_OUTPUT_CLK_DIS: + mask = YT8521_SCR_SYNCE_ENABLE; + val = 0; + break; + case YTPHY_DTS_OUTPUT_CLK_25M: + mask = YT8521_SCR_SYNCE_ENABLE | + YT8521_SCR_CLK_SRC_MASK | + YT8521_SCR_CLK_FRE_SEL_125M; + val = YT8521_SCR_SYNCE_ENABLE | + FIELD_PREP(YT8521_SCR_CLK_SRC_MASK, + YT8521_SCR_CLK_SRC_REF_25M); + break; + case YTPHY_DTS_OUTPUT_CLK_125M: + mask = YT8521_SCR_SYNCE_ENABLE | + YT8521_SCR_CLK_SRC_MASK | + YT8521_SCR_CLK_FRE_SEL_125M; + val = YT8521_SCR_SYNCE_ENABLE | + YT8521_SCR_CLK_FRE_SEL_125M | + FIELD_PREP(YT8521_SCR_CLK_SRC_MASK, + YT8521_SCR_CLK_SRC_PLL_125M); + break; + default: + phydev_warn(phydev, "Freq err:%u\n", freq); + return -EINVAL; + } + } else if (phydev->drv->phy_id == PHY_ID_YT8531S) { + return 0; + } else { + phydev_warn(phydev, "PHY id err\n"); + return -EINVAL; + } + + return ytphy_modify_ext_with_lock(phydev, YTPHY_SYNCE_CFG_REG, mask, + val); } /** @@ -1180,61 +1350,36 @@ static int yt8521_resume(struct phy_device *phydev) */ static int yt8521_config_init(struct phy_device *phydev) { + struct device_node *node = phydev->mdio.dev.of_node; int old_page; int ret = 0; - u16 val; old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE); if (old_page < 0) goto err_restore_page; - switch (phydev->interface) { - case PHY_INTERFACE_MODE_RGMII: - val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS; - val |= YT8521_RC1R_RX_DELAY_DIS; - break; - case PHY_INTERFACE_MODE_RGMII_RXID: - val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS; - val |= YT8521_RC1R_RX_DELAY_EN; - break; - case PHY_INTERFACE_MODE_RGMII_TXID: - val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN; - val |= YT8521_RC1R_RX_DELAY_DIS; - break; - case PHY_INTERFACE_MODE_RGMII_ID: - val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN; - val |= YT8521_RC1R_RX_DELAY_EN; - break; - case PHY_INTERFACE_MODE_SGMII: - break; - default: /* do not support other modes */ - ret = -EOPNOTSUPP; - goto err_restore_page; - } - /* set rgmii delay mode */ if (phydev->interface != PHY_INTERFACE_MODE_SGMII) { - ret = ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, - (YT8521_RC1R_RX_DELAY_MASK | - YT8521_RC1R_FE_TX_DELAY_MASK | - YT8521_RC1R_GE_TX_DELAY_MASK), - val); + ret = ytphy_rgmii_clk_delay_config(phydev); if (ret < 0) goto err_restore_page; } - /* disable auto sleep */ - ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG, - YT8521_ESC1R_SLEEP_SW, 0); - if (ret < 0) - goto err_restore_page; - - /* enable RXC clock when no wire plug */ - ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG, - YT8521_CGR_RX_CLK_EN, 0); - if (ret < 0) - goto err_restore_page; + if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled")) { + /* disable auto sleep */ + ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG, + YT8521_ESC1R_SLEEP_SW, 0); + if (ret < 0) + goto err_restore_page; + } + if (of_property_read_bool(node, "motorcomm,keep-pll-enabled")) { + /* enable RXC clock when no wire plug */ + ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG, + YT8521_CGR_RX_CLK_EN, 0); + if (ret < 0) + goto err_restore_page; + } err_restore_page: return phy_restore_page(phydev, old_page, ret); } -- 2.7.4 From e7c98b35dab73ae82d649adbd9e8bc31d3294a3f Mon Sep 17 00:00:00 2001 From: Frank Sae Date: Thu, 2 Feb 2023 11:00:36 +0800 Subject: [PATCH 05/16] net: phy: Add dts support for Motorcomm yt8531s gigabit ethernet phy Add dts support for Motorcomm yt8531s gigabit ethernet phy. Change yt8521_probe to support clk config of yt8531s. Becase yt8521_probe does the things which yt8531s is needed, so removed yt8531s function. This patch has been verified on AM335x platform with yt8531s board. Signed-off-by: Frank Sae Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Jaehoon Chung Change-Id: I85e5655baba7120eadad1e25c4da1797c9943154 --- drivers/net/phy/motorcomm.c | 51 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index ee30e8a..bdc6a55 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -258,8 +258,6 @@ #define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3 #define YT8531_SCR_CLK_SRC_REF_25M 4 #define YT8531_SCR_CLK_SRC_SSC_25M 5 -#define YT8531S_SYNCE_CFG_REG 0xA012 -#define YT8531S_SCR_SYNCE_ENABLE BIT(6) /* Extended Register end */ @@ -858,7 +856,32 @@ static int yt8521_probe(struct phy_device *phydev) return -EINVAL; } } else if (phydev->drv->phy_id == PHY_ID_YT8531S) { - return 0; + switch (freq) { + case YTPHY_DTS_OUTPUT_CLK_DIS: + mask = YT8531_SCR_SYNCE_ENABLE; + val = 0; + break; + case YTPHY_DTS_OUTPUT_CLK_25M: + mask = YT8531_SCR_SYNCE_ENABLE | + YT8531_SCR_CLK_SRC_MASK | + YT8531_SCR_CLK_FRE_SEL_125M; + val = YT8531_SCR_SYNCE_ENABLE | + FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, + YT8531_SCR_CLK_SRC_REF_25M); + break; + case YTPHY_DTS_OUTPUT_CLK_125M: + mask = YT8531_SCR_SYNCE_ENABLE | + YT8531_SCR_CLK_SRC_MASK | + YT8531_SCR_CLK_FRE_SEL_125M; + val = YT8531_SCR_SYNCE_ENABLE | + YT8531_SCR_CLK_FRE_SEL_125M | + FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, + YT8531_SCR_CLK_SRC_PLL_125M); + break; + default: + phydev_warn(phydev, "Freq err:%u\n", freq); + return -EINVAL; + } } else { phydev_warn(phydev, "PHY id err\n"); return -EINVAL; @@ -869,26 +892,6 @@ static int yt8521_probe(struct phy_device *phydev) } /** - * yt8531s_probe() - read chip config then set suitable polling_mode - * @phydev: a pointer to a &struct phy_device - * - * returns 0 or negative errno code - */ -static int yt8531s_probe(struct phy_device *phydev) -{ - int ret; - - /* Disable SyncE clock output by default */ - ret = ytphy_modify_ext_with_lock(phydev, YT8531S_SYNCE_CFG_REG, - YT8531S_SCR_SYNCE_ENABLE, 0); - if (ret < 0) - return ret; - - /* same as yt8521_probe */ - return yt8521_probe(phydev); -} - -/** * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp * @phydev: a pointer to a &struct phy_device * @@ -1970,7 +1973,7 @@ static struct phy_driver motorcomm_phy_drvs[] = { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S), .name = "YT8531S Gigabit Ethernet", .get_features = yt8521_get_features, - .probe = yt8531s_probe, + .probe = yt8521_probe, .read_page = yt8521_read_page, .write_page = yt8521_write_page, .get_wol = ytphy_get_wol, -- 2.7.4 From 61798109146566953101c5f33e6d8736ed39c7f7 Mon Sep 17 00:00:00 2001 From: Frank Sae Date: Thu, 2 Feb 2023 11:00:37 +0800 Subject: [PATCH 06/16] net: phy: Add driver for Motorcomm yt8531 gigabit ethernet phy Add a driver for the motorcomm yt8531 gigabit ethernet phy. We have verified the driver on AM335x platform with yt8531 board. On the board, yt8531 gigabit ethernet phy works in utp mode, RGMII interface, supports 1000M/100M/10M speeds, and wol(magic package). Signed-off-by: Frank Sae Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Jaehoon Chung Change-Id: Iaab41bb4da6fc537ec994ec09beaf65a92a4d8f6 --- drivers/net/phy/Kconfig | 2 +- drivers/net/phy/motorcomm.c | 208 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 207 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index af00cf4..b321950 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -260,7 +260,7 @@ config MOTORCOMM_PHY tristate "Motorcomm PHYs" help Enables support for Motorcomm network PHYs. - Currently supports the YT8511, YT8521, YT8531S Gigabit Ethernet PHYs. + Currently supports YT85xx Gigabit Ethernet PHYs. config NATIONAL_PHY tristate "National Semiconductor PHYs" diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index bdc6a55..ee7c37d 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Motorcomm 8511/8521/8531S PHY driver. + * Motorcomm 8511/8521/8531/8531S PHY driver. * * Author: Peter Geis * Author: Frank @@ -14,6 +14,7 @@ #define PHY_ID_YT8511 0x0000010a #define PHY_ID_YT8521 0x0000011a +#define PHY_ID_YT8531 0x4f51e91b #define PHY_ID_YT8531S 0x4f51e91a /* YT8521/YT8531S Register Overview @@ -517,6 +518,61 @@ err_restore_page: return phy_restore_page(phydev, old_page, ret); } +static int yt8531_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + const u16 mac_addr_reg[] = { + YTPHY_WOL_MACADDR2_REG, + YTPHY_WOL_MACADDR1_REG, + YTPHY_WOL_MACADDR0_REG, + }; + const u8 *mac_addr; + u16 mask, val; + int ret; + u8 i; + + if (wol->wolopts & WAKE_MAGIC) { + mac_addr = phydev->attached_dev->dev_addr; + + /* Store the device address for the magic packet */ + for (i = 0; i < 3; i++) { + ret = ytphy_write_ext_with_lock(phydev, mac_addr_reg[i], + ((mac_addr[i * 2] << 8)) | + (mac_addr[i * 2 + 1])); + if (ret < 0) + return ret; + } + + /* Enable WOL feature */ + mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL; + val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL; + val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS; + ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG, + mask, val); + if (ret < 0) + return ret; + + /* Enable WOL interrupt */ + ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0, + YTPHY_IER_WOL); + if (ret < 0) + return ret; + } else { + /* Disable WOL feature */ + mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL; + ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG, + mask, 0); + + /* Disable WOL interrupt */ + ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, + YTPHY_IER_WOL, 0); + if (ret < 0) + return ret; + } + + return 0; +} + static int yt8511_read_page(struct phy_device *phydev) { return __phy_read(phydev, YT8511_PAGE_SELECT); @@ -767,6 +823,17 @@ static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev) return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val); } +static int ytphy_rgmii_clk_delay_config_with_lock(struct phy_device *phydev) +{ + int ret; + + phy_lock_mdio_bus(phydev); + ret = ytphy_rgmii_clk_delay_config(phydev); + phy_unlock_mdio_bus(phydev); + + return ret; +} + /** * yt8521_probe() - read chip config then set suitable polling_mode * @phydev: a pointer to a &struct phy_device @@ -891,6 +958,43 @@ static int yt8521_probe(struct phy_device *phydev) val); } +static int yt8531_probe(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + u16 mask, val; + u32 freq; + + if (of_property_read_u32(node, "motorcomm,clk-out-frequency-hz", &freq)) + freq = YTPHY_DTS_OUTPUT_CLK_DIS; + + switch (freq) { + case YTPHY_DTS_OUTPUT_CLK_DIS: + mask = YT8531_SCR_SYNCE_ENABLE; + val = 0; + break; + case YTPHY_DTS_OUTPUT_CLK_25M: + mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK | + YT8531_SCR_CLK_FRE_SEL_125M; + val = YT8531_SCR_SYNCE_ENABLE | + FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, + YT8531_SCR_CLK_SRC_REF_25M); + break; + case YTPHY_DTS_OUTPUT_CLK_125M: + mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK | + YT8531_SCR_CLK_FRE_SEL_125M; + val = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_FRE_SEL_125M | + FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, + YT8531_SCR_CLK_SRC_PLL_125M); + break; + default: + phydev_warn(phydev, "Freq err:%u\n", freq); + return -EINVAL; + } + + return ytphy_modify_ext_with_lock(phydev, YTPHY_SYNCE_CFG_REG, mask, + val); +} + /** * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp * @phydev: a pointer to a &struct phy_device @@ -1387,6 +1491,94 @@ err_restore_page: return phy_restore_page(phydev, old_page, ret); } +static int yt8531_config_init(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + int ret; + + ret = ytphy_rgmii_clk_delay_config_with_lock(phydev); + if (ret < 0) + return ret; + + if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled")) { + /* disable auto sleep */ + ret = ytphy_modify_ext_with_lock(phydev, + YT8521_EXTREG_SLEEP_CONTROL1_REG, + YT8521_ESC1R_SLEEP_SW, 0); + if (ret < 0) + return ret; + } + + if (of_property_read_bool(node, "motorcomm,keep-pll-enabled")) { + /* enable RXC clock when no wire plug */ + ret = ytphy_modify_ext_with_lock(phydev, + YT8521_CLOCK_GATING_REG, + YT8521_CGR_RX_CLK_EN, 0); + if (ret < 0) + return ret; + } + + return 0; +} + +/** + * yt8531_link_change_notify() - Adjust the tx clock direction according to + * the current speed and dts config. + * @phydev: a pointer to a &struct phy_device + * + * NOTE: This function is only used to adapt to VF2 with JH7110 SoC. Please + * keep "motorcomm,tx-clk-adj-enabled" not exist in dts when the soc is not + * JH7110. + */ +static void yt8531_link_change_notify(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + bool tx_clk_adj_enabled = false; + bool tx_clk_1000_inverted; + bool tx_clk_100_inverted; + bool tx_clk_10_inverted; + u16 val = 0; + int ret; + + if (of_property_read_bool(node, "motorcomm,tx-clk-adj-enabled")) + tx_clk_adj_enabled = true; + + if (!tx_clk_adj_enabled) + return; + + if (of_property_read_bool(node, "motorcomm,tx-clk-10-inverted")) + tx_clk_10_inverted = true; + if (of_property_read_bool(node, "motorcomm,tx-clk-100-inverted")) + tx_clk_100_inverted = true; + if (of_property_read_bool(node, "motorcomm,tx-clk-1000-inverted")) + tx_clk_1000_inverted = true; + + if (phydev->speed < 0) + return; + + switch (phydev->speed) { + case SPEED_1000: + if (tx_clk_1000_inverted) + val = YT8521_RC1R_TX_CLK_SEL_INVERTED; + break; + case SPEED_100: + if (tx_clk_100_inverted) + val = YT8521_RC1R_TX_CLK_SEL_INVERTED; + break; + case SPEED_10: + if (tx_clk_10_inverted) + val = YT8521_RC1R_TX_CLK_SEL_INVERTED; + break; + default: + return; + } + + ret = ytphy_modify_ext_with_lock(phydev, YT8521_RGMII_CONFIG1_REG, + YT8521_RC1R_TX_CLK_SEL_INVERTED, val); + if (ret < 0) + phydev_warn(phydev, "Modify TX_CLK_SEL err:%d\n", ret); +} + /** * yt8521_prepare_fiber_features() - A small helper function that setup * fiber's features. @@ -1970,6 +2162,17 @@ static struct phy_driver motorcomm_phy_drvs[] = { .resume = yt8521_resume, }, { + PHY_ID_MATCH_EXACT(PHY_ID_YT8531), + .name = "YT8531 Gigabit Ethernet", + .probe = yt8531_probe, + .config_init = yt8531_config_init, + .suspend = genphy_suspend, + .resume = genphy_resume, + .get_wol = ytphy_get_wol, + .set_wol = yt8531_set_wol, + .link_change_notify = yt8531_link_change_notify, + }, + { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S), .name = "YT8531S Gigabit Ethernet", .get_features = yt8521_get_features, @@ -1990,7 +2193,7 @@ static struct phy_driver motorcomm_phy_drvs[] = { module_phy_driver(motorcomm_phy_drvs); -MODULE_DESCRIPTION("Motorcomm 8511/8521/8531S PHY driver"); +MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S PHY driver"); MODULE_AUTHOR("Peter Geis"); MODULE_AUTHOR("Frank"); MODULE_LICENSE("GPL"); @@ -1998,6 +2201,7 @@ MODULE_LICENSE("GPL"); static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) }, + { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) }, { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, { /* sentinel */ } }; -- 2.7.4 From 96d239c460ed2b7f7c359b30449b5d9547a4fd03 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 15 Feb 2023 07:21:47 +0300 Subject: [PATCH 07/16] net: phy: motorcomm: uninitialized variables in yt8531_link_change_notify() These booleans are never set to false, but are just used without being initialized. Fixes: 4ac94f728a58 ("net: phy: Add driver for Motorcomm yt8531 gigabit ethernet phy") Signed-off-by: Dan Carpenter Reviewed-by: Frank Sae Link: https://lore.kernel.org/r/Y+xd2yJet2ImHLoQ@kili Signed-off-by: Jakub Kicinski Signed-off-by: Jaehoon Chung Change-Id: I1b34e53290b0e99aa7d2e5c7269625cdc6a779cb --- drivers/net/phy/motorcomm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index ee7c37d..2fa5a90 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -1533,10 +1533,10 @@ static int yt8531_config_init(struct phy_device *phydev) static void yt8531_link_change_notify(struct phy_device *phydev) { struct device_node *node = phydev->mdio.dev.of_node; + bool tx_clk_1000_inverted = false; + bool tx_clk_100_inverted = false; + bool tx_clk_10_inverted = false; bool tx_clk_adj_enabled = false; - bool tx_clk_1000_inverted; - bool tx_clk_100_inverted; - bool tx_clk_10_inverted; u16 val = 0; int ret; -- 2.7.4 From 375c3483898ea1f2cfbec0eb07c8bab4f17a9778 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 10 Apr 2023 11:14:16 +0900 Subject: [PATCH 08/16] RISCV: configs: enable motorcomm phy driver Enable motrocomm phy driver to use ethernet. Change-Id: I71e988989fc9332b2d38339858fa49109daf6163 Signed-off-by: Jaehoon Chung --- arch/riscv/configs/tizen_vf2_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/configs/tizen_vf2_defconfig b/arch/riscv/configs/tizen_vf2_defconfig index 51e6e94..c0dc85b 100644 --- a/arch/riscv/configs/tizen_vf2_defconfig +++ b/arch/riscv/configs/tizen_vf2_defconfig @@ -134,6 +134,7 @@ CONFIG_R8169=y CONFIG_STMMAC_ETH=y CONFIG_DWMAC_STARFIVE=y CONFIG_MICROSEMI_PHY=y +CONFIG_MOTORCOMM_PHY=y CONFIG_INPUT_MOUSEDEV=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -- 2.7.4 From 5c11e5a3bf84e547b55ced394519528da0cfe1d4 Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Fri, 7 Apr 2023 17:46:01 +0900 Subject: [PATCH 09/16] RISCV: configs: Fix to build-in clk_starfive When the clk operates as a module, defered occurs in ethernet, causing a problem in which eth0 and eth1 are switched. Modify the corresponding clk to built-in. Change-Id: I734b470294538a080aa02a01f0585c52a3d29acf Signed-off-by: Hoegeun Kwon --- arch/riscv/configs/tizen_vf2_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/riscv/configs/tizen_vf2_defconfig b/arch/riscv/configs/tizen_vf2_defconfig index c0dc85b..02e7378 100644 --- a/arch/riscv/configs/tizen_vf2_defconfig +++ b/arch/riscv/configs/tizen_vf2_defconfig @@ -187,6 +187,10 @@ CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_INPUT=y CONFIG_VIRTIO_MMIO=y +CONFIG_CLK_STARFIVE_JH7110_AON=y +CONFIG_CLK_STARFIVE_JH7110_STG=y +CONFIG_CLK_STARFIVE_JH7110_ISP=y +CONFIG_CLK_STARFIVE_JH7110_VOUT=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_CTRL=y CONFIG_RPMSG_VIRTIO=y -- 2.7.4 From b31cbbfa7c21b27610b850734b419469494948b7 Mon Sep 17 00:00:00 2001 From: "ke.zhu" Date: Fri, 14 Apr 2023 13:22:11 +0900 Subject: [PATCH 10/16] PCI: Add support plda pcie host controller driver Add support plda pcie host controller driver and device tree of starfive JH7110. This driver is from [1], and the imported patch list [2]. We modified pinctrl and clock in device-tree to fit kernel v6.1. [1] https://github.com/starfive-tech/linux [2] patch list from v5.15.y 9edf6749fde8 drivers: pci: Fix crash in rt-linux because of an uninitialized lock. 2757ebeaf399 drivers: pci: Add PHY settings in pcie host driver. d3b5483a84d4 drivers: pci: Set PCIe PCI standard configuration ID. 758a22e27bc6 dts: starfive: Modified PCIe pin setting for bring up PCIe USB hub. 1c1671ff173d drivers: pci: Support system pm no irq ops. d38610f5403c drivers: pci: Support runtime pm & release when found empty slot in probe. fecebab6581f drivers: pci: Support 64bit prefetchable MMIO range. 39cbd7746b45 driver: pci: Add extended reset time for better compatibility b1163a7a7de2 driver: pci: Fix kernel stuck caused by ASPM LTR 036944785f52 PCIe: plda: Add support for evb 38e23080fe16 PCI: plda: Add port1 support 157cf2806f0a PCI: plda: Fix kernel compile warnings 64e6d9f6f659 PCI: plda: Add syscon register config 48ed9fb901ff PCI: plda: Add pcie clk & rst 08c3249e8021 PCI: plda: Optimize plda pcie host driver 4ac91988fa82 1.Add plda pcie host controller driver. 2.Add PCIe host controller DT bingdings of starfive JH7110. Signed-off-by: ke.zhu Signed-off-by: mason.huo Signed-off-by: Kevin.xie Change-Id: I7e58f62026e69318c9305e5fea4d0a3d9e40e7e3 Signed-off-by: Hoegeun Kwon --- .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 91 ++ arch/riscv/boot/dts/starfive/jh7110.dtsi | 90 ++ drivers/pci/controller/Kconfig | 8 + drivers/pci/controller/Makefile | 1 + drivers/pci/controller/pcie-plda.c | 1061 ++++++++++++++++++++ 5 files changed, 1251 insertions(+) mode change 100644 => 100755 drivers/pci/controller/Kconfig mode change 100644 => 100755 drivers/pci/controller/Makefile create mode 100644 drivers/pci/controller/pcie-plda.c diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 752bb0b..3fbcdaa 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -319,6 +319,78 @@ slew-rate = <0>; }; }; + + pcie0_perst_default: pcie0-perst-default { + perst-pins { + pinmux = ; + }; + }; + + pcie0_perst_active: pcie0-perst-active { + perst-pins { + pinmux = ; + }; + }; + + pcie0_wake_default: pcie0-wake-default { + wake-pins { + pinmux = ; + }; + }; + + pcie0_clkreq_default: pcie0-clkreq-default { + clkreq-pins { + pinmux = ; + }; + }; + + pcie0_vbus_default: pcie0-vbus-default { + drive-vbus-pin { + pinmux = ; + }; + }; + + pcie1_perst_default: pcie1-perst-default { + perst-pins { + pinmux = ; + }; + }; + + pcie1_perst_active: pcie1-perst-active { + perst-pins { + pinmux = ; + }; + }; + + pcie1_wake_default: pcie1-wake-default { + wake-pins { + pinmux = ; + }; + }; + + pcie1_clkreq_default: pcie1-clkreq-default { + clkreq-pins { + pinmux = ; + }; + }; }; &uart0 { @@ -333,3 +405,22 @@ dr_mode = "peripheral"; }; }; + +&pcie0 { + pinctrl-names = "default", "perst-default", "perst-active"; + pinctrl-0 = <&pcie0_wake_default>, + <&pcie0_clkreq_default>, + <&pcie0_vbus_default>; + pinctrl-1 = <&pcie0_perst_default>; + pinctrl-2 = <&pcie0_perst_active>; + status = "okay"; +}; + +&pcie1 { + pinctrl-names = "default", "perst-default", "perst-active"; + pinctrl-0 = <&pcie1_wake_default>, + <&pcie1_clkreq_default>; + pinctrl-1 = <&pcie1_perst_default>; + pinctrl-2 = <&pcie1_perst_active>; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index 95abd5f..da70de9 100644 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -293,6 +293,16 @@ cache-unified; }; + phyctrl0: multi-phyctrl@10210000 { + compatible = "starfive,phyctrl"; + reg = <0x0 0x10210000 0x0 0x10000>; + }; + + phyctrl1: pcie1-phyctrl@10220000 { + compatible = "starfive,phyctrl"; + reg = <0x0 0x10220000 0x0 0x10000>; + }; + plic: interrupt-controller@c000000 { compatible = "starfive,jh7110-plic", "sifive,plic-1.0.0"; reg = <0x0 0xc000000 0x0 0x4000000>; @@ -922,5 +932,85 @@ #reset-cells = <1>; power-domains = <&pwrc JH7110_PD_VOUT>; }; + + pcie0: pcie@2B000000 { + compatible = "plda,pci-xpressrich3-axi"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + reg = <0x0 0x2B000000 0x0 0x1000000 + 0x9 0x40000000 0x0 0x10000000>; + reg-names = "reg", "config"; + device_type = "pci"; + starfive,stg-syscon = <&stg_syscon 0xc0 0xc4 0x130 0x1b8>; + starfive,phyctrl = <&phyctrl0 0x28 0x80>; + bus-range = <0x0 0xff>; + ranges = <0x82000000 0x0 0x30000000 0x0 0x30000000 0x0 0x08000000>, + <0xc3000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>; + msi-parent = <&plic>; + interrupts = <56>; + interrupt-controller; + interrupt-names = "msi"; + interrupt-parent = <&plic>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 0x1>, + <0x0 0x0 0x0 0x2 &plic 0x2>, + <0x0 0x0 0x0 0x3 &plic 0x3>, + <0x0 0x0 0x0 0x4 &plic 0x4>; + resets = <&stgcrg JH7110_STGRST_PCIE0_AXI_MST0>, + <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV0>, + <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV>, + <&stgcrg JH7110_STGRST_PCIE0_BRG>, + <&stgcrg JH7110_STGRST_PCIE0_CORE>, + <&stgcrg JH7110_STGRST_PCIE0_APB>; + reset-names = "rst_mst0", "rst_slv0", "rst_slv", + "rst_brg", "rst_core", "rst_apb"; + clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>, + <&stgcrg JH7110_STGCLK_PCIE0_TL>, + <&stgcrg JH7110_STGCLK_PCIE0_AXI_MST0>, + <&stgcrg JH7110_STGCLK_PCIE0_APB>; + clock-names = "noc_bus_stg_axi", "tl", "axi_mst0", "apb"; + status = "disabled"; + }; + + pcie1:pcie@2C000000 { + compatible = "plda,pci-xpressrich3-axi"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + reg = <0x0 0x2C000000 0x0 0x1000000 + 0x9 0xc0000000 0x0 0x10000000>; + reg-names = "reg", "config"; + device_type = "pci"; + starfive,stg-syscon = <&stg_syscon 0x270 0x274 0x2e0 0x368>; + starfive,phyctrl = <&phyctrl1 0x28 0x80>; + bus-range = <0x0 0xff>; + ranges = <0x82000000 0x0 0x38000000 0x0 0x38000000 0x0 0x08000000>, + <0xc3000000 0x9 0x80000000 0x9 0x80000000 0x0 0x40000000>; + msi-parent = <&plic>; + interrupts = <57>; + interrupt-controller; + interrupt-names = "msi"; + interrupt-parent = <&plic>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 0x1>, + <0x0 0x0 0x0 0x2 &plic 0x2>, + <0x0 0x0 0x0 0x3 &plic 0x3>, + <0x0 0x0 0x0 0x4 &plic 0x4>; + resets = <&stgcrg JH7110_STGRST_PCIE1_AXI_MST0>, + <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV0>, + <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV>, + <&stgcrg JH7110_STGRST_PCIE1_BRG>, + <&stgcrg JH7110_STGRST_PCIE1_CORE>, + <&stgcrg JH7110_STGRST_PCIE1_APB>; + reset-names = "rst_mst0", "rst_slv0", "rst_slv", + "rst_brg", "rst_core", "rst_apb"; + clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>, + <&stgcrg JH7110_STGCLK_PCIE1_TL>, + <&stgcrg JH7110_STGCLK_PCIE1_AXI_MST0>, + <&stgcrg JH7110_STGCLK_PCIE1_APB>; + clock-names = "noc_bus_stg_axi", "tl", "axi_mst0", "apb"; + status = "disabled"; + }; }; }; diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig old mode 100644 new mode 100755 index bfd9bac..be1fcb8 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -343,6 +343,14 @@ config PCIE_MT7621 help This selects a driver for the MediaTek MT7621 PCIe Controller. +config PCIE_PLDA + tristate "PLDA XpressRICH3-AXI PCIe controller" + depends on OF + select PCI_MSI_IRQ_DOMAIN + help + Say 'Y' here if you want kernel to support the PLDA XpressRICH3-AXI + (with ECAM disabled) PCIe Host driver. + source "drivers/pci/controller/dwc/Kconfig" source "drivers/pci/controller/mobiveil/Kconfig" source "drivers/pci/controller/cadence/Kconfig" diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile old mode 100644 new mode 100755 index 37c8663..edcc6d4 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o obj-$(CONFIG_PCIE_APPLE) += pcie-apple.o obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o +obj-$(CONFIG_PCIE_PLDA) += pcie-plda.o # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW obj-y += dwc/ diff --git a/drivers/pci/controller/pcie-plda.c b/drivers/pci/controller/pcie-plda.c new file mode 100644 index 0000000..3eb0487 --- /dev/null +++ b/drivers/pci/controller/pcie-plda.c @@ -0,0 +1,1061 @@ +/* + * PCIe host controller driver for Starfive JH7110 Soc. + * + * Based on pcie-altera.c, pcie-altera-msi.c. + * + * Copyright (C) Shanghai StarFive Technology Co., Ltd. + * + * Author: ke.zhu@starfivetech.com + * + * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../pci.h" + +#define PCIE_BASIC_STATUS 0x018 +#define PCIE_CFGNUM 0x140 +#define IMASK_LOCAL 0x180 +#define ISTATUS_LOCAL 0x184 +#define IMSI_ADDR 0x190 +#define ISTATUS_MSI 0x194 +#define CFG_SPACE 0x1000 +#define GEN_SETTINGS 0x80 +#define PCIE_PCI_IDS 0x9C +#define PCIE_WINROM 0xFC +#define PMSG_SUPPORT_RX 0x3F0 + +#define PCI_MISC 0xB4 + +#define PLDA_EP_ENABLE 0 +#define PLDA_RP_ENABLE 1 + +#define PLDA_LINK_UP 1 +#define PLDA_LINK_DOWN 0 + +#define IDS_REVISION_ID 0x02 +#define IDS_PCI_TO_PCI_BRIDGE 0x060400 +#define IDS_CLASS_CODE_SHIFT 8 + +#define PLDA_DATA_LINK_ACTIVE BIT(5) +#define PREF_MEM_WIN_64_SUPPORT BIT(3) +#define PMSG_LTR_SUPPORT BIT(2) +#define PDLA_LINK_SPEED_GEN2 BIT(12) +#define PLDA_FUNCTION_DIS BIT(15) +#define PLDA_FUNC_NUM 4 +#define PLDA_PHY_FUNC_SHIFT 9 +#define PHY_KVCO_FINE_TUNE_LEVEL 0x91 +#define PHY_KVCO_FINE_TUNE_SIGNALS 0xc + +#define XR3PCI_ATR_AXI4_SLV0 0x800 +#define XR3PCI_ATR_SRC_ADDR_LOW 0x0 +#define XR3PCI_ATR_SRC_ADDR_HIGH 0x4 +#define XR3PCI_ATR_TRSL_ADDR_LOW 0x8 +#define XR3PCI_ATR_TRSL_ADDR_HIGH 0xc +#define XR3PCI_ATR_TRSL_PARAM 0x10 +#define XR3PCI_ATR_TABLE_OFFSET 0x20 +#define XR3PCI_ATR_MAX_TABLE_NUM 8 + +#define XR3PCI_ATR_SRC_WIN_SIZE_SHIFT 1 +#define XR3PCI_ATR_SRC_ADDR_MASK 0xfffff000 +#define XR3PCI_ATR_TRSL_ADDR_MASK 0xfffff000 +#define XR3_PCI_ECAM_SIZE 28 +#define XR3PCI_ATR_TRSL_DIR BIT(22) +/* IDs used in the XR3PCI_ATR_TRSL_PARAM */ +#define XR3PCI_ATR_TRSLID_PCIE_MEMORY 0x0 +#define XR3PCI_ATR_TRSLID_PCIE_CONFIG 0x1 + +#define CFGNUM_DEVFN_SHIFT 0 +#define CFGNUM_BUS_SHIFT 8 +#define CFGNUM_BE_SHIFT 16 +#define CFGNUM_FBE_SHIFT 20 + +#define ECAM_BUS_SHIFT 20 +#define ECAM_DEV_SHIFT 15 +#define ECAM_FUNC_SHIFT 12 + +#define INT_AXI_POST_ERROR BIT(16) +#define INT_AXI_FETCH_ERROR BIT(17) +#define INT_AXI_DISCARD_ERROR BIT(18) +#define INT_PCIE_POST_ERROR BIT(20) +#define INT_PCIE_FETCH_ERROR BIT(21) +#define INT_PCIE_DISCARD_ERROR BIT(22) +#define INT_ERRORS (INT_AXI_POST_ERROR | INT_AXI_FETCH_ERROR | \ + INT_AXI_DISCARD_ERROR | INT_PCIE_POST_ERROR | \ + INT_PCIE_FETCH_ERROR | INT_PCIE_DISCARD_ERROR) + +#define INTA_OFFSET 24 +#define INTA BIT(24) +#define INTB BIT(25) +#define INTC BIT(26) +#define INTD BIT(27) +#define INT_MSI BIT(28) +#define INT_INTX_MASK (INTA | INTB | INTC | INTD) +#define INT_MASK (INT_INTX_MASK | INT_MSI | INT_ERRORS) + +#define INT_PCI_MSI_NR 32 +#define LINK_UP_MASK 0xff + +#define PERST_DELAY_US 1000 + +/* system control */ +#define STG_SYSCON_K_RP_NEP_SHIFT 0x8 +#define STG_SYSCON_K_RP_NEP_MASK 0x100 +#define STG_SYSCON_AXI4_SLVL_ARFUNC_MASK 0x7FFF00 +#define STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT 0x8 +#define STG_SYSCON_AXI4_SLVL_AWFUNC_MASK 0x7FFF +#define STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT 0x0 +#define STG_SYSCON_CLKREQ_SHIFT 0x16 +#define STG_SYSCON_CLKREQ_MASK 0x400000 +#define STG_SYSCON_CKREF_SRC_SHIFT 0x12 +#define STG_SYSCON_CKREF_SRC_MASK 0xC0000 + +#define PCI_DEV(d) (((d) >> 3) & 0x1f) + +/* MSI information */ +struct plda_msi { + DECLARE_BITMAP(used, INT_PCI_MSI_NR); + struct irq_domain *msi_domain; + struct irq_domain *inner_domain; + /* Protect bitmap variable */ + struct mutex lock; +}; + +struct plda_pcie { + struct platform_device *pdev; + void __iomem *reg_base; + void __iomem *config_base; + struct resource *cfg_res; + struct regmap *reg_syscon; + struct regmap *reg_phyctrl; + u32 stg_arfun; + u32 stg_awfun; + u32 stg_rp_nep; + u32 stg_lnksta; + u32 phy_kvco_level; + u32 phy_kvco_tune_signals; + int irq; + struct irq_domain *legacy_irq_domain; + struct pci_host_bridge *bridge; + struct plda_msi msi; + struct reset_control *resets; + struct clk_bulk_data *clks; + int num_clks; + int atr_table_num; + struct pinctrl *pinctrl; + struct pinctrl_state *perst_state_def; + struct pinctrl_state *perst_state_active; +}; + +static inline void plda_writel(struct plda_pcie *pcie, const u32 value, + const u32 reg) +{ + writel_relaxed(value, pcie->reg_base + reg); +} + +static inline u32 plda_readl(struct plda_pcie *pcie, const u32 reg) +{ + return readl_relaxed(pcie->reg_base + reg); +} + +static bool plda_pcie_hide_rc_bar(struct pci_bus *bus, unsigned int devfn, + int offset) +{ + if (pci_is_root_bus(bus) && (devfn == 0) && + (offset == PCI_BASE_ADDRESS_0)) + return true; + + return false; +} + +static int _plda_pcie_config_read(struct plda_pcie *pcie, unsigned char busno, + unsigned int devfn, int where, int size, + u32 *value) +{ + void __iomem *addr; + + addr = pcie->config_base; + addr += (busno << ECAM_BUS_SHIFT); + addr += (PCI_DEV(devfn) << ECAM_DEV_SHIFT); + addr += (PCI_FUNC(devfn) << ECAM_FUNC_SHIFT); + addr += where; + + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + switch (size) { + case 1: + *(unsigned char *)value = readb(addr); + break; + case 2: + *(unsigned short *)value = readw(addr); + break; + case 4: + *(unsigned int *)value = readl(addr); + break; + default: + return PCIBIOS_SET_FAILED; + } + + return PCIBIOS_SUCCESSFUL; +} + +int _plda_pcie_config_write(struct plda_pcie *pcie, unsigned char busno, + unsigned int devfn, int where, int size, u32 value) +{ + void __iomem *addr; + + addr = pcie->config_base; + addr += (busno << ECAM_BUS_SHIFT); + addr += (PCI_DEV(devfn) << ECAM_DEV_SHIFT); + addr += (PCI_FUNC(devfn) << ECAM_FUNC_SHIFT); + addr += where; + + if (!addr) + return PCIBIOS_DEVICE_NOT_FOUND; + + switch (size) { + case 1: + writeb(value, addr); + break; + case 2: + writew(value, addr); + break; + case 4: + writel(value, addr); + break; + default: + return PCIBIOS_SET_FAILED; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int plda_pcie_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *value) +{ + struct plda_pcie *pcie = bus->sysdata; + + return _plda_pcie_config_read(pcie, bus->number, devfn, where, size, + value); +} + +int plda_pcie_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 value) +{ + struct plda_pcie *pcie = bus->sysdata; + + if (plda_pcie_hide_rc_bar(bus, devfn, where)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + return _plda_pcie_config_write(pcie, bus->number, devfn, where, size, + value); +} + +static void plda_pcie_handle_msi_irq(struct plda_pcie *pcie) +{ + struct plda_msi *msi = &pcie->msi; + u32 bit; + u32 virq; + unsigned long status = plda_readl(pcie, ISTATUS_MSI); + + for_each_set_bit(bit, &status, INT_PCI_MSI_NR) { + /* Clear interrupts */ + plda_writel(pcie, 1 << bit, ISTATUS_MSI); + + virq = irq_find_mapping(msi->inner_domain, bit); + if (virq) { + if (test_bit(bit, msi->used)) + generic_handle_irq(virq); + else + dev_err(&pcie->pdev->dev, + "Unhandled MSI, MSI%d virq %d\n", bit, + virq); + } else + dev_err(&pcie->pdev->dev, "Unexpected MSI, MSI%d\n", + bit); + + } + plda_writel(pcie, INT_MSI, ISTATUS_LOCAL); +} + +static void plda_pcie_handle_intx_irq(struct plda_pcie *pcie, + unsigned long status) +{ + u32 bit; + u32 virq; + + status >>= INTA_OFFSET; + + for_each_set_bit(bit, &status, PCI_NUM_INTX) { + /* Clear interrupts */ + plda_writel(pcie, 1 << (bit + INTA_OFFSET), ISTATUS_LOCAL); + + virq = irq_find_mapping(pcie->legacy_irq_domain, bit); + if (virq) + generic_handle_irq(virq); + else + dev_err(&pcie->pdev->dev, + "plda_pcie_handle_intx_irq unexpected IRQ, INT%d\n", bit); + } +} + +static void plda_pcie_handle_errors_irq(struct plda_pcie *pcie, u32 status) +{ + if (status & INT_AXI_POST_ERROR) + dev_err(&pcie->pdev->dev, "AXI post error\n"); + if (status & INT_AXI_FETCH_ERROR) + dev_err(&pcie->pdev->dev, "AXI fetch error\n"); + if (status & INT_AXI_DISCARD_ERROR) + dev_err(&pcie->pdev->dev, "AXI discard error\n"); + if (status & INT_PCIE_POST_ERROR) + dev_err(&pcie->pdev->dev, "PCIe post error\n"); + if (status & INT_PCIE_FETCH_ERROR) + dev_err(&pcie->pdev->dev, "PCIe fetch error\n"); + if (status & INT_PCIE_DISCARD_ERROR) + dev_err(&pcie->pdev->dev, "PCIe discard error\n"); + + plda_writel(pcie, INT_ERRORS, ISTATUS_LOCAL); +} + +static void plda_pcie_isr(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct plda_pcie *pcie; + u32 status; + + chained_irq_enter(chip, desc); + pcie = irq_desc_get_handler_data(desc); + + status = plda_readl(pcie, ISTATUS_LOCAL); + while ((status = (plda_readl(pcie, ISTATUS_LOCAL) & INT_MASK))) { + if (status & INT_INTX_MASK) + plda_pcie_handle_intx_irq(pcie, status); + + if (status & INT_MSI) + plda_pcie_handle_msi_irq(pcie); + + if (status & INT_ERRORS) + plda_pcie_handle_errors_irq(pcie, status); + } + + chained_irq_exit(chip, desc); +} + +#ifdef CONFIG_PCI_MSI +static struct irq_chip plda_msi_irq_chip = { + .name = "PLDA PCIe MSI", + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, +}; + +static struct msi_domain_info plda_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_PCI_MSIX), + .chip = &plda_msi_irq_chip, +}; +#endif + +static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) +{ + struct plda_pcie *pcie = irq_data_get_irq_chip_data(data); + phys_addr_t msi_addr = plda_readl(pcie, IMSI_ADDR); + + msg->address_lo = lower_32_bits(msi_addr); + msg->address_hi = upper_32_bits(msi_addr); + msg->data = data->hwirq; + + dev_info(&pcie->pdev->dev, "msi#%d address_hi %#x address_lo %#x\n", + (int)data->hwirq, msg->address_hi, msg->address_lo); +} + +static int plda_msi_set_affinity(struct irq_data *irq_data, + const struct cpumask *mask, bool force) +{ + return -EINVAL; +} + +static struct irq_chip plda_irq_chip = { + .name = "PLDA MSI", + .irq_compose_msi_msg = plda_compose_msi_msg, + .irq_set_affinity = plda_msi_set_affinity, +}; + +static int plda_msi_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *args) +{ + struct plda_pcie *pcie = domain->host_data; + struct plda_msi *msi = &pcie->msi; + int bit; + + WARN_ON(nr_irqs != 1); + mutex_lock(&msi->lock); + + bit = find_first_zero_bit(msi->used, INT_PCI_MSI_NR); + if (bit >= INT_PCI_MSI_NR) { + mutex_unlock(&msi->lock); + return -ENOSPC; + } + + set_bit(bit, msi->used); + + irq_domain_set_info(domain, virq, bit, &plda_irq_chip, + domain->host_data, handle_simple_irq, + NULL, NULL); + mutex_unlock(&msi->lock); + + return 0; +} + +static void plda_msi_free(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs) +{ + struct irq_data *data = irq_domain_get_irq_data(domain, virq); + struct plda_pcie *pcie = irq_data_get_irq_chip_data(data); + struct plda_msi *msi = &pcie->msi; + + mutex_lock(&msi->lock); + + if (!test_bit(data->hwirq, msi->used)) + dev_err(&pcie->pdev->dev, "Trying to free unused MSI#%lu\n", + data->hwirq); + else + __clear_bit(data->hwirq, msi->used); + + mutex_unlock(&msi->lock); +} + +static const struct irq_domain_ops dev_msi_domain_ops = { + .alloc = plda_msi_alloc, + .free = plda_msi_free, +}; + +static void plda_msi_free_irq_domain(struct plda_pcie *pcie) +{ +#ifdef CONFIG_PCI_MSI + struct plda_msi *msi = &pcie->msi; + u32 irq; + int i; + + for (i = 0; i < INT_PCI_MSI_NR; i++) { + irq = irq_find_mapping(msi->inner_domain, i); + if (irq > 0) + irq_dispose_mapping(irq); + } + + if (msi->msi_domain) + irq_domain_remove(msi->msi_domain); + + if (msi->inner_domain) + irq_domain_remove(msi->inner_domain); +#endif +} + +static void plda_pcie_free_irq_domain(struct plda_pcie *pcie) +{ + int i; + u32 irq; + + /* Disable all interrupts */ + plda_writel(pcie, 0, IMASK_LOCAL); + + if (pcie->legacy_irq_domain) { + for (i = 0; i < PCI_NUM_INTX; i++) { + irq = irq_find_mapping(pcie->legacy_irq_domain, i); + if (irq > 0) + irq_dispose_mapping(irq); + } + irq_domain_remove(pcie->legacy_irq_domain); + } + + if (pci_msi_enabled()) + plda_msi_free_irq_domain(pcie); + irq_set_chained_handler_and_data(pcie->irq, NULL, NULL); +} + +static int plda_pcie_init_msi_irq_domain(struct plda_pcie *pcie) +{ +#ifdef CONFIG_PCI_MSI + struct fwnode_handle *fwn = of_node_to_fwnode(pcie->pdev->dev.of_node); + struct plda_msi *msi = &pcie->msi; + + msi->inner_domain = irq_domain_add_linear(NULL, INT_PCI_MSI_NR, + &dev_msi_domain_ops, pcie); + if (!msi->inner_domain) { + dev_err(&pcie->pdev->dev, "Failed to create dev IRQ domain\n"); + return -ENOMEM; + } + msi->msi_domain = pci_msi_create_irq_domain(fwn, &plda_msi_domain_info, + msi->inner_domain); + if (!msi->msi_domain) { + dev_err(&pcie->pdev->dev, "Failed to create msi IRQ domain\n"); + irq_domain_remove(msi->inner_domain); + return -ENOMEM; + } +#endif + return 0; +} + +static int plda_pcie_enable_msi(struct plda_pcie *pcie, struct pci_bus *bus) +{ + struct plda_msi *msi = &pcie->msi; + u32 reg; + + mutex_init(&msi->lock); + + /* Enable MSI */ + reg = plda_readl(pcie, IMASK_LOCAL); + reg |= INT_MSI; + plda_writel(pcie, reg, IMASK_LOCAL); + return 0; +} + +static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); + irq_set_chip_data(irq, domain->host_data); + + return 0; +} + +static const struct irq_domain_ops intx_domain_ops = { + .map = plda_pcie_intx_map, + .xlate = pci_irqd_intx_xlate, +}; + +static int plda_pcie_init_irq_domain(struct plda_pcie *pcie) +{ + struct device *dev = &pcie->pdev->dev; + struct device_node *node = dev->of_node; + int ret; + + if (pci_msi_enabled()) { + ret = plda_pcie_init_msi_irq_domain(pcie); + if (ret != 0) + return -ENOMEM; + } + + /* Setup INTx */ + pcie->legacy_irq_domain = irq_domain_add_linear(node, PCI_NUM_INTX, + &intx_domain_ops, pcie); + + if (!pcie->legacy_irq_domain) { + dev_err(dev, "Failed to get a INTx IRQ domain\n"); + return -ENOMEM; + } + + irq_set_chained_handler_and_data(pcie->irq, plda_pcie_isr, pcie); + return 0; +} + +static int plda_pcie_parse_dt(struct plda_pcie *pcie) +{ + struct resource *reg_res; + struct platform_device *pdev = pcie->pdev; + struct of_phandle_args syscon_args, phyctrl_args; + int ret; + + reg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); + if (!reg_res) { + dev_err(&pdev->dev, "Missing required reg address range\n"); + return -ENODEV; + } + + pcie->reg_base = devm_ioremap_resource(&pdev->dev, reg_res); + if (IS_ERR(pcie->reg_base)) { + dev_err(&pdev->dev, "Failed to map reg memory\n"); + return PTR_ERR(pcie->reg_base); + } + + pcie->cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); + if (!pcie->cfg_res) { + dev_err(&pdev->dev, "Missing required config address range"); + return -ENODEV; + } + + pcie->config_base = devm_ioremap_resource(&pdev->dev, pcie->cfg_res); + if (IS_ERR(pcie->config_base)){ + dev_err(&pdev->dev, "Failed to map config memory\n"); + return PTR_ERR(pcie->config_base); + } + + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "starfive,phyctrl", 2, 0, &phyctrl_args); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to parse starfive,phyctrl\n"); + return -EINVAL; + } + + if (!of_device_is_compatible(phyctrl_args.np, "starfive,phyctrl")) + return -EINVAL; + pcie->reg_phyctrl = device_node_to_regmap(phyctrl_args.np); + of_node_put(phyctrl_args.np); + if (IS_ERR(pcie->reg_phyctrl)) + return PTR_ERR(pcie->reg_phyctrl); + + pcie->phy_kvco_level = phyctrl_args.args[0]; + pcie->phy_kvco_tune_signals = phyctrl_args.args[1]; + + pcie->irq = platform_get_irq(pdev, 0); + if (pcie->irq <= 0) { + dev_err(&pdev->dev, "Failed to get IRQ: %d\n", pcie->irq); + return -EINVAL; + } + + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "starfive,stg-syscon", 4, 0, &syscon_args); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to parse starfive,stg-syscon\n"); + return -EINVAL; + } + + pcie->reg_syscon = syscon_node_to_regmap(syscon_args.np); + of_node_put(syscon_args.np); + if (IS_ERR(pcie->reg_syscon)) + return PTR_ERR(pcie->reg_syscon); + + pcie->stg_arfun = syscon_args.args[0]; + pcie->stg_awfun = syscon_args.args[1]; + pcie->stg_rp_nep = syscon_args.args[2]; + pcie->stg_lnksta = syscon_args.args[3]; + + /* Clear all interrupts */ + plda_writel(pcie, 0xffffffff, ISTATUS_LOCAL); + plda_writel(pcie, INT_INTX_MASK | INT_ERRORS, IMASK_LOCAL); + + return 0; +} + +static struct pci_ops plda_pcie_ops = { + .read = plda_pcie_config_read, + .write = plda_pcie_config_write, +}; + +void plda_set_atr_entry(struct plda_pcie *pcie, phys_addr_t src_addr, + phys_addr_t trsl_addr, size_t window_size, + int trsl_param) +{ + void __iomem *base = + pcie->reg_base + XR3PCI_ATR_AXI4_SLV0; + + /* Support AXI4 Slave 0 Address Translation Tables 0-7. */ + if (pcie->atr_table_num >= XR3PCI_ATR_MAX_TABLE_NUM) + pcie->atr_table_num = XR3PCI_ATR_MAX_TABLE_NUM - 1; + base += XR3PCI_ATR_TABLE_OFFSET * pcie->atr_table_num; + pcie->atr_table_num++; + + /* X3PCI_ATR_SRC_ADDR_LOW: + * - bit 0: enable entry, + * - bits 1-6: ATR window size: total size in bytes: 2^(ATR_WSIZE + 1) + * - bits 7-11: reserved + * - bits 12-31: start of source address + */ + writel((lower_32_bits(src_addr) & XR3PCI_ATR_SRC_ADDR_MASK) | + (fls(window_size) - 1) << XR3PCI_ATR_SRC_WIN_SIZE_SHIFT | 1, + base + XR3PCI_ATR_SRC_ADDR_LOW); + writel(upper_32_bits(src_addr), base + XR3PCI_ATR_SRC_ADDR_HIGH); + writel((lower_32_bits(trsl_addr) & XR3PCI_ATR_TRSL_ADDR_MASK), + base + XR3PCI_ATR_TRSL_ADDR_LOW); + writel(upper_32_bits(trsl_addr), base + XR3PCI_ATR_TRSL_ADDR_HIGH); + writel(trsl_param, base + XR3PCI_ATR_TRSL_PARAM); + + pr_info("ATR entry: 0x%010llx %s 0x%010llx [0x%010llx] (param: 0x%06x)\n", + src_addr, (trsl_param & XR3PCI_ATR_TRSL_DIR) ? "<-" : "->", + trsl_addr, (u64)window_size, trsl_param); +} + +static int plda_pcie_setup_windows(struct plda_pcie *pcie) +{ + struct pci_host_bridge *bridge = pcie->bridge; + struct resource_entry *entry; + u64 pci_addr; + + resource_list_for_each_entry(entry, &bridge->windows) { + if (resource_type(entry->res) == IORESOURCE_MEM) { + pci_addr = entry->res->start - entry->offset; + plda_set_atr_entry(pcie, + entry->res->start, pci_addr, + resource_size(entry->res), + XR3PCI_ATR_TRSLID_PCIE_MEMORY); + } + } + + return 0; +} + +static int plda_clk_rst_init(struct plda_pcie *pcie) +{ + int ret; + struct device *dev = &pcie->pdev->dev; + + pcie->num_clks = devm_clk_bulk_get_all(dev, &pcie->clks); + if (pcie->num_clks < 0) { + dev_err(dev, "Failed to get pcie clocks\n"); + ret = -ENODEV; + goto exit; + } + ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks); + if (ret) { + dev_err(&pcie->pdev->dev, "Failed to enable clocks\n"); + goto exit; + } + + pcie->resets = devm_reset_control_array_get_exclusive(dev); + if (IS_ERR(pcie->resets)) { + ret = PTR_ERR(pcie->resets); + dev_err(dev, "Failed to get pcie resets"); + goto err_clk_init; + } + ret = reset_control_deassert(pcie->resets); + goto exit; + +err_clk_init: + clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); +exit: + return ret; +} + +static void plda_clk_rst_deinit(struct plda_pcie *pcie) +{ + reset_control_assert(pcie->resets); + clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); +} + +int plda_pinctrl_init(struct plda_pcie *pcie) +{ + struct device *dev = &pcie->pdev->dev; + + pcie->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(pcie->pinctrl)) { + dev_err(dev, "Getting pinctrl handle failed\n"); + return -EINVAL; + } + + pcie->perst_state_def + = pinctrl_lookup_state(pcie->pinctrl, "perst-default"); + if (IS_ERR_OR_NULL(pcie->perst_state_def)) { + dev_err(dev, "Failed to get the perst-default pinctrl handle\n"); + return -EINVAL; + } + + pcie->perst_state_active + = pinctrl_lookup_state(pcie->pinctrl, "perst-active"); + if (IS_ERR_OR_NULL(pcie->perst_state_active)) { + dev_err(dev, "Failed to get the perst-active pinctrl handle\n"); + return -EINVAL; + } + + return 0; +} + +static void plda_pcie_hw_init(struct plda_pcie *pcie) +{ + unsigned int value; + int i, ret; + struct device *dev = &pcie->pdev->dev; + + if (pcie->perst_state_active) { + ret = pinctrl_select_state(pcie->pinctrl, pcie->perst_state_active); + if (ret) + dev_err(dev, "Cannot set reset pin to low\n"); + } + + /* Disable physical functions except #0 */ + for (i = 1; i < PLDA_FUNC_NUM; i++) { + regmap_update_bits(pcie->reg_syscon, + pcie->stg_arfun, + STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, + (i << PLDA_PHY_FUNC_SHIFT) << + STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT); + regmap_update_bits(pcie->reg_syscon, + pcie->stg_awfun, + STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, + (i << PLDA_PHY_FUNC_SHIFT) << + STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT); + + value = readl(pcie->reg_base + PCI_MISC); + value |= PLDA_FUNCTION_DIS; + writel(value, pcie->reg_base + PCI_MISC); + } + regmap_update_bits(pcie->reg_syscon, + pcie->stg_arfun, + STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, + 0 << STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT); + regmap_update_bits(pcie->reg_syscon, + pcie->stg_awfun, + STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, + 0 << STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT); + + /* PCIe Multi-PHY PLL KVCO Gain fine tune settings: */ + regmap_write(pcie->reg_phyctrl, pcie->phy_kvco_level, + PHY_KVCO_FINE_TUNE_LEVEL); + regmap_write(pcie->reg_phyctrl, pcie->phy_kvco_tune_signals, + PHY_KVCO_FINE_TUNE_SIGNALS); + + /* Enable root port*/ + value = readl(pcie->reg_base + GEN_SETTINGS); + value |= PLDA_RP_ENABLE; + writel(value, pcie->reg_base + GEN_SETTINGS); + + /* PCIe PCI Standard Configuration Identification Settings. */ + value = (IDS_PCI_TO_PCI_BRIDGE << IDS_CLASS_CODE_SHIFT) | IDS_REVISION_ID; + writel(value, pcie->reg_base + PCIE_PCI_IDS); + + /* The LTR message forwarding of PCIe Message Reception was set by core + * as default, but the forward id & addr are also need to be reset. + * If we do not disable LTR message forwarding here, or set a legal + * forwarding address, the kernel will get stuck after this driver probe. + * To workaround, disable the LTR message forwarding support on + * PCIe Message Reception. + */ + value = readl(pcie->reg_base + PMSG_SUPPORT_RX); + value &= ~PMSG_LTR_SUPPORT; + writel(value, pcie->reg_base + PMSG_SUPPORT_RX); + + /* Prefetchable memory window 64-bit addressing support */ + value = readl(pcie->reg_base + PCIE_WINROM); + value |= PREF_MEM_WIN_64_SUPPORT; + writel(value, pcie->reg_base + PCIE_WINROM); + + /* As the two host bridges in JH7110 soc have the same default + * address translation table, this cause the second root port can't + * access it's host bridge config space correctly. + * To workaround, config the ATR of host bridge config space by SW. + */ + plda_set_atr_entry(pcie, + pcie->cfg_res->start, 0, + 1 << XR3_PCI_ECAM_SIZE, + XR3PCI_ATR_TRSLID_PCIE_CONFIG); + + plda_pcie_setup_windows(pcie); + + /* Ensure that PERST has been asserted for at least 100 ms */ + msleep(300); + if (pcie->perst_state_def) { + ret = pinctrl_select_state(pcie->pinctrl, pcie->perst_state_def); + if (ret) + dev_err(dev, "Cannot set reset pin to high\n"); + } +} + +static int plda_pcie_is_link_up(struct plda_pcie *pcie) +{ + struct device *dev = &pcie->pdev->dev; + int ret; + u32 stg_reg_val; + + /* 100ms timeout value should be enough for Gen1/2 training */ + ret = regmap_read_poll_timeout(pcie->reg_syscon, + pcie->stg_lnksta, + stg_reg_val, + stg_reg_val & PLDA_DATA_LINK_ACTIVE, + 10 * 1000, 100 * 1000); + + /* If the link is down (no device in slot), then exit. */ + if (ret == -ETIMEDOUT) { + dev_info(dev, "Port link down, exit.\n"); + return PLDA_LINK_DOWN; + } else if (ret == 0) { + dev_info(dev, "Port link up.\n"); + return PLDA_LINK_UP; + } + + dev_warn(dev, "Read stg_linksta failed.\n"); + return ret; +} + +static int plda_pcie_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct plda_pcie *pcie; + struct pci_bus *bus; + struct pci_host_bridge *bridge; + int ret; + + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->pdev = pdev; + pcie->atr_table_num = 0; + + ret = plda_pcie_parse_dt(pcie); + if (ret) { + dev_err(&pdev->dev, "Parsing DT failed\n"); + return ret; + } + + platform_set_drvdata(pdev, pcie); + + plda_pinctrl_init(pcie); + if (ret) { + dev_err(&pdev->dev, "Init pinctrl failed\n"); + return ret; + } + + regmap_update_bits(pcie->reg_syscon, + pcie->stg_rp_nep, + STG_SYSCON_K_RP_NEP_MASK, + 1 << STG_SYSCON_K_RP_NEP_SHIFT); + + regmap_update_bits(pcie->reg_syscon, + pcie->stg_awfun, + STG_SYSCON_CKREF_SRC_MASK, + 2 << STG_SYSCON_CKREF_SRC_SHIFT); + + regmap_update_bits(pcie->reg_syscon, + pcie->stg_awfun, + STG_SYSCON_CLKREQ_MASK, + 1 << STG_SYSCON_CLKREQ_SHIFT); + + ret = plda_clk_rst_init(pcie); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to init pcie clk reset: %d\n", ret); + goto exit; + } + + ret = plda_pcie_init_irq_domain(pcie); + if (ret) { + dev_err(&pdev->dev, "Failed creating IRQ Domain\n"); + goto exit; + } + + bridge = devm_pci_alloc_host_bridge(dev, 0); + if (!bridge) { + ret = -ENOMEM; + goto exit; + } + + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + /* Set default bus ops */ + bridge->ops = &plda_pcie_ops; + bridge->sysdata = pcie; + pcie->bridge = bridge; + + plda_pcie_hw_init(pcie); + + if (plda_pcie_is_link_up(pcie) == PLDA_LINK_DOWN) + goto release; + + if (IS_ENABLED(CONFIG_PCI_MSI)) { + ret = plda_pcie_enable_msi(pcie, bus); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable MSI support: %d\n", ret); + goto release; + } + } + + ret = pci_host_probe(bridge); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to pci host probe: %d\n", ret); + goto release; + } + +exit: + return ret; + +release: + plda_clk_rst_deinit(pcie); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + pci_free_host_bridge(pcie->bridge); + devm_kfree(&pdev->dev, pcie); + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int plda_pcie_remove(struct platform_device *pdev) +{ + struct plda_pcie *pcie = platform_get_drvdata(pdev); + + plda_pcie_free_irq_domain(pcie); + plda_clk_rst_deinit(pcie); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int __maybe_unused plda_pcie_suspend_noirq(struct device *dev) +{ + struct plda_pcie *pcie = dev_get_drvdata(dev); + + if (!pcie) + return 0; + + clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); + + return 0; +} + +static int __maybe_unused plda_pcie_resume_noirq(struct device *dev) +{ + struct plda_pcie *pcie = dev_get_drvdata(dev); + int ret; + + if (!pcie) + return 0; + + ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks); + if (ret) + dev_err(dev, "Failed to enable clocks\n"); + + return ret; +} + +static const struct dev_pm_ops plda_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(plda_pcie_suspend_noirq, + plda_pcie_resume_noirq) +}; +#endif + +static const struct of_device_id plda_pcie_of_match[] = { + { .compatible = "plda,pci-xpressrich3-axi"}, + { }, +}; +MODULE_DEVICE_TABLE(of, plda_pcie_of_match); + +static struct platform_driver plda_pcie_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = of_match_ptr(plda_pcie_of_match), +#ifdef CONFIG_PM_SLEEP + .pm = &plda_pcie_pm_ops, +#endif + }, + .probe = plda_pcie_probe, + .remove = plda_pcie_remove, +}; +module_platform_driver(plda_pcie_driver); + +MODULE_DESCRIPTION("StarFive JH7110 PCIe host driver"); +MODULE_AUTHOR("ke.zhu "); +MODULE_AUTHOR("Mason Huo "); +MODULE_LICENSE("GPL v2"); -- 2.7.4 From c8cfb82195d6e397017aa28e3e347766402e43ac Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Fri, 14 Apr 2023 13:27:13 +0900 Subject: [PATCH 11/16] RISCV: configs: Enable pcie plda defconfig Enable CONFIG_PCIE_PLDA defconfig for plda pcie host controller driver. Change-Id: Ie09fdf5761d4b5a4a758b69c91f7f7100e820f0f Signed-off-by: Hoegeun Kwon --- arch/riscv/configs/tizen_vf2_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/configs/tizen_vf2_defconfig b/arch/riscv/configs/tizen_vf2_defconfig index 02e7378..6a90238 100644 --- a/arch/riscv/configs/tizen_vf2_defconfig +++ b/arch/riscv/configs/tizen_vf2_defconfig @@ -100,6 +100,7 @@ CONFIG_PCI=y CONFIG_PCIEPORTBUS=y CONFIG_PCI_HOST_GENERIC=y CONFIG_PCIE_XILINX=y +CONFIG_PCIE_PLDA=y CONFIG_PCIE_FU740=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -- 2.7.4 From 93d6e1e743901c1abde97f8de0aa60b4655bd0e1 Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Thu, 13 Apr 2023 13:33:52 +0900 Subject: [PATCH 12/16] RISCV: configs: Enable usb wireless defconfig Enable usb wireless defconfig and realtek module. Change-Id: Id186de5d13078a11b7142afceb881ade5da2683d Signed-off-by: Hoegeun Kwon --- arch/riscv/configs/tizen_vf2_defconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/riscv/configs/tizen_vf2_defconfig b/arch/riscv/configs/tizen_vf2_defconfig index 6a90238..a59b4e9 100644 --- a/arch/riscv/configs/tizen_vf2_defconfig +++ b/arch/riscv/configs/tizen_vf2_defconfig @@ -94,6 +94,7 @@ CONFIG_CGROUP_NET_PRIO=y CONFIG_CFG80211=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=y CONFIG_NET_9P=y CONFIG_NET_9P_VIRTIO=y CONFIG_PCI=y @@ -136,6 +137,10 @@ CONFIG_STMMAC_ETH=y CONFIG_DWMAC_STARFIVE=y CONFIG_MICROSEMI_PHY=y CONFIG_MOTORCOMM_PHY=y +CONFIG_USB_RTL8152=y +CONFIG_USB_LAN78XX=y +CONFIG_USB_USBNET=y +CONFIG_RTL8192CU=m CONFIG_INPUT_MOUSEDEV=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -- 2.7.4 From 86a52f26d44ec8c20ec20621ed0b573f462a563a Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Thu, 13 Apr 2023 20:43:26 +0900 Subject: [PATCH 13/16] RISCV: configs: Enable usb BT defconfig Enable usb BT defconfig. Change-Id: Ia751e369e4a6aad13c730c7e1f5129f347877b6b Signed-off-by: Hoegeun Kwon --- arch/riscv/configs/tizen_vf2_defconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/riscv/configs/tizen_vf2_defconfig b/arch/riscv/configs/tizen_vf2_defconfig index a59b4e9..a9694d2 100644 --- a/arch/riscv/configs/tizen_vf2_defconfig +++ b/arch/riscv/configs/tizen_vf2_defconfig @@ -87,14 +87,27 @@ CONFIG_IP6_NF_MANGLE=m CONFIG_BRIDGE=y CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_VLAN_8021Q=y +CONFIG_6LOWPAN=y CONFIG_NET_SCHED=y CONFIG_NET_CLS_CGROUP=m CONFIG_NETLINK_DIAG=y CONFIG_CGROUP_NET_PRIO=y +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y +CONFIG_BT_6LOWPAN=y +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIBCM203X=m CONFIG_CFG80211=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_CFG80211_WEXT=y CONFIG_MAC80211=y +CONFIG_RFKILL=y CONFIG_NET_9P=y CONFIG_NET_9P_VIRTIO=y CONFIG_PCI=y -- 2.7.4 From 2ca6b2ad5466c8e656004f23e62ba86eeea45f9e Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Mon, 17 Apr 2023 15:18:41 +0900 Subject: [PATCH 14/16] Revert "RISCV: configs: Enable pcie plda defconfig" This reverts commit c8cfb82195d6e397017aa28e3e347766402e43ac. Revert this patch for use the pcie driver from upstream branch of starfive-tech/linux. Change-Id: I2769cb8e90bd8430508bda95762f39ac21fe0580 Signed-off-by: Hoegeun Kwon --- arch/riscv/configs/tizen_vf2_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/riscv/configs/tizen_vf2_defconfig b/arch/riscv/configs/tizen_vf2_defconfig index a9694d2..87f1f64 100644 --- a/arch/riscv/configs/tizen_vf2_defconfig +++ b/arch/riscv/configs/tizen_vf2_defconfig @@ -114,7 +114,6 @@ CONFIG_PCI=y CONFIG_PCIEPORTBUS=y CONFIG_PCI_HOST_GENERIC=y CONFIG_PCIE_XILINX=y -CONFIG_PCIE_PLDA=y CONFIG_PCIE_FU740=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y -- 2.7.4 From 14d237f47641896175a1f5c5d87a83f4e8d72981 Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Mon, 17 Apr 2023 15:18:48 +0900 Subject: [PATCH 15/16] Revert "PCI: Add support plda pcie host controller driver" This reverts commit b31cbbfa7c21b27610b850734b419469494948b7. Revert this patch for use the pcie driver from upstream branch of starfive-tech/linux. Change-Id: I7617faba6679d0988140b22bda05c2cfd2a8d4cf Signed-off-by: Hoegeun Kwon --- .../dts/starfive/jh7110-starfive-visionfive-2.dtsi | 91 -- arch/riscv/boot/dts/starfive/jh7110.dtsi | 90 -- drivers/pci/controller/Kconfig | 8 - drivers/pci/controller/Makefile | 1 - drivers/pci/controller/pcie-plda.c | 1061 -------------------- 5 files changed, 1251 deletions(-) mode change 100755 => 100644 drivers/pci/controller/Kconfig mode change 100755 => 100644 drivers/pci/controller/Makefile delete mode 100644 drivers/pci/controller/pcie-plda.c diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 3fbcdaa..752bb0b 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -319,78 +319,6 @@ slew-rate = <0>; }; }; - - pcie0_perst_default: pcie0-perst-default { - perst-pins { - pinmux = ; - }; - }; - - pcie0_perst_active: pcie0-perst-active { - perst-pins { - pinmux = ; - }; - }; - - pcie0_wake_default: pcie0-wake-default { - wake-pins { - pinmux = ; - }; - }; - - pcie0_clkreq_default: pcie0-clkreq-default { - clkreq-pins { - pinmux = ; - }; - }; - - pcie0_vbus_default: pcie0-vbus-default { - drive-vbus-pin { - pinmux = ; - }; - }; - - pcie1_perst_default: pcie1-perst-default { - perst-pins { - pinmux = ; - }; - }; - - pcie1_perst_active: pcie1-perst-active { - perst-pins { - pinmux = ; - }; - }; - - pcie1_wake_default: pcie1-wake-default { - wake-pins { - pinmux = ; - }; - }; - - pcie1_clkreq_default: pcie1-clkreq-default { - clkreq-pins { - pinmux = ; - }; - }; }; &uart0 { @@ -405,22 +333,3 @@ dr_mode = "peripheral"; }; }; - -&pcie0 { - pinctrl-names = "default", "perst-default", "perst-active"; - pinctrl-0 = <&pcie0_wake_default>, - <&pcie0_clkreq_default>, - <&pcie0_vbus_default>; - pinctrl-1 = <&pcie0_perst_default>; - pinctrl-2 = <&pcie0_perst_active>; - status = "okay"; -}; - -&pcie1 { - pinctrl-names = "default", "perst-default", "perst-active"; - pinctrl-0 = <&pcie1_wake_default>, - <&pcie1_clkreq_default>; - pinctrl-1 = <&pcie1_perst_default>; - pinctrl-2 = <&pcie1_perst_active>; - status = "okay"; -}; diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index da70de9..95abd5f 100644 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -293,16 +293,6 @@ cache-unified; }; - phyctrl0: multi-phyctrl@10210000 { - compatible = "starfive,phyctrl"; - reg = <0x0 0x10210000 0x0 0x10000>; - }; - - phyctrl1: pcie1-phyctrl@10220000 { - compatible = "starfive,phyctrl"; - reg = <0x0 0x10220000 0x0 0x10000>; - }; - plic: interrupt-controller@c000000 { compatible = "starfive,jh7110-plic", "sifive,plic-1.0.0"; reg = <0x0 0xc000000 0x0 0x4000000>; @@ -932,85 +922,5 @@ #reset-cells = <1>; power-domains = <&pwrc JH7110_PD_VOUT>; }; - - pcie0: pcie@2B000000 { - compatible = "plda,pci-xpressrich3-axi"; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - reg = <0x0 0x2B000000 0x0 0x1000000 - 0x9 0x40000000 0x0 0x10000000>; - reg-names = "reg", "config"; - device_type = "pci"; - starfive,stg-syscon = <&stg_syscon 0xc0 0xc4 0x130 0x1b8>; - starfive,phyctrl = <&phyctrl0 0x28 0x80>; - bus-range = <0x0 0xff>; - ranges = <0x82000000 0x0 0x30000000 0x0 0x30000000 0x0 0x08000000>, - <0xc3000000 0x9 0x00000000 0x9 0x00000000 0x0 0x40000000>; - msi-parent = <&plic>; - interrupts = <56>; - interrupt-controller; - interrupt-names = "msi"; - interrupt-parent = <&plic>; - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = <0x0 0x0 0x0 0x1 &plic 0x1>, - <0x0 0x0 0x0 0x2 &plic 0x2>, - <0x0 0x0 0x0 0x3 &plic 0x3>, - <0x0 0x0 0x0 0x4 &plic 0x4>; - resets = <&stgcrg JH7110_STGRST_PCIE0_AXI_MST0>, - <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV0>, - <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV>, - <&stgcrg JH7110_STGRST_PCIE0_BRG>, - <&stgcrg JH7110_STGRST_PCIE0_CORE>, - <&stgcrg JH7110_STGRST_PCIE0_APB>; - reset-names = "rst_mst0", "rst_slv0", "rst_slv", - "rst_brg", "rst_core", "rst_apb"; - clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>, - <&stgcrg JH7110_STGCLK_PCIE0_TL>, - <&stgcrg JH7110_STGCLK_PCIE0_AXI_MST0>, - <&stgcrg JH7110_STGCLK_PCIE0_APB>; - clock-names = "noc_bus_stg_axi", "tl", "axi_mst0", "apb"; - status = "disabled"; - }; - - pcie1:pcie@2C000000 { - compatible = "plda,pci-xpressrich3-axi"; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - reg = <0x0 0x2C000000 0x0 0x1000000 - 0x9 0xc0000000 0x0 0x10000000>; - reg-names = "reg", "config"; - device_type = "pci"; - starfive,stg-syscon = <&stg_syscon 0x270 0x274 0x2e0 0x368>; - starfive,phyctrl = <&phyctrl1 0x28 0x80>; - bus-range = <0x0 0xff>; - ranges = <0x82000000 0x0 0x38000000 0x0 0x38000000 0x0 0x08000000>, - <0xc3000000 0x9 0x80000000 0x9 0x80000000 0x0 0x40000000>; - msi-parent = <&plic>; - interrupts = <57>; - interrupt-controller; - interrupt-names = "msi"; - interrupt-parent = <&plic>; - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = <0x0 0x0 0x0 0x1 &plic 0x1>, - <0x0 0x0 0x0 0x2 &plic 0x2>, - <0x0 0x0 0x0 0x3 &plic 0x3>, - <0x0 0x0 0x0 0x4 &plic 0x4>; - resets = <&stgcrg JH7110_STGRST_PCIE1_AXI_MST0>, - <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV0>, - <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV>, - <&stgcrg JH7110_STGRST_PCIE1_BRG>, - <&stgcrg JH7110_STGRST_PCIE1_CORE>, - <&stgcrg JH7110_STGRST_PCIE1_APB>; - reset-names = "rst_mst0", "rst_slv0", "rst_slv", - "rst_brg", "rst_core", "rst_apb"; - clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>, - <&stgcrg JH7110_STGCLK_PCIE1_TL>, - <&stgcrg JH7110_STGCLK_PCIE1_AXI_MST0>, - <&stgcrg JH7110_STGCLK_PCIE1_APB>; - clock-names = "noc_bus_stg_axi", "tl", "axi_mst0", "apb"; - status = "disabled"; - }; }; }; diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig old mode 100755 new mode 100644 index be1fcb8..bfd9bac --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -343,14 +343,6 @@ config PCIE_MT7621 help This selects a driver for the MediaTek MT7621 PCIe Controller. -config PCIE_PLDA - tristate "PLDA XpressRICH3-AXI PCIe controller" - depends on OF - select PCI_MSI_IRQ_DOMAIN - help - Say 'Y' here if you want kernel to support the PLDA XpressRICH3-AXI - (with ECAM disabled) PCIe Host driver. - source "drivers/pci/controller/dwc/Kconfig" source "drivers/pci/controller/mobiveil/Kconfig" source "drivers/pci/controller/cadence/Kconfig" diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile old mode 100755 new mode 100644 index edcc6d4..37c8663 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -39,7 +39,6 @@ obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o obj-$(CONFIG_PCIE_HISI_ERR) += pcie-hisi-error.o obj-$(CONFIG_PCIE_APPLE) += pcie-apple.o obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o -obj-$(CONFIG_PCIE_PLDA) += pcie-plda.o # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW obj-y += dwc/ diff --git a/drivers/pci/controller/pcie-plda.c b/drivers/pci/controller/pcie-plda.c deleted file mode 100644 index 3eb0487..0000000 --- a/drivers/pci/controller/pcie-plda.c +++ /dev/null @@ -1,1061 +0,0 @@ -/* - * PCIe host controller driver for Starfive JH7110 Soc. - * - * Based on pcie-altera.c, pcie-altera-msi.c. - * - * Copyright (C) Shanghai StarFive Technology Co., Ltd. - * - * Author: ke.zhu@starfivetech.com - * - * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS - * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE - * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY - * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING - * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE - * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../pci.h" - -#define PCIE_BASIC_STATUS 0x018 -#define PCIE_CFGNUM 0x140 -#define IMASK_LOCAL 0x180 -#define ISTATUS_LOCAL 0x184 -#define IMSI_ADDR 0x190 -#define ISTATUS_MSI 0x194 -#define CFG_SPACE 0x1000 -#define GEN_SETTINGS 0x80 -#define PCIE_PCI_IDS 0x9C -#define PCIE_WINROM 0xFC -#define PMSG_SUPPORT_RX 0x3F0 - -#define PCI_MISC 0xB4 - -#define PLDA_EP_ENABLE 0 -#define PLDA_RP_ENABLE 1 - -#define PLDA_LINK_UP 1 -#define PLDA_LINK_DOWN 0 - -#define IDS_REVISION_ID 0x02 -#define IDS_PCI_TO_PCI_BRIDGE 0x060400 -#define IDS_CLASS_CODE_SHIFT 8 - -#define PLDA_DATA_LINK_ACTIVE BIT(5) -#define PREF_MEM_WIN_64_SUPPORT BIT(3) -#define PMSG_LTR_SUPPORT BIT(2) -#define PDLA_LINK_SPEED_GEN2 BIT(12) -#define PLDA_FUNCTION_DIS BIT(15) -#define PLDA_FUNC_NUM 4 -#define PLDA_PHY_FUNC_SHIFT 9 -#define PHY_KVCO_FINE_TUNE_LEVEL 0x91 -#define PHY_KVCO_FINE_TUNE_SIGNALS 0xc - -#define XR3PCI_ATR_AXI4_SLV0 0x800 -#define XR3PCI_ATR_SRC_ADDR_LOW 0x0 -#define XR3PCI_ATR_SRC_ADDR_HIGH 0x4 -#define XR3PCI_ATR_TRSL_ADDR_LOW 0x8 -#define XR3PCI_ATR_TRSL_ADDR_HIGH 0xc -#define XR3PCI_ATR_TRSL_PARAM 0x10 -#define XR3PCI_ATR_TABLE_OFFSET 0x20 -#define XR3PCI_ATR_MAX_TABLE_NUM 8 - -#define XR3PCI_ATR_SRC_WIN_SIZE_SHIFT 1 -#define XR3PCI_ATR_SRC_ADDR_MASK 0xfffff000 -#define XR3PCI_ATR_TRSL_ADDR_MASK 0xfffff000 -#define XR3_PCI_ECAM_SIZE 28 -#define XR3PCI_ATR_TRSL_DIR BIT(22) -/* IDs used in the XR3PCI_ATR_TRSL_PARAM */ -#define XR3PCI_ATR_TRSLID_PCIE_MEMORY 0x0 -#define XR3PCI_ATR_TRSLID_PCIE_CONFIG 0x1 - -#define CFGNUM_DEVFN_SHIFT 0 -#define CFGNUM_BUS_SHIFT 8 -#define CFGNUM_BE_SHIFT 16 -#define CFGNUM_FBE_SHIFT 20 - -#define ECAM_BUS_SHIFT 20 -#define ECAM_DEV_SHIFT 15 -#define ECAM_FUNC_SHIFT 12 - -#define INT_AXI_POST_ERROR BIT(16) -#define INT_AXI_FETCH_ERROR BIT(17) -#define INT_AXI_DISCARD_ERROR BIT(18) -#define INT_PCIE_POST_ERROR BIT(20) -#define INT_PCIE_FETCH_ERROR BIT(21) -#define INT_PCIE_DISCARD_ERROR BIT(22) -#define INT_ERRORS (INT_AXI_POST_ERROR | INT_AXI_FETCH_ERROR | \ - INT_AXI_DISCARD_ERROR | INT_PCIE_POST_ERROR | \ - INT_PCIE_FETCH_ERROR | INT_PCIE_DISCARD_ERROR) - -#define INTA_OFFSET 24 -#define INTA BIT(24) -#define INTB BIT(25) -#define INTC BIT(26) -#define INTD BIT(27) -#define INT_MSI BIT(28) -#define INT_INTX_MASK (INTA | INTB | INTC | INTD) -#define INT_MASK (INT_INTX_MASK | INT_MSI | INT_ERRORS) - -#define INT_PCI_MSI_NR 32 -#define LINK_UP_MASK 0xff - -#define PERST_DELAY_US 1000 - -/* system control */ -#define STG_SYSCON_K_RP_NEP_SHIFT 0x8 -#define STG_SYSCON_K_RP_NEP_MASK 0x100 -#define STG_SYSCON_AXI4_SLVL_ARFUNC_MASK 0x7FFF00 -#define STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT 0x8 -#define STG_SYSCON_AXI4_SLVL_AWFUNC_MASK 0x7FFF -#define STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT 0x0 -#define STG_SYSCON_CLKREQ_SHIFT 0x16 -#define STG_SYSCON_CLKREQ_MASK 0x400000 -#define STG_SYSCON_CKREF_SRC_SHIFT 0x12 -#define STG_SYSCON_CKREF_SRC_MASK 0xC0000 - -#define PCI_DEV(d) (((d) >> 3) & 0x1f) - -/* MSI information */ -struct plda_msi { - DECLARE_BITMAP(used, INT_PCI_MSI_NR); - struct irq_domain *msi_domain; - struct irq_domain *inner_domain; - /* Protect bitmap variable */ - struct mutex lock; -}; - -struct plda_pcie { - struct platform_device *pdev; - void __iomem *reg_base; - void __iomem *config_base; - struct resource *cfg_res; - struct regmap *reg_syscon; - struct regmap *reg_phyctrl; - u32 stg_arfun; - u32 stg_awfun; - u32 stg_rp_nep; - u32 stg_lnksta; - u32 phy_kvco_level; - u32 phy_kvco_tune_signals; - int irq; - struct irq_domain *legacy_irq_domain; - struct pci_host_bridge *bridge; - struct plda_msi msi; - struct reset_control *resets; - struct clk_bulk_data *clks; - int num_clks; - int atr_table_num; - struct pinctrl *pinctrl; - struct pinctrl_state *perst_state_def; - struct pinctrl_state *perst_state_active; -}; - -static inline void plda_writel(struct plda_pcie *pcie, const u32 value, - const u32 reg) -{ - writel_relaxed(value, pcie->reg_base + reg); -} - -static inline u32 plda_readl(struct plda_pcie *pcie, const u32 reg) -{ - return readl_relaxed(pcie->reg_base + reg); -} - -static bool plda_pcie_hide_rc_bar(struct pci_bus *bus, unsigned int devfn, - int offset) -{ - if (pci_is_root_bus(bus) && (devfn == 0) && - (offset == PCI_BASE_ADDRESS_0)) - return true; - - return false; -} - -static int _plda_pcie_config_read(struct plda_pcie *pcie, unsigned char busno, - unsigned int devfn, int where, int size, - u32 *value) -{ - void __iomem *addr; - - addr = pcie->config_base; - addr += (busno << ECAM_BUS_SHIFT); - addr += (PCI_DEV(devfn) << ECAM_DEV_SHIFT); - addr += (PCI_FUNC(devfn) << ECAM_FUNC_SHIFT); - addr += where; - - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (size) { - case 1: - *(unsigned char *)value = readb(addr); - break; - case 2: - *(unsigned short *)value = readw(addr); - break; - case 4: - *(unsigned int *)value = readl(addr); - break; - default: - return PCIBIOS_SET_FAILED; - } - - return PCIBIOS_SUCCESSFUL; -} - -int _plda_pcie_config_write(struct plda_pcie *pcie, unsigned char busno, - unsigned int devfn, int where, int size, u32 value) -{ - void __iomem *addr; - - addr = pcie->config_base; - addr += (busno << ECAM_BUS_SHIFT); - addr += (PCI_DEV(devfn) << ECAM_DEV_SHIFT); - addr += (PCI_FUNC(devfn) << ECAM_FUNC_SHIFT); - addr += where; - - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (size) { - case 1: - writeb(value, addr); - break; - case 2: - writew(value, addr); - break; - case 4: - writel(value, addr); - break; - default: - return PCIBIOS_SET_FAILED; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int plda_pcie_config_read(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *value) -{ - struct plda_pcie *pcie = bus->sysdata; - - return _plda_pcie_config_read(pcie, bus->number, devfn, where, size, - value); -} - -int plda_pcie_config_write(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 value) -{ - struct plda_pcie *pcie = bus->sysdata; - - if (plda_pcie_hide_rc_bar(bus, devfn, where)) - return PCIBIOS_BAD_REGISTER_NUMBER; - - return _plda_pcie_config_write(pcie, bus->number, devfn, where, size, - value); -} - -static void plda_pcie_handle_msi_irq(struct plda_pcie *pcie) -{ - struct plda_msi *msi = &pcie->msi; - u32 bit; - u32 virq; - unsigned long status = plda_readl(pcie, ISTATUS_MSI); - - for_each_set_bit(bit, &status, INT_PCI_MSI_NR) { - /* Clear interrupts */ - plda_writel(pcie, 1 << bit, ISTATUS_MSI); - - virq = irq_find_mapping(msi->inner_domain, bit); - if (virq) { - if (test_bit(bit, msi->used)) - generic_handle_irq(virq); - else - dev_err(&pcie->pdev->dev, - "Unhandled MSI, MSI%d virq %d\n", bit, - virq); - } else - dev_err(&pcie->pdev->dev, "Unexpected MSI, MSI%d\n", - bit); - - } - plda_writel(pcie, INT_MSI, ISTATUS_LOCAL); -} - -static void plda_pcie_handle_intx_irq(struct plda_pcie *pcie, - unsigned long status) -{ - u32 bit; - u32 virq; - - status >>= INTA_OFFSET; - - for_each_set_bit(bit, &status, PCI_NUM_INTX) { - /* Clear interrupts */ - plda_writel(pcie, 1 << (bit + INTA_OFFSET), ISTATUS_LOCAL); - - virq = irq_find_mapping(pcie->legacy_irq_domain, bit); - if (virq) - generic_handle_irq(virq); - else - dev_err(&pcie->pdev->dev, - "plda_pcie_handle_intx_irq unexpected IRQ, INT%d\n", bit); - } -} - -static void plda_pcie_handle_errors_irq(struct plda_pcie *pcie, u32 status) -{ - if (status & INT_AXI_POST_ERROR) - dev_err(&pcie->pdev->dev, "AXI post error\n"); - if (status & INT_AXI_FETCH_ERROR) - dev_err(&pcie->pdev->dev, "AXI fetch error\n"); - if (status & INT_AXI_DISCARD_ERROR) - dev_err(&pcie->pdev->dev, "AXI discard error\n"); - if (status & INT_PCIE_POST_ERROR) - dev_err(&pcie->pdev->dev, "PCIe post error\n"); - if (status & INT_PCIE_FETCH_ERROR) - dev_err(&pcie->pdev->dev, "PCIe fetch error\n"); - if (status & INT_PCIE_DISCARD_ERROR) - dev_err(&pcie->pdev->dev, "PCIe discard error\n"); - - plda_writel(pcie, INT_ERRORS, ISTATUS_LOCAL); -} - -static void plda_pcie_isr(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - struct plda_pcie *pcie; - u32 status; - - chained_irq_enter(chip, desc); - pcie = irq_desc_get_handler_data(desc); - - status = plda_readl(pcie, ISTATUS_LOCAL); - while ((status = (plda_readl(pcie, ISTATUS_LOCAL) & INT_MASK))) { - if (status & INT_INTX_MASK) - plda_pcie_handle_intx_irq(pcie, status); - - if (status & INT_MSI) - plda_pcie_handle_msi_irq(pcie); - - if (status & INT_ERRORS) - plda_pcie_handle_errors_irq(pcie, status); - } - - chained_irq_exit(chip, desc); -} - -#ifdef CONFIG_PCI_MSI -static struct irq_chip plda_msi_irq_chip = { - .name = "PLDA PCIe MSI", - .irq_mask = pci_msi_mask_irq, - .irq_unmask = pci_msi_unmask_irq, -}; - -static struct msi_domain_info plda_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_PCI_MSIX), - .chip = &plda_msi_irq_chip, -}; -#endif - -static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) -{ - struct plda_pcie *pcie = irq_data_get_irq_chip_data(data); - phys_addr_t msi_addr = plda_readl(pcie, IMSI_ADDR); - - msg->address_lo = lower_32_bits(msi_addr); - msg->address_hi = upper_32_bits(msi_addr); - msg->data = data->hwirq; - - dev_info(&pcie->pdev->dev, "msi#%d address_hi %#x address_lo %#x\n", - (int)data->hwirq, msg->address_hi, msg->address_lo); -} - -static int plda_msi_set_affinity(struct irq_data *irq_data, - const struct cpumask *mask, bool force) -{ - return -EINVAL; -} - -static struct irq_chip plda_irq_chip = { - .name = "PLDA MSI", - .irq_compose_msi_msg = plda_compose_msi_msg, - .irq_set_affinity = plda_msi_set_affinity, -}; - -static int plda_msi_alloc(struct irq_domain *domain, unsigned int virq, - unsigned int nr_irqs, void *args) -{ - struct plda_pcie *pcie = domain->host_data; - struct plda_msi *msi = &pcie->msi; - int bit; - - WARN_ON(nr_irqs != 1); - mutex_lock(&msi->lock); - - bit = find_first_zero_bit(msi->used, INT_PCI_MSI_NR); - if (bit >= INT_PCI_MSI_NR) { - mutex_unlock(&msi->lock); - return -ENOSPC; - } - - set_bit(bit, msi->used); - - irq_domain_set_info(domain, virq, bit, &plda_irq_chip, - domain->host_data, handle_simple_irq, - NULL, NULL); - mutex_unlock(&msi->lock); - - return 0; -} - -static void plda_msi_free(struct irq_domain *domain, unsigned int virq, - unsigned int nr_irqs) -{ - struct irq_data *data = irq_domain_get_irq_data(domain, virq); - struct plda_pcie *pcie = irq_data_get_irq_chip_data(data); - struct plda_msi *msi = &pcie->msi; - - mutex_lock(&msi->lock); - - if (!test_bit(data->hwirq, msi->used)) - dev_err(&pcie->pdev->dev, "Trying to free unused MSI#%lu\n", - data->hwirq); - else - __clear_bit(data->hwirq, msi->used); - - mutex_unlock(&msi->lock); -} - -static const struct irq_domain_ops dev_msi_domain_ops = { - .alloc = plda_msi_alloc, - .free = plda_msi_free, -}; - -static void plda_msi_free_irq_domain(struct plda_pcie *pcie) -{ -#ifdef CONFIG_PCI_MSI - struct plda_msi *msi = &pcie->msi; - u32 irq; - int i; - - for (i = 0; i < INT_PCI_MSI_NR; i++) { - irq = irq_find_mapping(msi->inner_domain, i); - if (irq > 0) - irq_dispose_mapping(irq); - } - - if (msi->msi_domain) - irq_domain_remove(msi->msi_domain); - - if (msi->inner_domain) - irq_domain_remove(msi->inner_domain); -#endif -} - -static void plda_pcie_free_irq_domain(struct plda_pcie *pcie) -{ - int i; - u32 irq; - - /* Disable all interrupts */ - plda_writel(pcie, 0, IMASK_LOCAL); - - if (pcie->legacy_irq_domain) { - for (i = 0; i < PCI_NUM_INTX; i++) { - irq = irq_find_mapping(pcie->legacy_irq_domain, i); - if (irq > 0) - irq_dispose_mapping(irq); - } - irq_domain_remove(pcie->legacy_irq_domain); - } - - if (pci_msi_enabled()) - plda_msi_free_irq_domain(pcie); - irq_set_chained_handler_and_data(pcie->irq, NULL, NULL); -} - -static int plda_pcie_init_msi_irq_domain(struct plda_pcie *pcie) -{ -#ifdef CONFIG_PCI_MSI - struct fwnode_handle *fwn = of_node_to_fwnode(pcie->pdev->dev.of_node); - struct plda_msi *msi = &pcie->msi; - - msi->inner_domain = irq_domain_add_linear(NULL, INT_PCI_MSI_NR, - &dev_msi_domain_ops, pcie); - if (!msi->inner_domain) { - dev_err(&pcie->pdev->dev, "Failed to create dev IRQ domain\n"); - return -ENOMEM; - } - msi->msi_domain = pci_msi_create_irq_domain(fwn, &plda_msi_domain_info, - msi->inner_domain); - if (!msi->msi_domain) { - dev_err(&pcie->pdev->dev, "Failed to create msi IRQ domain\n"); - irq_domain_remove(msi->inner_domain); - return -ENOMEM; - } -#endif - return 0; -} - -static int plda_pcie_enable_msi(struct plda_pcie *pcie, struct pci_bus *bus) -{ - struct plda_msi *msi = &pcie->msi; - u32 reg; - - mutex_init(&msi->lock); - - /* Enable MSI */ - reg = plda_readl(pcie, IMASK_LOCAL); - reg |= INT_MSI; - plda_writel(pcie, reg, IMASK_LOCAL); - return 0; -} - -static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq, - irq_hw_number_t hwirq) -{ - irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); - irq_set_chip_data(irq, domain->host_data); - - return 0; -} - -static const struct irq_domain_ops intx_domain_ops = { - .map = plda_pcie_intx_map, - .xlate = pci_irqd_intx_xlate, -}; - -static int plda_pcie_init_irq_domain(struct plda_pcie *pcie) -{ - struct device *dev = &pcie->pdev->dev; - struct device_node *node = dev->of_node; - int ret; - - if (pci_msi_enabled()) { - ret = plda_pcie_init_msi_irq_domain(pcie); - if (ret != 0) - return -ENOMEM; - } - - /* Setup INTx */ - pcie->legacy_irq_domain = irq_domain_add_linear(node, PCI_NUM_INTX, - &intx_domain_ops, pcie); - - if (!pcie->legacy_irq_domain) { - dev_err(dev, "Failed to get a INTx IRQ domain\n"); - return -ENOMEM; - } - - irq_set_chained_handler_and_data(pcie->irq, plda_pcie_isr, pcie); - return 0; -} - -static int plda_pcie_parse_dt(struct plda_pcie *pcie) -{ - struct resource *reg_res; - struct platform_device *pdev = pcie->pdev; - struct of_phandle_args syscon_args, phyctrl_args; - int ret; - - reg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); - if (!reg_res) { - dev_err(&pdev->dev, "Missing required reg address range\n"); - return -ENODEV; - } - - pcie->reg_base = devm_ioremap_resource(&pdev->dev, reg_res); - if (IS_ERR(pcie->reg_base)) { - dev_err(&pdev->dev, "Failed to map reg memory\n"); - return PTR_ERR(pcie->reg_base); - } - - pcie->cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); - if (!pcie->cfg_res) { - dev_err(&pdev->dev, "Missing required config address range"); - return -ENODEV; - } - - pcie->config_base = devm_ioremap_resource(&pdev->dev, pcie->cfg_res); - if (IS_ERR(pcie->config_base)){ - dev_err(&pdev->dev, "Failed to map config memory\n"); - return PTR_ERR(pcie->config_base); - } - - ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, - "starfive,phyctrl", 2, 0, &phyctrl_args); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to parse starfive,phyctrl\n"); - return -EINVAL; - } - - if (!of_device_is_compatible(phyctrl_args.np, "starfive,phyctrl")) - return -EINVAL; - pcie->reg_phyctrl = device_node_to_regmap(phyctrl_args.np); - of_node_put(phyctrl_args.np); - if (IS_ERR(pcie->reg_phyctrl)) - return PTR_ERR(pcie->reg_phyctrl); - - pcie->phy_kvco_level = phyctrl_args.args[0]; - pcie->phy_kvco_tune_signals = phyctrl_args.args[1]; - - pcie->irq = platform_get_irq(pdev, 0); - if (pcie->irq <= 0) { - dev_err(&pdev->dev, "Failed to get IRQ: %d\n", pcie->irq); - return -EINVAL; - } - - ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, - "starfive,stg-syscon", 4, 0, &syscon_args); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to parse starfive,stg-syscon\n"); - return -EINVAL; - } - - pcie->reg_syscon = syscon_node_to_regmap(syscon_args.np); - of_node_put(syscon_args.np); - if (IS_ERR(pcie->reg_syscon)) - return PTR_ERR(pcie->reg_syscon); - - pcie->stg_arfun = syscon_args.args[0]; - pcie->stg_awfun = syscon_args.args[1]; - pcie->stg_rp_nep = syscon_args.args[2]; - pcie->stg_lnksta = syscon_args.args[3]; - - /* Clear all interrupts */ - plda_writel(pcie, 0xffffffff, ISTATUS_LOCAL); - plda_writel(pcie, INT_INTX_MASK | INT_ERRORS, IMASK_LOCAL); - - return 0; -} - -static struct pci_ops plda_pcie_ops = { - .read = plda_pcie_config_read, - .write = plda_pcie_config_write, -}; - -void plda_set_atr_entry(struct plda_pcie *pcie, phys_addr_t src_addr, - phys_addr_t trsl_addr, size_t window_size, - int trsl_param) -{ - void __iomem *base = - pcie->reg_base + XR3PCI_ATR_AXI4_SLV0; - - /* Support AXI4 Slave 0 Address Translation Tables 0-7. */ - if (pcie->atr_table_num >= XR3PCI_ATR_MAX_TABLE_NUM) - pcie->atr_table_num = XR3PCI_ATR_MAX_TABLE_NUM - 1; - base += XR3PCI_ATR_TABLE_OFFSET * pcie->atr_table_num; - pcie->atr_table_num++; - - /* X3PCI_ATR_SRC_ADDR_LOW: - * - bit 0: enable entry, - * - bits 1-6: ATR window size: total size in bytes: 2^(ATR_WSIZE + 1) - * - bits 7-11: reserved - * - bits 12-31: start of source address - */ - writel((lower_32_bits(src_addr) & XR3PCI_ATR_SRC_ADDR_MASK) | - (fls(window_size) - 1) << XR3PCI_ATR_SRC_WIN_SIZE_SHIFT | 1, - base + XR3PCI_ATR_SRC_ADDR_LOW); - writel(upper_32_bits(src_addr), base + XR3PCI_ATR_SRC_ADDR_HIGH); - writel((lower_32_bits(trsl_addr) & XR3PCI_ATR_TRSL_ADDR_MASK), - base + XR3PCI_ATR_TRSL_ADDR_LOW); - writel(upper_32_bits(trsl_addr), base + XR3PCI_ATR_TRSL_ADDR_HIGH); - writel(trsl_param, base + XR3PCI_ATR_TRSL_PARAM); - - pr_info("ATR entry: 0x%010llx %s 0x%010llx [0x%010llx] (param: 0x%06x)\n", - src_addr, (trsl_param & XR3PCI_ATR_TRSL_DIR) ? "<-" : "->", - trsl_addr, (u64)window_size, trsl_param); -} - -static int plda_pcie_setup_windows(struct plda_pcie *pcie) -{ - struct pci_host_bridge *bridge = pcie->bridge; - struct resource_entry *entry; - u64 pci_addr; - - resource_list_for_each_entry(entry, &bridge->windows) { - if (resource_type(entry->res) == IORESOURCE_MEM) { - pci_addr = entry->res->start - entry->offset; - plda_set_atr_entry(pcie, - entry->res->start, pci_addr, - resource_size(entry->res), - XR3PCI_ATR_TRSLID_PCIE_MEMORY); - } - } - - return 0; -} - -static int plda_clk_rst_init(struct plda_pcie *pcie) -{ - int ret; - struct device *dev = &pcie->pdev->dev; - - pcie->num_clks = devm_clk_bulk_get_all(dev, &pcie->clks); - if (pcie->num_clks < 0) { - dev_err(dev, "Failed to get pcie clocks\n"); - ret = -ENODEV; - goto exit; - } - ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks); - if (ret) { - dev_err(&pcie->pdev->dev, "Failed to enable clocks\n"); - goto exit; - } - - pcie->resets = devm_reset_control_array_get_exclusive(dev); - if (IS_ERR(pcie->resets)) { - ret = PTR_ERR(pcie->resets); - dev_err(dev, "Failed to get pcie resets"); - goto err_clk_init; - } - ret = reset_control_deassert(pcie->resets); - goto exit; - -err_clk_init: - clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); -exit: - return ret; -} - -static void plda_clk_rst_deinit(struct plda_pcie *pcie) -{ - reset_control_assert(pcie->resets); - clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); -} - -int plda_pinctrl_init(struct plda_pcie *pcie) -{ - struct device *dev = &pcie->pdev->dev; - - pcie->pinctrl = devm_pinctrl_get(dev); - if (IS_ERR_OR_NULL(pcie->pinctrl)) { - dev_err(dev, "Getting pinctrl handle failed\n"); - return -EINVAL; - } - - pcie->perst_state_def - = pinctrl_lookup_state(pcie->pinctrl, "perst-default"); - if (IS_ERR_OR_NULL(pcie->perst_state_def)) { - dev_err(dev, "Failed to get the perst-default pinctrl handle\n"); - return -EINVAL; - } - - pcie->perst_state_active - = pinctrl_lookup_state(pcie->pinctrl, "perst-active"); - if (IS_ERR_OR_NULL(pcie->perst_state_active)) { - dev_err(dev, "Failed to get the perst-active pinctrl handle\n"); - return -EINVAL; - } - - return 0; -} - -static void plda_pcie_hw_init(struct plda_pcie *pcie) -{ - unsigned int value; - int i, ret; - struct device *dev = &pcie->pdev->dev; - - if (pcie->perst_state_active) { - ret = pinctrl_select_state(pcie->pinctrl, pcie->perst_state_active); - if (ret) - dev_err(dev, "Cannot set reset pin to low\n"); - } - - /* Disable physical functions except #0 */ - for (i = 1; i < PLDA_FUNC_NUM; i++) { - regmap_update_bits(pcie->reg_syscon, - pcie->stg_arfun, - STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, - (i << PLDA_PHY_FUNC_SHIFT) << - STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT); - regmap_update_bits(pcie->reg_syscon, - pcie->stg_awfun, - STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, - (i << PLDA_PHY_FUNC_SHIFT) << - STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT); - - value = readl(pcie->reg_base + PCI_MISC); - value |= PLDA_FUNCTION_DIS; - writel(value, pcie->reg_base + PCI_MISC); - } - regmap_update_bits(pcie->reg_syscon, - pcie->stg_arfun, - STG_SYSCON_AXI4_SLVL_ARFUNC_MASK, - 0 << STG_SYSCON_AXI4_SLVL_ARFUNC_SHIFT); - regmap_update_bits(pcie->reg_syscon, - pcie->stg_awfun, - STG_SYSCON_AXI4_SLVL_AWFUNC_MASK, - 0 << STG_SYSCON_AXI4_SLVL_AWFUNC_SHIFT); - - /* PCIe Multi-PHY PLL KVCO Gain fine tune settings: */ - regmap_write(pcie->reg_phyctrl, pcie->phy_kvco_level, - PHY_KVCO_FINE_TUNE_LEVEL); - regmap_write(pcie->reg_phyctrl, pcie->phy_kvco_tune_signals, - PHY_KVCO_FINE_TUNE_SIGNALS); - - /* Enable root port*/ - value = readl(pcie->reg_base + GEN_SETTINGS); - value |= PLDA_RP_ENABLE; - writel(value, pcie->reg_base + GEN_SETTINGS); - - /* PCIe PCI Standard Configuration Identification Settings. */ - value = (IDS_PCI_TO_PCI_BRIDGE << IDS_CLASS_CODE_SHIFT) | IDS_REVISION_ID; - writel(value, pcie->reg_base + PCIE_PCI_IDS); - - /* The LTR message forwarding of PCIe Message Reception was set by core - * as default, but the forward id & addr are also need to be reset. - * If we do not disable LTR message forwarding here, or set a legal - * forwarding address, the kernel will get stuck after this driver probe. - * To workaround, disable the LTR message forwarding support on - * PCIe Message Reception. - */ - value = readl(pcie->reg_base + PMSG_SUPPORT_RX); - value &= ~PMSG_LTR_SUPPORT; - writel(value, pcie->reg_base + PMSG_SUPPORT_RX); - - /* Prefetchable memory window 64-bit addressing support */ - value = readl(pcie->reg_base + PCIE_WINROM); - value |= PREF_MEM_WIN_64_SUPPORT; - writel(value, pcie->reg_base + PCIE_WINROM); - - /* As the two host bridges in JH7110 soc have the same default - * address translation table, this cause the second root port can't - * access it's host bridge config space correctly. - * To workaround, config the ATR of host bridge config space by SW. - */ - plda_set_atr_entry(pcie, - pcie->cfg_res->start, 0, - 1 << XR3_PCI_ECAM_SIZE, - XR3PCI_ATR_TRSLID_PCIE_CONFIG); - - plda_pcie_setup_windows(pcie); - - /* Ensure that PERST has been asserted for at least 100 ms */ - msleep(300); - if (pcie->perst_state_def) { - ret = pinctrl_select_state(pcie->pinctrl, pcie->perst_state_def); - if (ret) - dev_err(dev, "Cannot set reset pin to high\n"); - } -} - -static int plda_pcie_is_link_up(struct plda_pcie *pcie) -{ - struct device *dev = &pcie->pdev->dev; - int ret; - u32 stg_reg_val; - - /* 100ms timeout value should be enough for Gen1/2 training */ - ret = regmap_read_poll_timeout(pcie->reg_syscon, - pcie->stg_lnksta, - stg_reg_val, - stg_reg_val & PLDA_DATA_LINK_ACTIVE, - 10 * 1000, 100 * 1000); - - /* If the link is down (no device in slot), then exit. */ - if (ret == -ETIMEDOUT) { - dev_info(dev, "Port link down, exit.\n"); - return PLDA_LINK_DOWN; - } else if (ret == 0) { - dev_info(dev, "Port link up.\n"); - return PLDA_LINK_UP; - } - - dev_warn(dev, "Read stg_linksta failed.\n"); - return ret; -} - -static int plda_pcie_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct plda_pcie *pcie; - struct pci_bus *bus; - struct pci_host_bridge *bridge; - int ret; - - pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) - return -ENOMEM; - - pcie->pdev = pdev; - pcie->atr_table_num = 0; - - ret = plda_pcie_parse_dt(pcie); - if (ret) { - dev_err(&pdev->dev, "Parsing DT failed\n"); - return ret; - } - - platform_set_drvdata(pdev, pcie); - - plda_pinctrl_init(pcie); - if (ret) { - dev_err(&pdev->dev, "Init pinctrl failed\n"); - return ret; - } - - regmap_update_bits(pcie->reg_syscon, - pcie->stg_rp_nep, - STG_SYSCON_K_RP_NEP_MASK, - 1 << STG_SYSCON_K_RP_NEP_SHIFT); - - regmap_update_bits(pcie->reg_syscon, - pcie->stg_awfun, - STG_SYSCON_CKREF_SRC_MASK, - 2 << STG_SYSCON_CKREF_SRC_SHIFT); - - regmap_update_bits(pcie->reg_syscon, - pcie->stg_awfun, - STG_SYSCON_CLKREQ_MASK, - 1 << STG_SYSCON_CLKREQ_SHIFT); - - ret = plda_clk_rst_init(pcie); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to init pcie clk reset: %d\n", ret); - goto exit; - } - - ret = plda_pcie_init_irq_domain(pcie); - if (ret) { - dev_err(&pdev->dev, "Failed creating IRQ Domain\n"); - goto exit; - } - - bridge = devm_pci_alloc_host_bridge(dev, 0); - if (!bridge) { - ret = -ENOMEM; - goto exit; - } - - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); - - /* Set default bus ops */ - bridge->ops = &plda_pcie_ops; - bridge->sysdata = pcie; - pcie->bridge = bridge; - - plda_pcie_hw_init(pcie); - - if (plda_pcie_is_link_up(pcie) == PLDA_LINK_DOWN) - goto release; - - if (IS_ENABLED(CONFIG_PCI_MSI)) { - ret = plda_pcie_enable_msi(pcie, bus); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to enable MSI support: %d\n", ret); - goto release; - } - } - - ret = pci_host_probe(bridge); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to pci host probe: %d\n", ret); - goto release; - } - -exit: - return ret; - -release: - plda_clk_rst_deinit(pcie); - - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - pci_free_host_bridge(pcie->bridge); - devm_kfree(&pdev->dev, pcie); - platform_set_drvdata(pdev, NULL); - - return ret; -} - -static int plda_pcie_remove(struct platform_device *pdev) -{ - struct plda_pcie *pcie = platform_get_drvdata(pdev); - - plda_pcie_free_irq_domain(pcie); - plda_clk_rst_deinit(pcie); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int __maybe_unused plda_pcie_suspend_noirq(struct device *dev) -{ - struct plda_pcie *pcie = dev_get_drvdata(dev); - - if (!pcie) - return 0; - - clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks); - - return 0; -} - -static int __maybe_unused plda_pcie_resume_noirq(struct device *dev) -{ - struct plda_pcie *pcie = dev_get_drvdata(dev); - int ret; - - if (!pcie) - return 0; - - ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks); - if (ret) - dev_err(dev, "Failed to enable clocks\n"); - - return ret; -} - -static const struct dev_pm_ops plda_pcie_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(plda_pcie_suspend_noirq, - plda_pcie_resume_noirq) -}; -#endif - -static const struct of_device_id plda_pcie_of_match[] = { - { .compatible = "plda,pci-xpressrich3-axi"}, - { }, -}; -MODULE_DEVICE_TABLE(of, plda_pcie_of_match); - -static struct platform_driver plda_pcie_driver = { - .driver = { - .name = KBUILD_MODNAME, - .of_match_table = of_match_ptr(plda_pcie_of_match), -#ifdef CONFIG_PM_SLEEP - .pm = &plda_pcie_pm_ops, -#endif - }, - .probe = plda_pcie_probe, - .remove = plda_pcie_remove, -}; -module_platform_driver(plda_pcie_driver); - -MODULE_DESCRIPTION("StarFive JH7110 PCIe host driver"); -MODULE_AUTHOR("ke.zhu "); -MODULE_AUTHOR("Mason Huo "); -MODULE_LICENSE("GPL v2"); -- 2.7.4 From 871007e46f0f61928bc742304da43f977408d2cd Mon Sep 17 00:00:00 2001 From: Minda Chen Date: Thu, 6 Apr 2023 09:52:10 +0800 Subject: [PATCH 16/16] dt-bindings: phy: Add StarFive JH7110 USB document Add StarFive JH7110 SoC USB 2.0 PHY dt-binding. Signed-off-by: Minda Chen [Backported from https://github.com/starfive-tech/linux/tree/JH7110_VisionFive2_upstream] Change-Id: I402d255181b5ff3a14e2faea7f54753f83757cd2 Signed-off-by: Hoegeun Kwon --- .../bindings/phy/starfive,jh7110-usb-phy.yaml | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml b/Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml new file mode 100644 index 0000000..80604df --- /dev/null +++ b/Documentation/devicetree/bindings/phy/starfive,jh7110-usb-phy.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/starfive,jh7110-usb-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive USB 2.0 PHY + +maintainers: + - Minda Chen + +properties: + compatible: + const: starfive,jh7110-usb-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + clocks: + items: + - description: usb 125m clock + - description: app 125m clock + + clock-names: + items: + - const: 125m + - const: app_125 + +required: + - compatible + - reg + - clocks + - clock-names + - "#phy-cells" + +additionalProperties: false + +examples: + - | + phy@10200000 { + compatible = "starfive,jh7110-usb-phy"; + reg = <0x10200000 0x10000>; + clocks = <&syscrg 95>, + <&stgcrg 6>; + clock-names = "125m", "app_125"; + #phy-cells = <0>; + }; -- 2.7.4