diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-android-avb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-android-avb.dts index bde1d3fb5683..76bc85e709ee 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-android-avb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-android-avb.dts @@ -141,7 +141,7 @@ }; }; - vm149c: vm149c@0c { + vm149c: vm149c@c { compatible = "silicon touch,vm149c"; status = "okay"; reg = <0x0c>; @@ -254,9 +254,9 @@ }; }; - /delete-node/ tc358749x@0f; + /delete-node/ tc358749x@f; - tc35874x: tc35874x@0f { + tc35874x: tc35874x@f { status = "disabled"; reg = <0x0f>; compatible = "toshiba,tc358749"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-linux.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-linux.dts index bc82021e125e..c59dce42358e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-linux.dts @@ -137,7 +137,7 @@ &i2c1 { status = "okay"; - vm149c: vm149c@0c { + vm149c: vm149c@c { compatible = "silicon touch,vm149c"; status = "okay"; reg = <0x0c>; @@ -335,6 +335,9 @@ &vopb { status = "okay"; + assigned-clocks = <&cru DCLK_VOP0_DIV>; + /* The dclk parent for VOP->HDMI must from VPLL */ + assigned-clock-parents = <&cru PLL_VPLL>; }; &vopb_mmu { @@ -343,6 +346,8 @@ &vopl { status = "okay"; + assigned-clocks = <&cru DCLK_VOP1_DIV>; + assigned-clock-parents = <&cru PLL_CPLL>; }; &vopl_mmu { diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-v13-android-avb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-v13-android-avb.dts index 0ba611e25240..9809438d94ed 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-v13-android-avb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind-lpddr4-v13-android-avb.dts @@ -127,7 +127,7 @@ &i2c1 { status = "okay"; - vm149c: vm149c@0c { + vm149c: vm149c@c { compatible = "silicon touch,vm149c"; status = "okay"; reg = <0x0c>; @@ -216,7 +216,7 @@ }; }; - /delete-node/ tc358749x@0f; + /delete-node/ tc358749x@f; tc35874x: tc35874x@0f { status = "disabled"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dtsi index 6b96f571c8cb..26f2737da34f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb-ind.dtsi @@ -793,7 +793,7 @@ rst_gpio_number = <&gpio1 1 GPIO_ACTIVE_HIGH>; }; - tc358749x: tc358749x@0f { + tc358749x: tc358749x@f { #sound-dai-cells = <0>; compatible = "toshiba,tc358749x"; reg = <0x0f>; @@ -914,7 +914,7 @@ }; }; - sensor@0d { + sensor@d { status = "okay"; compatible = "ak8963"; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-mid-818-android.dts b/arch/arm64/boot/dts/rockchip/rk3399-mid-818-android.dts index 3eda89f629ad..abe6a9d6863b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-mid-818-android.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-mid-818-android.dts @@ -705,7 +705,7 @@ mpu-debug = <1>; }; - sensor@0d { + sensor@d { status = "okay"; compatible = "ak8963"; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator-linux-for-rk1808-cascade.dts b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator-linux-for-rk1808-cascade.dts index e1e482938481..669491480022 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator-linux-for-rk1808-cascade.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator-linux-for-rk1808-cascade.dts @@ -400,7 +400,7 @@ }; }; - vm149c: vm149c@0c { + vm149c: vm149c@c { compatible = "silicon touch,vm149c"; status = "okay"; reg = <0x0c>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator-linux.dts b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator-linux.dts index 0dbe011b02d7..fe85b95428ca 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator-linux.dts @@ -355,7 +355,7 @@ }; }; - vm149c: vm149c@0c { + vm149c: vm149c@c { compatible = "silicon touch,vm149c"; status = "okay"; reg = <0x0c>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-tve1030g-avb.dts b/arch/arm64/boot/dts/rockchip/rk3399-tve1030g-avb.dts index eeca9cf54373..01281ccef008 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-tve1030g-avb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-tve1030g-avb.dts @@ -13,7 +13,7 @@ &i2c1 { status = "okay"; - vm149c: vm149c@0c { + vm149c: vm149c@c { compatible = "silicon touch,vm149c"; status = "okay"; reg = <0x0c>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v10-linux.dts b/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v10-linux.dts index 8d505aa839a8..8a9d57d387b0 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v10-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v10-linux.dts @@ -705,7 +705,7 @@ layout = <3>; }; - vm149c: vm149c@0c { + vm149c: vm149c@c { compatible = "silicon touch,vm149c"; status = "okay"; reg = <0x0c>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v11-linux.dts b/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v11-linux.dts index 7621cf27c766..3cb1ae1744c8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v11-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v11-linux.dts @@ -725,7 +725,7 @@ layout = <3>; }; - vm149c: vm149c@0c { + vm149c: vm149c@c { compatible = "silicon touch,vm149c"; status = "okay"; reg = <0x0c>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v14-linux.dts b/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v14-linux.dts index 4f8546eb80bf..42fdbcc98fd9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v14-linux.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399pro-evb-v14-linux.dts @@ -60,7 +60,7 @@ i2c-scl-rising-time-ns = <345>; i2c-scl-falling-time-ns = <11>; - vm149c: vm149c@0c { + vm149c: vm149c@c { compatible = "silicon touch,vm149c"; status = "okay"; reg = <0x0c>; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index ef28e01dd172..6a8e91a7c256 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -4705,6 +4705,12 @@ static void vop2_disable(struct drm_crtc *crtc) if (--vop2->enable_count > 0) return; + /* + * Reset AXI to get a clean state, which is conducive to recovering + * from exceptions when enable at next time(such as iommu page fault) + */ + vop2_clk_reset(vop2->axi_rst); + if (vop2->is_iommu_enabled) { /* * vop2 standby complete, so iommu detach is safe. diff --git a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c index ab538e563162..bc643379902d 100644 --- a/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_bt1120_v4l2.c @@ -627,7 +627,8 @@ static void enable_stream(struct v4l2_subdev *sd, bool en) if (en) { if (bt1120->rk628->version >= RK628F_VERSION) { rk628_i2c_read(bt1120->rk628, HDMI_RX_SCDC_REGS2, &val); - if (rk628_hdmirx_scdc_ced_err(bt1120->rk628)) { + if (rk628_hdmirx_scdc_ced_err(bt1120->rk628) || + !rk628_hdmirx_is_locked(bt1120->rk628)) { rk628_hdmirx_plugout(sd); schedule_delayed_work(&bt1120->delayed_work_enable_hotplug, msecs_to_jiffies(800)); diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index ee9ee734d34b..d47f21c43898 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -939,7 +939,8 @@ static void enable_stream(struct v4l2_subdev *sd, bool en) return; } - if (rk628_hdmirx_scdc_ced_err(csi->rk628)) { + if (rk628_hdmirx_scdc_ced_err(csi->rk628) || + !rk628_hdmirx_is_locked(csi->rk628)) { rk628_hdmirx_plugout(sd); schedule_delayed_work(&csi->delayed_work_enable_hotplug, msecs_to_jiffies(800)); diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index a31a525c1154..9946403c7da3 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -1079,6 +1079,10 @@ static __maybe_unused u32 hdmirxphy_read(struct rk628 *rk628, u32 offset) static void rk628_hdmirxphy_enable(struct rk628 *rk628, bool is_hdmi2, bool scramble_en) { + hdmirxphy_write(rk628, 0x3e, 0x0); + hdmirxphy_write(rk628, 0x5e, 0x0); + hdmirxphy_write(rk628, 0x7e, 0x0); + hdmirxphy_write(rk628, 0x02, 0x1860); hdmirxphy_write(rk628, 0x03, 0x0060); if (!is_hdmi2 && scramble_en) @@ -1093,10 +1097,14 @@ static void rk628_hdmirxphy_enable(struct rk628 *rk628, bool is_hdmi2, bool scra hdmirxphy_write(rk628, 0x2d, 0x008c); hdmirxphy_write(rk628, 0x2e, 0x0001); - if (is_hdmi2) + if (is_hdmi2) { hdmirxphy_write(rk628, 0x0e, 0x0108); - else + hdmirxphy_write(rk628, 0x3e, 0x610); + hdmirxphy_write(rk628, 0x5e, 0x610); + hdmirxphy_write(rk628, 0x7e, 0x610); + } else { hdmirxphy_write(rk628, 0x0e, 0x0008); + } } @@ -1118,8 +1126,10 @@ static int rk628_hdmirx_cec_log_addr(struct cec_adapter *adap, u8 logical_addr) else cec->addresses |= BIT(logical_addr) | BIT(15); + mutex_lock(&rk628->rst_lock); rk628_i2c_write(rk628, HDMI_RX_CEC_ADDR_L, cec->addresses & 0xff); rk628_i2c_write(rk628, HDMI_RX_CEC_ADDR_H, (cec->addresses >> 8) & 0xff); + mutex_unlock(&rk628->rst_lock); return 0; } @@ -1129,13 +1139,13 @@ static int rk628_hdmirx_cec_enable(struct cec_adapter *adap, bool enable) struct rk628_hdmirx_cec *cec = cec_get_drvdata(adap); struct rk628 *rk628 = cec->rk628; + mutex_lock(&rk628->rst_lock); if (!enable) { rk628_i2c_write(rk628, HDMI_RX_AUD_CEC_IEN_CLR, ~0); rk628_i2c_update_bits(rk628, HDMI_RX_DMI_DISABLE_IF, CEC_ENABLE_MASK, 0); } else { unsigned int irqs; - rk628_hdmirx_cec_log_addr(cec->adap, CEC_LOG_ADDR_INVALID); rk628_i2c_update_bits(rk628, HDMI_RX_DMI_DISABLE_IF, CEC_ENABLE_MASK, CEC_ENABLE_MASK); @@ -1146,6 +1156,7 @@ static int rk628_hdmirx_cec_enable(struct cec_adapter *adap, bool enable) irqs = ERROR_INIT_ENSET | NACK_ENSET | EOM_ENSET | DONE_ENSET; rk628_i2c_write(rk628, HDMI_RX_AUD_CEC_IEN_SET, irqs); } + mutex_unlock(&rk628->rst_lock); return 0; } @@ -1177,11 +1188,13 @@ static int rk628_hdmirx_cec_transmit(struct cec_adapter *adap, u8 attempts, if (msg_len <= 0) return 0; + mutex_lock(&rk628->rst_lock); for (i = 0; i < msg_len; i++) rk628_i2c_write(rk628, HDMI_RX_CEC_TX_DATA_0 + i * 4, msg->msg[i]); rk628_i2c_write(rk628, HDMI_RX_CEC_TX_CNT, msg_len); rk628_i2c_write(rk628, HDMI_RX_CEC_CTRL, ctrl | CEC_SEND); + mutex_unlock(&rk628->rst_lock); return 0; } @@ -1880,6 +1893,24 @@ bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628) } EXPORT_SYMBOL(rk628_hdmirx_scdc_ced_err); +bool rk628_hdmirx_is_locked(struct rk628 *rk628) +{ + u32 val; + + rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS1, &val); + if (!(val & 0x100)) + return false; + if (!(val & 0x200)) + return false; + if (!(val & 0x400)) + return false; + if (!(val & 0x800)) + return false; + + return true; +} +EXPORT_SYMBOL(rk628_hdmirx_is_locked); + bool rk628_hdmirx_is_signal_change_ists(struct rk628 *rk628, u32 md_ints, u32 pdec_ints) { u32 md_mask, pded_madk; diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index 095178ff6cd3..e3dedad6b5ca 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -547,6 +547,7 @@ u8 rk628_hdmirx_get_color_space(struct rk628 *rk628); int rk628_hdmirx_get_hdcp_enc_status(struct rk628 *rk628); void rk628_hdmirx_controller_reset(struct rk628 *rk628); bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628); +bool rk628_hdmirx_is_locked(struct rk628 *rk628); bool rk628_hdmirx_is_signal_change_ists(struct rk628 *rk628, u32 md_ints, u32 pdec_ints); void rk628_hdmirx_cec_irq(struct rk628 *rk628, struct rk628_hdmirx_cec *cec); diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index 7fa9d7bc1534..5c46a4fd2cfa 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -39,14 +39,6 @@ config PHY_ROCKCHIP_EMMC help Enable this to support the Rockchip EMMC PHY. -config PHY_ROCKCHIP_INNO_COMBPHY - tristate "Rockchip INNO USB 3.0 and PCIe COMBPHY Driver" - depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST - select GENERIC_PHY - help - Enable this to support the Rockchip SoCs COMBPHY. - If unsure, say N. - config PHY_ROCKCHIP_INNO_HDMI tristate "Rockchip INNO HDMI PHY Driver" depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile index 0996befcbed3..2b0b6b341a2a 100644 --- a/drivers/phy/rockchip/Makefile +++ b/drivers/phy/rockchip/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_PHY_ROCKCHIP_CSI2_DPHY) += phy-rockchip-csi2-dphy-hw.o \ obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o obj-$(CONFIG_PHY_ROCKCHIP_DPHY_RX0) += phy-rockchip-dphy-rx0.o obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o -obj-$(CONFIG_PHY_ROCKCHIP_INNO_COMBPHY) += phy-rockchip-inno-combphy.o obj-$(CONFIG_PHY_ROCKCHIP_INNO_CSIDPHY) += phy-rockchip-inno-csidphy.o obj-$(CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY) += phy-rockchip-inno-dsidphy.o obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi-phy.o diff --git a/drivers/phy/rockchip/phy-rockchip-inno-combphy.c b/drivers/phy/rockchip/phy-rockchip-inno-combphy.c deleted file mode 100644 index 8b93016edce5..000000000000 --- a/drivers/phy/rockchip/phy-rockchip-inno-combphy.c +++ /dev/null @@ -1,1024 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip USB3.0 and PCIE COMBPHY with Innosilicon IP block driver - * - * Copyright (C) 2018 Fuzhou Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BIT_WRITEABLE_SHIFT 16 - -struct rockchip_combphy_priv; - -enum rockchip_combphy_rst { - OTG_RSTN = 0, - PHY_POR_RSTN = 1, - PHY_APB_RSTN = 2, - PHY_PIPE_RSTN = 3, - PHY_GRF_P_RSTN = 4, - PHY_RESET_MAX = 5, -}; - -struct combphy_reg { - u32 offset; - u32 bitend; - u32 bitstart; - u32 disable; - u32 enable; -}; - -struct rockchip_combphy_grfcfg { - struct combphy_reg pipe_l1_sel; - struct combphy_reg pipe_l1_set; - struct combphy_reg pipe_l1pd_sel; - struct combphy_reg pipe_l1pd_p3; - struct combphy_reg pipe_l0pd_sel; - struct combphy_reg pipe_l0pd_p3; - struct combphy_reg pipe_clk_sel; - struct combphy_reg pipe_clk_set; - struct combphy_reg pipe_rate_sel; - struct combphy_reg pipe_rate_set; - struct combphy_reg pipe_mode_sel; - struct combphy_reg pipe_mode_set; - struct combphy_reg pipe_txrx_sel; - struct combphy_reg pipe_txrx_set; - struct combphy_reg pipe_width_sel; - struct combphy_reg pipe_width_set; - struct combphy_reg pipe_usb3_sel; - struct combphy_reg pipe_pll_lock; - struct combphy_reg pipe_status_l0; - struct combphy_reg pipe_l0rxterm_sel; - struct combphy_reg pipe_l1rxterm_sel; - struct combphy_reg pipe_l0rxterm_set; - struct combphy_reg pipe_l1rxterm_set; - struct combphy_reg pipe_l0rxelec_set; - struct combphy_reg u3_port_disable; - struct combphy_reg u3_port_num; -}; - -struct rockchip_combphy_cfg { - const struct rockchip_combphy_grfcfg grfcfg; - int (*combphy_cfg)(struct rockchip_combphy_priv *priv); - int (*combphy_low_power_ctrl)(struct rockchip_combphy_priv *priv, - bool en); -}; - -struct rockchip_combphy_priv { - bool phy_initialized; - bool phy_suspended; - u8 phy_type; - void __iomem *mmio; - struct device *dev; - struct clk *ref_clk; - struct phy *phy; - struct regmap *combphy_grf; - struct regmap *usb_pcie_grf; - struct reset_control *rsts[PHY_RESET_MAX]; - const struct rockchip_combphy_cfg *cfg; -}; - -static const char *get_reset_name(enum rockchip_combphy_rst rst) -{ - switch (rst) { - case OTG_RSTN: - return "otg-rst"; - case PHY_POR_RSTN: - return "combphy-por"; - case PHY_APB_RSTN: - return "combphy-apb"; - case PHY_PIPE_RSTN: - return "combphy-pipe"; - case PHY_GRF_P_RSTN: - return "usb3phy_grf_p"; - default: - return "invalid"; - } -} - -static inline bool param_read(struct regmap *base, - const struct combphy_reg *reg, u32 val) -{ - int ret; - u32 mask, orig, tmp; - - ret = regmap_read(base, reg->offset, &orig); - if (ret) - return false; - - mask = GENMASK(reg->bitend, reg->bitstart); - tmp = (orig & mask) >> reg->bitstart; - - return tmp == val; -} - -static inline int param_write(struct regmap *base, - const struct combphy_reg *reg, bool en) -{ - u32 val, mask, tmp; - - tmp = en ? reg->enable : reg->disable; - mask = GENMASK(reg->bitend, reg->bitstart); - val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); - - return regmap_write(base, reg->offset, val); -} - -static ssize_t u3phy_mode_show(struct device *device, - struct device_attribute *attr, - char *buf) -{ - struct rockchip_combphy_priv *priv = dev_get_drvdata(device); - - if (param_read(priv->usb_pcie_grf, &priv->cfg->grfcfg.u3_port_num, 0)) - return sprintf(buf, "u2\n"); - else - return sprintf(buf, "u3\n"); -} - -static ssize_t u3phy_mode_store(struct device *device, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct rockchip_combphy_priv *priv = dev_get_drvdata(device); - - if (!strncmp(buf, "u3", 2) && - param_read(priv->usb_pcie_grf, &priv->cfg->grfcfg.u3_port_num, 0)) { - /* - * Enable USB 3.0 rx termination, need to select - * pipe_l0_rxtermination from USB 3.0 controller. - */ - param_write(priv->combphy_grf, - &priv->cfg->grfcfg.pipe_l0rxterm_sel, false); - /* Set xHCI USB 3.0 port number to 1 */ - param_write(priv->usb_pcie_grf, - &priv->cfg->grfcfg.u3_port_num, true); - /* Enable xHCI USB 3.0 port */ - param_write(priv->usb_pcie_grf, - &priv->cfg->grfcfg.u3_port_disable, false); - dev_info(priv->dev, "Set usb3.0 and usb2.0 mode successfully\n"); - } else if (!strncmp(buf, "u2", 2) && - param_read(priv->usb_pcie_grf, - &priv->cfg->grfcfg.u3_port_num, 1)) { - /* - * Disable USB 3.0 rx termination, need to select - * pipe_l0_rxtermination from grf and remove rx - * termimation by grf. - */ - param_write(priv->combphy_grf, - &priv->cfg->grfcfg.pipe_l0rxterm_set, false); - param_write(priv->combphy_grf, - &priv->cfg->grfcfg.pipe_l0rxterm_sel, true); - /* Set xHCI USB 3.0 port number to 0 */ - param_write(priv->usb_pcie_grf, - &priv->cfg->grfcfg.u3_port_num, false); - /* Disable xHCI USB 3.0 port */ - param_write(priv->usb_pcie_grf, - &priv->cfg->grfcfg.u3_port_disable, true); - /* - * Note: - * Don't disable the USB 3.0 PIPE pclk here(set reg - * pipe_usb3_sel to false), because USB 3.0 PHY depend - * on this clk, if we disable it, we need to reinit - * the USB 3.0 PHY when use USB 3.0 mode, in order to - * simplify the process, don't disable this PIPE pclk. - */ - dev_info(priv->dev, "Set usb2.0 only mode successfully\n"); - } else { - dev_info(priv->dev, "Same or illegal mode\n"); - } - - return count; -} - -static DEVICE_ATTR_RW(u3phy_mode); - -static struct attribute *rockchip_combphy_u3phy_mode_attrs[] = { - &dev_attr_u3phy_mode.attr, - NULL, -}; - -static struct attribute_group rockchip_combphy_u3phy_mode_attr_group = { - .name = NULL, /* we want them in the same directory */ - .attrs = rockchip_combphy_u3phy_mode_attrs, -}; - -static u32 rockchip_combphy_pll_lock(struct rockchip_combphy_priv *priv) -{ - const struct rockchip_combphy_grfcfg *grfcfg; - u32 mask, val; - - grfcfg = &priv->cfg->grfcfg; - mask = GENMASK(grfcfg->pipe_pll_lock.bitend, - grfcfg->pipe_pll_lock.bitstart); - - regmap_read(priv->combphy_grf, grfcfg->pipe_pll_lock.offset, &val); - val = (val & mask) >> grfcfg->pipe_pll_lock.bitstart; - - return val; -} - -static u32 rockchip_combphy_is_ready(struct rockchip_combphy_priv *priv) -{ - const struct rockchip_combphy_grfcfg *grfcfg; - u32 mask, val; - - grfcfg = &priv->cfg->grfcfg; - mask = GENMASK(grfcfg->pipe_status_l0.bitend, - grfcfg->pipe_status_l0.bitstart); - - regmap_read(priv->combphy_grf, grfcfg->pipe_status_l0.offset, &val); - val = (val & mask) >> grfcfg->pipe_status_l0.bitstart; - - return val; -} - -static int phy_pcie_init(struct rockchip_combphy_priv *priv) -{ - const struct rockchip_combphy_grfcfg *grfcfg; - u32 val; - int ret = 0; - - grfcfg = &priv->cfg->grfcfg; - - /* reset PCIe phy to default configuration */ - reset_control_assert(priv->rsts[PHY_POR_RSTN]); - reset_control_assert(priv->rsts[PHY_APB_RSTN]); - reset_control_assert(priv->rsts[PHY_PIPE_RSTN]); - - reset_control_deassert(priv->rsts[PHY_POR_RSTN]); - /* Wait PHY power on stable */ - udelay(5); - reset_control_deassert(priv->rsts[PHY_APB_RSTN]); - udelay(5); - - /* Set rxtermination for lane0 */ - param_write(priv->combphy_grf, &grfcfg->pipe_l0rxterm_set, true); - /* Set rxtermination for lane1 */ - param_write(priv->combphy_grf, &grfcfg->pipe_l1rxterm_set, true); - /* Select pipe_l0_rxtermination from grf */ - param_write(priv->combphy_grf, &grfcfg->pipe_l0rxterm_sel, true); - /* Select pipe_l1_rxtermination from grf */ - param_write(priv->combphy_grf, &grfcfg->pipe_l1rxterm_sel, true); - /* Select rxelecidle_disable and txcommonmode from PCIe controller */ - param_write(priv->combphy_grf, &grfcfg->pipe_txrx_sel, false); - - /* Start to configurate PHY registers for PCIE. */ - if (priv->cfg->combphy_cfg) { - ret = priv->cfg->combphy_cfg(priv); - if (ret) - goto error; - } - - /* Wait Tx PLL lock */ - usleep_range(300, 350); - ret = readx_poll_timeout_atomic(rockchip_combphy_pll_lock, priv, val, - val == grfcfg->pipe_pll_lock.enable, - 10, 1000); - if (ret) { - dev_err(priv->dev, "wait phy PLL lock timeout\n"); - goto error; - } - - reset_control_deassert(priv->rsts[PHY_PIPE_RSTN]); -error: - return ret; -} - -static int phy_u3_init(struct rockchip_combphy_priv *priv) -{ - const struct rockchip_combphy_grfcfg *grfcfg; - u32 val; - int ret = 0; - - grfcfg = &priv->cfg->grfcfg; - - /* Reset the USB3 controller first. */ - reset_control_assert(priv->rsts[OTG_RSTN]); - - reset_control_deassert(priv->rsts[PHY_POR_RSTN]); - /* Wait PHY power on stable. */ - udelay(5); - - reset_control_deassert(priv->rsts[PHY_APB_RSTN]); - udelay(5); - - /* - * Start to configurate PHY registers for USB3. - * Note: set operation must be done before corresponding - * sel operation, otherwise, the PIPE PHY status lane0 - * may be unable to get ready. - */ - - /* Disable PHY lane1 which isn't needed for USB3 */ - param_write(priv->combphy_grf, &grfcfg->pipe_l1_set, true); - param_write(priv->combphy_grf, &grfcfg->pipe_l1_sel, true); - - /* Set PHY Tx and Rx for USB3 */ - param_write(priv->combphy_grf, &grfcfg->pipe_txrx_set, true); - param_write(priv->combphy_grf, &grfcfg->pipe_txrx_sel, true); - - /* Set PHY PIPE MAC pclk request */ - param_write(priv->combphy_grf, &grfcfg->pipe_clk_set, true); - param_write(priv->combphy_grf, &grfcfg->pipe_clk_sel, true); - - /* Set PHY PIPE rate for USB3 */ - param_write(priv->combphy_grf, &grfcfg->pipe_rate_set, true); - param_write(priv->combphy_grf, &grfcfg->pipe_rate_sel, true); - - /* Set PHY mode for USB3 */ - param_write(priv->combphy_grf, &grfcfg->pipe_mode_set, true); - param_write(priv->combphy_grf, &grfcfg->pipe_mode_sel, true); - - /* Set PHY data bus width for USB3 */ - param_write(priv->combphy_grf, &grfcfg->pipe_width_set, true); - param_write(priv->combphy_grf, &grfcfg->pipe_width_sel, true); - - /* Select PIPE for USB3 */ - param_write(priv->combphy_grf, &grfcfg->pipe_usb3_sel, true); - - if (priv->cfg->combphy_cfg) { - ret = priv->cfg->combphy_cfg(priv); - if (ret) - goto error; - } - - /* Wait Tx PLL lock */ - usleep_range(300, 350); - ret = readx_poll_timeout_atomic(rockchip_combphy_pll_lock, priv, val, - val == grfcfg->pipe_pll_lock.enable, - 10, 1000); - if (ret) { - dev_err(priv->dev, "wait phy PLL lock timeout\n"); - goto error; - } - - reset_control_deassert(priv->rsts[PHY_PIPE_RSTN]); - - /* Wait PIPE PHY status lane0 ready */ - ret = readx_poll_timeout_atomic(rockchip_combphy_is_ready, priv, val, - val == grfcfg->pipe_status_l0.enable, - 10, 1000); - if (ret) { - dev_err(priv->dev, "wait phy status lane0 ready timeout\n"); - goto error; - } - - reset_control_deassert(priv->rsts[OTG_RSTN]); - -error: - return ret; -} - -static int rockchip_combphy_set_phy_type(struct rockchip_combphy_priv *priv) -{ - int ret = 0; - - if (priv->phy_initialized) - return ret; - - switch (priv->phy_type) { - case PHY_TYPE_PCIE: - ret = phy_pcie_init(priv); - break; - case PHY_TYPE_USB3: - ret = phy_u3_init(priv); - if (ret) - return ret; - - /* Attributes */ - ret = sysfs_create_group(&priv->dev->kobj, - &rockchip_combphy_u3phy_mode_attr_group); - break; - default: - dev_err(priv->dev, "incompatible PHY type\n"); - return -EINVAL; - } - - return ret; -} - -static int rockchip_combphy_init(struct phy *phy) -{ - struct rockchip_combphy_priv *priv = phy_get_drvdata(phy); - int ret; - - ret = clk_prepare_enable(priv->ref_clk); - if (ret) { - dev_err(priv->dev, "failed to enable ref_clk\n"); - return ret; - } - - ret = rockchip_combphy_set_phy_type(priv); - if (ret) { - dev_err(priv->dev, "failed to set phy type\n"); - return ret; - } - - priv->phy_initialized = true; - - return 0; -} - -static int rockchip_combphy_exit(struct phy *phy) -{ - struct rockchip_combphy_priv *priv = phy_get_drvdata(phy); - - /* - * Note: don't assert PHY reset here, because - * we set many phy configurations during phy - * init to reduce PHY power consumption, if we - * assert PHY reset here, these configurations - * will be lost, and increase power consumption. - */ - clk_disable_unprepare(priv->ref_clk); - - /* in case of waiting phy PLL lock timeout */ - if (priv->phy_type == PHY_TYPE_PCIE) { - reset_control_assert(priv->rsts[PHY_GRF_P_RSTN]); - udelay(5); - reset_control_deassert(priv->rsts[PHY_GRF_P_RSTN]); - priv->phy_initialized = false; - } - - return 0; -} - -static int rockchip_combphy_power_on(struct phy *phy) -{ - struct rockchip_combphy_priv *priv = phy_get_drvdata(phy); - const struct rockchip_combphy_grfcfg *grfcfg; - - if (!priv->phy_suspended) - return 0; - - grfcfg = &priv->cfg->grfcfg; - - if (priv->phy_type == PHY_TYPE_USB3) { - if (priv->cfg->combphy_low_power_ctrl) - priv->cfg->combphy_low_power_ctrl(priv, false); - - /* Enable lane 0 squelch detection */ - param_write(priv->combphy_grf, &grfcfg->pipe_l0rxelec_set, - false); - - /* - * Check if lane 0 powerdown is already - * controlled by USB 3.0 controller. - */ - if (param_read(priv->combphy_grf, - &grfcfg->pipe_l0pd_sel, 0)) - goto done; - - /* Exit to P0 from P3 */ - param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_p3, false); - usleep_range(250, 300); - - /* - * Set lane 0 powerdown to be controlled - * by USB 3.0 controller. - */ - param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_sel, false); - } - -done: - priv->phy_suspended = false; - return 0; -} - -static int rockchip_combphy_power_off(struct phy *phy) -{ - struct rockchip_combphy_priv *priv = phy_get_drvdata(phy); - const struct rockchip_combphy_grfcfg *grfcfg; - - if (priv->phy_suspended) - return 0; - - grfcfg = &priv->cfg->grfcfg; - - if (priv->phy_type == PHY_TYPE_USB3 || - priv->phy_type == PHY_TYPE_PCIE) { - /* - * Check if lane 0 powerdown is already - * controlled by grf and in P3 state. - */ - if (param_read(priv->combphy_grf, - &grfcfg->pipe_l0pd_sel, 1) && - param_read(priv->combphy_grf, - &grfcfg->pipe_l0pd_p3, 3)) - goto done; - - /* Exit to P0 */ - param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_p3, false); - param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_sel, true); - udelay(1); - - /* Enter to P3 from P0 */ - param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_p3, true); - udelay(2); - - /* - * Disable lane 0 squelch detection. - * Note: if squelch detection is disabled, - * the PHY can't detect LFPS. - */ - param_write(priv->combphy_grf, &grfcfg->pipe_l0rxelec_set, - true); - - if (priv->cfg->combphy_low_power_ctrl) - priv->cfg->combphy_low_power_ctrl(priv, true); - } - -done: - priv->phy_suspended = true; - return 0; -} - -static int rockchip_combphy_set_mode(struct phy *phy, enum phy_mode mode, int submode) -{ - struct rockchip_combphy_priv *priv = phy_get_drvdata(phy); - u32 reg; - - if (priv->phy_type != PHY_TYPE_PCIE) - return -EINVAL; - - reg = readl(priv->mmio + 0x21a8); - - if (PHY_MODE_PCIE_EP == submode) - reg |= (0x1 << 2); - else if (PHY_MODE_PCIE_RC == submode) - reg &= ~(0x1 << 2); - else - return -EINVAL; - - writel(reg, priv->mmio + 0x21a8); - return 0; -} - -static const struct phy_ops rockchip_combphy_ops = { - .init = rockchip_combphy_init, - .exit = rockchip_combphy_exit, - .power_on = rockchip_combphy_power_on, - .power_off = rockchip_combphy_power_off, - .set_mode = rockchip_combphy_set_mode, - .owner = THIS_MODULE, -}; - -static struct phy *rockchip_combphy_xlate(struct device *dev, - struct of_phandle_args *args) -{ - struct rockchip_combphy_priv *priv = dev_get_drvdata(dev); - - if (args->args_count < 1) { - dev_err(dev, "invalid number of arguments\n"); - return ERR_PTR(-EINVAL); - } - - if (priv->phy_type != PHY_NONE && priv->phy_type != args->args[0]) { - dev_err(dev, "type select %d overwriting phy type %d\n", - args->args[0], priv->phy_type); - return ERR_PTR(-ENODEV); - } - - priv->phy_type = args->args[0]; - - if (priv->phy_type < PHY_TYPE_SATA || priv->phy_type > PHY_TYPE_USB3) { - dev_err(dev, "invalid phy type select argument\n"); - return ERR_PTR(-EINVAL); - } - - return priv->phy; -} - -static int rockchip_combphy_parse_dt(struct device *dev, - struct rockchip_combphy_priv *priv) -{ - u32 i; - - priv->combphy_grf = syscon_regmap_lookup_by_phandle(dev->of_node, - "rockchip,combphygrf"); - if (IS_ERR(priv->combphy_grf)) { - dev_err(dev, "failed to find combphy grf regmap\n"); - return PTR_ERR(priv->combphy_grf); - } - - priv->usb_pcie_grf = syscon_regmap_lookup_by_phandle(dev->of_node, - "rockchip,usbpciegrf"); - if (IS_ERR(priv->usb_pcie_grf)) { - dev_err(dev, "failed to find usb_pcie_grf regmap\n"); - return PTR_ERR(priv->usb_pcie_grf); - } - - priv->ref_clk = devm_clk_get(dev, "refclk"); - if (IS_ERR(priv->ref_clk)) { - dev_err(dev, "failed to find ref clock\n"); - return PTR_ERR(priv->ref_clk); - } - - for (i = 0; i < PHY_RESET_MAX; i++) { - priv->rsts[i] = devm_reset_control_get(dev, get_reset_name(i)); - if (IS_ERR(priv->rsts[i])) { - dev_warn(dev, "no %s reset control specified\n", - get_reset_name(i)); - priv->rsts[i] = NULL; - } - } - - return 0; -} - -static int rockchip_combphy_probe(struct platform_device *pdev) -{ - struct phy_provider *phy_provider; - struct device *dev = &pdev->dev; - struct rockchip_combphy_priv *priv; - struct resource *res; - const struct rockchip_combphy_cfg *phy_cfg; - int ret; - - phy_cfg = of_device_get_match_data(dev); - if (!phy_cfg) { - dev_err(dev, "No OF match data provided\n"); - return -EINVAL; - } - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->mmio = devm_ioremap_resource(dev, res); - if (IS_ERR(priv->mmio)) { - ret = PTR_ERR(priv->mmio); - return ret; - } - - ret = rockchip_combphy_parse_dt(dev, priv); - if (ret) { - dev_err(dev, "parse dt failed, ret(%d)\n", ret); - return ret; - } - - reset_control_assert(priv->rsts[PHY_POR_RSTN]); - reset_control_assert(priv->rsts[PHY_APB_RSTN]); - reset_control_assert(priv->rsts[PHY_PIPE_RSTN]); - - priv->phy_type = PHY_NONE; - priv->dev = dev; - priv->cfg = phy_cfg; - priv->phy = devm_phy_create(dev, NULL, &rockchip_combphy_ops); - if (IS_ERR(priv->phy)) { - dev_err(dev, "failed to create combphy\n"); - return PTR_ERR(priv->phy); - } - - dev_set_drvdata(dev, priv); - phy_set_drvdata(priv->phy, priv); - - phy_provider = devm_of_phy_provider_register(dev, - rockchip_combphy_xlate); - return PTR_ERR_OR_ZERO(phy_provider); -} - -static int rockchip_combphy_remove(struct platform_device *pdev) -{ - struct rockchip_combphy_priv *priv = platform_get_drvdata(pdev); - - if (priv->phy_type == PHY_TYPE_USB3 && priv->phy_initialized) - sysfs_remove_group(&priv->dev->kobj, - &rockchip_combphy_u3phy_mode_attr_group); - - return 0; -} - -static int rk1808_combphy_cfg(struct rockchip_combphy_priv *priv) -{ - unsigned long rate; - u32 reg; - bool ssc_en = false; - - rate = clk_get_rate(priv->ref_clk); - - /* Configure PHY reference clock frequency */ - switch (rate) { - case 24000000: - /* - * The default PHY refclk frequency - * configuration is 24MHz. - */ - break; - case 25000000: - writel(0x00, priv->mmio + 0x2118); - writel(0x64, priv->mmio + 0x211c); - writel(0x01, priv->mmio + 0x2020); - writel(0x64, priv->mmio + 0x2028); - writel(0x21, priv->mmio + 0x2030); - - if (priv->phy_type == PHY_TYPE_PCIE) { - writel(0x1, priv->mmio + 0x3020); - writel(0x64, priv->mmio + 0x3028); - writel(0x21, priv->mmio + 0x3030); - } - - break; - case 50000000: - writel(0x00, priv->mmio + 0x2118); - writel(0x32, priv->mmio + 0x211c); - writel(0x01, priv->mmio + 0x2020); - writel(0x32, priv->mmio + 0x2028); - writel(0x21, priv->mmio + 0x2030); - break; - default: - dev_err(priv->dev, "Unsupported rate: %lu\n", rate); - return -EINVAL; - } - - if (priv->phy_type == PHY_TYPE_PCIE) { - /* turn on pcie phy pd */ - writel(0x08400000, priv->mmio + 0x0); - writel(0x03030000, priv->mmio + 0x8); - - /* Adjust Lane 0 Rx interface timing */ - writel(0x20, priv->mmio + 0x20ac); - writel(0x12, priv->mmio + 0x20c8); - writel(0x76, priv->mmio + 0x2150); - - /* Adjust Lane 1 Rx interface timing */ - writel(0x20, priv->mmio + 0x30ac); - writel(0x12, priv->mmio + 0x30c8); - writel(0x76, priv->mmio + 0x3150); - /* Set PHY output refclk path */ - writel(0x0, priv->mmio + 0x21a4); - writel(0x0, priv->mmio + 0x21a8); - writel(0xb, priv->mmio + 0x21ec); - - /* Physical ordered set for PCIe */ - writel(0x02, priv->mmio + 0x45c0); - writel(0x83, priv->mmio + 0x45c4); - writel(0x03, priv->mmio + 0x45c8); - writel(0x43, priv->mmio + 0x45cc); - writel(0x00, priv->mmio + 0x45d0); - writel(0xbc, priv->mmio + 0x45d4); - - /* Boost pre-emphasis */ - writel(0xaa, priv->mmio + 0x21b8); - writel(0xaa, priv->mmio + 0x31b8); - } else if (priv->phy_type == PHY_TYPE_USB3) { - /* - * Disable PHY Lane 1 which isn't needed - * for USB3 to reduce power consumption. - */ - /* Lane 1 cdr power down */ - writel(0x09, priv->mmio + 0x3148); - - /* Lane 1 rx bias disable */ - writel(0x01, priv->mmio + 0x21cc); - - /* Lane 1 cdr disable */ - writel(0x08, priv->mmio + 0x30c4); - writel(0x08, priv->mmio + 0x20f4); - - /* Lane 1 rx lock disable and tx bias disable */ - writel(0x12, priv->mmio + 0x3150); - - /* Lane 1 rx termination disable, and tx_cmenb disable */ - writel(0x04, priv->mmio + 0x3080); - - /* Lane 1 tx termination disable */ - writel(0x1d, priv->mmio + 0x3090); - - /* Lane 1 tx driver disable */ - writel(0x50, priv->mmio + 0x21c4); - writel(0x10, priv->mmio + 0x2050); - - /* Lane 1 txldo_refsel disable */ - writel(0x81, priv->mmio + 0x31a8); - - /* Lane 1 txdetrx_en disable */ - writel(0x00, priv->mmio + 0x31e8); - - /* Lane 1 rxcm_en disable */ - writel(0x08, priv->mmio + 0x30c0); - - /* Adjust Lane 0 Rx interface timing */ - writel(0x20, priv->mmio + 0x20ac); - - /* Set and enable SSC */ - switch (rate) { - case 24000000: - /* Set SSC rate to 31.25KHz */ - reg = readl(priv->mmio + 0x2108); - reg = (reg & ~0xf) | 0x1; - writel(reg, priv->mmio + 0x2108); - ssc_en = true; - break; - case 25000000: - /* Set SSC rate to 32.55KHz */ - reg = readl(priv->mmio + 0x2108); - reg = (reg & ~0xf) | 0x6; - writel(reg, priv->mmio + 0x2108); - ssc_en = true; - break; - default: - dev_warn(priv->dev, - "failed to set SSC on rate: %lu\n", rate); - break; - } - - if (ssc_en) { - /* Enable SSC */ - reg = readl(priv->mmio + 0x2120); - reg &= ~BIT(4); - writel(reg, priv->mmio + 0x2120); - - reg = readl(priv->mmio + 0x2000); - reg &= ~0x6; - writel(reg, priv->mmio + 0x2000); - } - - /* - * Tuning Tx: - * offset 0x21b8 bit[7:4]: lane 0 TX driver swing - * tuning bits with weight, "1111" represents the - * largest swing and "0000" the smallest. - */ - reg = readl(priv->mmio + 0x21b8); - reg = (reg & ~0xf0) | 0xe0; - writel(reg, priv->mmio + 0x21b8); - - /* - * Tuning Rx for RJTL: - * Decrease CDR Chump Bump current. - */ - reg = readl(priv->mmio + 0x20c8); - reg = (reg & ~0x6) | BIT(1); - writel(reg, priv->mmio + 0x20c8); - reg = readl(priv->mmio + 0x2150); - reg |= BIT(2); - writel(reg, priv->mmio + 0x2150); - } else { - dev_err(priv->dev, "failed to cfg incompatible PHY type\n"); - return -EINVAL; - } - - return 0; -} - -static int rk1808_combphy_low_power_control(struct rockchip_combphy_priv *priv, - bool en) -{ - if (priv->phy_type != PHY_TYPE_USB3) { - /* turn off pcie phy pd */ - writel(0x08400840, priv->mmio + 0x0); - writel(0x03030303, priv->mmio + 0x8); - - /* enter PCIe phy low power mode */ - writel(0x36, priv->mmio + 0x2150); - writel(0x36, priv->mmio + 0x3150); - writel(0x02, priv->mmio + 0x21e8); - writel(0x02, priv->mmio + 0x31e8); - writel(0x0c, priv->mmio + 0x2080); - writel(0x0c, priv->mmio + 0x3080); - writel(0x08, priv->mmio + 0x20c0); - writel(0x08, priv->mmio + 0x30c0); - writel(0x08, priv->mmio + 0x2058); - - writel(0x10, priv->mmio + 0x2044); - writel(0x10, priv->mmio + 0x21a8); - writel(0x10, priv->mmio + 0x31a8); - writel(0x08, priv->mmio + 0x2058); - writel(0x08, priv->mmio + 0x3058); - writel(0x40, priv->mmio + 0x205c); - writel(0x40, priv->mmio + 0x305c); - writel(0x08, priv->mmio + 0x2184); - writel(0x08, priv->mmio + 0x3184); - writel(0x00, priv->mmio + 0x2150); - writel(0x00, priv->mmio + 0x3150); - writel(0x10, priv->mmio + 0x20e0); - writel(0x00, priv->mmio + 0x21e8); - writel(0x00, priv->mmio + 0x31e8); - - return 0; - } - - if (en) { - /* Lane 0 tx_biasen disable */ - writel(0x36, priv->mmio + 0x2150); - - /* Lane 0 txdetrx_en disable */ - writel(0x02, priv->mmio + 0x21e8); - - /* Lane 0 tx_cmenb disable */ - writel(0x0c, priv->mmio + 0x2080); - - /* Lane 0 rxcm_en disable */ - writel(0x08, priv->mmio + 0x20c0); - - /* Lane 0 and Lane 1 bg_pwrdn */ - writel(0x10, priv->mmio + 0x2044); - - /* Lane 0 and Lane 1 rcomp_osenseampen disable */ - writel(0x08, priv->mmio + 0x2058); - - /* Lane 0 txldo_refsel disable and LDO disable */ - writel(0x91, priv->mmio + 0x21a8); - - /* Lane 1 LDO disable */ - writel(0x91, priv->mmio + 0x31a8); - } else { - /* Lane 0 tx_biasen enable */ - writel(0x76, priv->mmio + 0x2150); - - /* Lane 0 txdetrx_en enable */ - writel(0x02, priv->mmio + 0x21e8); - - /* Lane 0 tx_cmenb enable */ - writel(0x08, priv->mmio + 0x2080); - - /* Lane 0 rxcm_en enable */ - writel(0x18, priv->mmio + 0x20c0); - - /* Lane 0 and Lane 1 bg_pwrdn */ - writel(0x00, priv->mmio + 0x2044); - - /* Lane 0 and Lane 1 rcomp_osenseampen enable */ - writel(0x28, priv->mmio + 0x2058); - - /* Lane 0 txldo_refsel enable and LDO enable */ - writel(0x01, priv->mmio + 0x21a8); - - /* Lane 1 LDO enable */ - writel(0x81, priv->mmio + 0x31a8); - } - - return 0; -} - -static const struct rockchip_combphy_cfg rk1808_combphy_cfgs = { - .grfcfg = { - .pipe_l1_sel = { 0x0000, 15, 11, 0x00, 0x1f }, - .pipe_l1_set = { 0x0008, 13, 8, 0x00, 0x13 }, - .pipe_l1rxterm_sel = { 0x0000, 12, 12, 0x0, 0x1 }, - .pipe_l1pd_sel = { 0x0000, 11, 11, 0x0, 0x1}, - .pipe_l1pd_p3 = { 0x0008, 9, 8, 0x0, 0x3 }, - .pipe_l0rxterm_sel = { 0x0000, 7, 7, 0x0, 0x1 }, - .pipe_l0pd_sel = { 0x0000, 6, 6, 0x0, 0x1 }, - .pipe_l0pd_p3 = { 0x0008, 1, 0, 0x0, 0x3 }, - .pipe_clk_sel = { 0x0000, 3, 3, 0x0, 0x1 }, - .pipe_clk_set = { 0x0004, 7, 6, 0x1, 0x0 }, - .pipe_rate_sel = { 0x0000, 2, 2, 0x0, 0x1 }, - .pipe_rate_set = { 0x0004, 5, 4, 0x0, 0x1 }, - .pipe_mode_sel = { 0x0000, 1, 1, 0x0, 0x1 }, - .pipe_mode_set = { 0x0004, 3, 2, 0x0, 0x1 }, - .pipe_txrx_sel = { 0x0004, 15, 8, 0x10, 0x2f }, - .pipe_txrx_set = { 0x0008, 15, 14, 0x0, 0x3 }, - .pipe_l1rxterm_set = { 0x0008, 10, 10, 0x0, 0x1 }, - .pipe_l0rxterm_set = { 0x0008, 2, 2, 0x0, 0x1 }, - .pipe_l0rxelec_set = { 0x0008, 6, 6, 0x0, 0x1 }, - .pipe_width_sel = { 0x0000, 0, 0, 0x0, 0x1 }, - .pipe_width_set = { 0x0004, 1, 0, 0x2, 0x0 }, - .pipe_usb3_sel = { 0x000c, 0, 0, 0x0, 0x1 }, - .pipe_pll_lock = { 0x0034, 14, 14, 0x0, 0x1 }, - .pipe_status_l0 = { 0x0034, 7, 7, 0x1, 0x0 }, - .u3_port_disable = { 0x0434, 0, 0, 0, 1}, - .u3_port_num = { 0x0434, 15, 12, 0, 1}, - }, - .combphy_cfg = rk1808_combphy_cfg, - .combphy_low_power_ctrl = rk1808_combphy_low_power_control, -}; - -static const struct of_device_id rockchip_combphy_of_match[] = { - { - .compatible = "rockchip,rk1808-combphy", - .data = &rk1808_combphy_cfgs, - }, - { }, -}; - -MODULE_DEVICE_TABLE(of, rockchip_combphy_of_match); - -static struct platform_driver rockchip_combphy_driver = { - .probe = rockchip_combphy_probe, - .remove = rockchip_combphy_remove, - .driver = { - .name = "rockchip-combphy", - .of_match_table = rockchip_combphy_of_match, - }, -}; -module_platform_driver(rockchip_combphy_driver); - -MODULE_AUTHOR("William Wu "); -MODULE_DESCRIPTION("Rockchip USB3.0 and PCIE COMBPHY driver"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index d8eb5a5c6900..febc94ed1592 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -106,29 +106,42 @@ static bool rockchip_sai_stream_valid(struct snd_pcm_substream *substream, return false; } -static int rockchip_sai_fsync_lost_detect(struct rk_sai_dev *sai, bool en) +static int rockchip_sai_fsync_lost_threshold_cfg(struct rk_sai_dev *sai, + unsigned int sample_rate) { - unsigned int fw, cnt; + unsigned int div, cnt, mclk_rate; if (sai->is_master_mode || sai->version < SAI_VER_2311) return 0; - regmap_read(sai->regmap, SAI_FSCR, &fw); - cnt = SAI_FSCR_FW_V(fw) << 1; /* two fsync lost */ + regmap_read(sai->regmap, SAI_CKR, &div); + div = SAI_CKR_MDIV_V(div); + mclk_rate = clk_get_rate(sai->mclk) / div; + + cnt = (mclk_rate + sample_rate - 1) / sample_rate; + cnt = cnt << 1; /* two fsync lost */ + + /* the cnt is cycles of SCLK from cru, not external SCLK */ + regmap_update_bits(sai->regmap, SAI_FS_TIMEOUT, + SAI_FS_TIMEOUT_VAL_MASK, + SAI_FS_TIMEOUT_VAL(cnt)); + + return 0; +} + +static int rockchip_sai_fsync_lost_detect(struct rk_sai_dev *sai, bool en) +{ + if (sai->is_master_mode || sai->version < SAI_VER_2311) + return 0; regmap_update_bits(sai->regmap, SAI_INTCR, SAI_INTCR_FSLOSTC, SAI_INTCR_FSLOSTC); regmap_update_bits(sai->regmap, SAI_INTCR, SAI_INTCR_FSLOST_MASK, SAI_INTCR_FSLOST(en)); - /* - * the cnt is cycles of SCLK from cru, not external SCLK. - * so, suggest to set SCLK freq equal to external SCLK - * in SLAVE mode. - */ regmap_update_bits(sai->regmap, SAI_FS_TIMEOUT, - SAI_FS_TIMEOUT_VAL_MASK | SAI_FS_TIMEOUT_EN_MASK, - SAI_FS_TIMEOUT_VAL(cnt) | SAI_FS_TIMEOUT_EN(en)); + SAI_FS_TIMEOUT_EN_MASK, + SAI_FS_TIMEOUT_EN(en)); return 0; } @@ -201,12 +214,11 @@ static int rockchip_sai_runtime_suspend(struct device *dev) rockchip_sai_fsync_lost_detect(sai, 0); rockchip_sai_fsync_err_detect(sai, 0); - if (sai->is_master_mode) - regmap_update_bits(sai->regmap, SAI_XFER, - SAI_XFER_CLK_MASK | - SAI_XFER_FSS_MASK, - SAI_XFER_CLK_DIS | - SAI_XFER_FSS_DIS); + regmap_update_bits(sai->regmap, SAI_XFER, + SAI_XFER_CLK_MASK | + SAI_XFER_FSS_MASK, + SAI_XFER_CLK_DIS | + SAI_XFER_FSS_DIS); rockchip_sai_poll_clk_idle(sai); @@ -642,6 +654,8 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream, SAI_CKR_MDIV(div_bclk)); } + rockchip_sai_fsync_lost_threshold_cfg(sai, params_rate(params)); + rockchip_utils_get_performance(substream, params, dai, fifo); return 0; @@ -666,24 +680,22 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream, if (!rockchip_sai_stream_valid(substream, dai)) return 0; - if (sai->is_master_mode) { - /* - * Should wait for one BCLK ready after DIV and then ungate - * output clk to achieve the clean clk. - * - * The best way is to use delay per samplerate, but, the max time - * is quite a tiny value, so, let's make it simple to use the max - * time. - * - * The max BCLK cycle time is: 15.6us @ 8K-8Bit (64K BCLK) - */ - udelay(20); - regmap_update_bits(sai->regmap, SAI_XFER, - SAI_XFER_CLK_MASK | - SAI_XFER_FSS_MASK, - SAI_XFER_CLK_EN | - SAI_XFER_FSS_EN); - } + /* + * Should wait for one BCLK ready after DIV and then ungate + * output clk to achieve the clean clk. + * + * The best way is to use delay per samplerate, but, the max time + * is quite a tiny value, so, let's make it simple to use the max + * time. + * + * The max BCLK cycle time is: 15.6us @ 8K-8Bit (64K BCLK) + */ + udelay(20); + regmap_update_bits(sai->regmap, SAI_XFER, + SAI_XFER_CLK_MASK | + SAI_XFER_FSS_MASK, + SAI_XFER_CLK_EN | + SAI_XFER_FSS_EN); rockchip_sai_fsync_lost_detect(sai, 1); rockchip_sai_fsync_err_detect(sai, 1); diff --git a/sound/soc/rockchip/rockchip_sai.h b/sound/soc/rockchip/rockchip_sai.h index 00320aced846..a94d840f66cd 100644 --- a/sound/soc/rockchip/rockchip_sai.h +++ b/sound/soc/rockchip/rockchip_sai.h @@ -95,6 +95,7 @@ /* CKR Clock Generation Register */ #define SAI_CKR_MDIV_MASK GENMASK(14, 3) #define SAI_CKR_MDIV(x) ((x - 1) << 3) +#define SAI_CKR_MDIV_V(v) ((((v) & SAI_CKR_MDIV_MASK) >> 3) + 1) #define SAI_CKR_MSS_MASK BIT(2) #define SAI_CKR_MSS_SLAVE BIT(2) #define SAI_CKR_MSS_MASTER 0