[PATCH v7 5/5] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So get phy config values from dts and use software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training Changes in v4: - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest Changes in v5: - fix some whitespcae issue Changes in v6: - None Changes in v7: - None drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 505 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..783d57a 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..73c3290 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong <z...@rock-chips.com> + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static
[PATCH v7 2/5] Documentation: dt-bindings: phy: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang <h...@rock-chips.com> Reviewed-by: Rob Herring <r...@kernel.org> --- Changes in v2: - None Changes in v3: - modify property description and add this property to Example Changes in v4: - None Changes in v5: - None Changes in v6: - change rockchip,phy_config to rockchip,phy-config and descript it in detail. Changes in v7: - None .../devicetree/bindings/phy/phy-rockchip-typec.txt | 36 +- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..40d5e7a 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,11 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy-config : A list of voltage swing(mV) and pre-emphasis + (dB) pairs. They are 3 blocks of 4 entries and + correspond to s0p0 ~ s0p3, s1p0 ~ s1p3, + s2p0 ~ s2p3, s3p0 ~ s2p3 swing and pre-emphasis + values. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +54,21 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy-config = <0x2a 0x00>, + <0x1f 0x15>, + <0x14 0x22>, + <0x02 0x2b>, + + <0x21 0x00>, + <0x12 0x15>, + <0x02 0x22>, + <0 0>, + + <0x15 0x00>, + <0x00 0x15>, + <0 0>, + <0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +93,21 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy-config = <0x2a 0x00>, + <0x1f 0x15>, + <0x14 0x22>, + <0x02 0x2b>, + + <0x21 0x00>, + <0x12 0x15>, + <0x02 0x22>, + <0 0>, + + <0x15 0x00>, + <0x00 0x15>, + <0 0>, + <0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v7 5/5] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So get phy config values from dts and use software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang Reviewed-by: Sean Paul --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training Changes in v4: - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest Changes in v5: - fix some whitespcae issue Changes in v6: - None Changes in v7: - None drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 505 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..783d57a 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..73c3290 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp
[PATCH v7 2/5] Documentation: dt-bindings: phy: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang Reviewed-by: Rob Herring --- Changes in v2: - None Changes in v3: - modify property description and add this property to Example Changes in v4: - None Changes in v5: - None Changes in v6: - change rockchip,phy_config to rockchip,phy-config and descript it in detail. Changes in v7: - None .../devicetree/bindings/phy/phy-rockchip-typec.txt | 36 +- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..40d5e7a 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,11 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy-config : A list of voltage swing(mV) and pre-emphasis + (dB) pairs. They are 3 blocks of 4 entries and + correspond to s0p0 ~ s0p3, s1p0 ~ s1p3, + s2p0 ~ s2p3, s3p0 ~ s2p3 swing and pre-emphasis + values. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +54,21 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy-config = <0x2a 0x00>, + <0x1f 0x15>, + <0x14 0x22>, + <0x02 0x2b>, + + <0x21 0x00>, + <0x12 0x15>, + <0x02 0x22>, + <0 0>, + + <0x15 0x00>, + <0x00 0x15>, + <0 0>, + <0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +93,21 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy-config = <0x2a 0x00>, + <0x1f 0x15>, + <0x14 0x22>, + <0x02 0x2b>, + + <0x21 0x00>, + <0x12 0x15>, + <0x02 0x22>, + <0 0>, + + <0x15 0x00>, + <0x00 0x15>, + <0 0>, + <0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v7 3/5] soc: rockchip: split rockchip_typec_phy struct to separate header
we may use rockchip_phy_typec struct in other driver, so split it to separate header. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - None Changes in v3: - None Changes in v4: - None Changes in v5: - None Changes in v6: - new patch here Changes in v7: - move new element to next patch drivers/phy/rockchip/phy-rockchip-typec.c | 47 +- include/soc/rockchip/rockchip_phy_typec.h | 55 +++ 2 files changed, 56 insertions(+), 46 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..795055f 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -349,52 +350,6 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; - struct phy_reg { u16 value; u32 addr; diff --git a/include/soc/rockchip/rockchip_phy_typec.h b/include/soc/rockchip/rockchip_phy_typec.h new file mode 100644 index 000..4afe039 --- /dev/null +++ b/include/soc/rockchip/rockchip_phy_typec.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Lin Huang <h...@rock-chips.com> + */ + +#ifndef __SOC_ROCKCHIP_PHY_TYPEC_H +#define __SOC_ROCKCHIP_PHY_TYPEC_H + +struct usb3phy_reg { + u32 offset; + u32 enable_bit; + u32 write_enable; +}; + +/** + * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. + * @reg: the base address for usb3-phy config. + * @typec_conn_dir: the register of type-c connector direction. + * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. + * @external_psm: the register of type-c phy external psm clock. + * @pipe_status: the register of type-c phy pipe status. + * @usb3_host_disable: the register of type-c usb3 host disable. + * @usb3_host_port: the register of type-c usb3 host port. + * @uphy_dp_sel: the register of type-c phy DP select control. + */ +struct rockchip_usb3phy_port_cfg { + unsigned int reg; + struct usb3phy_reg typec_conn_dir; + struct usb3phy_reg usb3tousb2_en; + struct usb3phy_reg external_psm; + struct usb3phy_reg pipe_status; + struct usb3phy_reg usb3_host_disable; + struct usb3phy_reg usb3_host_port; + struct usb3phy_reg uphy_dp_sel; +}; + +struct rockchip_typec_phy { + struct device *dev; + void __iomem *base; + struct extcon_dev *extcon; + struct regmap *grf_regs; + struct clk *clk_core; + struct clk *clk_ref; + struct reset_control *uphy_rst; + struct reset_control *pipe_rst; + struct reset_control *tcphy_rst; + const struct rockchip_usb3phy_port_cfg *port_cfgs; + /* mutex to protect access to individual PHYs */ + struct mutex lock; + bool flip; + u8 mode; +}; + +#endif -- 2.7.4
[PATCH v7 3/5] soc: rockchip: split rockchip_typec_phy struct to separate header
we may use rockchip_phy_typec struct in other driver, so split it to separate header. Signed-off-by: Lin Huang --- Changes in v2: - None Changes in v3: - None Changes in v4: - None Changes in v5: - None Changes in v6: - new patch here Changes in v7: - move new element to next patch drivers/phy/rockchip/phy-rockchip-typec.c | 47 +- include/soc/rockchip/rockchip_phy_typec.h | 55 +++ 2 files changed, 56 insertions(+), 46 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..795055f 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -349,52 +350,6 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; - struct phy_reg { u16 value; u32 addr; diff --git a/include/soc/rockchip/rockchip_phy_typec.h b/include/soc/rockchip/rockchip_phy_typec.h new file mode 100644 index 000..4afe039 --- /dev/null +++ b/include/soc/rockchip/rockchip_phy_typec.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Lin Huang + */ + +#ifndef __SOC_ROCKCHIP_PHY_TYPEC_H +#define __SOC_ROCKCHIP_PHY_TYPEC_H + +struct usb3phy_reg { + u32 offset; + u32 enable_bit; + u32 write_enable; +}; + +/** + * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. + * @reg: the base address for usb3-phy config. + * @typec_conn_dir: the register of type-c connector direction. + * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. + * @external_psm: the register of type-c phy external psm clock. + * @pipe_status: the register of type-c phy pipe status. + * @usb3_host_disable: the register of type-c usb3 host disable. + * @usb3_host_port: the register of type-c usb3 host port. + * @uphy_dp_sel: the register of type-c phy DP select control. + */ +struct rockchip_usb3phy_port_cfg { + unsigned int reg; + struct usb3phy_reg typec_conn_dir; + struct usb3phy_reg usb3tousb2_en; + struct usb3phy_reg external_psm; + struct usb3phy_reg pipe_status; + struct usb3phy_reg usb3_host_disable; + struct usb3phy_reg usb3_host_port; + struct usb3phy_reg uphy_dp_sel; +}; + +struct rockchip_typec_phy { + struct device *dev; + void __iomem *base; + struct extcon_dev *extcon; + struct regmap *grf_regs; + struct clk *clk_core; + struct clk *clk_ref; + struct reset_control *uphy_rst; + struct reset_control *pipe_rst; + struct reset_control *tcphy_rst; + const struct rockchip_usb3phy_port_cfg *port_cfgs; + /* mutex to protect access to individual PHYs */ + struct mutex lock; + bool flip; + u8 mode; +}; + +#endif -- 2.7.4
[PATCH v7 4/5] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value Changes in v4: - rename variable config to tcphy_default_config Changes in v5: - None Changes in v6: - split the header file to new patch Changes in v7: - add default case when check link rate - move struct rockchip_typec_phy new element to this patch drivers/phy/rockchip/phy-rockchip-typec.c | 263 -- include/soc/rockchip/rockchip_phy_typec.h | 8 + 2 files changed, 218 insertions(+), 53 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 795055f..69af90e 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -324,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -350,6 +358,8 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) +#define DP_DEFAULT_RATE162000 + struct phy_reg { u16 value; u32 addr; @@ -372,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, { 0x20, CMN_PLL1_DSM_DIAG }, { 0,CMN_PLLSM1_USER_DEF_CTRL }, { 0,CMN_DIAG_PLL1_OVRD }, @@ -391,9 +401,52 @@ struct phy_reg dp_pll_cfg[] = { { 0x8, CMN_DIAG_PLL1_LF_PROG }, { 0x100,CMN_DIAG_PLL1_PTATIS_TUNE1 }, { 0x7, CMN_DIAG_PLL1_PTATIS_TUNE2 }, - { 0x4, CMN_DIAG_PLL1_INCLK_CTRL }, + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL }, }; +struct phy_reg dp_pll_hbr_cfg[] = { + { 0xf0, CMN_PLL1_VCOCAL_INIT }, + { 0x18, CMN_PLL1_VCOCAL_ITER }, + { 0x30b4, CMN_PLL1_VCOCAL_START }, + { 0xe1, CMN_PLL1_INTDIV }, + { 0,CMN_PLL1_FRACDIV }, + { 0x5, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, + { 0x20, CMN_PLL1_DSM_DIAG }, + { 0x1000, CMN_PLLSM1_USER_DEF_CTRL }, + { 0,CMN_DIAG_PLL1_OVRD }, + { 0,CMN_DIAG_PLL1_FBH_OVRD }, + { 0,CMN_DIAG_PLL1_FBL_OVRD }, + { 0x7, CMN_DIAG_PLL1_V2I_TUNE }, + { 0x45, CMN_DIAG_PLL1_CP_TUNE }, + { 0x8, CMN_DIAG_PLL1_LF_PROG }, + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE1 }, + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE2 }, + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL }, +}; + +struct phy_reg dp_pll_hbr2_cfg[] = { + { 0xf0, CMN_PLL1_VCOCAL_INIT
[PATCH v7 1/5] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong <z...@rock-chips.com> We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> Reviewed-by: Enric Balletbo <enric.balle...@collabora.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - None Changes in v4: - None Changes in v5: - None Changes in v6: - None Changes in v7: - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/driv
[PATCH v7 1/5] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang Reviewed-by: Sean Paul Reviewed-by: Enric Balletbo --- Changes in v2: - update patch following Enric suggest Changes in v3: - None Changes in v4: - None Changes in v5: - None Changes in v6: - None Changes in v7: - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..979355d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drive
[PATCH v7 4/5] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value Changes in v4: - rename variable config to tcphy_default_config Changes in v5: - None Changes in v6: - split the header file to new patch Changes in v7: - add default case when check link rate - move struct rockchip_typec_phy new element to this patch drivers/phy/rockchip/phy-rockchip-typec.c | 263 -- include/soc/rockchip/rockchip_phy_typec.h | 8 + 2 files changed, 218 insertions(+), 53 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 795055f..69af90e 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -324,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -350,6 +358,8 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) +#define DP_DEFAULT_RATE162000 + struct phy_reg { u16 value; u32 addr; @@ -372,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, { 0x20, CMN_PLL1_DSM_DIAG }, { 0,CMN_PLLSM1_USER_DEF_CTRL }, { 0,CMN_DIAG_PLL1_OVRD }, @@ -391,9 +401,52 @@ struct phy_reg dp_pll_cfg[] = { { 0x8, CMN_DIAG_PLL1_LF_PROG }, { 0x100,CMN_DIAG_PLL1_PTATIS_TUNE1 }, { 0x7, CMN_DIAG_PLL1_PTATIS_TUNE2 }, - { 0x4, CMN_DIAG_PLL1_INCLK_CTRL }, + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL }, }; +struct phy_reg dp_pll_hbr_cfg[] = { + { 0xf0, CMN_PLL1_VCOCAL_INIT }, + { 0x18, CMN_PLL1_VCOCAL_ITER }, + { 0x30b4, CMN_PLL1_VCOCAL_START }, + { 0xe1, CMN_PLL1_INTDIV }, + { 0,CMN_PLL1_FRACDIV }, + { 0x5, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, + { 0x20, CMN_PLL1_DSM_DIAG }, + { 0x1000, CMN_PLLSM1_USER_DEF_CTRL }, + { 0,CMN_DIAG_PLL1_OVRD }, + { 0,CMN_DIAG_PLL1_FBH_OVRD }, + { 0,CMN_DIAG_PLL1_FBL_OVRD }, + { 0x7, CMN_DIAG_PLL1_V2I_TUNE }, + { 0x45, CMN_DIAG_PLL1_CP_TUNE }, + { 0x8, CMN_DIAG_PLL1_LF_PROG }, + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE1 }, + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE2 }, + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL }, +}; + +struct phy_reg dp_pll_hbr2_cfg[] = { + { 0xf0, CMN_PLL1_VCOCAL_INIT }, + { 0x18, CMN_
[PATCH 2/2] ASoC: rockchip: cdn-dp sound output use spdif
some monitors care about the parity bit in the sub-frame of I2S, but the cdn-dp always set this bit to "1", so these monitors do not have sound output if use i2s, use spdif can fix this issue. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- sound/soc/rockchip/rk3399_gru_sound.c | 46 +-- 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 9a10181..f184168 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -220,45 +220,6 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int rockchip_sound_cdndp_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int mclk, ret; - - /* in bypass mode, the mclk has to be one of the frequencies below */ - switch (params_rate(params)) { - case 8000: - case 16000: - case 24000: - case 32000: - case 48000: - case 64000: - case 96000: - mclk = 12288000; - break; - case 11025: - case 22050: - case 44100: - case 88200: - mclk = 11289600; - break; - default: - return -EINVAL; - } - - ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, -SND_SOC_CLOCK_OUT); - if (ret < 0) { - dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret); - return ret; - } - - return 0; -} - static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -293,10 +254,6 @@ static const struct snd_soc_ops rockchip_sound_da7219_ops = { .hw_params = rockchip_sound_da7219_hw_params, }; -static const struct snd_soc_ops rockchip_sound_cdndp_ops = { - .hw_params = rockchip_sound_cdndp_hw_params, -}; - static const struct snd_soc_ops rockchip_sound_dmic_ops = { .hw_params = rockchip_sound_dmic_hw_params, }; @@ -323,8 +280,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = { [DAILINK_CDNDP] = { .name = "DP", .stream_name = "DP PCM", - .codec_dai_name = "i2s-hifi", - .ops = _sound_cdndp_ops, + .codec_dai_name = "spdif-hifi", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, }, -- 2.7.4
[PATCH 2/2] ASoC: rockchip: cdn-dp sound output use spdif
some monitors care about the parity bit in the sub-frame of I2S, but the cdn-dp always set this bit to "1", so these monitors do not have sound output if use i2s, use spdif can fix this issue. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- sound/soc/rockchip/rk3399_gru_sound.c | 46 +-- 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 9a10181..f184168 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -220,45 +220,6 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int rockchip_sound_cdndp_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - int mclk, ret; - - /* in bypass mode, the mclk has to be one of the frequencies below */ - switch (params_rate(params)) { - case 8000: - case 16000: - case 24000: - case 32000: - case 48000: - case 64000: - case 96000: - mclk = 12288000; - break; - case 11025: - case 22050: - case 44100: - case 88200: - mclk = 11289600; - break; - default: - return -EINVAL; - } - - ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, -SND_SOC_CLOCK_OUT); - if (ret < 0) { - dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret); - return ret; - } - - return 0; -} - static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -293,10 +254,6 @@ static const struct snd_soc_ops rockchip_sound_da7219_ops = { .hw_params = rockchip_sound_da7219_hw_params, }; -static const struct snd_soc_ops rockchip_sound_cdndp_ops = { - .hw_params = rockchip_sound_cdndp_hw_params, -}; - static const struct snd_soc_ops rockchip_sound_dmic_ops = { .hw_params = rockchip_sound_dmic_hw_params, }; @@ -323,8 +280,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = { [DAILINK_CDNDP] = { .name = "DP", .stream_name = "DP PCM", - .codec_dai_name = "i2s-hifi", - .ops = _sound_cdndp_ops, + .codec_dai_name = "spdif-hifi", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, }, -- 2.7.4
[PATCH 1/2] drm/rockchip: cnd-dp: adjust spdif register setting
We use jitter bypass mode for spdif, so do not need to set jitter mode related bit in SPDIF_CTRL_ADDR register. Also, we need to enable SPDIF_ENABLE bit. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- drivers/gpu/drm/rockchip/cdn-dp-reg.c | 16 +--- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..3105965 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -792,7 +792,6 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) { - u32 val; int ret; ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0); @@ -801,11 +800,7 @@ int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) return ret; } - val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; - val |= SPDIF_FIFO_MID_RANGE(0xe0); - val |= SPDIF_JITTER_THRSH(0xe0); - val |= SPDIF_JITTER_AVG_WIN(7); - writel(val, dp->regs + SPDIF_CTRL_ADDR); + writel(0, dp->regs + SPDIF_CTRL_ADDR); /* clearn the audio config and reset */ writel(0, dp->regs + AUDIO_SRC_CNTL); @@ -929,12 +924,6 @@ static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) { u32 val; - val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; - val |= SPDIF_FIFO_MID_RANGE(0xe0); - val |= SPDIF_JITTER_THRSH(0xe0); - val |= SPDIF_JITTER_AVG_WIN(7); - writel(val, dp->regs + SPDIF_CTRL_ADDR); - writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); @@ -942,9 +931,6 @@ static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; - val |= SPDIF_FIFO_MID_RANGE(0xe0); - val |= SPDIF_JITTER_THRSH(0xe0); - val |= SPDIF_JITTER_AVG_WIN(7); writel(val, dp->regs + SPDIF_CTRL_ADDR); clk_prepare_enable(dp->spdif_clk); -- 2.7.4
[PATCH 1/2] drm/rockchip: cnd-dp: adjust spdif register setting
We use jitter bypass mode for spdif, so do not need to set jitter mode related bit in SPDIF_CTRL_ADDR register. Also, we need to enable SPDIF_ENABLE bit. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- drivers/gpu/drm/rockchip/cdn-dp-reg.c | 16 +--- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..3105965 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -792,7 +792,6 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) { - u32 val; int ret; ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0); @@ -801,11 +800,7 @@ int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) return ret; } - val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; - val |= SPDIF_FIFO_MID_RANGE(0xe0); - val |= SPDIF_JITTER_THRSH(0xe0); - val |= SPDIF_JITTER_AVG_WIN(7); - writel(val, dp->regs + SPDIF_CTRL_ADDR); + writel(0, dp->regs + SPDIF_CTRL_ADDR); /* clearn the audio config and reset */ writel(0, dp->regs + AUDIO_SRC_CNTL); @@ -929,12 +924,6 @@ static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) { u32 val; - val = SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; - val |= SPDIF_FIFO_MID_RANGE(0xe0); - val |= SPDIF_JITTER_THRSH(0xe0); - val |= SPDIF_JITTER_AVG_WIN(7); - writel(val, dp->regs + SPDIF_CTRL_ADDR); - writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); @@ -942,9 +931,6 @@ static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; - val |= SPDIF_FIFO_MID_RANGE(0xe0); - val |= SPDIF_JITTER_THRSH(0xe0); - val |= SPDIF_JITTER_AVG_WIN(7); writel(val, dp->regs + SPDIF_CTRL_ADDR); clk_prepare_enable(dp->spdif_clk); -- 2.7.4
[PATCH v6 5/5] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So get phy config values from dts and use software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training Changes in v4: - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest Changes in v5: - fix some whitespcae issue Changes in v6: - None drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 505 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..d9d0d4d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..73c3290 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong <z...@rock-chips.com> + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_s
[PATCH v6 4/5] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value Changes in v4: - rename variable config to tcphy_default_config Changes in v5: - None Changes in v6: - split the header file to new patch drivers/phy/rockchip/phy-rockchip-typec.c | 261 -- 1 file changed, 208 insertions(+), 53 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 795055f..4c4b925 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -324,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -350,6 +358,8 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) +#define DP_DEFAULT_RATE162000 + struct phy_reg { u16 value; u32 addr; @@ -372,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, { 0x20, CMN_PLL1_DSM_DIAG }, { 0,CMN_PLLSM1_USER_DEF_CTRL }, { 0,CMN_DIAG_PLL1_OVRD }, @@ -391,9 +401,52 @@ struct phy_reg dp_pll_cfg[] = { { 0x8, CMN_DIAG_PLL1_LF_PROG }, { 0x100,CMN_DIAG_PLL1_PTATIS_TUNE1 }, { 0x7, CMN_DIAG_PLL1_PTATIS_TUNE2 }, - { 0x4, CMN_DIAG_PLL1_INCLK_CTRL }, + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL }, }; +struct phy_reg dp_pll_hbr_cfg[] = { + { 0xf0, CMN_PLL1_VCOCAL_INIT }, + { 0x18, CMN_PLL1_VCOCAL_ITER }, + { 0x30b4, CMN_PLL1_VCOCAL_START }, + { 0xe1, CMN_PLL1_INTDIV }, + { 0,CMN_PLL1_FRACDIV }, + { 0x5, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, + { 0x20, CMN_PLL1_DSM_DIAG }, + { 0x1000, CMN_PLLSM1_USER_DEF_CTRL }, + { 0,CMN_DIAG_PLL1_OVRD }, + { 0,CMN_DIAG_PLL1_FBH_OVRD }, + { 0,CMN_DIAG_PLL1_FBL_OVRD }, + { 0x7, CMN_DIAG_PLL1_V2I_TUNE }, + { 0x45, CMN_DIAG_PLL1_CP_TUNE }, + { 0x8, CMN_DIAG_PLL1_LF_PROG }, + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE1 }, + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE2 }, + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL }, +}; + +struct phy_reg dp_pll_hbr2_cfg[] = { + { 0xf0, CMN_PLL1_VCOCAL_INIT }, + { 0x18, CMN_PLL1_VCOCAL_ITER }, + { 0x30b4, CMN_PLL1_VCOCAL_START }, + { 0xe1, CMN_PLL1_INTDIV }, + {
[PATCH v6 4/5] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value Changes in v4: - rename variable config to tcphy_default_config Changes in v5: - None Changes in v6: - split the header file to new patch drivers/phy/rockchip/phy-rockchip-typec.c | 261 -- 1 file changed, 208 insertions(+), 53 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 795055f..4c4b925 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -324,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -350,6 +358,8 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) +#define DP_DEFAULT_RATE162000 + struct phy_reg { u16 value; u32 addr; @@ -372,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, { 0x20, CMN_PLL1_DSM_DIAG }, { 0,CMN_PLLSM1_USER_DEF_CTRL }, { 0,CMN_DIAG_PLL1_OVRD }, @@ -391,9 +401,52 @@ struct phy_reg dp_pll_cfg[] = { { 0x8, CMN_DIAG_PLL1_LF_PROG }, { 0x100,CMN_DIAG_PLL1_PTATIS_TUNE1 }, { 0x7, CMN_DIAG_PLL1_PTATIS_TUNE2 }, - { 0x4, CMN_DIAG_PLL1_INCLK_CTRL }, + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL }, }; +struct phy_reg dp_pll_hbr_cfg[] = { + { 0xf0, CMN_PLL1_VCOCAL_INIT }, + { 0x18, CMN_PLL1_VCOCAL_ITER }, + { 0x30b4, CMN_PLL1_VCOCAL_START }, + { 0xe1, CMN_PLL1_INTDIV }, + { 0,CMN_PLL1_FRACDIV }, + { 0x5, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, + { 0x20, CMN_PLL1_DSM_DIAG }, + { 0x1000, CMN_PLLSM1_USER_DEF_CTRL }, + { 0,CMN_DIAG_PLL1_OVRD }, + { 0,CMN_DIAG_PLL1_FBH_OVRD }, + { 0,CMN_DIAG_PLL1_FBL_OVRD }, + { 0x7, CMN_DIAG_PLL1_V2I_TUNE }, + { 0x45, CMN_DIAG_PLL1_CP_TUNE }, + { 0x8, CMN_DIAG_PLL1_LF_PROG }, + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE1 }, + { 0x1, CMN_DIAG_PLL1_PTATIS_TUNE2 }, + { 0x1, CMN_DIAG_PLL1_INCLK_CTRL }, +}; + +struct phy_reg dp_pll_hbr2_cfg[] = { + { 0xf0, CMN_PLL1_VCOCAL_INIT }, + { 0x18, CMN_PLL1_VCOCAL_ITER }, + { 0x30b4, CMN_PLL1_VCOCAL_START }, + { 0xe1, CMN_PLL1_INTDIV }, + { 0,CMN_PLL1_FRACDIV }, + { 0x5, C
[PATCH v6 5/5] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So get phy config values from dts and use software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang Reviewed-by: Sean Paul --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training Changes in v4: - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest Changes in v5: - fix some whitespcae issue Changes in v6: - None drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 505 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..d9d0d4d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..73c3290 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp->active_port
[PATCH v6 2/5] Documentation: dt-bindings: phy: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - None Changes in v3: - modify property description and add this property to Example Changes in v4: - None Changes in v5: - None Changes in v6: - change rockchip,phy_config to rockchip,phy-config and descript it in detail. .../devicetree/bindings/phy/phy-rockchip-typec.txt | 36 +- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..40d5e7a 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,11 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy-config : A list of voltage swing(mV) and pre-emphasis + (dB) pairs. They are 3 blocks of 4 entries and + correspond to s0p0 ~ s0p3, s1p0 ~ s1p3, + s2p0 ~ s2p3, s3p0 ~ s2p3 swing and pre-emphasis + values. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +54,21 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy-config = <0x2a 0x00>, + <0x1f 0x15>, + <0x14 0x22>, + <0x02 0x2b>, + + <0x21 0x00>, + <0x12 0x15>, + <0x02 0x22>, + <0 0>, + + <0x15 0x00>, + <0x00 0x15>, + <0 0>, + <0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +93,21 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy-config = <0x2a 0x00>, + <0x1f 0x15>, + <0x14 0x22>, + <0x02 0x2b>, + + <0x21 0x00>, + <0x12 0x15>, + <0x02 0x22>, + <0 0>, + + <0x15 0x00>, + <0x00 0x15>, + <0 0>, + <0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v6 3/5] soc: rockchip: split rockchip_typec_phy struct to separate header
we may use rockchip_phy_typec struct in other driver, so split it to separate header. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - None Changes in v3: - None Changes in v4: - None Changes in v5: - None Changes in v6: - new patch here drivers/phy/rockchip/phy-rockchip-typec.c | 47 +-- include/soc/rockchip/rockchip_phy_typec.h | 63 +++ 2 files changed, 64 insertions(+), 46 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..795055f 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -349,52 +350,6 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; - struct phy_reg { u16 value; u32 addr; diff --git a/include/soc/rockchip/rockchip_phy_typec.h b/include/soc/rockchip/rockchip_phy_typec.h new file mode 100644 index 000..be6af0e --- /dev/null +++ b/include/soc/rockchip/rockchip_phy_typec.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Lin Huang <h...@rock-chips.com> + */ + +#ifndef __SOC_ROCKCHIP_PHY_TYPEC_H +#define __SOC_ROCKCHIP_PHY_TYPEC_H + +struct usb3phy_reg { + u32 offset; + u32 enable_bit; + u32 write_enable; +}; + +/** + * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. + * @reg: the base address for usb3-phy config. + * @typec_conn_dir: the register of type-c connector direction. + * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. + * @external_psm: the register of type-c phy external psm clock. + * @pipe_status: the register of type-c phy pipe status. + * @usb3_host_disable: the register of type-c usb3 host disable. + * @usb3_host_port: the register of type-c usb3 host port. + * @uphy_dp_sel: the register of type-c phy DP select control. + */ +struct rockchip_usb3phy_port_cfg { + unsigned int reg; + struct usb3phy_reg typec_conn_dir; + struct usb3phy_reg usb3tousb2_en; + struct usb3phy_reg external_psm; + struct usb3phy_reg pipe_status; + struct usb3phy_reg usb3_host_disable; + struct usb3phy_reg usb3_host_port; + struct usb3phy_reg uphy_dp_sel; +}; + +struct phy_config { + int swing; + int pe; +}; + +struct rockchip_typec_phy { + struct device *dev; + void __iomem *base; + struct extcon_dev *extcon; + struct regmap *grf_regs; + struct clk *clk_core; + struct clk *clk_ref; + struct reset_control *uphy_rst; + struct reset_control *pipe_rst; + struct reset_control *tcphy_rst; + const struct rockchip_usb3phy_port_cfg *port_cfgs; + /* mutex to protect access to individual PHYs */ + struct mutex lock; + struct phy_config config[3][4]; + bool flip; + u8 mode; + int (*typec_phy_config)(struct phy *phy, int link_rate, + int lanes, u8 swing, u8 pre_emp); +}; + +#endif -- 2.7.4
[PATCH v6 2/5] Documentation: dt-bindings: phy: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang --- Changes in v2: - None Changes in v3: - modify property description and add this property to Example Changes in v4: - None Changes in v5: - None Changes in v6: - change rockchip,phy_config to rockchip,phy-config and descript it in detail. .../devicetree/bindings/phy/phy-rockchip-typec.txt | 36 +- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..40d5e7a 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,11 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy-config : A list of voltage swing(mV) and pre-emphasis + (dB) pairs. They are 3 blocks of 4 entries and + correspond to s0p0 ~ s0p3, s1p0 ~ s1p3, + s2p0 ~ s2p3, s3p0 ~ s2p3 swing and pre-emphasis + values. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +54,21 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy-config = <0x2a 0x00>, + <0x1f 0x15>, + <0x14 0x22>, + <0x02 0x2b>, + + <0x21 0x00>, + <0x12 0x15>, + <0x02 0x22>, + <0 0>, + + <0x15 0x00>, + <0x00 0x15>, + <0 0>, + <0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +93,21 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy-config = <0x2a 0x00>, + <0x1f 0x15>, + <0x14 0x22>, + <0x02 0x2b>, + + <0x21 0x00>, + <0x12 0x15>, + <0x02 0x22>, + <0 0>, + + <0x15 0x00>, + <0x00 0x15>, + <0 0>, + <0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v6 3/5] soc: rockchip: split rockchip_typec_phy struct to separate header
we may use rockchip_phy_typec struct in other driver, so split it to separate header. Signed-off-by: Lin Huang --- Changes in v2: - None Changes in v3: - None Changes in v4: - None Changes in v5: - None Changes in v6: - new patch here drivers/phy/rockchip/phy-rockchip-typec.c | 47 +-- include/soc/rockchip/rockchip_phy_typec.h | 63 +++ 2 files changed, 64 insertions(+), 46 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..795055f 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -349,52 +350,6 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; - struct phy_reg { u16 value; u32 addr; diff --git a/include/soc/rockchip/rockchip_phy_typec.h b/include/soc/rockchip/rockchip_phy_typec.h new file mode 100644 index 000..be6af0e --- /dev/null +++ b/include/soc/rockchip/rockchip_phy_typec.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Lin Huang + */ + +#ifndef __SOC_ROCKCHIP_PHY_TYPEC_H +#define __SOC_ROCKCHIP_PHY_TYPEC_H + +struct usb3phy_reg { + u32 offset; + u32 enable_bit; + u32 write_enable; +}; + +/** + * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. + * @reg: the base address for usb3-phy config. + * @typec_conn_dir: the register of type-c connector direction. + * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. + * @external_psm: the register of type-c phy external psm clock. + * @pipe_status: the register of type-c phy pipe status. + * @usb3_host_disable: the register of type-c usb3 host disable. + * @usb3_host_port: the register of type-c usb3 host port. + * @uphy_dp_sel: the register of type-c phy DP select control. + */ +struct rockchip_usb3phy_port_cfg { + unsigned int reg; + struct usb3phy_reg typec_conn_dir; + struct usb3phy_reg usb3tousb2_en; + struct usb3phy_reg external_psm; + struct usb3phy_reg pipe_status; + struct usb3phy_reg usb3_host_disable; + struct usb3phy_reg usb3_host_port; + struct usb3phy_reg uphy_dp_sel; +}; + +struct phy_config { + int swing; + int pe; +}; + +struct rockchip_typec_phy { + struct device *dev; + void __iomem *base; + struct extcon_dev *extcon; + struct regmap *grf_regs; + struct clk *clk_core; + struct clk *clk_ref; + struct reset_control *uphy_rst; + struct reset_control *pipe_rst; + struct reset_control *tcphy_rst; + const struct rockchip_usb3phy_port_cfg *port_cfgs; + /* mutex to protect access to individual PHYs */ + struct mutex lock; + struct phy_config config[3][4]; + bool flip; + u8 mode; + int (*typec_phy_config)(struct phy *phy, int link_rate, + int lanes, u8 swing, u8 pre_emp); +}; + +#endif -- 2.7.4
[PATCH v6 1/5] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong <z...@rock-chips.com> We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> Reviewed-by: Enric Balletbo <enric.balle...@collabora.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - None Changes in v4: - None Changes in v5: - None Changes in v6: - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockch
[PATCH v6 1/5] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang Reviewed-by: Sean Paul Reviewed-by: Enric Balletbo --- Changes in v2: - update patch following Enric suggest Changes in v3: - None Changes in v4: - None Changes in v5: - None Changes in v6: - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..979355d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -221,7 +221,1
[PATCH v5 4/4] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So get phy config values from dts and use software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training Changes in v4: - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest Changes in v5: - fix some whitespcae issue drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 505 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..d9d0d4d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..73c3290 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong <z...@rock-chips.com> + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *por
[PATCH v5 4/4] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So get phy config values from dts and use software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training Changes in v4: - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest Changes in v5: - fix some whitespcae issue drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 505 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..d9d0d4d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..73c3290 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp->active_port]; + struct rockchip_typec_phy *tcphy = phy
[PATCH v5 2/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - None Changes in v3: - modify property description and add this property to Example Change in v4: - None Change in v5: - None .../devicetree/bindings/phy/phy-rockchip-typec.txt | 29 +- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..af298f2 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,8 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : A list of voltage swing(mv) and pre-emphasis + (dB) pairs. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +51,19 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +88,19 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v5 3/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value Changes in v4: - rename variable config to tcphy_default_config Changes in v5: - None drivers/phy/rockchip/phy-rockchip-typec.c | 306 -- include/soc/rockchip/rockchip_phy_typec.h | 63 ++ 2 files changed, 271 insertions(+), 98 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..5d8692d 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DP_DEFAULT_RATE162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CM
[PATCH v5 2/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang --- Changes in v2: - None Changes in v3: - modify property description and add this property to Example Change in v4: - None Change in v5: - None .../devicetree/bindings/phy/phy-rockchip-typec.txt | 29 +- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..af298f2 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,8 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : A list of voltage swing(mv) and pre-emphasis + (dB) pairs. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +51,19 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +88,19 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v5 3/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value Changes in v4: - rename variable config to tcphy_default_config Changes in v5: - None drivers/phy/rockchip/phy-rockchip-typec.c | 306 -- include/soc/rockchip/rockchip_phy_typec.h | 63 ++ 2 files changed, 271 insertions(+), 98 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..5d8692d 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DP_DEFAULT_RATE162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CT
[PATCH v5 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong <z...@rock-chips.com> We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> Reviewed-by: Enric Balletbo <enric.balle...@collabora.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - None Changes in v4: - None Changes in v5: - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.
[PATCH v5 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang Reviewed-by: Sean Paul Reviewed-by: Enric Balletbo --- Changes in v2: - update patch following Enric suggest Changes in v3: - None Changes in v4: - None Changes in v5: - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..979355d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -221,7 +221,12 @@ static int cdn_
[PATCH v4 3/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value Changes in v4: - rename variable config to tcphy_default_config drivers/phy/rockchip/phy-rockchip-typec.c | 306 -- include/soc/rockchip/rockchip_phy_typec.h | 63 ++ 2 files changed, 271 insertions(+), 98 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..5d8692d 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DP_DEFAULT_RATE162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR
[PATCH v4 3/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value Changes in v4: - rename variable config to tcphy_default_config drivers/phy/rockchip/phy-rockchip-typec.c | 306 -- include/soc/rockchip/rockchip_phy_typec.h | 63 ++ 2 files changed, 271 insertions(+), 98 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..5d8692d 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DP_DEFAULT_RATE162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0
[PATCH v4 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong <z...@rock-chips.com> We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> Reviewed-by: Enric Balletbo <enric.balle...@collabora.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - None Changes in v4: - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..979355d 100
[PATCH v4 4/4] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So get phy config values from dts and use software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training Changes in v4: - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 505 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..d9d0d4d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..7efd070 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong <z...@rock-chips.com> + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp-&g
[PATCH v4 2/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - None Changes in v3: - modify property description and add this property to Example Change in v4: - None .../devicetree/bindings/phy/phy-rockchip-typec.txt | 29 +- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..af298f2 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,8 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : A list of voltage swing(mv) and pre-emphasis + (dB) pairs. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +51,19 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +88,19 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v4 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang Reviewed-by: Sean Paul Reviewed-by: Enric Balletbo --- Changes in v2: - update patch following Enric suggest Changes in v3: - None Changes in v4: - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..979355d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -221,7 +221,12 @@ static int cdn_dp_reg_write_bit(struct
[PATCH v4 4/4] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So get phy config values from dts and use software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training Changes in v4: - improve cdn_dp_get_lower_link_rate() and cdn_dp_software_train_link() follow Sean suggest drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 420 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 505 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..d9d0d4d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..7efd070 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp->active_port]; + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy); + +
[PATCH v4 2/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang --- Changes in v2: - None Changes in v3: - modify property description and add this property to Example Change in v4: - None .../devicetree/bindings/phy/phy-rockchip-typec.txt | 29 +- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..af298f2 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,8 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : A list of voltage swing(mv) and pre-emphasis + (dB) pairs. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +51,19 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +88,19 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v3 4/4] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So if the phy is using custom config values, do software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 416 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 501 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..d9d0d4d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..b8fd5bc --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong <z...@rock-chips.com> + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp->active_port]; + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy); + + int rate = dr
[PATCH v3 3/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value drivers/phy/rockchip/phy-rockchip-typec.c | 305 -- include/soc/rockchip/rockchip_phy_typec.h | 63 ++ 2 files changed, 270 insertions(+), 98 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..10253ad 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DP_DEFAULT_RATE162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CM
[PATCH v3 4/4] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So if the phy is using custom config values, do software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest Changes in v3: - use variable fw_training instead sw_training_success - base on DP SPCE, if training fail use lower link rate to retry training drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 416 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 31 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 501 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..d9d0d4d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->use_fw_training == true) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..77a9793 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool use_fw_training; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..b8fd5bc --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp->active_port]; + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy); + + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate); + u8 swing = (dp->train_set[
[PATCH v3 3/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest Changes in v3: - delete need_software_training variable - add default phy config value, if dts do not define phy config value, use these value drivers/phy/rockchip/phy-rockchip-typec.c | 305 -- include/soc/rockchip/rockchip_phy_typec.h | 63 ++ 2 files changed, 270 insertions(+), 98 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..10253ad 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DP_DEFAULT_RATE162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 },
[PATCH v3 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong <z...@rock-chips.com> We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> Reviewed-by: Sean Paul <seanp...@chromium.org> Reviewed-by: Enric Balletbo <eballe...@gmail.com> --- Changes in v2: - update patch following Enric suggest - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..979355d 100644 --- a/drivers/gpu/drm/roc
[PATCH v3 2/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - rebase Changes in v3: - modify property description and add this property to example .../devicetree/bindings/phy/phy-rockchip-typec.txt | 29 +- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..af298f2 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,8 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : A list of voltage swing(mv) and pre-emphasis + (dB) pairs. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +51,19 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +88,19 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v3 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang Reviewed-by: Sean Paul Reviewed-by: Enric Balletbo --- Changes in v2: - update patch following Enric suggest - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++ drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..979355d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -221,7 +221,12 @@ static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr,
[PATCH v3 2/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang --- Changes in v2: - rebase Changes in v3: - modify property description and add this property to example .../devicetree/bindings/phy/phy-rockchip-typec.txt | 29 +- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..af298f2 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,8 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : A list of voltage swing(mv) and pre-emphasis + (dB) pairs. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: @@ -50,6 +51,19 @@ Example: < SRST_P_UPHY0_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy0_dp: dp-port { #phy-cells = <0>; }; @@ -74,6 +88,19 @@ Example: < SRST_P_UPHY1_TCPHY>; reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,phy_config =<0x2a 0x00 + 0x1f 0x15 + 0x14 0x22 + 0x02 0x2b + 0x21 0x00 + 0x12 0x15 + 0x02 0x22 + 0 0 + 0x15 0x00 + 0x00 0x15 + 0 0 + 0 0>; + tcphy1_dp: dp-port { #phy-cells = <0>; }; -- 2.7.4
[PATCH v2 3/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - rebase Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..eda26dd 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,9 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : That's phy voltage swing and pre_emphasis +setting, if want to do dp training outside +dp firmware, need to add these value. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: -- 2.7.4
[PATCH v2 4/4] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So if the phy is using custom config values, do software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 391 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 34 ++- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 479 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..2359d82 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->sw_training_success == false) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->sw_training_success == false) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..c6050ab 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool sw_training_success; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..25282de --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong <z...@rock-chips.com> + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp->active_port]; + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy); + + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate); + u8 swing = (dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) >&g
[PATCH v2 3/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang --- Changes in v2: - rebase Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..eda26dd 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,9 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : That's phy voltage swing and pre_emphasis +setting, if want to do dp training outside +dp firmware, need to add these value. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: -- 2.7.4
[PATCH v2 4/4] drm/rockchip: support dp training outside dp firmware
DP firmware uses fixed phy config values to do training, but some boards need to adjust these values to fit for their unique hardware design. So if the phy is using custom config values, do software link training instead of relying on firmware, if software training fail, keep firmware training as a fallback if sw training fails. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 24 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 391 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 34 ++- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 479 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index cce64c1..2359d82 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->sw_training_success == false) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,15 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->sw_training_success == false) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..c6050ab 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool sw_training_success; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..25282de --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + */ + +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp->active_port]; + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy); + + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate); + u8 swing = (dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + u8 pre_emphasis = (dp->train_s
[PATCH v2 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong <z...@rock-chips.com> We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 67 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 120 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..afdfda0 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -221,7 +221,11 @@ static int cdn_dp_reg_write_bit(struct cdn_dp_dev
[PATCH v2 2/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - update patch following Enric suggest drivers/phy/rockchip/phy-rockchip-typec.c | 284 +++--- include/soc/rockchip/rockchip_phy_typec.h | 64 +++ 2 files changed, 250 insertions(+), 98 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..86cbd6c 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DP_DEFAULT_RATE162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, { 0x20, CMN_PLL1_DSM_DIAG }, { 0,CMN_PLLSM1_USER_DEF_CTRL }, { 0,
[PATCH v2 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 67 ++ drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++- 4 files changed, 120 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..afdfda0 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -221,7 +221,11 @@ static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, sizeof(field), fiel
[PATCH v2 2/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- Changes in v2: - update patch following Enric suggest drivers/phy/rockchip/phy-rockchip-typec.c | 284 +++--- include/soc/rockchip/rockchip_phy_typec.h | 64 +++ 2 files changed, 250 insertions(+), 98 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..86cbd6c 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,21 +324,29 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) #define PHY_MODE_SET_TIMEOUT 10 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DP_DEFAULT_RATE162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, { 0x20, CMN_PLL1_DSM_DIAG }, { 0,CMN_PLLSM1_USER_DEF_CTRL }, { 0,CMN_DIAG_PLL1_OVRD }, @@ -436,9 +401,52
[PATCH 3/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..eda26dd 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,9 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : That's phy voltage swing and pre_emphasis +setting, if want to do dp training outside +dp firmware, need to add these value. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: -- 2.7.4
[PATCH 3/4] Documentation: bindings: add phy_config for Rockchip USB Type-C PHY
If want to do training outside DP Firmware, need phy voltage swing and pre_emphasis value. Signed-off-by: Lin Huang --- Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt index 960da7f..eda26dd 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -17,7 +17,9 @@ Required properties: Optional properties: - extcon : extcon specifier for the Power Delivery - + - rockchip,phy_config : That's phy voltage swing and pre_emphasis +setting, if want to do dp training outside +dp firmware, need to add these value. Required nodes : a sub-node is required for each port the phy provides. The sub-node name is used to identify dp or usb3 port, and shall be the following entries: -- 2.7.4
[PATCH 2/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- drivers/phy/rockchip/phy-rockchip-typec.c | 286 +++--- include/soc/rockchip/rockchip_phy_typec.h | 72 2 files changed, 259 insertions(+), 99 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..831a93b 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,23 +324,31 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) -#define PHY_MODE_SET_TIMEOUT 10 +#define PHY_MODE_SET_TIMEOUT 100 #define PIN_ASSIGN_C_E 0x51d9 #define PIN_ASSIGN_D_F 0x5100 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DEFAULT_RATE 162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, { 0x20, CMN_PLL1_
[PATCH 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong <z...@rock-chips.com> We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 66 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++-- 4 files changed, 119 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..268c190 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STAUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STAUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STAUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..b2f532a 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -221,7 +221,11 @@ static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, s
[PATCH 1/4] drm/rockchip: add transfer function for cdn-dp
From: Chris Zhong We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 66 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++-- 4 files changed, 119 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..268c190 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, , 1); - if (ret) + ret = drm_dp_dpcd_read(>aux, DP_SINK_COUNT, , 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(>aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(>aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STAUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STAUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STAUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(>aux); + if (ret) + return ret; INIT_WORK(>event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..b2f532a 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -221,7 +221,11 @@ static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, sizeof(field), field); } -int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 add
[PATCH 2/4] phy: rockchip-typec: support variable phy config value
the phy config values used to fix in dp firmware, but some boards need change these values to do training and get the better eye diagram result. So support that in phy driver. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- drivers/phy/rockchip/phy-rockchip-typec.c | 286 +++--- include/soc/rockchip/rockchip_phy_typec.h | 72 2 files changed, 259 insertions(+), 99 deletions(-) create mode 100644 include/soc/rockchip/rockchip_phy_typec.h diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 76a4b58..831a93b 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -63,6 +63,7 @@ #include #include +#include #define CMN_SSM_BANDGAP(0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -323,23 +324,31 @@ * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL1_DIV1 0x20 +#define CLK_PLL1_DIV2 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) +#define DP_PLL_CLOCK_ENABLE_ACKBIT(3) #define DP_PLL_CLOCK_ENABLEBIT(2) +#define DP_PLL_ENABLE_ACK BIT(1) #define DP_PLL_ENABLE BIT(0) #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) +#define DP_PLL_DATA_RATE_MASK 0xff00 -#define DP_MODE_A0 BIT(4) -#define DP_MODE_A2 BIT(6) -#define DP_MODE_ENTER_A0 0xc101 -#define DP_MODE_ENTER_A2 0xc104 +#define DP_MODE_MASK 0xf +#define DP_MODE_ENTER_A0 BIT(0) +#define DP_MODE_ENTER_A2 BIT(2) +#define DP_MODE_ENTER_A3 BIT(3) +#define DP_MODE_A0_ACK BIT(4) +#define DP_MODE_A2_ACK BIT(6) +#define DP_MODE_A3_ACK BIT(7) +#define DP_LINK_RESET_DEASSERTED BIT(8) -#define PHY_MODE_SET_TIMEOUT 10 +#define PHY_MODE_SET_TIMEOUT 100 #define PIN_ASSIGN_C_E 0x51d9 #define PIN_ASSIGN_D_F 0x5100 @@ -349,51 +358,7 @@ #define MODE_DFP_USB BIT(1) #define MODE_DFP_DPBIT(2) -struct usb3phy_reg { - u32 offset; - u32 enable_bit; - u32 write_enable; -}; - -/** - * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. - * @reg: the base address for usb3-phy config. - * @typec_conn_dir: the register of type-c connector direction. - * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. - * @external_psm: the register of type-c phy external psm clock. - * @pipe_status: the register of type-c phy pipe status. - * @usb3_host_disable: the register of type-c usb3 host disable. - * @usb3_host_port: the register of type-c usb3 host port. - * @uphy_dp_sel: the register of type-c phy DP select control. - */ -struct rockchip_usb3phy_port_cfg { - unsigned int reg; - struct usb3phy_reg typec_conn_dir; - struct usb3phy_reg usb3tousb2_en; - struct usb3phy_reg external_psm; - struct usb3phy_reg pipe_status; - struct usb3phy_reg usb3_host_disable; - struct usb3phy_reg usb3_host_port; - struct usb3phy_reg uphy_dp_sel; -}; - -struct rockchip_typec_phy { - struct device *dev; - void __iomem *base; - struct extcon_dev *extcon; - struct regmap *grf_regs; - struct clk *clk_core; - struct clk *clk_ref; - struct reset_control *uphy_rst; - struct reset_control *pipe_rst; - struct reset_control *tcphy_rst; - const struct rockchip_usb3phy_port_cfg *port_cfgs; - /* mutex to protect access to individual PHYs */ - struct mutex lock; - - bool flip; - u8 mode; -}; +#define DEFAULT_RATE 162000 struct phy_reg { u16 value; @@ -417,15 +382,15 @@ struct phy_reg usb3_pll_cfg[] = { { 0x8, CMN_DIAG_PLL0_LF_PROG }, }; -struct phy_reg dp_pll_cfg[] = { +struct phy_reg dp_pll_rbr_cfg[] = { { 0xf0, CMN_PLL1_VCOCAL_INIT }, { 0x18, CMN_PLL1_VCOCAL_ITER }, { 0x30b9, CMN_PLL1_VCOCAL_START }, - { 0x21c,CMN_PLL1_INTDIV }, + { 0x87, CMN_PLL1_INTDIV }, { 0,CMN_PLL1_FRACDIV }, - { 0x5, CMN_PLL1_HIGH_THR }, - { 0x35, CMN_PLL1_SS_CTRL1 }, - { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x22, CMN_PLL1_HIGH_THR }, + { 0x8000, CMN_PLL1_SS_CTRL1 }, + { 0,CMN_PLL1_SS_CTRL2 }, { 0x20, CMN_PLL1_DSM_DIAG }, { 0,
[PATCH 4/4] drm/rockchip: support dp training outside dp firmware
DP firware use fix phy config value to do training, but some board need to adjust these value to fit for their hardware design, so we use new phy config to do training outside firmware to meet this situation, if there have new phy config pass from dts, it will use training outside firmware. Signed-off-by: Chris Zhong <z...@rock-chips.com> Signed-off-by: Lin Huang <h...@rock-chips.com> --- drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 23 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 398 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 33 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 480 insertions(+), 17 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 268c190..a2a4208 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->sw_training_success == false) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,14 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->sw_training_success == false) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..c6050ab 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool sw_training_success; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..558c945 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,398 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong <z...@rock-chips.com> + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp->active_port]; + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy); + + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate); + u8 swing = (dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + u8 pre_emphasis
[PATCH 4/4] drm/rockchip: support dp training outside dp firmware
DP firware use fix phy config value to do training, but some board need to adjust these value to fit for their hardware design, so we use new phy config to do training outside firmware to meet this situation, if there have new phy config pass from dts, it will use training outside firmware. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang --- drivers/gpu/drm/rockchip/Makefile | 3 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 23 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 + drivers/gpu/drm/rockchip/cdn-dp-link-training.c | 398 drivers/gpu/drm/rockchip/cdn-dp-reg.c | 33 +- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 38 ++- 6 files changed, 480 insertions(+), 17 deletions(-) create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-link-training.c diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e21..b932f62 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -9,7 +9,8 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o \ + cdn-dp-link-training.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 268c190..a2a4208 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -629,11 +629,13 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } } - - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); - goto out; + if (dp->sw_training_success == false) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + DRM_DEV_ERROR(dp->dev, + "Failed to idle video %d\n", ret); + goto out; + } } ret = cdn_dp_config_video(dp); @@ -642,11 +644,14 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) goto out; } - ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); - if (ret) { - DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); - goto out; + if (dp->sw_training_success == false) { + ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); + if (ret) { + DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); + goto out; + } } + out: mutex_unlock(>lock); } diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 46159b2..c6050ab 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -84,6 +84,7 @@ struct cdn_dp_device { bool connected; bool active; bool suspended; + bool sw_training_success; const struct firmware *fw; /* cdn dp firmware */ unsigned int fw_version;/* cdn fw version */ @@ -106,6 +107,7 @@ struct cdn_dp_device { u8 ports; u8 lanes; int active_port; + u8 train_set[4]; u8 dpcd[DP_RECEIVER_CAP_SIZE]; bool sink_has_audio; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-link-training.c b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c new file mode 100644 index 000..558c945 --- /dev/null +++ b/drivers/gpu/drm/rockchip/cdn-dp-link-training.c @@ -0,0 +1,398 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void cdn_dp_set_signal_levels(struct cdn_dp_device *dp) +{ + struct cdn_dp_port *port = dp->port[dp->active_port]; + struct rockchip_typec_phy *tcphy = phy_get_drvdata(port->phy); + + int rate = drm_dp_bw_code_to_link_rate(dp->link.rate); + u8 swing = (dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) >> + DP_TRAIN_VOLTAGE_SWING_SHIFT; + u8 pre_emphasis = (dp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) +
[PATCH v4 3/3] dt-bindings: Add INNOLUX P097PFG panel bindings
From: huang lin <h...@rock-chips.com> The Innolux P097PFG panel is 9.7" panel with 1536X2048 resolution, it reuse P079ZCA panel driver, so improve p079ZCA dt-binding to support P097PFG. Change-Id: I8704914898fe53b734d31fbe646df8aa5fd8b30d Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - None Changes in v3: - None Changes in v4: - None .../devicetree/bindings/display/panel/innolux,p079zca.txt | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt index d0f5516..8cadd8c 100644 --- a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt +++ b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt @@ -1,13 +1,18 @@ Innolux P079ZCA 7.85" 768x1024 TFT LCD panel +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel Required properties: -- compatible: should be "innolux,p079zca" +- compatible: should be should be one of the following. +-"innolux,p079zca" for Innolux 7.9" P079ZCA 768*1024 panel +-"innolux,p097pfg" for Innolux 9.7" P097PFG 1536*2048 panel - reg: DSI virtual channel of the peripheral -- power-supply: phandle of the regulator that provides the supply voltage - enable-gpios: panel enable gpio Optional properties: - backlight: phandle of the backlight device attached to the panel +- power-supply: phandle of the regulator that provides the supply voltage +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage Example: @@ -16,6 +21,8 @@ Example: compatible = "innolux,p079zca"; reg = <0>; power-supply = <...>; + avdd-supply = <...>; + avee-supply = <...>; backlight = <>; enable-gpios = < 13 GPIO_ACTIVE_HIGH>; }; -- 2.7.4
[PATCH v4 2/3] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it reuse the Innolux P079ZCA panel driver. Change-Id: I97923aa3735f707332681691b0231c9421b427d0 Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - None Changes in v3: - None Changes in v4: - download panel initial code drivers/gpu/drm/panel/panel-innolux-p079zca.c | 192 +- 1 file changed, 187 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 2075a9d..883b279 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,6 +20,15 @@ #include +struct panel_init_cmd { + int len; + const char *data; +}; + +#define _INIT_CMD(...) { \ + .len = sizeof((char[]){__VA_ARGS__}), \ + .data = (char[]){__VA_ARGS__} } + struct panel_desc { const struct drm_display_mode *modes; unsigned int bpc; @@ -30,6 +39,7 @@ struct panel_desc { unsigned long flags; enum mipi_dsi_pixel_format format; + const struct panel_init_cmd *init_cmds; unsigned int lanes; }; @@ -88,9 +98,12 @@ static int innolux_panel_unprepare(struct drm_panel *panel) return err; } + /* p097pfg: t15 */ + msleep(100); + gpiod_set_value_cansleep(innolux->enable_gpio, 0); - /* T8: 80ms - 1000ms */ + /* p079zca: t8*/ msleep(80); regulator_disable(innolux->avee); @@ -124,13 +137,43 @@ static int innolux_panel_prepare(struct drm_panel *panel) if (err < 0) goto disable_avdd; - /* T2: 15ms - 1000ms */ - usleep_range(15000, 16000); + /* p079zca: t2 (20ms), p097pfg: t4 (15ms) */ + usleep_range(2, 21000); gpiod_set_value_cansleep(innolux->enable_gpio, 1); - /* T4: 15ms - 1000ms */ - usleep_range(15000, 16000); + /* p079zca: t4, p097pfg: t5 */ + usleep_range(2, 21000); + + if (innolux->desc->init_cmds) { + const struct panel_init_cmd *cmds = + innolux->desc->init_cmds; + int i; + + for (i = 0; cmds[i].len != 0; i++) { + const struct panel_init_cmd *cmd = [i]; + + err = mipi_dsi_generic_write(innolux->link, cmd->data, +cmd->len); + if (err < 0) { + dev_err(panel->dev, + "failed to write command %d\n", i); + goto poweroff; + } + + /* +* Included by random guessing, because without this +* (or at least, some delay), the panel sometimes +* didn't appear to pick up the command sequence. +*/ + err = mipi_dsi_dcs_nop(innolux->link); + if (err < 0) { + dev_err(panel->dev, + "failed to send DCS nop: %d\n", err); + goto poweroff; + } + } + } err = mipi_dsi_dcs_exit_sleep_mode(innolux->link); if (err < 0) { @@ -213,6 +256,142 @@ static const struct panel_desc innolux_p079zca_panel_desc = { .lanes = 4, }; +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 229000, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 100, + .vsync_end = 2048 + 100 + 2, + .vtotal = 2048 + 100 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_init_cmd innolux_p097pfg_init_cmds[] = { + /* page 0 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00), + _INIT_CMD(0xB1, 0xE8, 0x11), + _INIT_CMD(0xB2, 0x25, 0x02), + _INIT_CMD(0xB5, 0x08, 0x00), + _INIT_CMD(0xBC, 0x0F, 0x00), + _INIT_CMD(0xB8, 0x03, 0x06, 0x00, 0x00), + _INIT_CMD(0xBD, 0x01, 0x90, 0x14, 0x14), + _INIT_CMD(0x6F, 0x01), + _INIT_CMD(0xC0, 0x03), + _INIT_CMD(0x6F, 0x02), + _INIT_CMD(0xC1, 0x0D), + _INIT_CMD(0xD9, 0x01, 0x09, 0x70), + _INIT_CMD(0xC5, 0x12, 0x21, 0x00), + _INIT_CMD(0xBB, 0x93, 0x93), + + /* page 1 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01), + _INIT_CMD(0xB3, 0x3C, 0x3C), + _INIT_CMD(0xB4, 0x0F, 0x0F), + _INIT_CMD(0xB9, 0x45, 0x45), + _INIT_CMD(0xBA, 0x14, 0x14), + _INIT_CMD(0xCA, 0x02), + _INIT_CMD(0xCE, 0x04), + _INIT_CMD(0xC3, 0x9B, 0x9B), + _INIT_CMD(0xD8,
[PATCH v4 3/3] dt-bindings: Add INNOLUX P097PFG panel bindings
From: huang lin The Innolux P097PFG panel is 9.7" panel with 1536X2048 resolution, it reuse P079ZCA panel driver, so improve p079ZCA dt-binding to support P097PFG. Change-Id: I8704914898fe53b734d31fbe646df8aa5fd8b30d Signed-off-by: Lin Huang --- Changes in v2: - None Changes in v3: - None Changes in v4: - None .../devicetree/bindings/display/panel/innolux,p079zca.txt | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt index d0f5516..8cadd8c 100644 --- a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt +++ b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt @@ -1,13 +1,18 @@ Innolux P079ZCA 7.85" 768x1024 TFT LCD panel +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel Required properties: -- compatible: should be "innolux,p079zca" +- compatible: should be should be one of the following. +-"innolux,p079zca" for Innolux 7.9" P079ZCA 768*1024 panel +-"innolux,p097pfg" for Innolux 9.7" P097PFG 1536*2048 panel - reg: DSI virtual channel of the peripheral -- power-supply: phandle of the regulator that provides the supply voltage - enable-gpios: panel enable gpio Optional properties: - backlight: phandle of the backlight device attached to the panel +- power-supply: phandle of the regulator that provides the supply voltage +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage Example: @@ -16,6 +21,8 @@ Example: compatible = "innolux,p079zca"; reg = <0>; power-supply = <...>; + avdd-supply = <...>; + avee-supply = <...>; backlight = <>; enable-gpios = < 13 GPIO_ACTIVE_HIGH>; }; -- 2.7.4
[PATCH v4 2/3] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it reuse the Innolux P079ZCA panel driver. Change-Id: I97923aa3735f707332681691b0231c9421b427d0 Signed-off-by: Lin Huang --- Changes in v2: - None Changes in v3: - None Changes in v4: - download panel initial code drivers/gpu/drm/panel/panel-innolux-p079zca.c | 192 +- 1 file changed, 187 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 2075a9d..883b279 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,6 +20,15 @@ #include +struct panel_init_cmd { + int len; + const char *data; +}; + +#define _INIT_CMD(...) { \ + .len = sizeof((char[]){__VA_ARGS__}), \ + .data = (char[]){__VA_ARGS__} } + struct panel_desc { const struct drm_display_mode *modes; unsigned int bpc; @@ -30,6 +39,7 @@ struct panel_desc { unsigned long flags; enum mipi_dsi_pixel_format format; + const struct panel_init_cmd *init_cmds; unsigned int lanes; }; @@ -88,9 +98,12 @@ static int innolux_panel_unprepare(struct drm_panel *panel) return err; } + /* p097pfg: t15 */ + msleep(100); + gpiod_set_value_cansleep(innolux->enable_gpio, 0); - /* T8: 80ms - 1000ms */ + /* p079zca: t8*/ msleep(80); regulator_disable(innolux->avee); @@ -124,13 +137,43 @@ static int innolux_panel_prepare(struct drm_panel *panel) if (err < 0) goto disable_avdd; - /* T2: 15ms - 1000ms */ - usleep_range(15000, 16000); + /* p079zca: t2 (20ms), p097pfg: t4 (15ms) */ + usleep_range(2, 21000); gpiod_set_value_cansleep(innolux->enable_gpio, 1); - /* T4: 15ms - 1000ms */ - usleep_range(15000, 16000); + /* p079zca: t4, p097pfg: t5 */ + usleep_range(2, 21000); + + if (innolux->desc->init_cmds) { + const struct panel_init_cmd *cmds = + innolux->desc->init_cmds; + int i; + + for (i = 0; cmds[i].len != 0; i++) { + const struct panel_init_cmd *cmd = [i]; + + err = mipi_dsi_generic_write(innolux->link, cmd->data, +cmd->len); + if (err < 0) { + dev_err(panel->dev, + "failed to write command %d\n", i); + goto poweroff; + } + + /* +* Included by random guessing, because without this +* (or at least, some delay), the panel sometimes +* didn't appear to pick up the command sequence. +*/ + err = mipi_dsi_dcs_nop(innolux->link); + if (err < 0) { + dev_err(panel->dev, + "failed to send DCS nop: %d\n", err); + goto poweroff; + } + } + } err = mipi_dsi_dcs_exit_sleep_mode(innolux->link); if (err < 0) { @@ -213,6 +256,142 @@ static const struct panel_desc innolux_p079zca_panel_desc = { .lanes = 4, }; +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 229000, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 100, + .vsync_end = 2048 + 100 + 2, + .vtotal = 2048 + 100 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_init_cmd innolux_p097pfg_init_cmds[] = { + /* page 0 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00), + _INIT_CMD(0xB1, 0xE8, 0x11), + _INIT_CMD(0xB2, 0x25, 0x02), + _INIT_CMD(0xB5, 0x08, 0x00), + _INIT_CMD(0xBC, 0x0F, 0x00), + _INIT_CMD(0xB8, 0x03, 0x06, 0x00, 0x00), + _INIT_CMD(0xBD, 0x01, 0x90, 0x14, 0x14), + _INIT_CMD(0x6F, 0x01), + _INIT_CMD(0xC0, 0x03), + _INIT_CMD(0x6F, 0x02), + _INIT_CMD(0xC1, 0x0D), + _INIT_CMD(0xD9, 0x01, 0x09, 0x70), + _INIT_CMD(0xC5, 0x12, 0x21, 0x00), + _INIT_CMD(0xBB, 0x93, 0x93), + + /* page 1 */ + _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01), + _INIT_CMD(0xB3, 0x3C, 0x3C), + _INIT_CMD(0xB4, 0x0F, 0x0F), + _INIT_CMD(0xB9, 0x45, 0x45), + _INIT_CMD(0xBA, 0x14, 0x14), + _INIT_CMD(0xCA, 0x02), + _INIT_CMD(0xCE, 0x04), + _INIT_CMD(0xC3, 0x9B, 0x9B), + _INIT_CMD(0xD8, 0xC0, 0x03), + _INIT_
[PATCH v4 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
From: huang lin <h...@rock-chips.com> Refactor Innolux P079ZCA panel driver, let it support multi panel. Change-Id: If89be5e56dba8cb498e2d50c1bbeb0e8016123a2 Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - Change regulator property name to meet the panel datasheet Changes in v3: - this patch only refactor P079ZCA panel to support multi panel, support P097PFG panel in another patch Changes in v4: - Modify the patch which suggest by Thierry drivers/gpu/drm/panel/panel-innolux-p079zca.c | 142 ++ 1 file changed, 101 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 57df39b..2075a9d 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,28 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc *desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -77,9 +93,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -89,17 +105,25 @@ static int innolux_panel_unprepare(struct drm_panel *panel) static int innolux_panel_prepare(struct drm_panel *panel) { struct innolux_panel *innolux = to_innolux_panel(panel); - int err, regulator_err; + int err; if (innolux->prepared) return 0; gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -133,12 +157,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -162,7 +187,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -175,15 +200,29 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc innolux_p079zca_panel_desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->desc->modes; - mode = drm_mode_duplicate(panel->drm, _mode); + mode = drm_mode_duplicate(panel->drm, m); if (!mode) { DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - default_mode.vrefresh); + m->hdisplay, m->vdisplay, m->vrefresh); return -ENOMEM; } @@ -191,9 +230,11 @@ static int innolux_panel_get_modes(struct drm_pa
[PATCH v4 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
From: huang lin Refactor Innolux P079ZCA panel driver, let it support multi panel. Change-Id: If89be5e56dba8cb498e2d50c1bbeb0e8016123a2 Signed-off-by: Lin Huang --- Changes in v2: - Change regulator property name to meet the panel datasheet Changes in v3: - this patch only refactor P079ZCA panel to support multi panel, support P097PFG panel in another patch Changes in v4: - Modify the patch which suggest by Thierry drivers/gpu/drm/panel/panel-innolux-p079zca.c | 142 ++ 1 file changed, 101 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 57df39b..2075a9d 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,28 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc *desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -77,9 +93,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -89,17 +105,25 @@ static int innolux_panel_unprepare(struct drm_panel *panel) static int innolux_panel_prepare(struct drm_panel *panel) { struct innolux_panel *innolux = to_innolux_panel(panel); - int err, regulator_err; + int err; if (innolux->prepared) return 0; gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -133,12 +157,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -162,7 +187,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -175,15 +200,29 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc innolux_p079zca_panel_desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->desc->modes; - mode = drm_mode_duplicate(panel->drm, _mode); + mode = drm_mode_duplicate(panel->drm, m); if (!mode) { DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - default_mode.vrefresh); + m->hdisplay, m->vdisplay, m->vrefresh); return -ENOMEM; } @@ -191,9 +230,11 @@ static int innolux_panel_get_modes(struct drm_panel *panel) drm_mode_probed_add(panel->connector,
[RESEND PATCH v3 3/3] dt-bindings: Add INNOLUX P097PFG panel bindings
The Innolux P097PFG panel is 9.7" panel with 1536X2048 resolution, it reuse P079ZCA panel driver, so improve p079ZCA dt-binding to support P097PFG. Signed-off-by: Lin Huang <h...@rock-chips.com> --- .../devicetree/bindings/display/panel/innolux,p079zca.txt | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt index d0f5516..8cadd8c 100644 --- a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt +++ b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt @@ -1,13 +1,18 @@ Innolux P079ZCA 7.85" 768x1024 TFT LCD panel +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel Required properties: -- compatible: should be "innolux,p079zca" +- compatible: should be should be one of the following. +-"innolux,p079zca" for Innolux 7.9" P079ZCA 768*1024 panel +-"innolux,p097pfg" for Innolux 9.7" P097PFG 1536*2048 panel - reg: DSI virtual channel of the peripheral -- power-supply: phandle of the regulator that provides the supply voltage - enable-gpios: panel enable gpio Optional properties: - backlight: phandle of the backlight device attached to the panel +- power-supply: phandle of the regulator that provides the supply voltage +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage Example: @@ -16,6 +21,8 @@ Example: compatible = "innolux,p079zca"; reg = <0>; power-supply = <...>; + avdd-supply = <...>; + avee-supply = <...>; backlight = <>; enable-gpios = < 13 GPIO_ACTIVE_HIGH>; }; -- 2.7.4
[RESEND PATCH v3 3/3] dt-bindings: Add INNOLUX P097PFG panel bindings
The Innolux P097PFG panel is 9.7" panel with 1536X2048 resolution, it reuse P079ZCA panel driver, so improve p079ZCA dt-binding to support P097PFG. Signed-off-by: Lin Huang --- .../devicetree/bindings/display/panel/innolux,p079zca.txt | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt index d0f5516..8cadd8c 100644 --- a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt +++ b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt @@ -1,13 +1,18 @@ Innolux P079ZCA 7.85" 768x1024 TFT LCD panel +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel Required properties: -- compatible: should be "innolux,p079zca" +- compatible: should be should be one of the following. +-"innolux,p079zca" for Innolux 7.9" P079ZCA 768*1024 panel +-"innolux,p097pfg" for Innolux 9.7" P097PFG 1536*2048 panel - reg: DSI virtual channel of the peripheral -- power-supply: phandle of the regulator that provides the supply voltage - enable-gpios: panel enable gpio Optional properties: - backlight: phandle of the backlight device attached to the panel +- power-supply: phandle of the regulator that provides the supply voltage +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage Example: @@ -16,6 +21,8 @@ Example: compatible = "innolux,p079zca"; reg = <0>; power-supply = <...>; + avdd-supply = <...>; + avee-supply = <...>; backlight = <>; enable-gpios = < 13 GPIO_ACTIVE_HIGH>; }; -- 2.7.4
[RESEND PATCH v3 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Refactor Innolux P079ZCA panel driver, let it support multi panel. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - Change regulator property name to meet the panel datasheet Changes in v3: - this patch only refactor P079ZCA panel to support multi panel, support P097PFG panel in another patch drivers/gpu/drm/panel/panel-innolux-p079zca.c | 147 ++ 1 file changed, 105 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..1597744 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,31 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->dsi_desc->desc.modes; - mode = drm_mode_duplicate(panel->drm, _mode); + mode = drm_mode_duplicate(panel->drm, m); if (!mode) { DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - default_mode.vrefresh); + m->hdisplay, m->vdisplay, m->vrefresh); return -ENOMEM; } @@ -193,9 +238,11 @@ static int innolux_panel_get_modes(struct drm_panel *panel) drm_mode_probed_add(panel->connector, mode); - panel->connector->display_info.width_mm = 120; - panel->connector->display_info.height_mm = 160; - panel->connector->display_info.bpc = 8;
[RESEND PATCH v3 2/3] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it reuse the Innolux P079ZCA panel driver. Signed-off-by: Lin Huang <h...@rock-chips.com> --- drivers/gpu/drm/panel/Kconfig | 9 drivers/gpu/drm/panel/panel-innolux-p079zca.c | 31 +++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 726f3fb..429cf59 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -29,15 +29,14 @@ config DRM_PANEL_SIMPLE low power state. config DRM_PANEL_INNOLUX_P079ZCA - tristate "Innolux P079ZCA panel" + tristate "Innolux P079ZCA or P097PFG panel" depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help - Say Y here if you want to enable support for Innolux P079ZCA - TFT-LCD modules. The panel has a 1024x768 resolution and uses - 24 bit RGB per pixel. It provides a MIPI DSI interface to - the host and has a built-in LED backlight. + Say Y here if you want to enable support for Innolux P079ZCA or + Innolux P097PFG panel. They provide a MIPI DSI interface to + the host and have a built-in LED backlight. config DRM_PANEL_JDI_LT070ME05000 tristate "JDI LT070ME05000 WUXGA DSI panel" diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 1597744..5d690b7 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -221,6 +221,34 @@ static const struct panel_desc_dsi innolux_p079zca_panel_desc = { .lanes = 4, }; +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; @@ -259,6 +287,9 @@ static const struct of_device_id innolux_of_match[] = { { .compatible = "innolux,p079zca", .data = _p079zca_panel_desc }, + { .compatible = "innolux,p097pfg", + .data = _p097pfg_panel_desc + } }; MODULE_DEVICE_TABLE(of, innolux_of_match); -- 2.7.4
[RESEND PATCH v3 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Refactor Innolux P079ZCA panel driver, let it support multi panel. Signed-off-by: Lin Huang --- Changes in v2: - Change regulator property name to meet the panel datasheet Changes in v3: - this patch only refactor P079ZCA panel to support multi panel, support P097PFG panel in another patch drivers/gpu/drm/panel/panel-innolux-p079zca.c | 147 ++ 1 file changed, 105 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..1597744 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,31 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->dsi_desc->desc.modes; - mode = drm_mode_duplicate(panel->drm, _mode); + mode = drm_mode_duplicate(panel->drm, m); if (!mode) { DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - default_mode.vrefresh); + m->hdisplay, m->vdisplay, m->vrefresh); return -ENOMEM; } @@ -193,9 +238,11 @@ static int innolux_panel_get_modes(struct drm_panel *panel) drm_mode_probed_add(panel->connector, mode); - panel->connector->display_info.width_mm = 120; - panel->connector->display_info.height_mm = 160; - panel->connector->display_info.bpc = 8; +
[RESEND PATCH v3 2/3] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it reuse the Innolux P079ZCA panel driver. Signed-off-by: Lin Huang --- drivers/gpu/drm/panel/Kconfig | 9 drivers/gpu/drm/panel/panel-innolux-p079zca.c | 31 +++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 726f3fb..429cf59 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -29,15 +29,14 @@ config DRM_PANEL_SIMPLE low power state. config DRM_PANEL_INNOLUX_P079ZCA - tristate "Innolux P079ZCA panel" + tristate "Innolux P079ZCA or P097PFG panel" depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help - Say Y here if you want to enable support for Innolux P079ZCA - TFT-LCD modules. The panel has a 1024x768 resolution and uses - 24 bit RGB per pixel. It provides a MIPI DSI interface to - the host and has a built-in LED backlight. + Say Y here if you want to enable support for Innolux P079ZCA or + Innolux P097PFG panel. They provide a MIPI DSI interface to + the host and have a built-in LED backlight. config DRM_PANEL_JDI_LT070ME05000 tristate "JDI LT070ME05000 WUXGA DSI panel" diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 1597744..5d690b7 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -221,6 +221,34 @@ static const struct panel_desc_dsi innolux_p079zca_panel_desc = { .lanes = 4, }; +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; @@ -259,6 +287,9 @@ static const struct of_device_id innolux_of_match[] = { { .compatible = "innolux,p079zca", .data = _p079zca_panel_desc }, + { .compatible = "innolux,p097pfg", + .data = _p097pfg_panel_desc + } }; MODULE_DEVICE_TABLE(of, innolux_of_match); -- 2.7.4
[PATCH v3 2/3] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it reuse the Innolux P079ZCA panel driver. Signed-off-by: Lin Huang <h...@rock-chips.com> --- drivers/gpu/drm/panel/Kconfig | 9 drivers/gpu/drm/panel/panel-innolux-p079zca.c | 31 +++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 726f3fb..429cf59 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -29,15 +29,14 @@ config DRM_PANEL_SIMPLE low power state. config DRM_PANEL_INNOLUX_P079ZCA - tristate "Innolux P079ZCA panel" + tristate "Innolux P079ZCA or P097PFG panel" depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help - Say Y here if you want to enable support for Innolux P079ZCA - TFT-LCD modules. The panel has a 1024x768 resolution and uses - 24 bit RGB per pixel. It provides a MIPI DSI interface to - the host and has a built-in LED backlight. + Say Y here if you want to enable support for Innolux P079ZCA or + Innolux P097PFG panel. They provide a MIPI DSI interface to + the host and have a built-in LED backlight. config DRM_PANEL_JDI_LT070ME05000 tristate "JDI LT070ME05000 WUXGA DSI panel" diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 1597744..5d690b7 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -221,6 +221,34 @@ static const struct panel_desc_dsi innolux_p079zca_panel_desc = { .lanes = 4, }; +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; @@ -259,6 +287,9 @@ static const struct of_device_id innolux_of_match[] = { { .compatible = "innolux,p079zca", .data = _p079zca_panel_desc }, + { .compatible = "innolux,p097pfg", + .data = _p097pfg_panel_desc + } }; MODULE_DEVICE_TABLE(of, innolux_of_match); -- 2.7.4
[PATCH v3 3/3] dt-bindings: Add INNOLUX P097PFG panel bindings
The Innolux P097PFG panel is 9.7" panel with 1536X2048 resolution, it reuse P079ZCA panel driver, so improve p079ZCA dt-binding to support P097PFG. Change-Id: I8704914898fe53b734d31fbe646df8aa5fd8b30d Signed-off-by: Lin Huang <h...@rock-chips.com> --- .../devicetree/bindings/display/panel/innolux,p079zca.txt | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt index d0f5516..8cadd8c 100644 --- a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt +++ b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt @@ -1,13 +1,18 @@ Innolux P079ZCA 7.85" 768x1024 TFT LCD panel +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel Required properties: -- compatible: should be "innolux,p079zca" +- compatible: should be should be one of the following. +-"innolux,p079zca" for Innolux 7.9" P079ZCA 768*1024 panel +-"innolux,p097pfg" for Innolux 9.7" P097PFG 1536*2048 panel - reg: DSI virtual channel of the peripheral -- power-supply: phandle of the regulator that provides the supply voltage - enable-gpios: panel enable gpio Optional properties: - backlight: phandle of the backlight device attached to the panel +- power-supply: phandle of the regulator that provides the supply voltage +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage Example: @@ -16,6 +21,8 @@ Example: compatible = "innolux,p079zca"; reg = <0>; power-supply = <...>; + avdd-supply = <...>; + avee-supply = <...>; backlight = <>; enable-gpios = < 13 GPIO_ACTIVE_HIGH>; }; -- 2.7.4
[PATCH v3 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Refactor Innolux P079ZCA panel driver, let it support multi panel. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - Change regulator property name to meet the panel datasheet Changes in v3: - this patch only refactor P079ZCA panel to support multi panel, support P097PFG panel in another patch drivers/gpu/drm/panel/panel-innolux-p079zca.c | 147 ++ 1 file changed, 105 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..1597744 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,31 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->dsi_desc->desc.modes; - mode = drm_mode_duplicate(panel->drm, _mode); + mode = drm_mode_duplicate(panel->drm, m); if (!mode) { DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - default_mode.vrefresh); + m->hdisplay, m->vdisplay, m->vrefresh); return -ENOMEM; } @@ -193,9 +238,11 @@ static int innolux_panel_get_modes(struct drm_panel *panel) drm_mode_probed_add(panel->connector, mode); - panel->connector->display_info.width_mm = 120; - panel->connector->display_info.height_mm = 160; - panel->connector->display_info.bpc = 8;
[PATCH v3 2/3] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it reuse the Innolux P079ZCA panel driver. Signed-off-by: Lin Huang --- drivers/gpu/drm/panel/Kconfig | 9 drivers/gpu/drm/panel/panel-innolux-p079zca.c | 31 +++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 726f3fb..429cf59 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -29,15 +29,14 @@ config DRM_PANEL_SIMPLE low power state. config DRM_PANEL_INNOLUX_P079ZCA - tristate "Innolux P079ZCA panel" + tristate "Innolux P079ZCA or P097PFG panel" depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE help - Say Y here if you want to enable support for Innolux P079ZCA - TFT-LCD modules. The panel has a 1024x768 resolution and uses - 24 bit RGB per pixel. It provides a MIPI DSI interface to - the host and has a built-in LED backlight. + Say Y here if you want to enable support for Innolux P079ZCA or + Innolux P097PFG panel. They provide a MIPI DSI interface to + the host and have a built-in LED backlight. config DRM_PANEL_JDI_LT070ME05000 tristate "JDI LT070ME05000 WUXGA DSI panel" diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 1597744..5d690b7 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -221,6 +221,34 @@ static const struct panel_desc_dsi innolux_p079zca_panel_desc = { .lanes = 4, }; +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; @@ -259,6 +287,9 @@ static const struct of_device_id innolux_of_match[] = { { .compatible = "innolux,p079zca", .data = _p079zca_panel_desc }, + { .compatible = "innolux,p097pfg", + .data = _p097pfg_panel_desc + } }; MODULE_DEVICE_TABLE(of, innolux_of_match); -- 2.7.4
[PATCH v3 3/3] dt-bindings: Add INNOLUX P097PFG panel bindings
The Innolux P097PFG panel is 9.7" panel with 1536X2048 resolution, it reuse P079ZCA panel driver, so improve p079ZCA dt-binding to support P097PFG. Change-Id: I8704914898fe53b734d31fbe646df8aa5fd8b30d Signed-off-by: Lin Huang --- .../devicetree/bindings/display/panel/innolux,p079zca.txt | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt index d0f5516..8cadd8c 100644 --- a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt +++ b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt @@ -1,13 +1,18 @@ Innolux P079ZCA 7.85" 768x1024 TFT LCD panel +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel Required properties: -- compatible: should be "innolux,p079zca" +- compatible: should be should be one of the following. +-"innolux,p079zca" for Innolux 7.9" P079ZCA 768*1024 panel +-"innolux,p097pfg" for Innolux 9.7" P097PFG 1536*2048 panel - reg: DSI virtual channel of the peripheral -- power-supply: phandle of the regulator that provides the supply voltage - enable-gpios: panel enable gpio Optional properties: - backlight: phandle of the backlight device attached to the panel +- power-supply: phandle of the regulator that provides the supply voltage +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage Example: @@ -16,6 +21,8 @@ Example: compatible = "innolux,p079zca"; reg = <0>; power-supply = <...>; + avdd-supply = <...>; + avee-supply = <...>; backlight = <>; enable-gpios = < 13 GPIO_ACTIVE_HIGH>; }; -- 2.7.4
[PATCH v3 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Refactor Innolux P079ZCA panel driver, let it support multi panel. Signed-off-by: Lin Huang --- Changes in v2: - Change regulator property name to meet the panel datasheet Changes in v3: - this patch only refactor P079ZCA panel to support multi panel, support P097PFG panel in another patch drivers/gpu/drm/panel/panel-innolux-p079zca.c | 147 ++ 1 file changed, 105 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..1597744 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,31 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->dsi_desc->desc.modes; - mode = drm_mode_duplicate(panel->drm, _mode); + mode = drm_mode_duplicate(panel->drm, m); if (!mode) { DRM_DEV_ERROR(panel->drm->dev, "failed to add mode %ux%ux@%u\n", - default_mode.hdisplay, default_mode.vdisplay, - default_mode.vrefresh); + m->hdisplay, m->vdisplay, m->vrefresh); return -ENOMEM; } @@ -193,9 +238,11 @@ static int innolux_panel_get_modes(struct drm_panel *panel) drm_mode_probed_add(panel->connector, mode); - panel->connector->display_info.width_mm = 120; - panel->connector->display_info.height_mm = 160; - panel->connector->display_info.bpc = 8; +
[PATCH v2 1/2] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it refactor Innolux P079ZCA panel driver, let it support multi panel, and add support P097PFG panel in this driver. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - change regulator property name to meet the panel datasheet drivers/gpu/drm/panel/panel-innolux-p079zca.c | 178 -- 1 file changed, 136 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..5d690b7 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,59 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *
[PATCH v2 1/2] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it refactor Innolux P079ZCA panel driver, let it support multi panel, and add support P097PFG panel in this driver. Signed-off-by: Lin Huang --- Changes in v2: - change regulator property name to meet the panel datasheet drivers/gpu/drm/panel/panel-innolux-p079zca.c | 178 -- 1 file changed, 136 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..5d690b7 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,59 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->dsi_desc->
[PATCH v2 2/2] dt-bindings: Add INNOLUX P097PFG panel bindings
The Innolux P097PFG panel is 9.7" panel with 1536X2048 resolution, it reuse P079ZCA panel driver, so improve p079ZCA dt-binding to support P097PFG. Signed-off-by: Lin Huang <h...@rock-chips.com> --- .../devicetree/bindings/display/panel/innolux,p079zca.txt | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt index d0f5516..8cadd8c 100644 --- a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt +++ b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt @@ -1,13 +1,18 @@ Innolux P079ZCA 7.85" 768x1024 TFT LCD panel +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel Required properties: -- compatible: should be "innolux,p079zca" +- compatible: should be should be one of the following. +-"innolux,p079zca" for Innolux 7.9" P079ZCA 768*1024 panel +-"innolux,p097pfg" for Innolux 9.7" P097PFG 1536*2048 panel - reg: DSI virtual channel of the peripheral -- power-supply: phandle of the regulator that provides the supply voltage - enable-gpios: panel enable gpio Optional properties: - backlight: phandle of the backlight device attached to the panel +- power-supply: phandle of the regulator that provides the supply voltage +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage Example: @@ -16,6 +21,8 @@ Example: compatible = "innolux,p079zca"; reg = <0>; power-supply = <...>; + avdd-supply = <...>; + avee-supply = <...>; backlight = <>; enable-gpios = < 13 GPIO_ACTIVE_HIGH>; }; -- 2.7.4
[PATCH v2 2/2] dt-bindings: Add INNOLUX P097PFG panel bindings
The Innolux P097PFG panel is 9.7" panel with 1536X2048 resolution, it reuse P079ZCA panel driver, so improve p079ZCA dt-binding to support P097PFG. Signed-off-by: Lin Huang --- .../devicetree/bindings/display/panel/innolux,p079zca.txt | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt index d0f5516..8cadd8c 100644 --- a/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt +++ b/Documentation/devicetree/bindings/display/panel/innolux,p079zca.txt @@ -1,13 +1,18 @@ Innolux P079ZCA 7.85" 768x1024 TFT LCD panel +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel Required properties: -- compatible: should be "innolux,p079zca" +- compatible: should be should be one of the following. +-"innolux,p079zca" for Innolux 7.9" P079ZCA 768*1024 panel +-"innolux,p097pfg" for Innolux 9.7" P097PFG 1536*2048 panel - reg: DSI virtual channel of the peripheral -- power-supply: phandle of the regulator that provides the supply voltage - enable-gpios: panel enable gpio Optional properties: - backlight: phandle of the backlight device attached to the panel +- power-supply: phandle of the regulator that provides the supply voltage +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage Example: @@ -16,6 +21,8 @@ Example: compatible = "innolux,p079zca"; reg = <0>; power-supply = <...>; + avdd-supply = <...>; + avee-supply = <...>; backlight = <>; enable-gpios = < 13 GPIO_ACTIVE_HIGH>; }; -- 2.7.4
[RESENT PATCH] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it refactor Innolux P079ZCA panel driver, let it support multi panel, and add support P097PFG panel in this driver. Signed-off-by: Lin Huang <h...@rock-chips.com> --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 178 -- 1 file changed, 136 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..a40798f 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,59 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->dsi_desc->desc.modes; - mode = drm_mode_duplicate(
[RESENT PATCH] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it refactor Innolux P079ZCA panel driver, let it support multi panel, and add support P097PFG panel in this driver. Signed-off-by: Lin Huang --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 178 -- 1 file changed, 136 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..a40798f 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,59 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->dsi_desc->desc.modes; - mode = drm_mode_duplicate(panel-
[PATCH] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it refactor Innolux P079ZCA panel driver, let it support multi panel, and add support P097PFG panel in this driver. Change-Id: If342e58a3de2861219b0b1313f402b6cb41ffa29 Signed-off-by: Lin Huang <h...@rock-chips.com> --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 178 -- 1 file changed, 136 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..a40798f 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,59 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->dsi_de
[PATCH] drm/panel: support Innolux P097PFG panel
Support Innolux P097PFG 9.7" 1536x2048 TFT LCD panel, it refactor Innolux P079ZCA panel driver, let it support multi panel, and add support P097PFG panel in this driver. Change-Id: If342e58a3de2861219b0b1313f402b6cb41ffa29 Signed-off-by: Lin Huang --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 178 -- 1 file changed, 136 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 6ba9344..a40798f 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -20,12 +20,32 @@ #include +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int bpc; + struct { + unsigned int width; + unsigned int height; + } size; +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + unsigned long flags; + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; struct backlight_device *backlight; - struct regulator *supply; + struct regulator *vddi; + struct regulator *avdd; + struct regulator *avee; struct gpio_desc *enable_gpio; bool prepared; @@ -78,9 +98,9 @@ static int innolux_panel_unprepare(struct drm_panel *panel) /* T8: 80ms - 1000ms */ msleep(80); - err = regulator_disable(innolux->supply); - if (err < 0) - return err; + regulator_disable(innolux->avee); + regulator_disable(innolux->avdd); + regulator_disable(innolux->vddi); innolux->prepared = false; @@ -97,10 +117,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) gpiod_set_value_cansleep(innolux->enable_gpio, 0); - err = regulator_enable(innolux->supply); + err = regulator_enable(innolux->vddi); if (err < 0) return err; + err = regulator_enable(innolux->avdd); + if (err < 0) + goto disable_vddi; + + err = regulator_enable(innolux->avee); + if (err < 0) + goto disable_avdd; + /* T2: 15ms - 1000ms */ usleep_range(15000, 16000); @@ -134,12 +162,13 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0; poweroff: - regulator_err = regulator_disable(innolux->supply); - if (regulator_err) - DRM_DEV_ERROR(panel->dev, "failed to disable regulator: %d\n", - regulator_err); - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + regulator_disable(innolux->avee); +disable_avdd: + regulator_disable(innolux->avdd); +disable_vddi: + regulator_disable(innolux->vddi); + return err; } @@ -164,7 +193,7 @@ static int innolux_panel_enable(struct drm_panel *panel) return 0; } -static const struct drm_display_mode default_mode = { +static const struct drm_display_mode innolux_p079zca_mode = { .clock = 56900, .hdisplay = 768, .hsync_start = 768 + 40, @@ -177,15 +206,59 @@ static const struct drm_display_mode default_mode = { .vrefresh = 60, }; +static const struct panel_desc_dsi innolux_p079zca_panel_desc = { + .desc = { + .modes = _p079zca_mode, + .bpc = 8, + .size = { + .width = 120, + .height = 160, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + +static const struct drm_display_mode innolux_p097pfg_mode = { + .clock = 22, + .hdisplay = 1536, + .hsync_start = 1536 + 100, + .hsync_end = 1536 + 100 + 24, + .htotal = 1536 + 100 + 24 + 100, + .vdisplay = 2048, + .vsync_start = 2048 + 18, + .vsync_end = 2048 + 18 + 2, + .vtotal = 2048 + 18 + 2 + 18, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi innolux_p097pfg_panel_desc = { + .desc = { + .modes = _p097pfg_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | +MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 8, +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct drm_display_mode *mode; + struct innolux_panel *innolux = to_innolux_panel(panel); + const struct drm_display_mode *m = innolux->dsi_desc->desc.modes; - mode
[PATCH v2 2/2] devicetree: i2c-hid: Add reset property
Document a "reset" and "assert-reset-us", it can be used for driver control reset property. And reuse post-power-on-delay-ms for deassert reset delay. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Documentation/devicetree/bindings/input/hid-over-i2c.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt index 28e8bd8..6ab0eed 100644 --- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt +++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt @@ -31,7 +31,9 @@ device-specific compatible properties, which should be used in addition to the - vdd-supply: phandle of the regulator that provides the supply voltage. - post-power-on-delay-ms: time required by the device after enabling its regulators - before it is ready for communication. Must be used with 'vdd-supply'. + or deassert reset pin before it is ready for communication. +- reset: phandle of the gpio that provides for hid reset pin. +- assert-reset-us: the device require reset assert time. Example: -- 2.7.4
[PATCH v2 2/2] devicetree: i2c-hid: Add reset property
Document a "reset" and "assert-reset-us", it can be used for driver control reset property. And reuse post-power-on-delay-ms for deassert reset delay. Signed-off-by: Lin Huang --- Documentation/devicetree/bindings/input/hid-over-i2c.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt index 28e8bd8..6ab0eed 100644 --- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt +++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt @@ -31,7 +31,9 @@ device-specific compatible properties, which should be used in addition to the - vdd-supply: phandle of the regulator that provides the supply voltage. - post-power-on-delay-ms: time required by the device after enabling its regulators - before it is ready for communication. Must be used with 'vdd-supply'. + or deassert reset pin before it is ready for communication. +- reset: phandle of the gpio that provides for hid reset pin. +- assert-reset-us: the device require reset assert time. Example: -- 2.7.4
[PATCH v2 1/2] HID: i2c-hid: add reset gpio property
some i2c hid devices have reset gpio, need to control it in the driver. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v2: - Add 10us in usleep_range() upper range - reuse post_power_delay_ms as deassert reset delay - delete deassert_reset_us property drivers/hid/i2c-hid/i2c-hid.c | 61 +++ include/linux/platform_data/i2c-hid.h | 3 ++ 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 9145c21..9f06135 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -793,6 +794,35 @@ struct hid_ll_driver i2c_hid_ll_driver = { }; EXPORT_SYMBOL_GPL(i2c_hid_ll_driver); +static int i2c_hid_hw_power_on(struct i2c_hid *ihid) +{ + int ret; + + ret = regulator_enable(ihid->pdata.supply); + if (ret < 0) + return ret; + + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 1); + if (ihid->pdata.assert_reset_us) + usleep_range(ihid->pdata.assert_reset_us, +ihid->pdata.assert_reset_us + 10); + + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 0); + + /* use for power supply delay or reset deassert delay */ + if (ihid->pdata.post_power_delay_ms) + msleep(ihid->pdata.post_power_delay_ms); + + return ret; +} + +static int i2c_hid_hw_power_off(struct i2c_hid *ihid) +{ + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 1); + + return regulator_disable(ihid->pdata.supply); +} + static int i2c_hid_init_irq(struct i2c_client *client) { struct i2c_hid *ihid = i2c_get_clientdata(client); @@ -934,6 +964,9 @@ static int i2c_hid_of_probe(struct i2c_client *client, if (!ret) pdata->post_power_delay_ms = val; + of_property_read_u32(dev->of_node, "assert-reset-us", +>assert_reset_us); + return 0; } @@ -1002,14 +1035,16 @@ static int i2c_hid_probe(struct i2c_client *client, goto err; } - ret = regulator_enable(ihid->pdata.supply); + ihid->pdata.reset_gpio = devm_gpiod_get_optional(>dev, "reset", +GPIOD_OUT_HIGH); + if (IS_ERR(ihid->pdata.reset_gpio)) + goto err; + + ret = i2c_hid_hw_power_on(ihid); if (ret < 0) { - dev_err(>dev, "Failed to enable regulator: %d\n", - ret); + dev_err(>dev, "Failed to power on: %d\n", ret); goto err; } - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); i2c_set_clientdata(client, ihid); @@ -1086,7 +1121,7 @@ static int i2c_hid_probe(struct i2c_client *client, pm_runtime_disable(>dev); err_regulator: - regulator_disable(ihid->pdata.supply); + i2c_hid_hw_power_off(ihid); err: i2c_hid_free_buffers(ihid); @@ -1112,8 +1147,7 @@ static int i2c_hid_remove(struct i2c_client *client) if (ihid->bufsize) i2c_hid_free_buffers(ihid); - regulator_disable(ihid->pdata.supply); - + i2c_hid_hw_power_off(ihid); kfree(ihid); return 0; @@ -1165,9 +1199,10 @@ static int i2c_hid_suspend(struct device *dev) hid_warn(hid, "Failed to enable irq wake: %d\n", wake_status); } else { - ret = regulator_disable(ihid->pdata.supply); + ret = i2c_hid_hw_power_off(ihid); if (ret < 0) - hid_warn(hid, "Failed to disable supply: %d\n", ret); + hid_warn(hid, "Failed to disable hw power: %d\n", +ret); } return 0; @@ -1182,11 +1217,9 @@ static int i2c_hid_resume(struct device *dev) int wake_status; if (!device_may_wakeup(>dev)) { - ret = regulator_enable(ihid->pdata.supply); + ret = i2c_hid_hw_power_on(ihid); if (ret < 0) - hid_warn(hid, "Failed to enable supply: %d\n", ret); - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); + hid_warn(hid, "Failed to enable hw power: %d\n", ret); } else if (ihid->irq_wake_enabled) { wake_status = disable_irq_wake(client->irq); if (!wake_status) diff --git a/include/linux/platform_data/i2c-hid.h b/include/linux/platform_data/i2c-hid.h index 1fb0882..40f1840 100644 --- a/include/linux/pl
[PATCH v2 1/2] HID: i2c-hid: add reset gpio property
some i2c hid devices have reset gpio, need to control it in the driver. Signed-off-by: Lin Huang --- Changes in v2: - Add 10us in usleep_range() upper range - reuse post_power_delay_ms as deassert reset delay - delete deassert_reset_us property drivers/hid/i2c-hid/i2c-hid.c | 61 +++ include/linux/platform_data/i2c-hid.h | 3 ++ 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 9145c21..9f06135 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -793,6 +794,35 @@ struct hid_ll_driver i2c_hid_ll_driver = { }; EXPORT_SYMBOL_GPL(i2c_hid_ll_driver); +static int i2c_hid_hw_power_on(struct i2c_hid *ihid) +{ + int ret; + + ret = regulator_enable(ihid->pdata.supply); + if (ret < 0) + return ret; + + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 1); + if (ihid->pdata.assert_reset_us) + usleep_range(ihid->pdata.assert_reset_us, +ihid->pdata.assert_reset_us + 10); + + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 0); + + /* use for power supply delay or reset deassert delay */ + if (ihid->pdata.post_power_delay_ms) + msleep(ihid->pdata.post_power_delay_ms); + + return ret; +} + +static int i2c_hid_hw_power_off(struct i2c_hid *ihid) +{ + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 1); + + return regulator_disable(ihid->pdata.supply); +} + static int i2c_hid_init_irq(struct i2c_client *client) { struct i2c_hid *ihid = i2c_get_clientdata(client); @@ -934,6 +964,9 @@ static int i2c_hid_of_probe(struct i2c_client *client, if (!ret) pdata->post_power_delay_ms = val; + of_property_read_u32(dev->of_node, "assert-reset-us", +>assert_reset_us); + return 0; } @@ -1002,14 +1035,16 @@ static int i2c_hid_probe(struct i2c_client *client, goto err; } - ret = regulator_enable(ihid->pdata.supply); + ihid->pdata.reset_gpio = devm_gpiod_get_optional(>dev, "reset", +GPIOD_OUT_HIGH); + if (IS_ERR(ihid->pdata.reset_gpio)) + goto err; + + ret = i2c_hid_hw_power_on(ihid); if (ret < 0) { - dev_err(>dev, "Failed to enable regulator: %d\n", - ret); + dev_err(>dev, "Failed to power on: %d\n", ret); goto err; } - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); i2c_set_clientdata(client, ihid); @@ -1086,7 +1121,7 @@ static int i2c_hid_probe(struct i2c_client *client, pm_runtime_disable(>dev); err_regulator: - regulator_disable(ihid->pdata.supply); + i2c_hid_hw_power_off(ihid); err: i2c_hid_free_buffers(ihid); @@ -1112,8 +1147,7 @@ static int i2c_hid_remove(struct i2c_client *client) if (ihid->bufsize) i2c_hid_free_buffers(ihid); - regulator_disable(ihid->pdata.supply); - + i2c_hid_hw_power_off(ihid); kfree(ihid); return 0; @@ -1165,9 +1199,10 @@ static int i2c_hid_suspend(struct device *dev) hid_warn(hid, "Failed to enable irq wake: %d\n", wake_status); } else { - ret = regulator_disable(ihid->pdata.supply); + ret = i2c_hid_hw_power_off(ihid); if (ret < 0) - hid_warn(hid, "Failed to disable supply: %d\n", ret); + hid_warn(hid, "Failed to disable hw power: %d\n", +ret); } return 0; @@ -1182,11 +1217,9 @@ static int i2c_hid_resume(struct device *dev) int wake_status; if (!device_may_wakeup(>dev)) { - ret = regulator_enable(ihid->pdata.supply); + ret = i2c_hid_hw_power_on(ihid); if (ret < 0) - hid_warn(hid, "Failed to enable supply: %d\n", ret); - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); + hid_warn(hid, "Failed to enable hw power: %d\n", ret); } else if (ihid->irq_wake_enabled) { wake_status = disable_irq_wake(client->irq); if (!wake_status) diff --git a/include/linux/platform_data/i2c-hid.h b/include/linux/platform_data/i2c-hid.h index 1fb0882..40f1840 100644 --- a/include/linux/platform_data/i2c-hid.h +++ b/i
[PATCH] HID: i2c-hid: add reset gpio property
some i2c hid devices have reset gpio, need to control it in the driver. Change-Id: I87bca954bffc7eb7b35711406f522cb3d0fc2ded Signed-off-by: Lin Huang <h...@rock-chips.com> --- drivers/hid/i2c-hid/i2c-hid.c | 63 +++ include/linux/platform_data/i2c-hid.h | 4 +++ 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 9145c21..a0e3a8e 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -793,6 +794,34 @@ struct hid_ll_driver i2c_hid_ll_driver = { }; EXPORT_SYMBOL_GPL(i2c_hid_ll_driver); +static int i2c_hid_hw_power_on(struct i2c_hid *ihid) +{ + int ret; + + ret = regulator_enable(ihid->pdata.supply); + if (ret < 0) + return ret; + + if (ihid->pdata.post_power_delay_ms) + msleep(ihid->pdata.post_power_delay_ms); + + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 1); + usleep_range(ihid->pdata.assert_reset_us, +ihid->pdata.assert_reset_us); + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 0); + usleep_range(ihid->pdata.deassert_reset_us, +ihid->pdata.deassert_reset_us); + + return ret; +} + +static int i2c_hid_hw_power_off(struct i2c_hid *ihid) +{ + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 1); + + return regulator_disable(ihid->pdata.supply); +} + static int i2c_hid_init_irq(struct i2c_client *client) { struct i2c_hid *ihid = i2c_get_clientdata(client); @@ -934,6 +963,12 @@ static int i2c_hid_of_probe(struct i2c_client *client, if (!ret) pdata->post_power_delay_ms = val; + ret = of_property_read_u32(dev->of_node, "assert-reset-us", + >assert_reset_us); + + ret = of_property_read_u32(dev->of_node, "deassert-reset-us", + >deassert_reset_us); + return 0; } @@ -1002,14 +1037,16 @@ static int i2c_hid_probe(struct i2c_client *client, goto err; } - ret = regulator_enable(ihid->pdata.supply); + ihid->pdata.reset_gpio = devm_gpiod_get_optional(>dev, "reset", +GPIOD_OUT_HIGH); + if (IS_ERR(ihid->pdata.reset_gpio)) + goto err; + + ret = i2c_hid_hw_power_on(ihid); if (ret < 0) { - dev_err(>dev, "Failed to enable regulator: %d\n", - ret); + dev_err(>dev, "Failed to power on: %d\n", ret); goto err; } - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); i2c_set_clientdata(client, ihid); @@ -1086,7 +1123,7 @@ static int i2c_hid_probe(struct i2c_client *client, pm_runtime_disable(>dev); err_regulator: - regulator_disable(ihid->pdata.supply); + i2c_hid_hw_power_off(ihid); err: i2c_hid_free_buffers(ihid); @@ -1112,8 +1149,7 @@ static int i2c_hid_remove(struct i2c_client *client) if (ihid->bufsize) i2c_hid_free_buffers(ihid); - regulator_disable(ihid->pdata.supply); - + i2c_hid_hw_power_off(ihid); kfree(ihid); return 0; @@ -1165,9 +1201,10 @@ static int i2c_hid_suspend(struct device *dev) hid_warn(hid, "Failed to enable irq wake: %d\n", wake_status); } else { - ret = regulator_disable(ihid->pdata.supply); + ret = i2c_hid_hw_power_off(ihid); if (ret < 0) - hid_warn(hid, "Failed to disable supply: %d\n", ret); + hid_warn(hid, "Failed to disable hw power: %d\n", +ret); } return 0; @@ -1182,11 +1219,9 @@ static int i2c_hid_resume(struct device *dev) int wake_status; if (!device_may_wakeup(>dev)) { - ret = regulator_enable(ihid->pdata.supply); + ret = i2c_hid_hw_power_on(ihid); if (ret < 0) - hid_warn(hid, "Failed to enable supply: %d\n", ret); - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); + hid_warn(hid, "Failed to enable hw power: %d\n", ret); } else if (ihid->irq_wake_enabled) { wake_status = disable_irq_wake(client->irq); if (!wake_status) diff --git a/include/linux/platform_data/i2c-hid.h b/include/linux/platform_data/i2c-hid.h index 1fb0882..3afc
[PATCH] HID: i2c-hid: add reset gpio property
some i2c hid devices have reset gpio, need to control it in the driver. Change-Id: I87bca954bffc7eb7b35711406f522cb3d0fc2ded Signed-off-by: Lin Huang --- drivers/hid/i2c-hid/i2c-hid.c | 63 +++ include/linux/platform_data/i2c-hid.h | 4 +++ 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 9145c21..a0e3a8e 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -793,6 +794,34 @@ struct hid_ll_driver i2c_hid_ll_driver = { }; EXPORT_SYMBOL_GPL(i2c_hid_ll_driver); +static int i2c_hid_hw_power_on(struct i2c_hid *ihid) +{ + int ret; + + ret = regulator_enable(ihid->pdata.supply); + if (ret < 0) + return ret; + + if (ihid->pdata.post_power_delay_ms) + msleep(ihid->pdata.post_power_delay_ms); + + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 1); + usleep_range(ihid->pdata.assert_reset_us, +ihid->pdata.assert_reset_us); + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 0); + usleep_range(ihid->pdata.deassert_reset_us, +ihid->pdata.deassert_reset_us); + + return ret; +} + +static int i2c_hid_hw_power_off(struct i2c_hid *ihid) +{ + gpiod_set_value_cansleep(ihid->pdata.reset_gpio, 1); + + return regulator_disable(ihid->pdata.supply); +} + static int i2c_hid_init_irq(struct i2c_client *client) { struct i2c_hid *ihid = i2c_get_clientdata(client); @@ -934,6 +963,12 @@ static int i2c_hid_of_probe(struct i2c_client *client, if (!ret) pdata->post_power_delay_ms = val; + ret = of_property_read_u32(dev->of_node, "assert-reset-us", + >assert_reset_us); + + ret = of_property_read_u32(dev->of_node, "deassert-reset-us", + >deassert_reset_us); + return 0; } @@ -1002,14 +1037,16 @@ static int i2c_hid_probe(struct i2c_client *client, goto err; } - ret = regulator_enable(ihid->pdata.supply); + ihid->pdata.reset_gpio = devm_gpiod_get_optional(>dev, "reset", +GPIOD_OUT_HIGH); + if (IS_ERR(ihid->pdata.reset_gpio)) + goto err; + + ret = i2c_hid_hw_power_on(ihid); if (ret < 0) { - dev_err(>dev, "Failed to enable regulator: %d\n", - ret); + dev_err(>dev, "Failed to power on: %d\n", ret); goto err; } - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); i2c_set_clientdata(client, ihid); @@ -1086,7 +1123,7 @@ static int i2c_hid_probe(struct i2c_client *client, pm_runtime_disable(>dev); err_regulator: - regulator_disable(ihid->pdata.supply); + i2c_hid_hw_power_off(ihid); err: i2c_hid_free_buffers(ihid); @@ -1112,8 +1149,7 @@ static int i2c_hid_remove(struct i2c_client *client) if (ihid->bufsize) i2c_hid_free_buffers(ihid); - regulator_disable(ihid->pdata.supply); - + i2c_hid_hw_power_off(ihid); kfree(ihid); return 0; @@ -1165,9 +1201,10 @@ static int i2c_hid_suspend(struct device *dev) hid_warn(hid, "Failed to enable irq wake: %d\n", wake_status); } else { - ret = regulator_disable(ihid->pdata.supply); + ret = i2c_hid_hw_power_off(ihid); if (ret < 0) - hid_warn(hid, "Failed to disable supply: %d\n", ret); + hid_warn(hid, "Failed to disable hw power: %d\n", +ret); } return 0; @@ -1182,11 +1219,9 @@ static int i2c_hid_resume(struct device *dev) int wake_status; if (!device_may_wakeup(>dev)) { - ret = regulator_enable(ihid->pdata.supply); + ret = i2c_hid_hw_power_on(ihid); if (ret < 0) - hid_warn(hid, "Failed to enable supply: %d\n", ret); - if (ihid->pdata.post_power_delay_ms) - msleep(ihid->pdata.post_power_delay_ms); + hid_warn(hid, "Failed to enable hw power: %d\n", ret); } else if (ihid->irq_wake_enabled) { wake_status = disable_irq_wake(client->irq); if (!wake_status) diff --git a/include/linux/platform_data/i2c-hid.h b/include/linux/platform_data/i2c-hid.h index 1fb0882..3afc781 100644 --- a/inc
[PATCH v2 1/2] ASoC: codec: use enable pin to control dmic start and stop
From: huang lin <h...@rock-chips.com> on some board use enable pin to control dmic start and stop, so add this feature in dmic driver. Signed-off-by: Lin Huang <h...@rock-chips.com> --- sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/dmic.c | 46 ++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 010811e..d98233b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -71,7 +71,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C select SND_SOC_DIO2125 - select SND_SOC_DMIC + select SND_SOC_DMIC if GPIOLIB select SND_SOC_ES8316 if I2C select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 12e07f9..b88a1ee 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -19,6 +19,8 @@ * */ +#include +#include #include #include #include @@ -27,6 +29,34 @@ #include #include +static int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct gpio_desc *dmic_en = snd_soc_dai_get_drvdata(dai); + + if (!dmic_en) + return 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + gpiod_set_value(dmic_en, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + gpiod_set_value(dmic_en, 0); + break; + } + + return 0; +} + +static const struct snd_soc_dai_ops dmic_dai_ops = { + .trigger= dmic_daiops_trigger, +}; + static struct snd_soc_dai_driver dmic_dai = { .name = "dmic-hifi", .capture = { @@ -38,8 +68,23 @@ static struct snd_soc_dai_driver dmic_dai = { | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, }, + .ops= _dai_ops, }; +static int dmic_codec_probe(struct snd_soc_codec *codec) +{ + struct gpio_desc *dmic_en; + + dmic_en = devm_gpiod_get_optional(codec->dev, + "dmicen", GPIOD_OUT_LOW); + if (IS_ERR(dmic_en)) + return PTR_ERR(dmic_en); + + snd_soc_codec_set_drvdata(codec, dmic_en); + + return 0; +} + static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0, SND_SOC_NOPM, 0, 0), @@ -51,6 +96,7 @@ static const struct snd_soc_dapm_route intercon[] = { }; static const struct snd_soc_codec_driver soc_dmic = { + .probe = dmic_codec_probe, .component_driver = { .dapm_widgets = dmic_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets), -- 2.7.4
[PATCH v2 1/2] ASoC: codec: use enable pin to control dmic start and stop
From: huang lin on some board use enable pin to control dmic start and stop, so add this feature in dmic driver. Signed-off-by: Lin Huang --- sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/dmic.c | 46 ++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 010811e..d98233b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -71,7 +71,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C select SND_SOC_DIO2125 - select SND_SOC_DMIC + select SND_SOC_DMIC if GPIOLIB select SND_SOC_ES8316 if I2C select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 12e07f9..b88a1ee 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -19,6 +19,8 @@ * */ +#include +#include #include #include #include @@ -27,6 +29,34 @@ #include #include +static int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct gpio_desc *dmic_en = snd_soc_dai_get_drvdata(dai); + + if (!dmic_en) + return 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + gpiod_set_value(dmic_en, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + gpiod_set_value(dmic_en, 0); + break; + } + + return 0; +} + +static const struct snd_soc_dai_ops dmic_dai_ops = { + .trigger= dmic_daiops_trigger, +}; + static struct snd_soc_dai_driver dmic_dai = { .name = "dmic-hifi", .capture = { @@ -38,8 +68,23 @@ static struct snd_soc_dai_driver dmic_dai = { | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, }, + .ops= _dai_ops, }; +static int dmic_codec_probe(struct snd_soc_codec *codec) +{ + struct gpio_desc *dmic_en; + + dmic_en = devm_gpiod_get_optional(codec->dev, + "dmicen", GPIOD_OUT_LOW); + if (IS_ERR(dmic_en)) + return PTR_ERR(dmic_en); + + snd_soc_codec_set_drvdata(codec, dmic_en); + + return 0; +} + static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0, SND_SOC_NOPM, 0, 0), @@ -51,6 +96,7 @@ static const struct snd_soc_dapm_route intercon[] = { }; static const struct snd_soc_codec_driver soc_dmic = { + .probe = dmic_codec_probe, .component_driver = { .dapm_widgets = dmic_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets), -- 2.7.4
[PATCH v2 2/2] dt-bindings: sound: add dmicen property in dmic driver
From: huang lin <h...@rock-chips.com> there may use enable pin to control dmic start and stop, so add this property in dt-bindings. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Documentation/devicetree/bindings/sound/dmic.txt | 4 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt index a0c58f2..54c8ef6 100644 --- a/Documentation/devicetree/bindings/sound/dmic.txt +++ b/Documentation/devicetree/bindings/sound/dmic.txt @@ -5,8 +5,12 @@ This device support generic PDM digital microphone. Required properties: - compatible: should be "dmic-codec". +Optional properties: + - dmicen-gpios: GPIO specifier for dmic to control start and stop + Example node: dmic_codec: dmic@0 { compatible = "dmic-codec"; + dmicen-gpios = < 3 GPIO_ACTIVE_HIGH>; }; -- 2.7.4
[PATCH v2 2/2] dt-bindings: sound: add dmicen property in dmic driver
From: huang lin there may use enable pin to control dmic start and stop, so add this property in dt-bindings. Signed-off-by: Lin Huang --- Documentation/devicetree/bindings/sound/dmic.txt | 4 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt index a0c58f2..54c8ef6 100644 --- a/Documentation/devicetree/bindings/sound/dmic.txt +++ b/Documentation/devicetree/bindings/sound/dmic.txt @@ -5,8 +5,12 @@ This device support generic PDM digital microphone. Required properties: - compatible: should be "dmic-codec". +Optional properties: + - dmicen-gpios: GPIO specifier for dmic to control start and stop + Example node: dmic_codec: dmic@0 { compatible = "dmic-codec"; + dmicen-gpios = < 3 GPIO_ACTIVE_HIGH>; }; -- 2.7.4