Re: [PATCH v6 5/5] drm/rockchip: support dp training outside dp firmware
Hi Enric, On Wednesday, May 23, 2018 01:06 AM, Enric Balletbo Serra wrote: Lin, 2018-05-22 9:41 GMT+02:00 Enric Balletbo Serra <eballe...@gmail.com>: Hi Lin 2018-05-22 3:08 GMT+02:00 hl <h...@rock-chips.com>: Hi Enric, On Monday, May 21, 2018 11:22 PM, Enric Balletbo Serra wrote: Hi Lin, 2018-05-21 11:37 GMT+02:00 Lin Huang <h...@rock-chips.com>: 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) { You don't need to compare to true. Simply do: 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 == true) { 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_ha
Re: [PATCH v6 5/5] drm/rockchip: support dp training outside dp firmware
Hi Enric, On Wednesday, May 23, 2018 01:06 AM, Enric Balletbo Serra wrote: Lin, 2018-05-22 9:41 GMT+02:00 Enric Balletbo Serra : Hi Lin 2018-05-22 3:08 GMT+02:00 hl : Hi Enric, On Monday, May 21, 2018 11:22 PM, Enric Balletbo Serra wrote: Hi Lin, 2018-05-21 11:37 GMT+02:00 Lin Huang : 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) { You don't need to compare to true. Simply do: 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 == true) { 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
Re: [PATCH v6 5/5] drm/rockchip: support dp training outside dp firmware
Hi Enric, On Monday, May 21, 2018 11:22 PM, Enric Balletbo Serra wrote: Hi Lin, 2018-05-21 11:37 GMT+02:00 Lin Huang: 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) { You don't need to compare to true. Simply do: 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 == true) { 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 + *
Re: [PATCH v6 5/5] drm/rockchip: support dp training outside dp firmware
Hi Enric, On Monday, May 21, 2018 11:22 PM, Enric Balletbo Serra wrote: Hi Lin, 2018-05-21 11:37 GMT+02:00 Lin Huang : 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) { You don't need to compare to true. Simply do: 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 == true) { 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
Re: [PATCH v5 4/4] drm/rockchip: support dp training outside dp firmware
+ Kishon On Thursday, May 17, 2018 09:51 PM, Sean Paul wrote: On Thu, May 17, 2018 at 05:18:00PM +0800, Lin Huang wrote: 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 ZhongSigned-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) +{ +
Re: [PATCH v5 4/4] drm/rockchip: support dp training outside dp firmware
+ Kishon On Thursday, May 17, 2018 09:51 PM, Sean Paul wrote: On Thu, May 17, 2018 at 05:18:00PM +0800, Lin Huang wrote: 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]; +
Re: [PATCH 4/4] drm/rockchip: support dp training outside dp firmware
On Monday, May 07, 2018 07:29 PM, Enric Balletbo Serra wrote: Hi Lin, Thanks for the patch. 2018-05-04 10:08 GMT+02:00 Lin Huang: DP firware use fix phy config value to do training, but some s/fiware/firmware/ 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. maybe you can rewrite all this in a better way. ooi, which boards needs this? 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 */ For a C source file the format is: (https://www.kernel.org/doc/html/latest/process/license-rules.html) // SPDX-License-Identifier: Thanks for pointing it, will fix it. +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + */ + +#include Why you need this include? +#include +#include +#include +#include +#include +#include +#include +#include + In fact, I think that there are other includes that can be removed, please review. +#include
Re: [PATCH 4/4] drm/rockchip: support dp training outside dp firmware
On Monday, May 07, 2018 07:29 PM, Enric Balletbo Serra wrote: Hi Lin, Thanks for the patch. 2018-05-04 10:08 GMT+02:00 Lin Huang : DP firware use fix phy config value to do training, but some s/fiware/firmware/ 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. maybe you can rewrite all this in a better way. ooi, which boards needs this? 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 */ For a C source file the format is: (https://www.kernel.org/doc/html/latest/process/license-rules.html) // SPDX-License-Identifier: Thanks for pointing it, will fix it. +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + */ + +#include Why you need this include? +#include +#include +#include +#include +#include +#include +#include +#include + In fact, I think that there are other includes that can be removed, please review. +#include "cdn-dp-core.h" +#include "cdn-dp-reg.h" + +static void
Re: [PATCH 2/4] phy: rockchip-typec: support variable phy config value
On Monday, May 07, 2018 09:59 PM, Enric Balletbo Serra wrote: Hi Lin, Thanks for the patch, apart from the new build warnings introduced some more comments below. 2018-05-04 10:08 GMT+02:00 Lin Huang: 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 Why do you need to increase this timeout? Is because the software link training timed out using the old value? That for debug, will fix it in next version. #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 DEFAULT_RATE seems a very common name for me, maybe add a prefix? Okay, will fix it. 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,
Re: [PATCH 2/4] phy: rockchip-typec: support variable phy config value
On Monday, May 07, 2018 09:59 PM, Enric Balletbo Serra wrote: Hi Lin, Thanks for the patch, apart from the new build warnings introduced some more comments below. 2018-05-04 10:08 GMT+02:00 Lin Huang : 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 Why do you need to increase this timeout? Is because the software link training timed out using the old value? That for debug, will fix it in next version. #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 DEFAULT_RATE seems a very common name for me, maybe add a prefix? Okay, will fix it. 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 }, + {
Re: [PATCH 1/4] drm/rockchip: add transfer function for cdn-dp
Hi Enric, On Monday, May 07, 2018 07:27 PM, Enric Balletbo Serra wrote: Hi Lin, I am interested in these patches, could you cc me on newer versions? Thanks. Some comments below. Sure, will cc to you next version. 2018-05-04 10:08 GMT+02:00 Lin Huang: 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(-) In general, for this patch and all the other patches in the series I saw that checkpatch spits out some warnings, could you fix these and ideally run checkpatch with the --strict --subjective option? Okay. 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; + I think that you would mean STATUS instead of STAUS on these defines. What happens if the status is AUX_STATUS_SINK_ERROR or AUX_STATUS_BUS_ERROR? drm_dp_i2c_do_msg() will mark it as invalid i2c relay and return error. + 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 +++
Re: [PATCH 1/4] drm/rockchip: add transfer function for cdn-dp
Hi Enric, On Monday, May 07, 2018 07:27 PM, Enric Balletbo Serra wrote: Hi Lin, I am interested in these patches, could you cc me on newer versions? Thanks. Some comments below. Sure, will cc to you next version. 2018-05-04 10:08 GMT+02:00 Lin Huang : 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(-) In general, for this patch and all the other patches in the series I saw that checkpatch spits out some warnings, could you fix these and ideally run checkpatch with the --strict --subjective option? Okay. 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; + I think that you would mean STATUS instead of STAUS on these defines. What happens if the status is AUX_STATUS_SINK_ERROR or AUX_STATUS_BUS_ERROR? drm_dp_i2c_do_msg() will mark it as invalid i2c relay and return error. + 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
Re: [PATCH v4 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Hi On Tuesday, March 20, 2018 06:20 PM, Emil Velikov wrote: On 20 March 2018 at 06:24, hl <h...@rock-chips.com> wrote: Hi Emil, On Monday, March 19, 2018 09:09 PM, Emil Velikov wrote: On 15 March 2018 at 02:35, hl <h...@rock-chips.com> wrote: Hi Emil, On Wednesday, March 14, 2018 08:02 PM, Emil Velikov wrote: Hi Lin, On 14 March 2018 at 09:12, Lin Huang <h...@rock-chips.com> wrote: 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 Thanks for splitting this up. I think there's another piece that fell through the cracks. I'm not deeply familiar with the driver, so just sharing some quick notes. 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; These two seem are new addition, as opposed to a dummy refactor. Are they optional, does one need them for the existing panel (separate patch?) or only for the new one (squash with the new panel code)? 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; Good call on dropping the early return here. @@ -207,19 +248,28 @@ static const struct drm_panel_funcs innolux_panel_funcs = { - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->desc = desc; + innolux->vddi = devm_regulator_get(dev, "power"); + innolux->avdd = devm_regulator_get(dev, "avdd"); + innolux->avee = devm_regulator_get(dev, "avee"); AFAICT devm_regulator_get returns a pointer which is unsuitable to be passed into regulator_{enable,disable}. Hence, the IS_ERR check should stay. If any of the regulators are optional, you want to call regulator_{enable,disable} only as applicable. devm_regulator_get() will use dummy_regulator if there not regulator pass to driver, so it not affect regulator_{enable, disable}. One of us is getting confused here: devm_regulator_get does not _use_ a regulator, it returns a pointer to a regulator, right? According to the 4.16-rc6 codebase - one error returns a ERR_PTR [1]. devm_regulator_get() will not reurn a ERR_PTR, it will pass NORMAL_GET mode to _regulator_get() when you call devm_regulator_get(), and with following code: Just before the _regulator_get() call we have "return ERR_PTR(-ENOMEM);" See https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/regulator/devres.c?h=v4.16-rc6#n34 Okay, i got what you concern now, yes, you are right, i will keep IS_ERR checking here. With the pointer dereferenced in regulator_enable [2], without a IS_ERR check, hence thing will go boom(?) These three regulator are optional, the p079zca will use "power" and , so i think it better not to check ERR here. What should happen if p079zca is missing "power" or p097pgf - "avdd" and "avee"? Obviously the latter two should be introduced with the p097pgf support. i think it need dts to make sure configure the power node correct, if missing "power" node fo p079zca or "avdd" "avee" node for p097pgf, the panel can not work, but do not affcet other driver, the kernel do not crash(as i explain before and i also test it). If you know it won't work just don't continue? And yes, it will crash ;-) Either way, if you don't like my feedback so be it. HTH Emil P.S. As a non native English speaker to another - spell checker helps a lot ;-)
Re: [PATCH v4 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Hi On Tuesday, March 20, 2018 06:20 PM, Emil Velikov wrote: On 20 March 2018 at 06:24, hl wrote: Hi Emil, On Monday, March 19, 2018 09:09 PM, Emil Velikov wrote: On 15 March 2018 at 02:35, hl wrote: Hi Emil, On Wednesday, March 14, 2018 08:02 PM, Emil Velikov wrote: Hi Lin, On 14 March 2018 at 09:12, Lin Huang wrote: 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 Thanks for splitting this up. I think there's another piece that fell through the cracks. I'm not deeply familiar with the driver, so just sharing some quick notes. 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; These two seem are new addition, as opposed to a dummy refactor. Are they optional, does one need them for the existing panel (separate patch?) or only for the new one (squash with the new panel code)? 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; Good call on dropping the early return here. @@ -207,19 +248,28 @@ static const struct drm_panel_funcs innolux_panel_funcs = { - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->desc = desc; + innolux->vddi = devm_regulator_get(dev, "power"); + innolux->avdd = devm_regulator_get(dev, "avdd"); + innolux->avee = devm_regulator_get(dev, "avee"); AFAICT devm_regulator_get returns a pointer which is unsuitable to be passed into regulator_{enable,disable}. Hence, the IS_ERR check should stay. If any of the regulators are optional, you want to call regulator_{enable,disable} only as applicable. devm_regulator_get() will use dummy_regulator if there not regulator pass to driver, so it not affect regulator_{enable, disable}. One of us is getting confused here: devm_regulator_get does not _use_ a regulator, it returns a pointer to a regulator, right? According to the 4.16-rc6 codebase - one error returns a ERR_PTR [1]. devm_regulator_get() will not reurn a ERR_PTR, it will pass NORMAL_GET mode to _regulator_get() when you call devm_regulator_get(), and with following code: Just before the _regulator_get() call we have "return ERR_PTR(-ENOMEM);" See https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/regulator/devres.c?h=v4.16-rc6#n34 Okay, i got what you concern now, yes, you are right, i will keep IS_ERR checking here. With the pointer dereferenced in regulator_enable [2], without a IS_ERR check, hence thing will go boom(?) These three regulator are optional, the p079zca will use "power" and , so i think it better not to check ERR here. What should happen if p079zca is missing "power" or p097pgf - "avdd" and "avee"? Obviously the latter two should be introduced with the p097pgf support. i think it need dts to make sure configure the power node correct, if missing "power" node fo p079zca or "avdd" "avee" node for p097pgf, the panel can not work, but do not affcet other driver, the kernel do not crash(as i explain before and i also test it). If you know it won't work just don't continue? And yes, it will crash ;-) Either way, if you don't like my feedback so be it. HTH Emil P.S. As a non native English speaker to another - spell checker helps a lot ;-)
Re: [PATCH v4 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Hi Emil, On Monday, March 19, 2018 09:09 PM, Emil Velikov wrote: On 15 March 2018 at 02:35, hl <h...@rock-chips.com> wrote: Hi Emil, On Wednesday, March 14, 2018 08:02 PM, Emil Velikov wrote: Hi Lin, On 14 March 2018 at 09:12, Lin Huang <h...@rock-chips.com> wrote: 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 Thanks for splitting this up. I think there's another piece that fell through the cracks. I'm not deeply familiar with the driver, so just sharing some quick notes. 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; These two seem are new addition, as opposed to a dummy refactor. Are they optional, does one need them for the existing panel (separate patch?) or only for the new one (squash with the new panel code)? 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; Good call on dropping the early return here. @@ -207,19 +248,28 @@ static const struct drm_panel_funcs innolux_panel_funcs = { - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->desc = desc; + innolux->vddi = devm_regulator_get(dev, "power"); + innolux->avdd = devm_regulator_get(dev, "avdd"); + innolux->avee = devm_regulator_get(dev, "avee"); AFAICT devm_regulator_get returns a pointer which is unsuitable to be passed into regulator_{enable,disable}. Hence, the IS_ERR check should stay. If any of the regulators are optional, you want to call regulator_{enable,disable} only as applicable. devm_regulator_get() will use dummy_regulator if there not regulator pass to driver, so it not affect regulator_{enable, disable}. One of us is getting confused here: devm_regulator_get does not _use_ a regulator, it returns a pointer to a regulator, right? According to the 4.16-rc6 codebase - one error returns a ERR_PTR [1]. devm_regulator_get() will not reurn a ERR_PTR, it will pass NORMAL_GET mode to _regulator_get() when you call devm_regulator_get(), and with following code: rdev = regulator_dev_lookup(dev, id); if (IS_ERR(rdev)) { . .. switch (get_type) { case NORMAL_GET: /* * Assume that a regulator is physically present and * enabled, even if it isn't hooked up, and just * provide a dummy. */ dev_warn(dev, "%s supply %s not found, using dummy regulator\n", devname, id); rdev = dummy_regulator_rdev; get_device(>dev); break; ... ... } regulator = create_regulator(rdev, dev, id); ... it wil get a dummy_regulator for it. With the pointer dereferenced in regulator_enable [2], without a IS_ERR check, hence thing will go boom(?) These three regulator are optional, the p079zca will use "power" and , so i think it better not to check ERR here. What should happen if p079zca is missing "power" or p097pgf - "avdd" and "avee"? Obviously the latter two should be introduced with the p097pgf support. i think it need dts to make sure configure the power node correct, if missing "power" node fo p079zca or "avdd" "avee" node for p097pgf, the panel can not work, but do not affcet other driver, the kernel do not crash(as i explain before and i also test it). HTH Emil [1] https://elixir.bootlin.com/linux/v4.16-rc6/source/drivers/regulator/devres.c#L27 [2] https://elixir.bootlin.com/linux/v4.16-rc6/source/drivers/regulator/core.c#L2189
Re: [PATCH v4 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Hi Emil, On Monday, March 19, 2018 09:09 PM, Emil Velikov wrote: On 15 March 2018 at 02:35, hl wrote: Hi Emil, On Wednesday, March 14, 2018 08:02 PM, Emil Velikov wrote: Hi Lin, On 14 March 2018 at 09:12, Lin Huang wrote: 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 Thanks for splitting this up. I think there's another piece that fell through the cracks. I'm not deeply familiar with the driver, so just sharing some quick notes. 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; These two seem are new addition, as opposed to a dummy refactor. Are they optional, does one need them for the existing panel (separate patch?) or only for the new one (squash with the new panel code)? 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; Good call on dropping the early return here. @@ -207,19 +248,28 @@ static const struct drm_panel_funcs innolux_panel_funcs = { - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->desc = desc; + innolux->vddi = devm_regulator_get(dev, "power"); + innolux->avdd = devm_regulator_get(dev, "avdd"); + innolux->avee = devm_regulator_get(dev, "avee"); AFAICT devm_regulator_get returns a pointer which is unsuitable to be passed into regulator_{enable,disable}. Hence, the IS_ERR check should stay. If any of the regulators are optional, you want to call regulator_{enable,disable} only as applicable. devm_regulator_get() will use dummy_regulator if there not regulator pass to driver, so it not affect regulator_{enable, disable}. One of us is getting confused here: devm_regulator_get does not _use_ a regulator, it returns a pointer to a regulator, right? According to the 4.16-rc6 codebase - one error returns a ERR_PTR [1]. devm_regulator_get() will not reurn a ERR_PTR, it will pass NORMAL_GET mode to _regulator_get() when you call devm_regulator_get(), and with following code: rdev = regulator_dev_lookup(dev, id); if (IS_ERR(rdev)) { . .. switch (get_type) { case NORMAL_GET: /* * Assume that a regulator is physically present and * enabled, even if it isn't hooked up, and just * provide a dummy. */ dev_warn(dev, "%s supply %s not found, using dummy regulator\n", devname, id); rdev = dummy_regulator_rdev; get_device(>dev); break; ... ... } regulator = create_regulator(rdev, dev, id); ... it wil get a dummy_regulator for it. With the pointer dereferenced in regulator_enable [2], without a IS_ERR check, hence thing will go boom(?) These three regulator are optional, the p079zca will use "power" and , so i think it better not to check ERR here. What should happen if p079zca is missing "power" or p097pgf - "avdd" and "avee"? Obviously the latter two should be introduced with the p097pgf support. i think it need dts to make sure configure the power node correct, if missing "power" node fo p079zca or "avdd" "avee" node for p097pgf, the panel can not work, but do not affcet other driver, the kernel do not crash(as i explain before and i also test it). HTH Emil [1] https://elixir.bootlin.com/linux/v4.16-rc6/source/drivers/regulator/devres.c#L27 [2] https://elixir.bootlin.com/linux/v4.16-rc6/source/drivers/regulator/core.c#L2189
Re: [PATCH v4 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Hi Emil, On Wednesday, March 14, 2018 08:02 PM, Emil Velikov wrote: Hi Lin, On 14 March 2018 at 09:12, Lin Huangwrote: 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 Thanks for splitting this up. I think there's another piece that fell through the cracks. I'm not deeply familiar with the driver, so just sharing some quick notes. 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; These two seem are new addition, as opposed to a dummy refactor. Are they optional, does one need them for the existing panel (separate patch?) or only for the new one (squash with the new panel code)? 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; Good call on dropping the early return here. @@ -207,19 +248,28 @@ static const struct drm_panel_funcs innolux_panel_funcs = { - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->desc = desc; + innolux->vddi = devm_regulator_get(dev, "power"); + innolux->avdd = devm_regulator_get(dev, "avdd"); + innolux->avee = devm_regulator_get(dev, "avee"); AFAICT devm_regulator_get returns a pointer which is unsuitable to be passed into regulator_{enable,disable}. Hence, the IS_ERR check should stay. If any of the regulators are optional, you want to call regulator_{enable,disable} only as applicable. devm_regulator_get() will use dummy_regulator if there not regulator pass to driver, so it not affect regulator_{enable, disable}. These three regulator are optional, the p079zca will use "power" and p097pgf will use "avdd" and "avee", so i think it better not to check ERR here. @@ -318,5 +377,6 @@ static struct mipi_dsi_driver innolux_panel_driver = { module_mipi_dsi_driver(innolux_panel_driver); MODULE_AUTHOR("Chris Zhong "); +MODULE_AUTHOR("Lin Huang "); I don't think refactoring existing code classify as being the module author. Then again, I could be wrong. HTH Emil
Re: [PATCH v4 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Hi Emil, On Wednesday, March 14, 2018 08:02 PM, Emil Velikov wrote: Hi Lin, On 14 March 2018 at 09:12, Lin Huang wrote: 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 Thanks for splitting this up. I think there's another piece that fell through the cracks. I'm not deeply familiar with the driver, so just sharing some quick notes. 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; These two seem are new addition, as opposed to a dummy refactor. Are they optional, does one need them for the existing panel (separate patch?) or only for the new one (squash with the new panel code)? 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; Good call on dropping the early return here. @@ -207,19 +248,28 @@ static const struct drm_panel_funcs innolux_panel_funcs = { - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->desc = desc; + innolux->vddi = devm_regulator_get(dev, "power"); + innolux->avdd = devm_regulator_get(dev, "avdd"); + innolux->avee = devm_regulator_get(dev, "avee"); AFAICT devm_regulator_get returns a pointer which is unsuitable to be passed into regulator_{enable,disable}. Hence, the IS_ERR check should stay. If any of the regulators are optional, you want to call regulator_{enable,disable} only as applicable. devm_regulator_get() will use dummy_regulator if there not regulator pass to driver, so it not affect regulator_{enable, disable}. These three regulator are optional, the p079zca will use "power" and p097pgf will use "avdd" and "avee", so i think it better not to check ERR here. @@ -318,5 +377,6 @@ static struct mipi_dsi_driver innolux_panel_driver = { module_mipi_dsi_driver(innolux_panel_driver); MODULE_AUTHOR("Chris Zhong "); +MODULE_AUTHOR("Lin Huang "); I don't think refactoring existing code classify as being the module author. Then again, I could be wrong. HTH Emil
Re: [RESEND PATCH v3 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Hi Thierry Reding, On Monday, March 12, 2018 05:21 PM, Thierry Reding wrote: On Mon, Dec 04, 2017 at 03:17:48PM +0800, Lin Huang wrote: 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; +}; There's no need for the two layers here. Just move everything from struct panel_desc_dsi into struct panel_desc. Okay, will fix it. + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; And then this can just become: const struct panel_desc *desc; The _dsi suffix is redundant because this driver is exclusively for DSI devices. Got it. -static int innolux_panel_add(struct innolux_panel *innolux) +static int innolux_panel_add(struct mipi_dsi_device *dsi, +const struct panel_desc_dsi *desc) { - struct device *dev = >link->dev; + struct innolux_panel *innolux; + struct device *dev = >dev; struct device_node *np; int err; - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->dsi_desc = desc; + innolux->vddi = devm_regulator_get(dev, "power"); + if (IS_ERR(innolux->vddi)) + return PTR_ERR(innolux->vddi); + + innolux->avdd = devm_regulator_get(dev, "avdd"); + if (IS_ERR(innolux->avdd)) + return PTR_ERR(innolux->avdd); + + innolux->avee = devm_regulator_get(dev, "avee"); + if (IS_ERR(innolux->avee)) + return PTR_ERR(innolux->avee); According to the device tree bindings these regulators are all optional. Now devm_regulator_get() will return a dummy regulator if one has not been specified in DT, so this seems like it should work fine, even for existing DTBs that don't have the avdd and avee regulators. However, the DT bindings seem to be wrong, because these are in fact required regulators. Actually, the vddi is request, and avdd and avee is optional, i will only check vddi error later. innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); @@ -243,14 +306,16 @@ static int innolux_panel_add(struct innolux_panel *innolux) drm_panel_init(>base); innolux->base.funcs = _panel_funcs; - innolux->base.dev = >link->dev; + innolux->base.dev = dev; err = drm_panel_add(>base); if (err < 0) goto put_backlight; - return 0; + dev_set_drvdata(dev, innolux); + innolux->link = dsi; + return 0; put_backlight: put_device(>backlight->dev); @@ -267,28 +332,25 @@ static void innolux_panel_del(struct innolux_panel *innolux) static int innolux_panel_probe(struct mipi_dsi_device *dsi) { - struct innolux_panel *innolux; - int err; - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_LPM; - - innolux = devm_kzalloc(>dev, sizeof(*innolux), GFP_KERNEL); - if (!innolux) - return -ENOMEM; + const struct panel_desc_dsi *dsi_desc; + const struct of_device_id *id; + int err; - mipi_dsi_set_drvdata(dsi, innolux); + id = of_match_node(innolux_of_match, dsi->dev.of_node); + if (!id) + return -ENODEV; - innolux->link = dsi; + dsi_desc = id->data; + dsi->mode_flags = dsi_desc->flags; + dsi->format = dsi_desc->format; + dsi->lanes = dsi_desc->lanes; - err = innolux_panel_add(innolux); + err = innolux_panel_add(dsi, dsi_desc); if (err < 0) return err; - err = mipi_dsi_attach(dsi); - return err; +
Re: [RESEND PATCH v3 1/3] drm/panel: refactor INNOLUX P079ZCA panel driver
Hi Thierry Reding, On Monday, March 12, 2018 05:21 PM, Thierry Reding wrote: On Mon, Dec 04, 2017 at 03:17:48PM +0800, Lin Huang wrote: 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; +}; There's no need for the two layers here. Just move everything from struct panel_desc_dsi into struct panel_desc. Okay, will fix it. + struct innolux_panel { struct drm_panel base; struct mipi_dsi_device *link; + const struct panel_desc_dsi *dsi_desc; And then this can just become: const struct panel_desc *desc; The _dsi suffix is redundant because this driver is exclusively for DSI devices. Got it. -static int innolux_panel_add(struct innolux_panel *innolux) +static int innolux_panel_add(struct mipi_dsi_device *dsi, +const struct panel_desc_dsi *desc) { - struct device *dev = >link->dev; + struct innolux_panel *innolux; + struct device *dev = >dev; struct device_node *np; int err; - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->dsi_desc = desc; + innolux->vddi = devm_regulator_get(dev, "power"); + if (IS_ERR(innolux->vddi)) + return PTR_ERR(innolux->vddi); + + innolux->avdd = devm_regulator_get(dev, "avdd"); + if (IS_ERR(innolux->avdd)) + return PTR_ERR(innolux->avdd); + + innolux->avee = devm_regulator_get(dev, "avee"); + if (IS_ERR(innolux->avee)) + return PTR_ERR(innolux->avee); According to the device tree bindings these regulators are all optional. Now devm_regulator_get() will return a dummy regulator if one has not been specified in DT, so this seems like it should work fine, even for existing DTBs that don't have the avdd and avee regulators. However, the DT bindings seem to be wrong, because these are in fact required regulators. Actually, the vddi is request, and avdd and avee is optional, i will only check vddi error later. innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); @@ -243,14 +306,16 @@ static int innolux_panel_add(struct innolux_panel *innolux) drm_panel_init(>base); innolux->base.funcs = _panel_funcs; - innolux->base.dev = >link->dev; + innolux->base.dev = dev; err = drm_panel_add(>base); if (err < 0) goto put_backlight; - return 0; + dev_set_drvdata(dev, innolux); + innolux->link = dsi; + return 0; put_backlight: put_device(>backlight->dev); @@ -267,28 +332,25 @@ static void innolux_panel_del(struct innolux_panel *innolux) static int innolux_panel_probe(struct mipi_dsi_device *dsi) { - struct innolux_panel *innolux; - int err; - dsi->lanes = 4; - dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | - MIPI_DSI_MODE_LPM; - - innolux = devm_kzalloc(>dev, sizeof(*innolux), GFP_KERNEL); - if (!innolux) - return -ENOMEM; + const struct panel_desc_dsi *dsi_desc; + const struct of_device_id *id; + int err; - mipi_dsi_set_drvdata(dsi, innolux); + id = of_match_node(innolux_of_match, dsi->dev.of_node); + if (!id) + return -ENODEV; - innolux->link = dsi; + dsi_desc = id->data; + dsi->mode_flags = dsi_desc->flags; + dsi->format = dsi_desc->format; + dsi->lanes = dsi_desc->lanes; - err = innolux_panel_add(innolux); + err = innolux_panel_add(dsi, dsi_desc); if (err < 0) return err; - err = mipi_dsi_attach(dsi); - return err; + return
Re: [RFC] pwm-backlight: Allow backlight to remain disabled on boot
Hi On Thursday, January 04, 2018 04:22 PM, Peter Ujfalusi wrote: Hi, On 2018-01-04 04:18, hl wrote: Hi All, Since many panel power sequence request backlight stay disable before panel power ready, but with now pwm-backlight drvier, it default to enable backlight when pwm-backlight probe, it mess up the panel power sequence. So we need this patch. This patch have been fly for a long time, does anyone have plan to merge it? you should not need this anymore since we have: 892c7788c724backlight: pwm_bl: Fix GPIO out for unimplemented .get_direction() d1b812945750 backlight: pwm_bl: Check the PWM state for initial backlight power state 7613c922315e backlight: pwm_bl: Move the checks for initial power state to a separate function With these in place the backlight will be kept disabled if it was disabled during boot _if_ you have booted via DT _and_ you have a phandle pointing to the backlight node (implying that the backlight is managed by the display driver). Oh, thanks for reminding me. On Thursday, July 31, 2014 07:42 PM, Thierry Reding wrote: From: Thierry Reding <tred...@nvidia.com> The default for backlight devices is to be enabled immediately when registering with the backlight core. This can be useful for setups that use a simple framebuffer device and where the backlight cannot otherwise be hooked up to the panel. However, when dealing with more complex setups, such as those of recent ARM SoCs, this can be problematic. Since the backlight is usually setup separately from the display controller, the probe order is not usually deterministic. That can lead to situations where the backlight will be powered up and the panel will show an uninitialized framebuffer. Furthermore, subsystems such as DRM have advanced functionality to set the power mode of a panel. In order to allow such setups to power up the panel at exactly the right moment, a way is needed to prevent the backlight core from powering the backlight up automatically when it is registered. This commit introduces a new boot_off field in the platform data (and also implements getting the same information from device tree). When set the initial backlight power mode will be set to "off". Signed-off-by: Thierry Reding <tred...@nvidia.com> --- I've been meaning to send this for a while but was always holding back because of the indoctrination that this type of configuration shouldn't be part of device tree. However this issue was recently raised again in the context of power up sequences for display panels. As described above the issue is that panel datasheets recommend that the backlight attached to a panel be turned on at the very last step to avoid visual glitches during the panel's power up sequence. With the current implementation it is typical for the backlight to be probed before the display panel. That has, in many cases, the side-effect of enabling the backlight, therefore making the screen content visible before it's actually initialized. Some panels come up with random garbage when uninitialized, others show all white. With some luck the panel will be all black and users won't really notice. This patch is an attempt to enable boards to override the default of turning on the backlight for the pwm-backlight driver. I'm not sure if there was a specific reason to turn on the backlight by default when this driver was initially written, but the fact is that since it has pretty much always been like this we can't really go and change the default, otherwise a lot of people may end up with no backlight and no clue as to how to enable it. So the only reasonable thing we can do is to keep the old behaviour and give new boards a way to override it if they know that some other part of the stack will enable it at the right moment. .../devicetree/bindings/video/backlight/pwm-backlight.txt | 1 + drivers/video/backlight/pwm_bl.c | 8 include/linux/pwm_backlight.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt index 764db86d441a..65e001a1733d 100644 --- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt +++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt @@ -17,6 +17,7 @@ Optional properties: "pwms" property (see PWM binding[0]) - enable-gpios: contains a single GPIO specifier for the GPIO which enables and disables the backlight (see GPIO binding[1]) + - backlight-boot-off: keep the backlight disabled on boot [0]: Documentation/devicetree/bindings/pwm/pwm.txt [1]: Documentation/devicetree/bindings/gpio/gpio.txt diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index d7a3d13e72ec..62adfc9d37a7 100644 --- a/drivers/video/backli
Re: [RFC] pwm-backlight: Allow backlight to remain disabled on boot
Hi On Thursday, January 04, 2018 04:22 PM, Peter Ujfalusi wrote: Hi, On 2018-01-04 04:18, hl wrote: Hi All, Since many panel power sequence request backlight stay disable before panel power ready, but with now pwm-backlight drvier, it default to enable backlight when pwm-backlight probe, it mess up the panel power sequence. So we need this patch. This patch have been fly for a long time, does anyone have plan to merge it? you should not need this anymore since we have: 892c7788c724backlight: pwm_bl: Fix GPIO out for unimplemented .get_direction() d1b812945750 backlight: pwm_bl: Check the PWM state for initial backlight power state 7613c922315e backlight: pwm_bl: Move the checks for initial power state to a separate function With these in place the backlight will be kept disabled if it was disabled during boot _if_ you have booted via DT _and_ you have a phandle pointing to the backlight node (implying that the backlight is managed by the display driver). Oh, thanks for reminding me. On Thursday, July 31, 2014 07:42 PM, Thierry Reding wrote: From: Thierry Reding The default for backlight devices is to be enabled immediately when registering with the backlight core. This can be useful for setups that use a simple framebuffer device and where the backlight cannot otherwise be hooked up to the panel. However, when dealing with more complex setups, such as those of recent ARM SoCs, this can be problematic. Since the backlight is usually setup separately from the display controller, the probe order is not usually deterministic. That can lead to situations where the backlight will be powered up and the panel will show an uninitialized framebuffer. Furthermore, subsystems such as DRM have advanced functionality to set the power mode of a panel. In order to allow such setups to power up the panel at exactly the right moment, a way is needed to prevent the backlight core from powering the backlight up automatically when it is registered. This commit introduces a new boot_off field in the platform data (and also implements getting the same information from device tree). When set the initial backlight power mode will be set to "off". Signed-off-by: Thierry Reding --- I've been meaning to send this for a while but was always holding back because of the indoctrination that this type of configuration shouldn't be part of device tree. However this issue was recently raised again in the context of power up sequences for display panels. As described above the issue is that panel datasheets recommend that the backlight attached to a panel be turned on at the very last step to avoid visual glitches during the panel's power up sequence. With the current implementation it is typical for the backlight to be probed before the display panel. That has, in many cases, the side-effect of enabling the backlight, therefore making the screen content visible before it's actually initialized. Some panels come up with random garbage when uninitialized, others show all white. With some luck the panel will be all black and users won't really notice. This patch is an attempt to enable boards to override the default of turning on the backlight for the pwm-backlight driver. I'm not sure if there was a specific reason to turn on the backlight by default when this driver was initially written, but the fact is that since it has pretty much always been like this we can't really go and change the default, otherwise a lot of people may end up with no backlight and no clue as to how to enable it. So the only reasonable thing we can do is to keep the old behaviour and give new boards a way to override it if they know that some other part of the stack will enable it at the right moment. .../devicetree/bindings/video/backlight/pwm-backlight.txt | 1 + drivers/video/backlight/pwm_bl.c | 8 include/linux/pwm_backlight.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt index 764db86d441a..65e001a1733d 100644 --- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt +++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt @@ -17,6 +17,7 @@ Optional properties: "pwms" property (see PWM binding[0]) - enable-gpios: contains a single GPIO specifier for the GPIO which enables and disables the backlight (see GPIO binding[1]) + - backlight-boot-off: keep the backlight disabled on boot [0]: Documentation/devicetree/bindings/pwm/pwm.txt [1]: Documentation/devicetree/bindings/gpio/gpio.txt diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index d7a3d13e72ec..62adfc9d37a7 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -17
Re: [RFC] pwm-backlight: Allow backlight to remain disabled on boot
Hi All, Since many panel power sequence request backlight stay disable before panel power ready, but with now pwm-backlight drvier, it default to enable backlight when pwm-backlight probe, it mess up the panel power sequence. So we need this patch. This patch have been fly for a long time, does anyone have plan to merge it? On Thursday, July 31, 2014 07:42 PM, Thierry Reding wrote: From: Thierry RedingThe default for backlight devices is to be enabled immediately when registering with the backlight core. This can be useful for setups that use a simple framebuffer device and where the backlight cannot otherwise be hooked up to the panel. However, when dealing with more complex setups, such as those of recent ARM SoCs, this can be problematic. Since the backlight is usually setup separately from the display controller, the probe order is not usually deterministic. That can lead to situations where the backlight will be powered up and the panel will show an uninitialized framebuffer. Furthermore, subsystems such as DRM have advanced functionality to set the power mode of a panel. In order to allow such setups to power up the panel at exactly the right moment, a way is needed to prevent the backlight core from powering the backlight up automatically when it is registered. This commit introduces a new boot_off field in the platform data (and also implements getting the same information from device tree). When set the initial backlight power mode will be set to "off". Signed-off-by: Thierry Reding --- I've been meaning to send this for a while but was always holding back because of the indoctrination that this type of configuration shouldn't be part of device tree. However this issue was recently raised again in the context of power up sequences for display panels. As described above the issue is that panel datasheets recommend that the backlight attached to a panel be turned on at the very last step to avoid visual glitches during the panel's power up sequence. With the current implementation it is typical for the backlight to be probed before the display panel. That has, in many cases, the side-effect of enabling the backlight, therefore making the screen content visible before it's actually initialized. Some panels come up with random garbage when uninitialized, others show all white. With some luck the panel will be all black and users won't really notice. This patch is an attempt to enable boards to override the default of turning on the backlight for the pwm-backlight driver. I'm not sure if there was a specific reason to turn on the backlight by default when this driver was initially written, but the fact is that since it has pretty much always been like this we can't really go and change the default, otherwise a lot of people may end up with no backlight and no clue as to how to enable it. So the only reasonable thing we can do is to keep the old behaviour and give new boards a way to override it if they know that some other part of the stack will enable it at the right moment. .../devicetree/bindings/video/backlight/pwm-backlight.txt | 1 + drivers/video/backlight/pwm_bl.c | 8 include/linux/pwm_backlight.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt index 764db86d441a..65e001a1733d 100644 --- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt +++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt @@ -17,6 +17,7 @@ Optional properties: "pwms" property (see PWM binding[0]) - enable-gpios: contains a single GPIO specifier for the GPIO which enables and disables the backlight (see GPIO binding[1]) + - backlight-boot-off: keep the backlight disabled on boot [0]: Documentation/devicetree/bindings/pwm/pwm.txt [1]: Documentation/devicetree/bindings/gpio/gpio.txt diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index d7a3d13e72ec..62adfc9d37a7 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -173,6 +173,8 @@ static int pwm_backlight_parse_dt(struct device *dev, data->max_brightness--; } + data->boot_off = of_property_read_bool(node, "backlight-boot-off"); + return 0; } @@ -317,6 +319,12 @@ static int pwm_backlight_probe(struct platform_device *pdev) } bl->props.brightness = data->dft_brightness; + + if (data->boot_off) + bl->props.power = FB_BLANK_POWERDOWN; + else + bl->props.power = FB_BLANK_UNBLANK; + backlight_update_status(bl); platform_set_drvdata(pdev, bl); diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
Re: [RFC] pwm-backlight: Allow backlight to remain disabled on boot
Hi All, Since many panel power sequence request backlight stay disable before panel power ready, but with now pwm-backlight drvier, it default to enable backlight when pwm-backlight probe, it mess up the panel power sequence. So we need this patch. This patch have been fly for a long time, does anyone have plan to merge it? On Thursday, July 31, 2014 07:42 PM, Thierry Reding wrote: From: Thierry Reding The default for backlight devices is to be enabled immediately when registering with the backlight core. This can be useful for setups that use a simple framebuffer device and where the backlight cannot otherwise be hooked up to the panel. However, when dealing with more complex setups, such as those of recent ARM SoCs, this can be problematic. Since the backlight is usually setup separately from the display controller, the probe order is not usually deterministic. That can lead to situations where the backlight will be powered up and the panel will show an uninitialized framebuffer. Furthermore, subsystems such as DRM have advanced functionality to set the power mode of a panel. In order to allow such setups to power up the panel at exactly the right moment, a way is needed to prevent the backlight core from powering the backlight up automatically when it is registered. This commit introduces a new boot_off field in the platform data (and also implements getting the same information from device tree). When set the initial backlight power mode will be set to "off". Signed-off-by: Thierry Reding --- I've been meaning to send this for a while but was always holding back because of the indoctrination that this type of configuration shouldn't be part of device tree. However this issue was recently raised again in the context of power up sequences for display panels. As described above the issue is that panel datasheets recommend that the backlight attached to a panel be turned on at the very last step to avoid visual glitches during the panel's power up sequence. With the current implementation it is typical for the backlight to be probed before the display panel. That has, in many cases, the side-effect of enabling the backlight, therefore making the screen content visible before it's actually initialized. Some panels come up with random garbage when uninitialized, others show all white. With some luck the panel will be all black and users won't really notice. This patch is an attempt to enable boards to override the default of turning on the backlight for the pwm-backlight driver. I'm not sure if there was a specific reason to turn on the backlight by default when this driver was initially written, but the fact is that since it has pretty much always been like this we can't really go and change the default, otherwise a lot of people may end up with no backlight and no clue as to how to enable it. So the only reasonable thing we can do is to keep the old behaviour and give new boards a way to override it if they know that some other part of the stack will enable it at the right moment. .../devicetree/bindings/video/backlight/pwm-backlight.txt | 1 + drivers/video/backlight/pwm_bl.c | 8 include/linux/pwm_backlight.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt index 764db86d441a..65e001a1733d 100644 --- a/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt +++ b/Documentation/devicetree/bindings/video/backlight/pwm-backlight.txt @@ -17,6 +17,7 @@ Optional properties: "pwms" property (see PWM binding[0]) - enable-gpios: contains a single GPIO specifier for the GPIO which enables and disables the backlight (see GPIO binding[1]) + - backlight-boot-off: keep the backlight disabled on boot [0]: Documentation/devicetree/bindings/pwm/pwm.txt [1]: Documentation/devicetree/bindings/gpio/gpio.txt diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index d7a3d13e72ec..62adfc9d37a7 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -173,6 +173,8 @@ static int pwm_backlight_parse_dt(struct device *dev, data->max_brightness--; } + data->boot_off = of_property_read_bool(node, "backlight-boot-off"); + return 0; } @@ -317,6 +319,12 @@ static int pwm_backlight_probe(struct platform_device *pdev) } bl->props.brightness = data->dft_brightness; + + if (data->boot_off) + bl->props.power = FB_BLANK_POWERDOWN; + else + bl->props.power = FB_BLANK_UNBLANK; + backlight_update_status(bl); platform_set_drvdata(pdev, bl); diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h index efdd9227a49c..1fc14989da4a 100644
Re: [PATCH] drm/panel: support Innolux P097PFG panel
Hi Emil, On Saturday, December 02, 2017 01:55 AM, Emil Velikov wrote: On 30 November 2017 at 06:13, Lin Huangwrote: 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. Couple of drive-by suggestions: Split the refactor vs new hw? Sorry, i don't get what you mean. MODULE_DESCRIPTION("Innolux P079ZCA panel driver"); Update this reference alongside the ones in Kconfig? Okay, will fix it next version. -Emil
Re: [PATCH] drm/panel: support Innolux P097PFG panel
Hi Emil, On Saturday, December 02, 2017 01:55 AM, Emil Velikov wrote: On 30 November 2017 at 06:13, Lin Huang wrote: 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. Couple of drive-by suggestions: Split the refactor vs new hw? Sorry, i don't get what you mean. MODULE_DESCRIPTION("Innolux P079ZCA panel driver"); Update this reference alongside the ones in Kconfig? Okay, will fix it next version. -Emil
Re: [RESENT PATCH] drm/panel: support Innolux P097PFG panel
Hi On Friday, December 01, 2017 10:54 AM, Brian Norris wrote: One more comment: On Thu, Nov 30, 2017 at 02:14:40PM +0800, Lin Huang wrote: 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 ... @@ -209,20 +284,39 @@ static const struct drm_panel_funcs innolux_panel_funcs = { }; static const struct of_device_id innolux_of_match[] = { - { .compatible = "innolux,p079zca", }, - { } + { .compatible = "innolux,p079zca", + .data = _p079zca_panel_desc + }, + { .compatible = "innolux,p097pfg", + .data = _p097pfg_panel_desc + } }; MODULE_DEVICE_TABLE(of, innolux_of_match); -static int innolux_panel_add(struct innolux_panel *innolux) +static int innolux_panel_add(struct mipi_dsi_device *dsi, +const struct panel_desc_dsi *desc) { - struct device *dev = >link->dev; + struct innolux_panel *innolux; + struct device *dev = >dev; struct device_node *np; int err; - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->dsi_desc = desc; + innolux->vddi = devm_regulator_get_optional(dev, "power"); + if (IS_ERR(innolux->vddi)) + return PTR_ERR(innolux->vddi); + + innolux->avdd = devm_regulator_get(dev, "ppvarp"); This name ("ppvarp" and the "ppvarn" below) are names from our board schematics, not from the panel datasheet. I would think these should be "vdd" and "vee", like your variable names. Okay, will fix it next version. Brian + if (IS_ERR(innolux->avdd)) + return PTR_ERR(innolux->avdd); + + innolux->avee = devm_regulator_get(dev, "ppvarn"); + if (IS_ERR(innolux->avee)) + return PTR_ERR(innolux->avee); innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); ...
Re: [RESENT PATCH] drm/panel: support Innolux P097PFG panel
Hi On Friday, December 01, 2017 10:54 AM, Brian Norris wrote: One more comment: On Thu, Nov 30, 2017 at 02:14:40PM +0800, Lin Huang wrote: 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 ... @@ -209,20 +284,39 @@ static const struct drm_panel_funcs innolux_panel_funcs = { }; static const struct of_device_id innolux_of_match[] = { - { .compatible = "innolux,p079zca", }, - { } + { .compatible = "innolux,p079zca", + .data = _p079zca_panel_desc + }, + { .compatible = "innolux,p097pfg", + .data = _p097pfg_panel_desc + } }; MODULE_DEVICE_TABLE(of, innolux_of_match); -static int innolux_panel_add(struct innolux_panel *innolux) +static int innolux_panel_add(struct mipi_dsi_device *dsi, +const struct panel_desc_dsi *desc) { - struct device *dev = >link->dev; + struct innolux_panel *innolux; + struct device *dev = >dev; struct device_node *np; int err; - innolux->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(innolux->supply)) - return PTR_ERR(innolux->supply); + innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL); + if (!innolux) + return -ENOMEM; + + innolux->dsi_desc = desc; + innolux->vddi = devm_regulator_get_optional(dev, "power"); + if (IS_ERR(innolux->vddi)) + return PTR_ERR(innolux->vddi); + + innolux->avdd = devm_regulator_get(dev, "ppvarp"); This name ("ppvarp" and the "ppvarn" below) are names from our board schematics, not from the panel datasheet. I would think these should be "vdd" and "vee", like your variable names. Okay, will fix it next version. Brian + if (IS_ERR(innolux->avdd)) + return PTR_ERR(innolux->avdd); + + innolux->avee = devm_regulator_get(dev, "ppvarn"); + if (IS_ERR(innolux->avee)) + return PTR_ERR(innolux->avee); innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); ...
Re: [PATCH v2 2/2] devicetree: i2c-hid: Add reset property
On Saturday, November 04, 2017 12:35 PM, Brian Norris wrote: On Mon, Oct 30, 2017 at 8:03 PM, Lin Huangwrote: 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. If there was any point in adding the device-specific description around "wacom,w9013"...then you should probably mention these properties there too. The idea was to document possible properties here (where you're adding them already), and to note the property names under the devices (or so far, just 1 device) that support them. Or IOW, you need an addition like this: - compatible: * "wacom,w9013" (Wacom W9013 digitizer). Supports: - vdd-supply - post-power-on-delay-ms +- reset-gpios +- assert-reset-us Okay, got it, will fix it next version. Brian
Re: [PATCH v2 2/2] devicetree: i2c-hid: Add reset property
On Saturday, November 04, 2017 12:35 PM, Brian Norris wrote: On Mon, Oct 30, 2017 at 8:03 PM, Lin Huang wrote: 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. If there was any point in adding the device-specific description around "wacom,w9013"...then you should probably mention these properties there too. The idea was to document possible properties here (where you're adding them already), and to note the property names under the devices (or so far, just 1 device) that support them. Or IOW, you need an addition like this: - compatible: * "wacom,w9013" (Wacom W9013 digitizer). Supports: - vdd-supply - post-power-on-delay-ms +- reset-gpios +- assert-reset-us Okay, got it, will fix it next version. Brian
Re: [PATCH 1/7] drm/rockchip/dsi: correct Feedback divider setting
On Wednesday, September 20, 2017 06:08 PM, John Keeping wrote: On Tue, Sep 19, 2017 at 01:27:40PM -0700, Sean Paul wrote: On Tue, Sep 19, 2017 at 11:19:01AM -0700, Brian Norris wrote: Hi Sean, On Tue, Sep 19, 2017 at 11:00:25AM -0700, Sean Paul wrote: On Mon, Sep 18, 2017 at 05:05:33PM +0800, Nickey Yang wrote: This patch correct Feedback divider setting: 1、Set Feedback divider [8:5] when HIGH_PROGRAM_EN 2、Due to the use of a "by 2 pre-scaler," the range of the feedback multiplication Feedback divider is limited to even division numbers, and Feedback divider must be greater than 12, less than 1000. 3、Make the previously configured Feedback divider(LSB) factors effective Signed-off-by: Nickey Yang--- drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 83 ++ 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 9a20b9d..52698b7 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -228,7 +228,7 @@ #define LOW_PROGRAM_EN0 #define HIGH_PROGRAM_EN BIT(7) #define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f) -#define LOOP_DIV_HIGH_SEL(val) val) - 1) >> 5) & 0x1f) +#define LOOP_DIV_HIGH_SEL(val) val) - 1) >> 5) & 0xf) #define PLL_LOOP_DIV_EN BIT(5) #define PLL_INPUT_DIV_EN BIT(4) @@ -461,6 +461,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div)); dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) | LOW_PROGRAM_EN); + dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN); You do the same write 2 lines down. Are both needed? It would be nice if the register names were also defined, so this is easier to read. If I'm reading correctly, I think this is what Nickey meant by: "3、Make the previously configured Feedback divider(LSB) factors effective" . My reading of the databook is that this step finalizes the previous two writes (to test code 0x17 and 0x18). Given this was buggy (?) previously, it does seem like having some extra language to document this could help. Register names (or "test codes", per the docs?) could help, but additionally, maybe a few more comments. Ah, yeah, thanks for the explanation. It's not clear that this latches the values above. I think register names and comments would be immensely helpful. According to the databook, 0x19 controls whether the loop/input dividers are derived from the hsfreqrange configuration or use the values in 0x17 and 0x18. I can't see why writing the same value to this register multiple times is necessary. According to databook, set 0x19 to 0x30 make the previously configured N(0x17) and M(0x18) factors effective, 0x18 need to be setted by twice, since we need to set 0x18 LSB and MSB separately, As we test, after set 0x18 LSB, if we do not set 0x19 immediately to make the configrued effective, when we set 0x18 MSB, the 0x18 LSB value will gone, and we will get wrong pll frequency. Anyway, I think should add some comment here to clear that. dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) | HIGH_PROGRAM_EN); dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN); [...] ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip
Re: [PATCH 1/7] drm/rockchip/dsi: correct Feedback divider setting
On Wednesday, September 20, 2017 06:08 PM, John Keeping wrote: On Tue, Sep 19, 2017 at 01:27:40PM -0700, Sean Paul wrote: On Tue, Sep 19, 2017 at 11:19:01AM -0700, Brian Norris wrote: Hi Sean, On Tue, Sep 19, 2017 at 11:00:25AM -0700, Sean Paul wrote: On Mon, Sep 18, 2017 at 05:05:33PM +0800, Nickey Yang wrote: This patch correct Feedback divider setting: 1、Set Feedback divider [8:5] when HIGH_PROGRAM_EN 2、Due to the use of a "by 2 pre-scaler," the range of the feedback multiplication Feedback divider is limited to even division numbers, and Feedback divider must be greater than 12, less than 1000. 3、Make the previously configured Feedback divider(LSB) factors effective Signed-off-by: Nickey Yang --- drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 83 ++ 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 9a20b9d..52698b7 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -228,7 +228,7 @@ #define LOW_PROGRAM_EN0 #define HIGH_PROGRAM_EN BIT(7) #define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f) -#define LOOP_DIV_HIGH_SEL(val) val) - 1) >> 5) & 0x1f) +#define LOOP_DIV_HIGH_SEL(val) val) - 1) >> 5) & 0xf) #define PLL_LOOP_DIV_EN BIT(5) #define PLL_INPUT_DIV_EN BIT(4) @@ -461,6 +461,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div)); dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) | LOW_PROGRAM_EN); + dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN); You do the same write 2 lines down. Are both needed? It would be nice if the register names were also defined, so this is easier to read. If I'm reading correctly, I think this is what Nickey meant by: "3、Make the previously configured Feedback divider(LSB) factors effective" . My reading of the databook is that this step finalizes the previous two writes (to test code 0x17 and 0x18). Given this was buggy (?) previously, it does seem like having some extra language to document this could help. Register names (or "test codes", per the docs?) could help, but additionally, maybe a few more comments. Ah, yeah, thanks for the explanation. It's not clear that this latches the values above. I think register names and comments would be immensely helpful. According to the databook, 0x19 controls whether the loop/input dividers are derived from the hsfreqrange configuration or use the values in 0x17 and 0x18. I can't see why writing the same value to this register multiple times is necessary. According to databook, set 0x19 to 0x30 make the previously configured N(0x17) and M(0x18) factors effective, 0x18 need to be setted by twice, since we need to set 0x18 LSB and MSB separately, As we test, after set 0x18 LSB, if we do not set 0x19 immediately to make the configrued effective, when we set 0x18 MSB, the 0x18 LSB value will gone, and we will get wrong pll frequency. Anyway, I think should add some comment here to clear that. dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) | HIGH_PROGRAM_EN); dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN); [...] ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip
Re: [PATCH v2 1/2] ASoC: codec: use enable pin to control dmic start and stop
On Monday, September 04, 2017 06:03 PM, Arnaud Pouliquen wrote: Hello Lin, Sorry for this late answer. I'm not maintainer, just a contributor... but as some update seems strange for me, so i prefer to highlight it to clarify them. On 08/17/2017 04:24 AM, Lin Huang wrote: From: huang linon some board use enable pin to control dmic start and stop, so add this feature in dmic driver. Please, Could you give data-sheet reference of your DMIC, to help me to understand your use-case? 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 Dependency also for DMIC without GPIO to handle gating? 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, +}; + should it be handle by trigger or DAPM? 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); Hypothesis here is that GPIO is always set to low? seems too limiting. Yes, you are right, maybe i can set it to devm_gpiod_get_optional(codec->dev, "dmicen", GPIOD_ASIS); Regards Arnaud + 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),
Re: [PATCH v2 1/2] ASoC: codec: use enable pin to control dmic start and stop
On Monday, September 04, 2017 06:03 PM, Arnaud Pouliquen wrote: Hello Lin, Sorry for this late answer. I'm not maintainer, just a contributor... but as some update seems strange for me, so i prefer to highlight it to clarify them. On 08/17/2017 04:24 AM, Lin Huang wrote: From: huang lin on some board use enable pin to control dmic start and stop, so add this feature in dmic driver. Please, Could you give data-sheet reference of your DMIC, to help me to understand your use-case? 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 Dependency also for DMIC without GPIO to handle gating? 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, +}; + should it be handle by trigger or DAPM? 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); Hypothesis here is that GPIO is always set to low? seems too limiting. Yes, you are right, maybe i can set it to devm_gpiod_get_optional(codec->dev, "dmicen", GPIOD_ASIS); Regards Arnaud + 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),
Re: [PATCH 1/2] ASoC: codec: use enable pin to control dmic start and stop
On Wednesday, August 16, 2017 10:50 PM, Mark Brown wrote: On Fri, Aug 11, 2017 at 03:31:28PM +0800, Lin Huang wrote: on some board use enable pin to control dmic start and stop, so add this feature in dmic driver. This doens't apply against current code, please check and resend. Oh, Thanks for pointing it, have send new version patches.
Re: [PATCH 1/2] ASoC: codec: use enable pin to control dmic start and stop
On Wednesday, August 16, 2017 10:50 PM, Mark Brown wrote: On Fri, Aug 11, 2017 at 03:31:28PM +0800, Lin Huang wrote: on some board use enable pin to control dmic start and stop, so add this feature in dmic driver. This doens't apply against current code, please check and resend. Oh, Thanks for pointing it, have send new version patches.
Re: [PATCH] clk: rockchip: fix the incorrect pclk_edp div width for RK3399
Tested-by: Lin HuangOn 2017年01月18日 12:20, Xing Zheng wrote: The range of the pclk_edp_div_con is [13:8] and 6 bits, not 5. Reported-by: Lin Huang Signed-off-by: Xing Zheng --- drivers/clk/rockchip/clk-rk3399.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 3490887..73121b14 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -1132,7 +1132,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(11), 8, GFLAGS), COMPOSITE(PCLK_EDP, "pclk_edp", mux_pll_src_cpll_gpll_p, 0, - RK3399_CLKSEL_CON(44), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKSEL_CON(44), 15, 1, MFLAGS, 8, 6, DFLAGS, RK3399_CLKGATE_CON(11), 11, GFLAGS), GATE(PCLK_EDP_NOC, "pclk_edp_noc", "pclk_edp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(32), 12, GFLAGS), -- Lin Huang
Re: [PATCH] clk: rockchip: fix the incorrect pclk_edp div width for RK3399
Tested-by: Lin Huang On 2017年01月18日 12:20, Xing Zheng wrote: The range of the pclk_edp_div_con is [13:8] and 6 bits, not 5. Reported-by: Lin Huang Signed-off-by: Xing Zheng --- drivers/clk/rockchip/clk-rk3399.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 3490887..73121b14 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -1132,7 +1132,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(11), 8, GFLAGS), COMPOSITE(PCLK_EDP, "pclk_edp", mux_pll_src_cpll_gpll_p, 0, - RK3399_CLKSEL_CON(44), 15, 1, MFLAGS, 8, 5, DFLAGS, + RK3399_CLKSEL_CON(44), 15, 1, MFLAGS, 8, 6, DFLAGS, RK3399_CLKGATE_CON(11), 11, GFLAGS), GATE(PCLK_EDP_NOC, "pclk_edp_noc", "pclk_edp", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(32), 12, GFLAGS), -- Lin Huang
Re: [PATCH v1 & v6 1/2] PM/devfreq: add suspend frequency support
Hi Chanwoo Choi, On 2016年11月24日 16:16, Chanwoo Choi wrote: Hi Lin, On 2016년 11월 24일 16:34, hl wrote: Hi Chanwoo Choi, I think the dev_pm_opp_get_suspend_opp() have implement most of the funtion, all we need is just define the node in dts, like following: _opp_table { opp06 { opp-suspend; }; }; Two approaches use the 'opp-suspend' property. I think that the method to support suspend-opp have to guarantee following conditions: - Support the all of devfreq's governors. As MyungJoo Ham suggestion, i will set the suspend frequency in devfreq_suspend_device(), which will ingore governor. - Devfreq framework have the responsibility to change the frequency/voltage for suspend-opp. If we uses the new devfreq_suspend(), each devfreq device don't care how to support the suspend-opp. Just the developer of each devfreq device need to add 'opp-suspend' propet to OPP entry in DT file. Why should support change the voltage in devfreq framework, i think it shuold be handle in specific driver, i think the devfreq only handle it can get the right frequency, then pass it to specific driver, i think the voltage should handle in the devfreq->profile->target(); Best Regards, Chanwoo Choi so i think my way semm more simple. On 2016年11月24日 15:10, Chanwoo Choi wrote: + Tobias Jakobi, Hi Lin, We need to discuss how to support the suspend-opp of devfreq device. Now, there are two patch thread for suspend-opp of devfreq. The Lin's approach modify the devfreq_suspend_device() to support suspend-opp. The Tobias's approach[1] add new devfreq_suspend() and then call it on dpm_suspend() when entering the suspend state. [1] [RFC 0/4] PM / devfreq: draft for OPP suspend impl - https://patchwork.kernel.org/patch/9443323/ - https://patchwork.kernel.org/patch/9443325/ - https://patchwork.kernel.org/patch/9443329/ - https://patchwork.kernel.org/patch/9443331/ I think we need to discuss it together. Regards, Chanwoo Choi On 2016년 11월 24일 15:45, hl wrote: Hi MyungJoo Ham, On 2016年11月24日 14:14, MyungJoo Ham wrote: On Thu, Nov 24, 2016 at 11:18 AM, hl <h...@rock-chips.com> wrote: Hi MyungJoo Ham, [] We still need to sync the all status even i call target() in devfreq_suspend/resume_device directly, so still need update_devfreq() other setp except devfreq->governor->get_target_freq(devfreq, ); And i think it better to be governor behaviors, for userspace they may not want to change the suspend frequency like other governor, the frequency should decide by the user, if they want this function, they should like other governor to rigister a devfreq_monitor_suspend(). What do you think about my rev6 patch? If I understand the intention correctly, this is for the stability of the device due to the behavior or bootloader/SoC-initializer, which has nothing to do with governors. Even if users are using userspace, as long as they set the custom frequencies lower than the default, they have the possibility of being unstable as ondemand is going to have. To reuse the update_devfreq() code, you may do something like: static int _update_freq(struct devfreq *devfreq, bool is_suspending) { /* original contents of update_freq with if statement with is_suspending wrapping get_target_freq */ } int update_freq(struct devfreq *devfreq) { return _update_freq(devfreq, false); } There should be other good non-invasive methods that are not governoe-specific as well. Thanks for your suggestion, i will update the new version soon. Cheers, MyungJoo ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang -- Lin Huang
Re: [PATCH v1 & v6 1/2] PM/devfreq: add suspend frequency support
Hi Chanwoo Choi, On 2016年11月24日 16:16, Chanwoo Choi wrote: Hi Lin, On 2016년 11월 24일 16:34, hl wrote: Hi Chanwoo Choi, I think the dev_pm_opp_get_suspend_opp() have implement most of the funtion, all we need is just define the node in dts, like following: _opp_table { opp06 { opp-suspend; }; }; Two approaches use the 'opp-suspend' property. I think that the method to support suspend-opp have to guarantee following conditions: - Support the all of devfreq's governors. As MyungJoo Ham suggestion, i will set the suspend frequency in devfreq_suspend_device(), which will ingore governor. - Devfreq framework have the responsibility to change the frequency/voltage for suspend-opp. If we uses the new devfreq_suspend(), each devfreq device don't care how to support the suspend-opp. Just the developer of each devfreq device need to add 'opp-suspend' propet to OPP entry in DT file. Why should support change the voltage in devfreq framework, i think it shuold be handle in specific driver, i think the devfreq only handle it can get the right frequency, then pass it to specific driver, i think the voltage should handle in the devfreq->profile->target(); Best Regards, Chanwoo Choi so i think my way semm more simple. On 2016年11月24日 15:10, Chanwoo Choi wrote: + Tobias Jakobi, Hi Lin, We need to discuss how to support the suspend-opp of devfreq device. Now, there are two patch thread for suspend-opp of devfreq. The Lin's approach modify the devfreq_suspend_device() to support suspend-opp. The Tobias's approach[1] add new devfreq_suspend() and then call it on dpm_suspend() when entering the suspend state. [1] [RFC 0/4] PM / devfreq: draft for OPP suspend impl - https://patchwork.kernel.org/patch/9443323/ - https://patchwork.kernel.org/patch/9443325/ - https://patchwork.kernel.org/patch/9443329/ - https://patchwork.kernel.org/patch/9443331/ I think we need to discuss it together. Regards, Chanwoo Choi On 2016년 11월 24일 15:45, hl wrote: Hi MyungJoo Ham, On 2016年11月24日 14:14, MyungJoo Ham wrote: On Thu, Nov 24, 2016 at 11:18 AM, hl wrote: Hi MyungJoo Ham, [] We still need to sync the all status even i call target() in devfreq_suspend/resume_device directly, so still need update_devfreq() other setp except devfreq->governor->get_target_freq(devfreq, ); And i think it better to be governor behaviors, for userspace they may not want to change the suspend frequency like other governor, the frequency should decide by the user, if they want this function, they should like other governor to rigister a devfreq_monitor_suspend(). What do you think about my rev6 patch? If I understand the intention correctly, this is for the stability of the device due to the behavior or bootloader/SoC-initializer, which has nothing to do with governors. Even if users are using userspace, as long as they set the custom frequencies lower than the default, they have the possibility of being unstable as ondemand is going to have. To reuse the update_devfreq() code, you may do something like: static int _update_freq(struct devfreq *devfreq, bool is_suspending) { /* original contents of update_freq with if statement with is_suspending wrapping get_target_freq */ } int update_freq(struct devfreq *devfreq) { return _update_freq(devfreq, false); } There should be other good non-invasive methods that are not governoe-specific as well. Thanks for your suggestion, i will update the new version soon. Cheers, MyungJoo ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang -- Lin Huang
Re: [PATCH v1 & v6 1/2] PM/devfreq: add suspend frequency support
Hi Chanwoo Choi, I think the dev_pm_opp_get_suspend_opp() have implement most of the funtion, all we need is just define the node in dts, like following: _opp_table { opp06 { opp-suspend; }; }; so i think my way semm more simple. On 2016年11月24日 15:10, Chanwoo Choi wrote: + Tobias Jakobi, Hi Lin, We need to discuss how to support the suspend-opp of devfreq device. Now, there are two patch thread for suspend-opp of devfreq. The Lin's approach modify the devfreq_suspend_device() to support suspend-opp. The Tobias's approach[1] add new devfreq_suspend() and then call it on dpm_suspend() when entering the suspend state. [1] [RFC 0/4] PM / devfreq: draft for OPP suspend impl - https://patchwork.kernel.org/patch/9443323/ - https://patchwork.kernel.org/patch/9443325/ - https://patchwork.kernel.org/patch/9443329/ - https://patchwork.kernel.org/patch/9443331/ I think we need to discuss it together. Regards, Chanwoo Choi On 2016년 11월 24일 15:45, hl wrote: Hi MyungJoo Ham, On 2016年11月24日 14:14, MyungJoo Ham wrote: On Thu, Nov 24, 2016 at 11:18 AM, hl <h...@rock-chips.com> wrote: Hi MyungJoo Ham, [] We still need to sync the all status even i call target() in devfreq_suspend/resume_device directly, so still need update_devfreq() other setp except devfreq->governor->get_target_freq(devfreq, ); And i think it better to be governor behaviors, for userspace they may not want to change the suspend frequency like other governor, the frequency should decide by the user, if they want this function, they should like other governor to rigister a devfreq_monitor_suspend(). What do you think about my rev6 patch? If I understand the intention correctly, this is for the stability of the device due to the behavior or bootloader/SoC-initializer, which has nothing to do with governors. Even if users are using userspace, as long as they set the custom frequencies lower than the default, they have the possibility of being unstable as ondemand is going to have. To reuse the update_devfreq() code, you may do something like: static int _update_freq(struct devfreq *devfreq, bool is_suspending) { /* original contents of update_freq with if statement with is_suspending wrapping get_target_freq */ } int update_freq(struct devfreq *devfreq) { return _update_freq(devfreq, false); } There should be other good non-invasive methods that are not governoe-specific as well. Thanks for your suggestion, i will update the new version soon. Cheers, MyungJoo ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang -- Lin Huang
Re: [PATCH v1 & v6 1/2] PM/devfreq: add suspend frequency support
Hi Chanwoo Choi, I think the dev_pm_opp_get_suspend_opp() have implement most of the funtion, all we need is just define the node in dts, like following: _opp_table { opp06 { opp-suspend; }; }; so i think my way semm more simple. On 2016年11月24日 15:10, Chanwoo Choi wrote: + Tobias Jakobi, Hi Lin, We need to discuss how to support the suspend-opp of devfreq device. Now, there are two patch thread for suspend-opp of devfreq. The Lin's approach modify the devfreq_suspend_device() to support suspend-opp. The Tobias's approach[1] add new devfreq_suspend() and then call it on dpm_suspend() when entering the suspend state. [1] [RFC 0/4] PM / devfreq: draft for OPP suspend impl - https://patchwork.kernel.org/patch/9443323/ - https://patchwork.kernel.org/patch/9443325/ - https://patchwork.kernel.org/patch/9443329/ - https://patchwork.kernel.org/patch/9443331/ I think we need to discuss it together. Regards, Chanwoo Choi On 2016년 11월 24일 15:45, hl wrote: Hi MyungJoo Ham, On 2016年11月24日 14:14, MyungJoo Ham wrote: On Thu, Nov 24, 2016 at 11:18 AM, hl wrote: Hi MyungJoo Ham, [] We still need to sync the all status even i call target() in devfreq_suspend/resume_device directly, so still need update_devfreq() other setp except devfreq->governor->get_target_freq(devfreq, ); And i think it better to be governor behaviors, for userspace they may not want to change the suspend frequency like other governor, the frequency should decide by the user, if they want this function, they should like other governor to rigister a devfreq_monitor_suspend(). What do you think about my rev6 patch? If I understand the intention correctly, this is for the stability of the device due to the behavior or bootloader/SoC-initializer, which has nothing to do with governors. Even if users are using userspace, as long as they set the custom frequencies lower than the default, they have the possibility of being unstable as ondemand is going to have. To reuse the update_devfreq() code, you may do something like: static int _update_freq(struct devfreq *devfreq, bool is_suspending) { /* original contents of update_freq with if statement with is_suspending wrapping get_target_freq */ } int update_freq(struct devfreq *devfreq) { return _update_freq(devfreq, false); } There should be other good non-invasive methods that are not governoe-specific as well. Thanks for your suggestion, i will update the new version soon. Cheers, MyungJoo ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang -- Lin Huang
Re: [PATCH v4] PM/devfreq: add suspend frequency support
Hi Chanwoo Choi, On 2016年11月08日 17:32, Chanwoo Choi wrote: Hi Lin, On 2016년 11월 08일 18:11, Lin Huang wrote: Add suspend frequency support and if needed set it to the frequency obtained from the suspend opp (can be defined using opp-v2 bindings and is optional). Signed-off-by: Lin Huang--- Changes in v2: - use update_devfreq() instead devfreq_update_status() Changes in v3: - fix build error Changes in v4: - move dev_pm_opp_get_suspend_opp() to devfreq_add_device() drivers/devfreq/devfreq.c | 15 +-- drivers/devfreq/governor_simpleondemand.c | 9 + include/linux/devfreq.h | 9 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index bf3ea76..d9d56e1 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -363,7 +363,10 @@ void devfreq_monitor_suspend(struct devfreq *devfreq) mutex_unlock(>lock); return; } - + if (devfreq->suspend_freq) { + update_devfreq(devfreq); + devfreq->suspend_flag = true; You don't need the additional variable (devfreq->suspend_flag). When adding the devfreq on devfreq_add_device(), you can initialize the devfreq->suspend_freq as zero(0). You can check whether devfreq->suspend_freq is 0 or not without the new suspend_flag. + } devfreq_update_status(devfreq, devfreq->previous_freq); devfreq->stop_polling = true; mutex_unlock(>lock); @@ -394,7 +397,8 @@ void devfreq_monitor_resume(struct devfreq *devfreq) devfreq->last_stat_updated = jiffies; devfreq->stop_polling = false; - + if (devfreq->suspend_freq) + devfreq->suspend_flag = false; ditto. You don't need to add this code. if (devfreq->profile->get_cur_freq && !devfreq->profile->get_cur_freq(devfreq->dev.parent, )) devfreq->previous_freq = freq; @@ -528,6 +532,7 @@ struct devfreq *devfreq_add_device(struct device *dev, struct devfreq *devfreq; struct devfreq_governor *governor; int err = 0; + struct dev_pm_opp *suspend_opp; if (!dev || !profile || !governor_name) { dev_err(dev, "%s: Invalid parameters.\n", __func__); @@ -563,6 +568,12 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->data = data; devfreq->nb.notifier_call = devfreq_notifier_call; + rcu_read_lock(); + suspend_opp = dev_pm_opp_get_suspend_opp(dev); + if (suspend_opp) + devfreq->suspend_freq = dev_pm_opp_get_freq(suspend_opp); + rcu_read_unlock(); + if (!devfreq->profile->max_state && !devfreq->profile->freq_table) { mutex_unlock(>lock); devfreq_set_freq_table(devfreq); diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index ae72ba5..84b3ce1 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -29,6 +29,15 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, struct devfreq_simple_ondemand_data *data = df->data; unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; + /* +* if devfreq in suspend status and have suspend_freq, +* the frequency need to set to suspend_freq +*/ + if (df->suspend_flag) { + *freq = df->suspend_freq; + return 0; + } You can check it as following: if (df->suspend_freq != 0) *freq = df->suspend_freq; If i do like this, it will always return suspend frequency, since devfreq->suspend_freq will be assigned value if we define it on dts. But what we want is only in suspend status we return the suspend frequency. + err = devfreq_update_stats(df); if (err) return err; diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 2de4e2e..c463ae1 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -172,6 +172,7 @@ struct devfreq { struct delayed_work work; unsigned long previous_freq; + unsigned long suspend_freq; struct devfreq_dev_status last_status; void *data; /* private data for governors */ @@ -179,6 +180,7 @@ struct devfreq { unsigned long min_freq; unsigned long max_freq; bool stop_polling; + bool suspend_flag; You don't need to add new variable. /* information for device frequency transition */ unsigned int total_trans; @@ -214,6 +216,8 @@ extern int devfreq_resume_device(struct devfreq *devfreq); /* Helper functions for devfreq user device driver with OPP. */ extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, u32 flags); +extern void devfreq_opp_get_suspend_opp(struct
Re: [PATCH v4] PM/devfreq: add suspend frequency support
Hi Chanwoo Choi, On 2016年11月08日 17:32, Chanwoo Choi wrote: Hi Lin, On 2016년 11월 08일 18:11, Lin Huang wrote: Add suspend frequency support and if needed set it to the frequency obtained from the suspend opp (can be defined using opp-v2 bindings and is optional). Signed-off-by: Lin Huang --- Changes in v2: - use update_devfreq() instead devfreq_update_status() Changes in v3: - fix build error Changes in v4: - move dev_pm_opp_get_suspend_opp() to devfreq_add_device() drivers/devfreq/devfreq.c | 15 +-- drivers/devfreq/governor_simpleondemand.c | 9 + include/linux/devfreq.h | 9 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index bf3ea76..d9d56e1 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -363,7 +363,10 @@ void devfreq_monitor_suspend(struct devfreq *devfreq) mutex_unlock(>lock); return; } - + if (devfreq->suspend_freq) { + update_devfreq(devfreq); + devfreq->suspend_flag = true; You don't need the additional variable (devfreq->suspend_flag). When adding the devfreq on devfreq_add_device(), you can initialize the devfreq->suspend_freq as zero(0). You can check whether devfreq->suspend_freq is 0 or not without the new suspend_flag. + } devfreq_update_status(devfreq, devfreq->previous_freq); devfreq->stop_polling = true; mutex_unlock(>lock); @@ -394,7 +397,8 @@ void devfreq_monitor_resume(struct devfreq *devfreq) devfreq->last_stat_updated = jiffies; devfreq->stop_polling = false; - + if (devfreq->suspend_freq) + devfreq->suspend_flag = false; ditto. You don't need to add this code. if (devfreq->profile->get_cur_freq && !devfreq->profile->get_cur_freq(devfreq->dev.parent, )) devfreq->previous_freq = freq; @@ -528,6 +532,7 @@ struct devfreq *devfreq_add_device(struct device *dev, struct devfreq *devfreq; struct devfreq_governor *governor; int err = 0; + struct dev_pm_opp *suspend_opp; if (!dev || !profile || !governor_name) { dev_err(dev, "%s: Invalid parameters.\n", __func__); @@ -563,6 +568,12 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->data = data; devfreq->nb.notifier_call = devfreq_notifier_call; + rcu_read_lock(); + suspend_opp = dev_pm_opp_get_suspend_opp(dev); + if (suspend_opp) + devfreq->suspend_freq = dev_pm_opp_get_freq(suspend_opp); + rcu_read_unlock(); + if (!devfreq->profile->max_state && !devfreq->profile->freq_table) { mutex_unlock(>lock); devfreq_set_freq_table(devfreq); diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index ae72ba5..84b3ce1 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -29,6 +29,15 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, struct devfreq_simple_ondemand_data *data = df->data; unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; + /* +* if devfreq in suspend status and have suspend_freq, +* the frequency need to set to suspend_freq +*/ + if (df->suspend_flag) { + *freq = df->suspend_freq; + return 0; + } You can check it as following: if (df->suspend_freq != 0) *freq = df->suspend_freq; If i do like this, it will always return suspend frequency, since devfreq->suspend_freq will be assigned value if we define it on dts. But what we want is only in suspend status we return the suspend frequency. + err = devfreq_update_stats(df); if (err) return err; diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 2de4e2e..c463ae1 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -172,6 +172,7 @@ struct devfreq { struct delayed_work work; unsigned long previous_freq; + unsigned long suspend_freq; struct devfreq_dev_status last_status; void *data; /* private data for governors */ @@ -179,6 +180,7 @@ struct devfreq { unsigned long min_freq; unsigned long max_freq; bool stop_polling; + bool suspend_flag; You don't need to add new variable. /* information for device frequency transition */ unsigned int total_trans; @@ -214,6 +216,8 @@ extern int devfreq_resume_device(struct devfreq *devfreq); /* Helper functions for devfreq user device driver with OPP. */ extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, u32 flags); +extern void devfreq_opp_get_suspend_opp(struct device *dev, +
Re: [PATCH v2 1/2] PM/devfreq: add suspend frequency support
Hi All, Miss something in this patch, just ignored it, sorry about that. On 2016年11月03日 14:16, Lin Huang wrote: Add suspend frequency support and if needed set it to the frequency obtained from the suspend opp (can be defined using opp-v2 bindings and is optional). Change-Id: Iaa0d3848d63d9ce03f65ea76f263e4685a4c295e Signed-off-by: Lin Huang--- Changes in v2: - use update_devfreq() instead devfreq_update_status() drivers/devfreq/devfreq.c | 17 - include/linux/devfreq.h | 9 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index bf3ea76..0a76282 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -364,7 +364,10 @@ void devfreq_monitor_suspend(struct devfreq *devfreq) return; } - devfreq_update_status(devfreq, devfreq->previous_freq); + if (devfreq->suspend_freq) + update_devfreq(devfreq, devfreq->suspend_freq); + else + devfreq_update_status(devfreq, devfreq->previous_freq); devfreq->stop_polling = true; mutex_unlock(>lock); cancel_delayed_work_sync(>work); @@ -1251,6 +1254,18 @@ struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, } EXPORT_SYMBOL(devfreq_recommended_opp); +void devfreq_opp_get_suspend_opp(struct device *dev, struct devfreq *devfreq) +{ + struct dev_pm_opp *suspend_opp; + + rcu_read_lock(); + suspend_opp = dev_pm_opp_get_suspend_opp(dev); + if (suspend_opp) + devfreq->suspend_freq = dev_pm_opp_get_freq(suspend_opp); + rcu_read_unlock(); +} +EXPORT_SYMBOL(devfreq_opp_get_suspend_opp); + /** * devfreq_register_opp_notifier() - Helper function to get devfreq notified * for any changes in the OPP availability diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 2de4e2e..c785ad9 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -88,6 +88,7 @@ struct devfreq_dev_status { */ struct devfreq_dev_profile { unsigned long initial_freq; + unsigned long suspend_freq; unsigned int polling_ms; int (*target)(struct device *dev, unsigned long *freq, u32 flags); @@ -172,6 +173,7 @@ struct devfreq { struct delayed_work work; unsigned long previous_freq; + unsigned long suspend_freq; struct devfreq_dev_status last_status; void *data; /* private data for governors */ @@ -214,6 +216,8 @@ extern void devm_devfreq_remove_device(struct device *dev, /* Helper functions for devfreq user device driver with OPP. */ extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, u32 flags); +extern void devfreq_opp_get_suspend_opp(struct device *dev, + struct devfreq *devfreq); extern int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq); extern int devfreq_unregister_opp_notifier(struct device *dev, @@ -348,6 +352,11 @@ static inline struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, return ERR_PTR(-EINVAL); } +static inline void devfreq_opp_get_suspend_opp(struct device *dev, + struct devfreq *devfreq) +{ +} + static inline int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) { -- Lin Huang
Re: [PATCH v2 1/2] PM/devfreq: add suspend frequency support
Hi All, Miss something in this patch, just ignored it, sorry about that. On 2016年11月03日 14:16, Lin Huang wrote: Add suspend frequency support and if needed set it to the frequency obtained from the suspend opp (can be defined using opp-v2 bindings and is optional). Change-Id: Iaa0d3848d63d9ce03f65ea76f263e4685a4c295e Signed-off-by: Lin Huang --- Changes in v2: - use update_devfreq() instead devfreq_update_status() drivers/devfreq/devfreq.c | 17 - include/linux/devfreq.h | 9 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index bf3ea76..0a76282 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -364,7 +364,10 @@ void devfreq_monitor_suspend(struct devfreq *devfreq) return; } - devfreq_update_status(devfreq, devfreq->previous_freq); + if (devfreq->suspend_freq) + update_devfreq(devfreq, devfreq->suspend_freq); + else + devfreq_update_status(devfreq, devfreq->previous_freq); devfreq->stop_polling = true; mutex_unlock(>lock); cancel_delayed_work_sync(>work); @@ -1251,6 +1254,18 @@ struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, } EXPORT_SYMBOL(devfreq_recommended_opp); +void devfreq_opp_get_suspend_opp(struct device *dev, struct devfreq *devfreq) +{ + struct dev_pm_opp *suspend_opp; + + rcu_read_lock(); + suspend_opp = dev_pm_opp_get_suspend_opp(dev); + if (suspend_opp) + devfreq->suspend_freq = dev_pm_opp_get_freq(suspend_opp); + rcu_read_unlock(); +} +EXPORT_SYMBOL(devfreq_opp_get_suspend_opp); + /** * devfreq_register_opp_notifier() - Helper function to get devfreq notified * for any changes in the OPP availability diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 2de4e2e..c785ad9 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -88,6 +88,7 @@ struct devfreq_dev_status { */ struct devfreq_dev_profile { unsigned long initial_freq; + unsigned long suspend_freq; unsigned int polling_ms; int (*target)(struct device *dev, unsigned long *freq, u32 flags); @@ -172,6 +173,7 @@ struct devfreq { struct delayed_work work; unsigned long previous_freq; + unsigned long suspend_freq; struct devfreq_dev_status last_status; void *data; /* private data for governors */ @@ -214,6 +216,8 @@ extern void devm_devfreq_remove_device(struct device *dev, /* Helper functions for devfreq user device driver with OPP. */ extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, u32 flags); +extern void devfreq_opp_get_suspend_opp(struct device *dev, + struct devfreq *devfreq); extern int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq); extern int devfreq_unregister_opp_notifier(struct device *dev, @@ -348,6 +352,11 @@ static inline struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, return ERR_PTR(-EINVAL); } +static inline void devfreq_opp_get_suspend_opp(struct device *dev, + struct devfreq *devfreq) +{ +} + static inline int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) { -- Lin Huang
Re: [PATCH v10 5/5] drm/rockchip: Add dmc notifier in vop driver
Hi On 2016年09月07日 02:55, Sean Paul wrote: On Tue, Sep 6, 2016 at 2:15 PM, hl <h...@rock-chips.com> wrote: Hi Sean, On 2016年09月07日 01:18, Sean Paul wrote: On Mon, Sep 5, 2016 at 1:06 AM, Lin Huang <h...@rock-chips.com> wrote: when in ddr frequency scaling process, vop can not do enable or disable operation, since in dcf we check vop clock to see whether vop work. If vop work, dcf do ddr frequency scaling when vop in vblank status, and we need to read vop register to check whether vop go into vblank status. If vop not work, dcf can do ddr frequency any time. So when do ddr frequency scaling, you disabled or enable vop, there may two bad thing happen: 1, the panel flicker(when vop from disable status change to enable). 2, kernel hang (when vop from enable status change to disable, dcf need to read vblank status, but if you disable vop clock, it can not get the status, it will lead soc dead) So we need register to devfreq notifier, and we can get the dmc status. Also, when there have two vop enabled, we need to disable dmc, since dcf only base on one vop vblank time, so the other panel will flicker when do ddr frequency scaling. Signed-off-by: Lin Huang <h...@rock-chips.com> Reviewed-by: Chanwoo Choi <cw00.c...@samsung.com> --- Changes in v10: - None Changes in v9: - None Changes in v8: - None Changes in v7: - None Changes in v6: - fix a build error Changes in v5: - improve some nits Changes in v4: - register notifier to devfreq_register_notifier - use DEVFREQ_PRECHANGE and DEVFREQ_POSTCHANGE to get dmc status - when two vop enable, disable dmc - when two vop back to one vop, enable dmc Changes in v3: - when do vop eanble/disable, dmc will wait until it finish Changes in v2: - None Changes in v1: - use wait_event instead usleep drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 116 1 file changed, 116 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index efbc41a..a73f3aa 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -118,6 +120,13 @@ struct vop { const struct vop_data *data; + struct devfreq *devfreq; + struct devfreq_event_dev *devfreq_event_dev; + struct notifier_block dmc_nb; + int dmc_in_process; + int vop_switch_status; + wait_queue_head_t wait_dmc_queue; + wait_queue_head_t wait_vop_switch_queue; uint32_t *regsbak; void __iomem *regs; @@ -428,11 +437,47 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +static int dmc_notify(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct vop *vop = container_of(nb, struct vop, dmc_nb); + + if (event == DEVFREQ_PRECHANGE) { + /* +* check if vop in enable or disable process, +* if yes, wait until it finishes, use 200ms as +* timeout. +*/ + if (!wait_event_timeout(vop->wait_vop_switch_queue, + !vop->vop_switch_status, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for vop swtich status\n"); + vop->dmc_in_process = 1; + } else if (event == DEVFREQ_POSTCHANGE) { + vop->dmc_in_process = 0; + wake_up(>wait_dmc_queue); + } + + return NOTIFY_OK; +} + static int vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); + int num_enabled_crtc = 0; int ret; + /* +* if in dmc scaling frequency process, wait until it finishes +* use 200ms as timeout time. +*/ + if (!wait_event_timeout(vop->wait_dmc_queue, + !vop->dmc_in_process, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for dmc when vop enable\n"); + This wait_event_timeout code is terribly racey (same goes above and below). No i use the vop_switch_status and dmc_in_progress to handle the vop and dmc racey, So what happens if dmc_in_progress becomes 1 right here, or anywhere during vop_enable()? In dmc_notify(), i will check the vop_switch_status, so in the vop_enable() and vop_crtc_disable(), the dmc_in_progress can not change value. Sean I assume this can fix the racey now. I do not better a idea now. + vop->vop_switch_status = 1; + ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); @@ -479,6 +524,21 @@ static int vop_enable
Re: [PATCH v10 5/5] drm/rockchip: Add dmc notifier in vop driver
Hi On 2016年09月07日 02:55, Sean Paul wrote: On Tue, Sep 6, 2016 at 2:15 PM, hl wrote: Hi Sean, On 2016年09月07日 01:18, Sean Paul wrote: On Mon, Sep 5, 2016 at 1:06 AM, Lin Huang wrote: when in ddr frequency scaling process, vop can not do enable or disable operation, since in dcf we check vop clock to see whether vop work. If vop work, dcf do ddr frequency scaling when vop in vblank status, and we need to read vop register to check whether vop go into vblank status. If vop not work, dcf can do ddr frequency any time. So when do ddr frequency scaling, you disabled or enable vop, there may two bad thing happen: 1, the panel flicker(when vop from disable status change to enable). 2, kernel hang (when vop from enable status change to disable, dcf need to read vblank status, but if you disable vop clock, it can not get the status, it will lead soc dead) So we need register to devfreq notifier, and we can get the dmc status. Also, when there have two vop enabled, we need to disable dmc, since dcf only base on one vop vblank time, so the other panel will flicker when do ddr frequency scaling. Signed-off-by: Lin Huang Reviewed-by: Chanwoo Choi --- Changes in v10: - None Changes in v9: - None Changes in v8: - None Changes in v7: - None Changes in v6: - fix a build error Changes in v5: - improve some nits Changes in v4: - register notifier to devfreq_register_notifier - use DEVFREQ_PRECHANGE and DEVFREQ_POSTCHANGE to get dmc status - when two vop enable, disable dmc - when two vop back to one vop, enable dmc Changes in v3: - when do vop eanble/disable, dmc will wait until it finish Changes in v2: - None Changes in v1: - use wait_event instead usleep drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 116 1 file changed, 116 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index efbc41a..a73f3aa 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -118,6 +120,13 @@ struct vop { const struct vop_data *data; + struct devfreq *devfreq; + struct devfreq_event_dev *devfreq_event_dev; + struct notifier_block dmc_nb; + int dmc_in_process; + int vop_switch_status; + wait_queue_head_t wait_dmc_queue; + wait_queue_head_t wait_vop_switch_queue; uint32_t *regsbak; void __iomem *regs; @@ -428,11 +437,47 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +static int dmc_notify(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct vop *vop = container_of(nb, struct vop, dmc_nb); + + if (event == DEVFREQ_PRECHANGE) { + /* +* check if vop in enable or disable process, +* if yes, wait until it finishes, use 200ms as +* timeout. +*/ + if (!wait_event_timeout(vop->wait_vop_switch_queue, + !vop->vop_switch_status, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for vop swtich status\n"); + vop->dmc_in_process = 1; + } else if (event == DEVFREQ_POSTCHANGE) { + vop->dmc_in_process = 0; + wake_up(>wait_dmc_queue); + } + + return NOTIFY_OK; +} + static int vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); + int num_enabled_crtc = 0; int ret; + /* +* if in dmc scaling frequency process, wait until it finishes +* use 200ms as timeout time. +*/ + if (!wait_event_timeout(vop->wait_dmc_queue, + !vop->dmc_in_process, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for dmc when vop enable\n"); + This wait_event_timeout code is terribly racey (same goes above and below). No i use the vop_switch_status and dmc_in_progress to handle the vop and dmc racey, So what happens if dmc_in_progress becomes 1 right here, or anywhere during vop_enable()? In dmc_notify(), i will check the vop_switch_status, so in the vop_enable() and vop_crtc_disable(), the dmc_in_progress can not change value. Sean I assume this can fix the racey now. I do not better a idea now. + vop->vop_switch_status = 1; + ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); @@ -479,6 +524,21 @@ static int vop_enable(struct drm_crtc *crtc) drm_crtc_vblank_on(crtc); + vop->vop_switch_status = 0; + w
Re: [PATCH v10 5/5] drm/rockchip: Add dmc notifier in vop driver
Hi Sean, On 2016年09月07日 01:18, Sean Paul wrote: On Mon, Sep 5, 2016 at 1:06 AM, Lin Huangwrote: when in ddr frequency scaling process, vop can not do enable or disable operation, since in dcf we check vop clock to see whether vop work. If vop work, dcf do ddr frequency scaling when vop in vblank status, and we need to read vop register to check whether vop go into vblank status. If vop not work, dcf can do ddr frequency any time. So when do ddr frequency scaling, you disabled or enable vop, there may two bad thing happen: 1, the panel flicker(when vop from disable status change to enable). 2, kernel hang (when vop from enable status change to disable, dcf need to read vblank status, but if you disable vop clock, it can not get the status, it will lead soc dead) So we need register to devfreq notifier, and we can get the dmc status. Also, when there have two vop enabled, we need to disable dmc, since dcf only base on one vop vblank time, so the other panel will flicker when do ddr frequency scaling. Signed-off-by: Lin Huang Reviewed-by: Chanwoo Choi --- Changes in v10: - None Changes in v9: - None Changes in v8: - None Changes in v7: - None Changes in v6: - fix a build error Changes in v5: - improve some nits Changes in v4: - register notifier to devfreq_register_notifier - use DEVFREQ_PRECHANGE and DEVFREQ_POSTCHANGE to get dmc status - when two vop enable, disable dmc - when two vop back to one vop, enable dmc Changes in v3: - when do vop eanble/disable, dmc will wait until it finish Changes in v2: - None Changes in v1: - use wait_event instead usleep drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 116 1 file changed, 116 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index efbc41a..a73f3aa 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -118,6 +120,13 @@ struct vop { const struct vop_data *data; + struct devfreq *devfreq; + struct devfreq_event_dev *devfreq_event_dev; + struct notifier_block dmc_nb; + int dmc_in_process; + int vop_switch_status; + wait_queue_head_t wait_dmc_queue; + wait_queue_head_t wait_vop_switch_queue; uint32_t *regsbak; void __iomem *regs; @@ -428,11 +437,47 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +static int dmc_notify(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct vop *vop = container_of(nb, struct vop, dmc_nb); + + if (event == DEVFREQ_PRECHANGE) { + /* +* check if vop in enable or disable process, +* if yes, wait until it finishes, use 200ms as +* timeout. +*/ + if (!wait_event_timeout(vop->wait_vop_switch_queue, + !vop->vop_switch_status, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for vop swtich status\n"); + vop->dmc_in_process = 1; + } else if (event == DEVFREQ_POSTCHANGE) { + vop->dmc_in_process = 0; + wake_up(>wait_dmc_queue); + } + + return NOTIFY_OK; +} + static int vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); + int num_enabled_crtc = 0; int ret; + /* +* if in dmc scaling frequency process, wait until it finishes +* use 200ms as timeout time. +*/ + if (!wait_event_timeout(vop->wait_dmc_queue, + !vop->dmc_in_process, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for dmc when vop enable\n"); + This wait_event_timeout code is terribly racey (same goes above and below). No i use the vop_switch_status and dmc_in_progress to handle the vop and dmc racey, I assume this can fix the racey now. I do not better a idea now. + vop->vop_switch_status = 1; + ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); @@ -479,6 +524,21 @@ static int vop_enable(struct drm_crtc *crtc) drm_crtc_vblank_on(crtc); + vop->vop_switch_status = 0; + wake_up(>wait_vop_switch_queue); + + /* check how many VOPs in use now */ + drm_for_each_crtc(crtc, vop->drm_dev) { + if (crtc->state->enable) I think you really want to check active, instead of enable. Okay, i will check it, thanks. + num_enabled_crtc++; + } + + /* if enable two vop, need to disable dmc */ +
Re: [PATCH v10 5/5] drm/rockchip: Add dmc notifier in vop driver
Hi Sean, On 2016年09月07日 01:18, Sean Paul wrote: On Mon, Sep 5, 2016 at 1:06 AM, Lin Huang wrote: when in ddr frequency scaling process, vop can not do enable or disable operation, since in dcf we check vop clock to see whether vop work. If vop work, dcf do ddr frequency scaling when vop in vblank status, and we need to read vop register to check whether vop go into vblank status. If vop not work, dcf can do ddr frequency any time. So when do ddr frequency scaling, you disabled or enable vop, there may two bad thing happen: 1, the panel flicker(when vop from disable status change to enable). 2, kernel hang (when vop from enable status change to disable, dcf need to read vblank status, but if you disable vop clock, it can not get the status, it will lead soc dead) So we need register to devfreq notifier, and we can get the dmc status. Also, when there have two vop enabled, we need to disable dmc, since dcf only base on one vop vblank time, so the other panel will flicker when do ddr frequency scaling. Signed-off-by: Lin Huang Reviewed-by: Chanwoo Choi --- Changes in v10: - None Changes in v9: - None Changes in v8: - None Changes in v7: - None Changes in v6: - fix a build error Changes in v5: - improve some nits Changes in v4: - register notifier to devfreq_register_notifier - use DEVFREQ_PRECHANGE and DEVFREQ_POSTCHANGE to get dmc status - when two vop enable, disable dmc - when two vop back to one vop, enable dmc Changes in v3: - when do vop eanble/disable, dmc will wait until it finish Changes in v2: - None Changes in v1: - use wait_event instead usleep drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 116 1 file changed, 116 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index efbc41a..a73f3aa 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -118,6 +120,13 @@ struct vop { const struct vop_data *data; + struct devfreq *devfreq; + struct devfreq_event_dev *devfreq_event_dev; + struct notifier_block dmc_nb; + int dmc_in_process; + int vop_switch_status; + wait_queue_head_t wait_dmc_queue; + wait_queue_head_t wait_vop_switch_queue; uint32_t *regsbak; void __iomem *regs; @@ -428,11 +437,47 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +static int dmc_notify(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct vop *vop = container_of(nb, struct vop, dmc_nb); + + if (event == DEVFREQ_PRECHANGE) { + /* +* check if vop in enable or disable process, +* if yes, wait until it finishes, use 200ms as +* timeout. +*/ + if (!wait_event_timeout(vop->wait_vop_switch_queue, + !vop->vop_switch_status, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for vop swtich status\n"); + vop->dmc_in_process = 1; + } else if (event == DEVFREQ_POSTCHANGE) { + vop->dmc_in_process = 0; + wake_up(>wait_dmc_queue); + } + + return NOTIFY_OK; +} + static int vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); + int num_enabled_crtc = 0; int ret; + /* +* if in dmc scaling frequency process, wait until it finishes +* use 200ms as timeout time. +*/ + if (!wait_event_timeout(vop->wait_dmc_queue, + !vop->dmc_in_process, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for dmc when vop enable\n"); + This wait_event_timeout code is terribly racey (same goes above and below). No i use the vop_switch_status and dmc_in_progress to handle the vop and dmc racey, I assume this can fix the racey now. I do not better a idea now. + vop->vop_switch_status = 1; + ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); @@ -479,6 +524,21 @@ static int vop_enable(struct drm_crtc *crtc) drm_crtc_vblank_on(crtc); + vop->vop_switch_status = 0; + wake_up(>wait_vop_switch_queue); + + /* check how many VOPs in use now */ + drm_for_each_crtc(crtc, vop->drm_dev) { + if (crtc->state->enable) I think you really want to check active, instead of enable. Okay, i will check it, thanks. + num_enabled_crtc++; + } + + /* if enable two vop, need to disable dmc */ + if ((num_enabled_crtc > 1) && vop->devfreq) { +
Re: [PATCH v6 6/8] Documentation: bindings: add dt documentation for rk3399 dmc
Hi Chanwoo Choi, On 2016年08月23日 13:05, Chanwoo Choi wrote: Hi Lin, On 2016년 08월 22일 07:16, hl wrote: Hi Chanwoo Choi, On 2016年08月17日 12:50, Chanwoo Choi wrote: Hi Lin, On 2016년 08월 17일 07:36, Lin Huang wrote: This patch adds the documentation for rockchip rk3399 dmc driver. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v6: -Add more detail in Documentation Changes in v5: -None Changes in v4: -None Changes in v3: -None Changes in v2: -None Changes in v1: -None .../devicetree/bindings/devfreq/rk3399_dmc.txt | 84 ++ 1 file changed, 84 insertions(+) create mode 100644 Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt diff --git a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt new file mode 100644 index 000..e73067c --- /dev/null +++ b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt @@ -0,0 +1,84 @@ +* Rockchip rk3399 DMC(Dynamic Memory Controller) device + +Required properties: +- compatible: Must be "rockchip,rk3399-dmc". +- devfreq-events: Node to get ddr loading, Refer to + Documentation/devicetree/bindings/devfreq/rockchip-dif.txt +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. it should be dcf interrupts, + when ddr dvfs finish, it will happen. If possible, you better to keep the indentation with other properties. s/it->It, dcf->DCF, ddr->DDR +- clocks: Phandles for clock specified in "clock-names" property +- clock-names : The name of clock used by the DFI, must be "pclk_ddr_mon"; +- operating-points-v2: Refer to Documentation/devicetree/bindings/power/opp.txt + for details. ditto. +- center-supply: Dmc supply node. s/Dmc/DMC becaue DMC an abbreviation. +- status: Marks the node enabled/disabled. + +Optional properties: +- ddr_timing: ddr timing need to pass to arm trust firmware +- upthreshold: the upthreshold to simpleondeamnd policy +- downdifferential: The downdifferential to simpleondeamnd policy + +Example: +ddr_timing: ddr_timing { +compatible = "rockchip,ddr-timing"; I can't find the 'rockchip,ddr-timing' driver on linux-next git repo (20160816). If ddr_timing includes the only properties for ddr_timing, I recommend you make the separate a .dtsi file including the ddr timing configuration. I add the reference and an example on below. +ddr3_speed_bin = <21>; +pd_idle = <0>; +sr_idle = <0>; +sr_mc_gate_idle = <0>; +srpd_lite_idle= <0>; +standby_idle = <0>; +dram_dll_dis_freq = <300>; +phy_dll_dis_freq = <125>; + +ddr3_odt_dis_freq = <333>; +ddr3_drv = ; +ddr3_odt = ; +phy_ddr3_ca_drv = ; +phy_ddr3_dq_drv = ; +phy_ddr3_odt = ; + +lpddr3_odt_dis_freq = <333>; +lpddr3_drv = ; +lpddr3_odt = ; +phy_lpddr3_ca_drv = ; +phy_lpddr3_dq_drv = ; +phy_lpddr3_odt = ; + +lpddr4_odt_dis_freq = <333>; +lpddr4_drv = ; +lpddr4_dq_odt = ; +lpddr4_ca_odt = ; +phy_lpddr4_ca_drv = ; +phy_lpddr4_ck_cs_drv = ; +phy_lpddr4_dq_drv = ; +phy_lpddr4_odt = ; +}; + +dmc_opp_table: dmc_opp_table { +compatible = "operating-points-v2"; + +opp00 { +opp-hz = /bits/ 64 <3>; +opp-microvolt = <90>; +}; +opp01 { +opp-hz = /bits/ 64 <66600>; +opp-microvolt = <90>; +}; +}; + +dmc: dmc { +compatible = "rockchip,rk3399-dmc"; +devfreq-events = <>; +interrupts = ; +clocks = < SCLK_DDRCLK>; +clock-names = "dmc_clk"; +ddr_timing = <_timing>; You can use the following '#include' instead of 'ddr_timing' because the ddr_timing is not a device driver. Instead, the rk3399-dmc must need the ddr timing configuration. #include "rk3399-dmc-timing-conf.dtsi" You can refer the similar usage case[1]. The *.conf.dtsi is used on exynos3250 tmu dt node[2]. [1] arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi [2] arch/arm/boot/dts/exynos3250.dtsi, 224 line. +operating-points-v2 = <_opp_table>; +center-supply = <_centerlogic>; +upthreshold = <15>; +downdifferential = <10>; +status = "disabled"; +}; + For example, I think that you can add the following timing .dtsi file. - arch/arm/boot/dts/rk3399-dmc-timing-conf.dtsi /* * Device tree sources for RK3399 DDR timing configuration * * Copyright (c) 2016 Lin Huang <h...@rock-chips.com> * * This program is free software
Re: [PATCH v6 6/8] Documentation: bindings: add dt documentation for rk3399 dmc
Hi Chanwoo Choi, On 2016年08月23日 13:05, Chanwoo Choi wrote: Hi Lin, On 2016년 08월 22일 07:16, hl wrote: Hi Chanwoo Choi, On 2016年08月17日 12:50, Chanwoo Choi wrote: Hi Lin, On 2016년 08월 17일 07:36, Lin Huang wrote: This patch adds the documentation for rockchip rk3399 dmc driver. Signed-off-by: Lin Huang --- Changes in v6: -Add more detail in Documentation Changes in v5: -None Changes in v4: -None Changes in v3: -None Changes in v2: -None Changes in v1: -None .../devicetree/bindings/devfreq/rk3399_dmc.txt | 84 ++ 1 file changed, 84 insertions(+) create mode 100644 Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt diff --git a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt new file mode 100644 index 000..e73067c --- /dev/null +++ b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt @@ -0,0 +1,84 @@ +* Rockchip rk3399 DMC(Dynamic Memory Controller) device + +Required properties: +- compatible: Must be "rockchip,rk3399-dmc". +- devfreq-events: Node to get ddr loading, Refer to + Documentation/devicetree/bindings/devfreq/rockchip-dif.txt +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. it should be dcf interrupts, + when ddr dvfs finish, it will happen. If possible, you better to keep the indentation with other properties. s/it->It, dcf->DCF, ddr->DDR +- clocks: Phandles for clock specified in "clock-names" property +- clock-names : The name of clock used by the DFI, must be "pclk_ddr_mon"; +- operating-points-v2: Refer to Documentation/devicetree/bindings/power/opp.txt + for details. ditto. +- center-supply: Dmc supply node. s/Dmc/DMC becaue DMC an abbreviation. +- status: Marks the node enabled/disabled. + +Optional properties: +- ddr_timing: ddr timing need to pass to arm trust firmware +- upthreshold: the upthreshold to simpleondeamnd policy +- downdifferential: The downdifferential to simpleondeamnd policy + +Example: +ddr_timing: ddr_timing { +compatible = "rockchip,ddr-timing"; I can't find the 'rockchip,ddr-timing' driver on linux-next git repo (20160816). If ddr_timing includes the only properties for ddr_timing, I recommend you make the separate a .dtsi file including the ddr timing configuration. I add the reference and an example on below. +ddr3_speed_bin = <21>; +pd_idle = <0>; +sr_idle = <0>; +sr_mc_gate_idle = <0>; +srpd_lite_idle= <0>; +standby_idle = <0>; +dram_dll_dis_freq = <300>; +phy_dll_dis_freq = <125>; + +ddr3_odt_dis_freq = <333>; +ddr3_drv = ; +ddr3_odt = ; +phy_ddr3_ca_drv = ; +phy_ddr3_dq_drv = ; +phy_ddr3_odt = ; + +lpddr3_odt_dis_freq = <333>; +lpddr3_drv = ; +lpddr3_odt = ; +phy_lpddr3_ca_drv = ; +phy_lpddr3_dq_drv = ; +phy_lpddr3_odt = ; + +lpddr4_odt_dis_freq = <333>; +lpddr4_drv = ; +lpddr4_dq_odt = ; +lpddr4_ca_odt = ; +phy_lpddr4_ca_drv = ; +phy_lpddr4_ck_cs_drv = ; +phy_lpddr4_dq_drv = ; +phy_lpddr4_odt = ; +}; + +dmc_opp_table: dmc_opp_table { +compatible = "operating-points-v2"; + +opp00 { +opp-hz = /bits/ 64 <3>; +opp-microvolt = <90>; +}; +opp01 { +opp-hz = /bits/ 64 <66600>; +opp-microvolt = <90>; +}; +}; + +dmc: dmc { +compatible = "rockchip,rk3399-dmc"; +devfreq-events = <>; +interrupts = ; +clocks = < SCLK_DDRCLK>; +clock-names = "dmc_clk"; +ddr_timing = <_timing>; You can use the following '#include' instead of 'ddr_timing' because the ddr_timing is not a device driver. Instead, the rk3399-dmc must need the ddr timing configuration. #include "rk3399-dmc-timing-conf.dtsi" You can refer the similar usage case[1]. The *.conf.dtsi is used on exynos3250 tmu dt node[2]. [1] arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi [2] arch/arm/boot/dts/exynos3250.dtsi, 224 line. +operating-points-v2 = <_opp_table>; +center-supply = <_centerlogic>; +upthreshold = <15>; +downdifferential = <10>; +status = "disabled"; +}; + For example, I think that you can add the following timing .dtsi file. - arch/arm/boot/dts/rk3399-dmc-timing-conf.dtsi /* * Device tree sources for RK3399 DDR timing configuration * * Copyright (c) 2016 Lin Huang * * This program is free software; you can redistribute it and/or modify * it under t
Re: [PATCH v6 6/8] Documentation: bindings: add dt documentation for rk3399 dmc
Hi Chanwoo Choi, On 2016年08月17日 12:50, Chanwoo Choi wrote: Hi Lin, On 2016년 08월 17일 07:36, Lin Huang wrote: This patch adds the documentation for rockchip rk3399 dmc driver. Signed-off-by: Lin Huang--- Changes in v6: -Add more detail in Documentation Changes in v5: -None Changes in v4: -None Changes in v3: -None Changes in v2: -None Changes in v1: -None .../devicetree/bindings/devfreq/rk3399_dmc.txt | 84 ++ 1 file changed, 84 insertions(+) create mode 100644 Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt diff --git a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt new file mode 100644 index 000..e73067c --- /dev/null +++ b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt @@ -0,0 +1,84 @@ +* Rockchip rk3399 DMC(Dynamic Memory Controller) device + +Required properties: +- compatible: Must be "rockchip,rk3399-dmc". +- devfreq-events: Node to get ddr loading, Refer to + Documentation/devicetree/bindings/devfreq/rockchip-dif.txt +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. it should be dcf interrupts, + when ddr dvfs finish, it will happen. If possible, you better to keep the indentation with other properties. s/it->It, dcf->DCF, ddr->DDR +- clocks: Phandles for clock specified in "clock-names" property +- clock-names : The name of clock used by the DFI, must be "pclk_ddr_mon"; +- operating-points-v2: Refer to Documentation/devicetree/bindings/power/opp.txt + for details. ditto. +- center-supply: Dmc supply node. s/Dmc/DMC becaue DMC an abbreviation. +- status: Marks the node enabled/disabled. + +Optional properties: +- ddr_timing: ddr timing need to pass to arm trust firmware +- upthreshold: the upthreshold to simpleondeamnd policy +- downdifferential: The downdifferential to simpleondeamnd policy + +Example: + ddr_timing: ddr_timing { + compatible = "rockchip,ddr-timing"; I can't find the 'rockchip,ddr-timing' driver on linux-next git repo (20160816). If ddr_timing includes the only properties for ddr_timing, I recommend you make the separate a .dtsi file including the ddr timing configuration. I add the reference and an example on below. + ddr3_speed_bin = <21>; + pd_idle = <0>; + sr_idle = <0>; + sr_mc_gate_idle = <0>; + srpd_lite_idle = <0>; + standby_idle = <0>; + dram_dll_dis_freq = <300>; + phy_dll_dis_freq = <125>; + + ddr3_odt_dis_freq = <333>; + ddr3_drv = ; + ddr3_odt = ; + phy_ddr3_ca_drv = ; + phy_ddr3_dq_drv = ; + phy_ddr3_odt = ; + + lpddr3_odt_dis_freq = <333>; + lpddr3_drv = ; + lpddr3_odt = ; + phy_lpddr3_ca_drv = ; + phy_lpddr3_dq_drv = ; + phy_lpddr3_odt = ; + + lpddr4_odt_dis_freq = <333>; + lpddr4_drv = ; + lpddr4_dq_odt = ; + lpddr4_ca_odt = ; + phy_lpddr4_ca_drv = ; + phy_lpddr4_ck_cs_drv = ; + phy_lpddr4_dq_drv = ; + phy_lpddr4_odt = ; + }; + + dmc_opp_table: dmc_opp_table { + compatible = "operating-points-v2"; + + opp00 { + opp-hz = /bits/ 64 <3>; + opp-microvolt = <90>; + }; + opp01 { + opp-hz = /bits/ 64 <66600>; + opp-microvolt = <90>; + }; + }; + + dmc: dmc { + compatible = "rockchip,rk3399-dmc"; + devfreq-events = <>; + interrupts = ; + clocks = < SCLK_DDRCLK>; + clock-names = "dmc_clk"; + ddr_timing = <_timing>; You can use the following '#include' instead of 'ddr_timing' because the ddr_timing is not a device driver. Instead, the rk3399-dmc must need the ddr timing configuration. #include "rk3399-dmc-timing-conf.dtsi" You can refer the similar usage case[1]. The *.conf.dtsi is used on exynos3250 tmu dt node[2]. [1] arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi [2] arch/arm/boot/dts/exynos3250.dtsi, 224 line. + operating-points-v2 = <_opp_table>; + center-supply = <_centerlogic>; + upthreshold = <15>; + downdifferential = <10>; + status = "disabled"; + }; + For example, I think that you can add the following timing .dtsi file. - arch/arm/boot/dts/rk3399-dmc-timing-conf.dtsi /* * Device tree sources for RK3399 DDR timing configuration * * Copyright (c) 2016 Lin Huang
Re: [PATCH v6 6/8] Documentation: bindings: add dt documentation for rk3399 dmc
Hi Chanwoo Choi, On 2016年08月17日 12:50, Chanwoo Choi wrote: Hi Lin, On 2016년 08월 17일 07:36, Lin Huang wrote: This patch adds the documentation for rockchip rk3399 dmc driver. Signed-off-by: Lin Huang --- Changes in v6: -Add more detail in Documentation Changes in v5: -None Changes in v4: -None Changes in v3: -None Changes in v2: -None Changes in v1: -None .../devicetree/bindings/devfreq/rk3399_dmc.txt | 84 ++ 1 file changed, 84 insertions(+) create mode 100644 Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt diff --git a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt new file mode 100644 index 000..e73067c --- /dev/null +++ b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt @@ -0,0 +1,84 @@ +* Rockchip rk3399 DMC(Dynamic Memory Controller) device + +Required properties: +- compatible: Must be "rockchip,rk3399-dmc". +- devfreq-events: Node to get ddr loading, Refer to + Documentation/devicetree/bindings/devfreq/rockchip-dif.txt +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. it should be dcf interrupts, + when ddr dvfs finish, it will happen. If possible, you better to keep the indentation with other properties. s/it->It, dcf->DCF, ddr->DDR +- clocks: Phandles for clock specified in "clock-names" property +- clock-names : The name of clock used by the DFI, must be "pclk_ddr_mon"; +- operating-points-v2: Refer to Documentation/devicetree/bindings/power/opp.txt + for details. ditto. +- center-supply: Dmc supply node. s/Dmc/DMC becaue DMC an abbreviation. +- status: Marks the node enabled/disabled. + +Optional properties: +- ddr_timing: ddr timing need to pass to arm trust firmware +- upthreshold: the upthreshold to simpleondeamnd policy +- downdifferential: The downdifferential to simpleondeamnd policy + +Example: + ddr_timing: ddr_timing { + compatible = "rockchip,ddr-timing"; I can't find the 'rockchip,ddr-timing' driver on linux-next git repo (20160816). If ddr_timing includes the only properties for ddr_timing, I recommend you make the separate a .dtsi file including the ddr timing configuration. I add the reference and an example on below. + ddr3_speed_bin = <21>; + pd_idle = <0>; + sr_idle = <0>; + sr_mc_gate_idle = <0>; + srpd_lite_idle = <0>; + standby_idle = <0>; + dram_dll_dis_freq = <300>; + phy_dll_dis_freq = <125>; + + ddr3_odt_dis_freq = <333>; + ddr3_drv = ; + ddr3_odt = ; + phy_ddr3_ca_drv = ; + phy_ddr3_dq_drv = ; + phy_ddr3_odt = ; + + lpddr3_odt_dis_freq = <333>; + lpddr3_drv = ; + lpddr3_odt = ; + phy_lpddr3_ca_drv = ; + phy_lpddr3_dq_drv = ; + phy_lpddr3_odt = ; + + lpddr4_odt_dis_freq = <333>; + lpddr4_drv = ; + lpddr4_dq_odt = ; + lpddr4_ca_odt = ; + phy_lpddr4_ca_drv = ; + phy_lpddr4_ck_cs_drv = ; + phy_lpddr4_dq_drv = ; + phy_lpddr4_odt = ; + }; + + dmc_opp_table: dmc_opp_table { + compatible = "operating-points-v2"; + + opp00 { + opp-hz = /bits/ 64 <3>; + opp-microvolt = <90>; + }; + opp01 { + opp-hz = /bits/ 64 <66600>; + opp-microvolt = <90>; + }; + }; + + dmc: dmc { + compatible = "rockchip,rk3399-dmc"; + devfreq-events = <>; + interrupts = ; + clocks = < SCLK_DDRCLK>; + clock-names = "dmc_clk"; + ddr_timing = <_timing>; You can use the following '#include' instead of 'ddr_timing' because the ddr_timing is not a device driver. Instead, the rk3399-dmc must need the ddr timing configuration. #include "rk3399-dmc-timing-conf.dtsi" You can refer the similar usage case[1]. The *.conf.dtsi is used on exynos3250 tmu dt node[2]. [1] arch/arm/boot/dts/exynos4412-tmu-sensor-conf.dtsi [2] arch/arm/boot/dts/exynos3250.dtsi, 224 line. + operating-points-v2 = <_opp_table>; + center-supply = <_centerlogic>; + upthreshold = <15>; + downdifferential = <10>; + status = "disabled"; + }; + For example, I think that you can add the following timing .dtsi file. - arch/arm/boot/dts/rk3399-dmc-timing-conf.dtsi /* * Device tree sources for RK3399 DDR timing configuration * * Copyright (c) 2016 Lin Huang * * This program is free software;
Re: [PATCH v6 8/8] drm/rockchip: Add dmc notifier in vop driver
Hi, On 2016年08月18日 02:14, Sean Paul wrote: On Tue, Aug 16, 2016 at 3:36 PM, Lin Huangwrote: when in ddr frequency scaling process, vop can not do enable or disable operation, since dcf will base on vop vblank time to do frequency scaling and need to get vop irq if there have vop enabled. I'm a little confused by this. Does this mean you need vblank irq to be enabled all the time when vop is enabled? We regularly disable it when there aren't new fbs coming in. maybe the commit message lead to misunderstanding, in dcf it will read the vop register to check whether is it in vblank status, if not, it will wait until it into vblank status. When vop enable, we need the vop clock enable, so we can read the vop register. So need register to devfreq notifier, and we can get the dmc status. Also, when there have two vop enabled, we need to disable dmc, since dcf only base on one vop vblank time, so the other panel will flicker when do ddr frequency scaling. Signed-off-by: Lin Huang Reviewed-by: Chanwoo Choi --- Changes in v6: - fix a build error Changes in v5: - improve some nits Changes in v4: - register notifier to devfreq_register_notifier - use DEVFREQ_PRECHANGE and DEVFREQ_POSTCHANGE to get dmc status - when two vop enable, disable dmc - when two vop back to one vop, enable dmc Changes in v3: - when do vop eanble/disable, dmc will wait until it finish Changes in v2: - None Changes in v1: - use wait_event instead usleep drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 121 +++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 31744fe..199529e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -12,6 +12,8 @@ * GNU General Public License for more details. */ +#include +#include #include #include #include @@ -118,6 +120,13 @@ struct vop { const struct vop_data *data; + struct devfreq *devfreq; + struct devfreq_event_dev *devfreq_event_dev; + struct notifier_block dmc_nb; + int dmc_in_process; + int vop_switch_status; + wait_queue_head_t wait_dmc_queue; + wait_queue_head_t wait_vop_switch_queue; uint32_t *regsbak; void __iomem *regs; @@ -428,21 +437,56 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +static int dmc_notify(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct vop *vop = container_of(nb, struct vop, dmc_nb); + + if (event == DEVFREQ_PRECHANGE) { + /* +* check if vop in enable or disable process, +* if yes, wait until it finishes, use 200ms as +* timeout. +*/ + if (!wait_event_timeout(vop->wait_vop_switch_queue, + !vop->vop_switch_status, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for vop swtich status\n"); + vop->dmc_in_process = 1; + } else if (event == DEVFREQ_POSTCHANGE) { + vop->dmc_in_process = 0; + wake_up(>wait_dmc_queue); + } + + return NOTIFY_OK; +} + static void vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); + int num_enabled_crtc = 0; int ret; + /* +* if in dmc scaling frequency process, wait until it finishes +* use 100ms as timeout time. +*/ + if (!wait_event_timeout(vop->wait_dmc_queue, + !vop->dmc_in_process, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for dmc when vop enable\n"); + + vop->vop_switch_status = 1; ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); - return; + goto err; } ret = clk_enable(vop->hclk); if (ret < 0) { dev_err(vop->dev, "failed to enable hclk - %d\n", ret); - return; + goto err; } ret = clk_enable(vop->dclk); @@ -485,6 +529,21 @@ static void vop_enable(struct drm_crtc *crtc) drm_crtc_vblank_on(crtc); + vop->vop_switch_status = 0; + wake_up(>wait_vop_switch_queue); + + /* check how many vop we use now */ + drm_for_each_crtc(crtc, vop->drm_dev) { + if (crtc->state->enable) + num_enabled_crtc++; + } + + /* if enable two vop, need to disable dmc */ + if ((num_enabled_crtc > 1) && vop->devfreq) { + if (vop->devfreq_event_dev) +
Re: [PATCH v6 8/8] drm/rockchip: Add dmc notifier in vop driver
Hi, On 2016年08月18日 02:14, Sean Paul wrote: On Tue, Aug 16, 2016 at 3:36 PM, Lin Huang wrote: when in ddr frequency scaling process, vop can not do enable or disable operation, since dcf will base on vop vblank time to do frequency scaling and need to get vop irq if there have vop enabled. I'm a little confused by this. Does this mean you need vblank irq to be enabled all the time when vop is enabled? We regularly disable it when there aren't new fbs coming in. maybe the commit message lead to misunderstanding, in dcf it will read the vop register to check whether is it in vblank status, if not, it will wait until it into vblank status. When vop enable, we need the vop clock enable, so we can read the vop register. So need register to devfreq notifier, and we can get the dmc status. Also, when there have two vop enabled, we need to disable dmc, since dcf only base on one vop vblank time, so the other panel will flicker when do ddr frequency scaling. Signed-off-by: Lin Huang Reviewed-by: Chanwoo Choi --- Changes in v6: - fix a build error Changes in v5: - improve some nits Changes in v4: - register notifier to devfreq_register_notifier - use DEVFREQ_PRECHANGE and DEVFREQ_POSTCHANGE to get dmc status - when two vop enable, disable dmc - when two vop back to one vop, enable dmc Changes in v3: - when do vop eanble/disable, dmc will wait until it finish Changes in v2: - None Changes in v1: - use wait_event instead usleep drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 121 +++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 31744fe..199529e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -12,6 +12,8 @@ * GNU General Public License for more details. */ +#include +#include #include #include #include @@ -118,6 +120,13 @@ struct vop { const struct vop_data *data; + struct devfreq *devfreq; + struct devfreq_event_dev *devfreq_event_dev; + struct notifier_block dmc_nb; + int dmc_in_process; + int vop_switch_status; + wait_queue_head_t wait_dmc_queue; + wait_queue_head_t wait_vop_switch_queue; uint32_t *regsbak; void __iomem *regs; @@ -428,21 +437,56 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop) spin_unlock_irqrestore(>irq_lock, flags); } +static int dmc_notify(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct vop *vop = container_of(nb, struct vop, dmc_nb); + + if (event == DEVFREQ_PRECHANGE) { + /* +* check if vop in enable or disable process, +* if yes, wait until it finishes, use 200ms as +* timeout. +*/ + if (!wait_event_timeout(vop->wait_vop_switch_queue, + !vop->vop_switch_status, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for vop swtich status\n"); + vop->dmc_in_process = 1; + } else if (event == DEVFREQ_POSTCHANGE) { + vop->dmc_in_process = 0; + wake_up(>wait_dmc_queue); + } + + return NOTIFY_OK; +} + static void vop_enable(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); + int num_enabled_crtc = 0; int ret; + /* +* if in dmc scaling frequency process, wait until it finishes +* use 100ms as timeout time. +*/ + if (!wait_event_timeout(vop->wait_dmc_queue, + !vop->dmc_in_process, HZ / 5)) + dev_warn(vop->dev, +"Timeout waiting for dmc when vop enable\n"); + + vop->vop_switch_status = 1; ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); - return; + goto err; } ret = clk_enable(vop->hclk); if (ret < 0) { dev_err(vop->dev, "failed to enable hclk - %d\n", ret); - return; + goto err; } ret = clk_enable(vop->dclk); @@ -485,6 +529,21 @@ static void vop_enable(struct drm_crtc *crtc) drm_crtc_vblank_on(crtc); + vop->vop_switch_status = 0; + wake_up(>wait_vop_switch_queue); + + /* check how many vop we use now */ + drm_for_each_crtc(crtc, vop->drm_dev) { + if (crtc->state->enable) + num_enabled_crtc++; + } + + /* if enable two vop, need to disable dmc */ + if ((num_enabled_crtc > 1) && vop->devfreq) { + if (vop->devfreq_event_dev) + devfreq_event_disable_edev(vop->devfreq_event_dev); +
Re: [PATCH v4 1/7] clk: rockchip: add clock flag parameter when register pll
Hi Heiko, On 2016年08月05日 06:37, Heiko Stuebner wrote: Am Freitag, 29. Juli 2016, 15:56:55 schrieb Lin Huang: From: Heiko Stübneradd clock flag parameter so we can pass specific clock flag (like CLK_GET_RATE_NOCACHE etc..)to pll driver. Signed-off-by: Heiko Stübner Signed-off-by: Lin Huang applied to my clock branch for 4.9 after some minor edits on the commit message. I can not found your clock branch for 4.9, can you share me the patch ID, i want cherry-pick it to my downstream branch. Thanks Heiko
Re: [PATCH v4 1/7] clk: rockchip: add clock flag parameter when register pll
Hi Heiko, On 2016年08月05日 06:37, Heiko Stuebner wrote: Am Freitag, 29. Juli 2016, 15:56:55 schrieb Lin Huang: From: Heiko Stübner add clock flag parameter so we can pass specific clock flag (like CLK_GET_RATE_NOCACHE etc..)to pll driver. Signed-off-by: Heiko Stübner Signed-off-by: Lin Huang applied to my clock branch for 4.9 after some minor edits on the commit message. I can not found your clock branch for 4.9, can you share me the patch ID, i want cherry-pick it to my downstream branch. Thanks Heiko
Re: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, On 2016年08月02日 12:21, Chanwoo Choi wrote: Hi Lin, On the next version, I'd like you to add the 'linux...@vger.kernel.org' because devfreq is a subsystem of power management. Sure, will do it next version. On 2016년 08월 02일 10:03, hl wrote: Hi Chanwoo Choi, Thanks for reviewing so carefully. And i have some question: On 2016年08月01日 18:28, Chanwoo Choi wrote: Hi Lin, As I mentioned on patch5, you better to make the documentation as following: - Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt And, I add the comments. On 2016년 07월 29일 16:57, Lin Huang wrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v4: - use arm_smccc_smc() function talk to bl31 - delete rockchip_dmc.c file and config - delete dmc_notify - adjust probe order Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile | 1 + drivers/devfreq/rockchip/Kconfig | 8 + drivers/devfreq/rockchip/Makefile | 1 + drivers/devfreq/rockchip/rk3399_dmc.c | 473 ++ 5 files changed, 484 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c [snip] + +static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq, + u32 flags) +{ +struct platform_device *pdev = container_of(dev, struct platform_device, +dev); +struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); You can use the 'dev_get_drvdata()' to simplify it instead of 'platform_get_drvdata()'. struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev); +struct dev_pm_opp *opp; +unsigned long old_clk_rate = dmcfreq->rate; +unsigned long target_volt, target_rate; +int err; + +rcu_read_lock(); +opp = devfreq_recommended_opp(dev, freq, flags); +if (IS_ERR(opp)) { +rcu_read_unlock(); +return PTR_ERR(opp); +} + +target_rate = dev_pm_opp_get_freq(opp); +target_volt = dev_pm_opp_get_voltage(opp); +opp = devfreq_recommended_opp(dev, >rate, flags); +if (IS_ERR(opp)) { +rcu_read_unlock(); +return PTR_ERR(opp); +} +dmcfreq->volt = dev_pm_opp_get_voltage(opp); If you add the 'curr_opp' variable to struct rk3399_dmcfreq, you can remove the calling of devfreq_recommended_opp(). dmcfreq->rate = dev_pm_opp_get_freq(dmcfreq->curr_opp); dmcfreq->volt = dev_pm_opp_get_freq(dmcfreq->curr_opp); Because the current rate and voltage is already decided on previous polling cycle, So we don't need to get the opp with devfreq_recommended_opp(). I prefer the way now use, since we get the dmcfreq->rate use clk_get_rate() after, Base on that, i do not care the set_rate success or fail. use curr_opp i need to care about set_rate status, when fail, i must set some rate, when success i must set other rate. I think that it is not good to get the alrady decided opp by devfreq_recommended_opp(). Usually, devfreq_recommended_opp() is used to get the proper opp which get the close frequency (dmcfreq->rate). Also, When finishing the rk3399_dmcfreq_target(), the rk3399_dmc.c have to know the current opp or rate without any finding sequence. The additional finding procedure is un-needed. +rcu_read_unlock(); + +if (dmcfreq->rate == target_rate) +return 0; + +mutex_lock(>lock); + +/* + * if frequency scaling from low to high, adjust voltage first; + * if frequency scaling from high to low, adjuset frequency first; + */ s/adjuset/adjust I recommend that you use a captital letter for first character and use the '.' instead of ';'. +if (old_clk_rate < target_rate) { +err = regulator_set_voltage(dmcfreq->vdd_center, target_volt, +target_volt); +if (err) { +dev_err(dev, "Unable to set vol %lu\n", target_volt); To readability, you better to use the corrent word to pass the precise the log message. - s/vol/voltage And, this patch uses the 'Unable to' or 'Cannot' to show the error log. I recommend that you use the consistent expression if there is not any specific reason. dev_err(dev, "Cannot set the voltage %lu uV\n", target_volt); +goto out; +} +} +dmcfreq->wait_dcf_flag = 1; +err = clk_set_rate(dmcfreq->dmc_clk, target_rate); +if (err) { +dev_err(dev, +"Una
Re: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, On 2016年08月02日 12:21, Chanwoo Choi wrote: Hi Lin, On the next version, I'd like you to add the 'linux...@vger.kernel.org' because devfreq is a subsystem of power management. Sure, will do it next version. On 2016년 08월 02일 10:03, hl wrote: Hi Chanwoo Choi, Thanks for reviewing so carefully. And i have some question: On 2016年08月01日 18:28, Chanwoo Choi wrote: Hi Lin, As I mentioned on patch5, you better to make the documentation as following: - Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt And, I add the comments. On 2016년 07월 29일 16:57, Lin Huang wrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang --- Changes in v4: - use arm_smccc_smc() function talk to bl31 - delete rockchip_dmc.c file and config - delete dmc_notify - adjust probe order Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile | 1 + drivers/devfreq/rockchip/Kconfig | 8 + drivers/devfreq/rockchip/Makefile | 1 + drivers/devfreq/rockchip/rk3399_dmc.c | 473 ++ 5 files changed, 484 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c [snip] + +static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq, + u32 flags) +{ +struct platform_device *pdev = container_of(dev, struct platform_device, +dev); +struct rk3399_dmcfreq *dmcfreq = platform_get_drvdata(pdev); You can use the 'dev_get_drvdata()' to simplify it instead of 'platform_get_drvdata()'. struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev); +struct dev_pm_opp *opp; +unsigned long old_clk_rate = dmcfreq->rate; +unsigned long target_volt, target_rate; +int err; + +rcu_read_lock(); +opp = devfreq_recommended_opp(dev, freq, flags); +if (IS_ERR(opp)) { +rcu_read_unlock(); +return PTR_ERR(opp); +} + +target_rate = dev_pm_opp_get_freq(opp); +target_volt = dev_pm_opp_get_voltage(opp); +opp = devfreq_recommended_opp(dev, >rate, flags); +if (IS_ERR(opp)) { +rcu_read_unlock(); +return PTR_ERR(opp); +} +dmcfreq->volt = dev_pm_opp_get_voltage(opp); If you add the 'curr_opp' variable to struct rk3399_dmcfreq, you can remove the calling of devfreq_recommended_opp(). dmcfreq->rate = dev_pm_opp_get_freq(dmcfreq->curr_opp); dmcfreq->volt = dev_pm_opp_get_freq(dmcfreq->curr_opp); Because the current rate and voltage is already decided on previous polling cycle, So we don't need to get the opp with devfreq_recommended_opp(). I prefer the way now use, since we get the dmcfreq->rate use clk_get_rate() after, Base on that, i do not care the set_rate success or fail. use curr_opp i need to care about set_rate status, when fail, i must set some rate, when success i must set other rate. I think that it is not good to get the alrady decided opp by devfreq_recommended_opp(). Usually, devfreq_recommended_opp() is used to get the proper opp which get the close frequency (dmcfreq->rate). Also, When finishing the rk3399_dmcfreq_target(), the rk3399_dmc.c have to know the current opp or rate without any finding sequence. The additional finding procedure is un-needed. +rcu_read_unlock(); + +if (dmcfreq->rate == target_rate) +return 0; + +mutex_lock(>lock); + +/* + * if frequency scaling from low to high, adjust voltage first; + * if frequency scaling from high to low, adjuset frequency first; + */ s/adjuset/adjust I recommend that you use a captital letter for first character and use the '.' instead of ';'. +if (old_clk_rate < target_rate) { +err = regulator_set_voltage(dmcfreq->vdd_center, target_volt, +target_volt); +if (err) { +dev_err(dev, "Unable to set vol %lu\n", target_volt); To readability, you better to use the corrent word to pass the precise the log message. - s/vol/voltage And, this patch uses the 'Unable to' or 'Cannot' to show the error log. I recommend that you use the consistent expression if there is not any specific reason. dev_err(dev, "Cannot set the voltage %lu uV\n", target_volt); +goto out; +} +} +dmcfreq->wait_dcf_flag = 1; +err = clk_set_rate(dmcfreq->dmc_clk, target_rate); +if (err) { +dev_err(dev, +"Unable to set freq %lu. Curr
Re: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, Thanks for reviewing so carefully. And i have some question: On 2016年08月01日 18:28, Chanwoo Choi wrote: Hi Lin, As I mentioned on patch5, you better to make the documentation as following: - Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt And, I add the comments. On 2016년 07월 29일 16:57, Lin Huang wrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang--- Changes in v4: - use arm_smccc_smc() function talk to bl31 - delete rockchip_dmc.c file and config - delete dmc_notify - adjust probe order Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile | 1 + drivers/devfreq/rockchip/Kconfig | 8 + drivers/devfreq/rockchip/Makefile | 1 + drivers/devfreq/rockchip/rk3399_dmc.c | 473 ++ 5 files changed, 484 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 64281bb..acb2a57 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -99,5 +99,6 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" +source "drivers/devfreq/rockchip/Kconfig" This patch include the only one patch. So, I think that you don't need to create the 'rockchip' directory. endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 5134f9e..d844e23 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/ obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/ obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ ditto. # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT)+= event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..d8f9e66 --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,8 @@ +config ARM_RK3399_DMC_DEVFREQ + tristate "ARM RK3399 DMC DEVFREQ Driver" + select PM_OPP + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency If you add the full description for 'dmc' as following, it is easy to understand the operation of this device driver. - DMC (Dynamic Memory Controller) + for the memory controller and reads the usage counts from hardware. + diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile new file mode 100644 index 000..c62c105 --- /dev/null +++ b/drivers/devfreq/rockchip/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c new file mode 100644 index 000..527aa11 --- /dev/null +++ b/drivers/devfreq/rockchip/rk3399_dmc.c @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd You miss the '.' at the end of the copylight. When you use an abbreviation, you should add '.' for Ltd. - s/Ltd/Ltd. + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include You don't need to include the "completion.h". Without "completion.h", the build is working. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include You don't need to include the "syscore_ops.h". Without "syscore_ops.h", the build is working. + +#include + +struct dram_timing { + unsigned int ddr3_speed_bin; + unsigned int pd_idle; + unsigned int sr_idle; + unsigned int sr_mc_gate_idle; + unsigned int srpd_lite_idle; + unsigned int standby_idle; + unsigned int dram_dll_dis_freq; + unsigned int phy_dll_dis_freq; + unsigned int
Re: [PATCH v4 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, Thanks for reviewing so carefully. And i have some question: On 2016年08月01日 18:28, Chanwoo Choi wrote: Hi Lin, As I mentioned on patch5, you better to make the documentation as following: - Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt And, I add the comments. On 2016년 07월 29일 16:57, Lin Huang wrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang --- Changes in v4: - use arm_smccc_smc() function talk to bl31 - delete rockchip_dmc.c file and config - delete dmc_notify - adjust probe order Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile | 1 + drivers/devfreq/rockchip/Kconfig | 8 + drivers/devfreq/rockchip/Makefile | 1 + drivers/devfreq/rockchip/rk3399_dmc.c | 473 ++ 5 files changed, 484 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 64281bb..acb2a57 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -99,5 +99,6 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" +source "drivers/devfreq/rockchip/Kconfig" This patch include the only one patch. So, I think that you don't need to create the 'rockchip' directory. endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 5134f9e..d844e23 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/ obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/ obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ ditto. # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT)+= event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..d8f9e66 --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,8 @@ +config ARM_RK3399_DMC_DEVFREQ + tristate "ARM RK3399 DMC DEVFREQ Driver" + select PM_OPP + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency If you add the full description for 'dmc' as following, it is easy to understand the operation of this device driver. - DMC (Dynamic Memory Controller) + for the memory controller and reads the usage counts from hardware. + diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile new file mode 100644 index 000..c62c105 --- /dev/null +++ b/drivers/devfreq/rockchip/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c new file mode 100644 index 000..527aa11 --- /dev/null +++ b/drivers/devfreq/rockchip/rk3399_dmc.c @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd You miss the '.' at the end of the copylight. When you use an abbreviation, you should add '.' for Ltd. - s/Ltd/Ltd. + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include You don't need to include the "completion.h". Without "completion.h", the build is working. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include You don't need to include the "syscore_ops.h". Without "syscore_ops.h", the build is working. + +#include + +struct dram_timing { + unsigned int ddr3_speed_bin; + unsigned int pd_idle; + unsigned int sr_idle; + unsigned int sr_mc_gate_idle; + unsigned int srpd_lite_idle; + unsigned int standby_idle; + unsigned int dram_dll_dis_freq; + unsigned int phy_dll_dis_freq; + unsigned int ddr3_odt_dis_freq; + unsigned int ddr3_drv; +
Re: [PATCH v4 5/7] PM / devfreq: event: support rockchip dfi controller
Hi Chanwoo Choi, On 2016年08月01日 16:08, Chanwoo Choi wrote: Hi Lin, I add the one minor comment for full name of 'DRI'. On 2016년 08월 01일 16:41, Chanwoo Choi wrote: Hi Lin, Because you remove the 'RFC' prefix on patch title, I think that you better to make the documentation as following: - Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt Regards, Chanwoo Choi On 2016년 07월 29일 16:56, Lin Huang wrote: on rk3399 platform, there is dfi conroller can monitor ddr load, base on this result, we can do ddr freqency scaling. Signed-off-by: Lin HuangAcked-by: Chanwoo Choi --- Changes in v4: - None Changes in v3: - None Changes in v2: - use clk_disable_unprepare and clk_enable_prepare - remove clk_enable_prepare in probe - remove rockchip_dfi_remove function Changes in v1: - None drivers/devfreq/event/Kconfig| 7 + drivers/devfreq/event/Makefile | 1 + drivers/devfreq/event/rockchip-dfi.c | 253 +++ 3 files changed, 261 insertions(+) create mode 100644 drivers/devfreq/event/rockchip-dfi.c diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig index a11720a..ff9279f 100644 --- a/drivers/devfreq/event/Kconfig +++ b/drivers/devfreq/event/Kconfig @@ -22,4 +22,11 @@ config DEVFREQ_EVENT_EXYNOS_PPMU (Platform Performance Monitoring Unit) counters to estimate the utilization of each module. +config DEVFREQ_EVENT_ROCKCHIP_DFI + tristate "ROCKCHIP DFI DEVFREQ event Driver" + depends on ARCH_ROCKCHIP + help + This add the devfreq-event driver for Rockchip SoC. It provides DFI + (DDR Monitor Module) driver to count ddr load. The DFI is "DDR Monitor Module" full name? I need the correct abbreviation and full name. We just call this module DFI in datasheet, and this module function is ddr monitor module, yes, it is do not fit the full name, but i think it is better follow the datasheet name. + endif # PM_DEVFREQ_EVENT diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile index be146ea..e3f88fc 100644 --- a/drivers/devfreq/event/Makefile +++ b/drivers/devfreq/event/Makefile @@ -1,2 +1,3 @@ # Exynos DEVFREQ Event Drivers obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o +obj-$(CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI) += rockchip-dfi.o diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c new file mode 100644 index 000..96a0307 --- /dev/null +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RK3399_DMC_NUM_CH 2 + +/* DDRMON_CTRL */ +#define DDRMON_CTRL0x04 +#define CLR_DDRMON_CTRL(0x1f << 0) +#define LPDDR4_EN (0x10001 << 4) +#define HARDWARE_EN(0x10001 << 3) +#define LPDDR3_EN (0x10001 << 2) +#define SOFTWARE_EN(0x10001 << 1) +#define TIME_CNT_EN(0x10001 << 0) + +#define DDRMON_CH0_COUNT_NUM 0x28 +#define DDRMON_CH0_DFI_ACCESS_NUM 0x2c +#define DDRMON_CH1_COUNT_NUM 0x3c +#define DDRMON_CH1_DFI_ACCESS_NUM 0x40 + +/* pmu grf */ +#define PMUGRF_OS_REG2 0x308 +#define DDRTYPE_SHIFT 13 +#define DDRTYPE_MASK 7 + +enum { + DDR3 = 3, + LPDDR3 = 6, + LPDDR4 = 7, + UNUSED = 0xFF +}; + +struct dmc_usage { + u32 access; + u32 total; +}; + +struct rockchip_dfi { + struct devfreq_event_dev *edev; + struct devfreq_event_desc *desc; + struct dmc_usage ch_usage[RK3399_DMC_NUM_CH]; + struct device *dev; + void __iomem *regs; + struct regmap *regmap_pmu; + struct clk *clk; +}; + +static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) +{ + struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); + void __iomem *dfi_regs = info->regs; + u32 val; + u32 ddr_type; + + /* get ddr type */ + regmap_read(info->regmap_pmu, PMUGRF_OS_REG2, ); + ddr_type = (val >> DDRTYPE_SHIFT) & DDRTYPE_MASK; + + /* clear DDRMON_CTRL setting */ + writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); + + /* set ddr type to dfi */ + if (ddr_type == LPDDR3) + writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL); +
Re: [PATCH v4 5/7] PM / devfreq: event: support rockchip dfi controller
Hi Chanwoo Choi, On 2016年08月01日 16:08, Chanwoo Choi wrote: Hi Lin, I add the one minor comment for full name of 'DRI'. On 2016년 08월 01일 16:41, Chanwoo Choi wrote: Hi Lin, Because you remove the 'RFC' prefix on patch title, I think that you better to make the documentation as following: - Documentation/devicetree/bindings/devfreq/event/rockchip-dfi.txt Regards, Chanwoo Choi On 2016년 07월 29일 16:56, Lin Huang wrote: on rk3399 platform, there is dfi conroller can monitor ddr load, base on this result, we can do ddr freqency scaling. Signed-off-by: Lin Huang Acked-by: Chanwoo Choi --- Changes in v4: - None Changes in v3: - None Changes in v2: - use clk_disable_unprepare and clk_enable_prepare - remove clk_enable_prepare in probe - remove rockchip_dfi_remove function Changes in v1: - None drivers/devfreq/event/Kconfig| 7 + drivers/devfreq/event/Makefile | 1 + drivers/devfreq/event/rockchip-dfi.c | 253 +++ 3 files changed, 261 insertions(+) create mode 100644 drivers/devfreq/event/rockchip-dfi.c diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig index a11720a..ff9279f 100644 --- a/drivers/devfreq/event/Kconfig +++ b/drivers/devfreq/event/Kconfig @@ -22,4 +22,11 @@ config DEVFREQ_EVENT_EXYNOS_PPMU (Platform Performance Monitoring Unit) counters to estimate the utilization of each module. +config DEVFREQ_EVENT_ROCKCHIP_DFI + tristate "ROCKCHIP DFI DEVFREQ event Driver" + depends on ARCH_ROCKCHIP + help + This add the devfreq-event driver for Rockchip SoC. It provides DFI + (DDR Monitor Module) driver to count ddr load. The DFI is "DDR Monitor Module" full name? I need the correct abbreviation and full name. We just call this module DFI in datasheet, and this module function is ddr monitor module, yes, it is do not fit the full name, but i think it is better follow the datasheet name. + endif # PM_DEVFREQ_EVENT diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile index be146ea..e3f88fc 100644 --- a/drivers/devfreq/event/Makefile +++ b/drivers/devfreq/event/Makefile @@ -1,2 +1,3 @@ # Exynos DEVFREQ Event Drivers obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o +obj-$(CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI) += rockchip-dfi.o diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c new file mode 100644 index 000..96a0307 --- /dev/null +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RK3399_DMC_NUM_CH 2 + +/* DDRMON_CTRL */ +#define DDRMON_CTRL0x04 +#define CLR_DDRMON_CTRL(0x1f << 0) +#define LPDDR4_EN (0x10001 << 4) +#define HARDWARE_EN(0x10001 << 3) +#define LPDDR3_EN (0x10001 << 2) +#define SOFTWARE_EN(0x10001 << 1) +#define TIME_CNT_EN(0x10001 << 0) + +#define DDRMON_CH0_COUNT_NUM 0x28 +#define DDRMON_CH0_DFI_ACCESS_NUM 0x2c +#define DDRMON_CH1_COUNT_NUM 0x3c +#define DDRMON_CH1_DFI_ACCESS_NUM 0x40 + +/* pmu grf */ +#define PMUGRF_OS_REG2 0x308 +#define DDRTYPE_SHIFT 13 +#define DDRTYPE_MASK 7 + +enum { + DDR3 = 3, + LPDDR3 = 6, + LPDDR4 = 7, + UNUSED = 0xFF +}; + +struct dmc_usage { + u32 access; + u32 total; +}; + +struct rockchip_dfi { + struct devfreq_event_dev *edev; + struct devfreq_event_desc *desc; + struct dmc_usage ch_usage[RK3399_DMC_NUM_CH]; + struct device *dev; + void __iomem *regs; + struct regmap *regmap_pmu; + struct clk *clk; +}; + +static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) +{ + struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); + void __iomem *dfi_regs = info->regs; + u32 val; + u32 ddr_type; + + /* get ddr type */ + regmap_read(info->regmap_pmu, PMUGRF_OS_REG2, ); + ddr_type = (val >> DDRTYPE_SHIFT) & DDRTYPE_MASK; + + /* clear DDRMON_CTRL setting */ + writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); + + /* set ddr type to dfi */ + if (ddr_type == LPDDR3) + writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL); + else if (ddr_type == LPDDR4) +
Re: [PATCH v4 0/7] rk3399 support ddr frequency scaling
Hi Chanwoo Choi, Ah, i am base on https://chromium.googlesource.com/chromiumos/third_party/kernel/v4.4, and forget to rebase on https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git, i will fix it in next version. I am sorry about that. And can you help to review the devfreq patch first, if something need to update, i will do it together. Thanks. On 2016年08月01日 15:39, Chanwoo Choi wrote: Hi Lin, On 2016년 07월 29일 16:56, Lin Huang wrote: rk3399 platform have dfi controller can monitor ddr load, and dcf controller to handle ddr register so we can get the right ddr frequency and make ddr controller happy work(which will implement in bl31). So we do ddr frequency scaling with following flow: kernelbl31 monitor ddr load | | get_target_rate | | pass rate to bl31 clk_set_rate(ddr) ->run dcf flow | | | | wait dcf interrupt<---trigger dcf interrupt | | return Lin Huang (6): clk: rockchip: add new clock-type for the ddrclk clk: rockchip: rk3399: add SCLK_DDRCLK ID for ddrc clk: rockchip: rk3399: add ddrc clock support PM / devfreq: event: support rockchip dfi controller PM / devfreq: rockchip: add devfreq driver for rk3399 dmc drm/rockchip: Add dmc notifier in vop driver Heiko Stübner (1): clk: rockchip: add clock flag parameter when register pll Lin Huang (6): clk: rockchip: add new clock-type for the ddrclk clk: rockchip: rk3399: add SCLK_DDRCLK ID for ddrc clk: rockchip: rk3399: add ddrc clock support PM / devfreq: event: support rockchip dfi controller PM / devfreq: rockchip: add devfreq driver for rk3399 dmc drm/rockchip: Add dmc notifier in vop driver The cover-letter includes the duplicate list of patches. Also, I want to test the build test. but, When I apply these patches, merge conflict happen. Could you give the information about base git repository? Regards, Chanwoo Choi drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-ddr.c | 146 + drivers/clk/rockchip/clk-pll.c | 4 +- drivers/clk/rockchip/clk-rk3399.c | 19 ++ drivers/clk/rockchip/clk.c | 11 +- drivers/clk/rockchip/clk.h | 29 +- drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile| 1 + drivers/devfreq/event/Kconfig | 7 + drivers/devfreq/event/Makefile | 1 + drivers/devfreq/event/rockchip-dfi.c| 253 +++ drivers/devfreq/rockchip/Kconfig| 8 + drivers/devfreq/rockchip/Makefile | 1 + drivers/devfreq/rockchip/rk3399_dmc.c | 473 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 124 +++- include/dt-bindings/clock/rk3399-cru.h | 1 + include/soc/rockchip/rockchip_sip.h | 27 ++ 17 files changed, 1098 insertions(+), 9 deletions(-) create mode 100644 drivers/clk/rockchip/clk-ddr.c create mode 100644 drivers/devfreq/event/rockchip-dfi.c create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 include/soc/rockchip/rockchip_sip.h -- Lin Huang
Re: [PATCH v4 0/7] rk3399 support ddr frequency scaling
Hi Chanwoo Choi, Ah, i am base on https://chromium.googlesource.com/chromiumos/third_party/kernel/v4.4, and forget to rebase on https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git, i will fix it in next version. I am sorry about that. And can you help to review the devfreq patch first, if something need to update, i will do it together. Thanks. On 2016年08月01日 15:39, Chanwoo Choi wrote: Hi Lin, On 2016년 07월 29일 16:56, Lin Huang wrote: rk3399 platform have dfi controller can monitor ddr load, and dcf controller to handle ddr register so we can get the right ddr frequency and make ddr controller happy work(which will implement in bl31). So we do ddr frequency scaling with following flow: kernelbl31 monitor ddr load | | get_target_rate | | pass rate to bl31 clk_set_rate(ddr) ->run dcf flow | | | | wait dcf interrupt<---trigger dcf interrupt | | return Lin Huang (6): clk: rockchip: add new clock-type for the ddrclk clk: rockchip: rk3399: add SCLK_DDRCLK ID for ddrc clk: rockchip: rk3399: add ddrc clock support PM / devfreq: event: support rockchip dfi controller PM / devfreq: rockchip: add devfreq driver for rk3399 dmc drm/rockchip: Add dmc notifier in vop driver Heiko Stübner (1): clk: rockchip: add clock flag parameter when register pll Lin Huang (6): clk: rockchip: add new clock-type for the ddrclk clk: rockchip: rk3399: add SCLK_DDRCLK ID for ddrc clk: rockchip: rk3399: add ddrc clock support PM / devfreq: event: support rockchip dfi controller PM / devfreq: rockchip: add devfreq driver for rk3399 dmc drm/rockchip: Add dmc notifier in vop driver The cover-letter includes the duplicate list of patches. Also, I want to test the build test. but, When I apply these patches, merge conflict happen. Could you give the information about base git repository? Regards, Chanwoo Choi drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-ddr.c | 146 + drivers/clk/rockchip/clk-pll.c | 4 +- drivers/clk/rockchip/clk-rk3399.c | 19 ++ drivers/clk/rockchip/clk.c | 11 +- drivers/clk/rockchip/clk.h | 29 +- drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile| 1 + drivers/devfreq/event/Kconfig | 7 + drivers/devfreq/event/Makefile | 1 + drivers/devfreq/event/rockchip-dfi.c| 253 +++ drivers/devfreq/rockchip/Kconfig| 8 + drivers/devfreq/rockchip/Makefile | 1 + drivers/devfreq/rockchip/rk3399_dmc.c | 473 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 124 +++- include/dt-bindings/clock/rk3399-cru.h | 1 + include/soc/rockchip/rockchip_sip.h | 27 ++ 17 files changed, 1098 insertions(+), 9 deletions(-) create mode 100644 drivers/clk/rockchip/clk-ddr.c create mode 100644 drivers/devfreq/event/rockchip-dfi.c create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 include/soc/rockchip/rockchip_sip.h -- Lin Huang
Re: [PATCH v3 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, On 2016年07月25日 17:45, Chanwoo Choi wrote: Hi Lin, On 2016년 07월 25일 17:47, hl wrote: Hi Chanwoo Choi, On 2016年07月25日 14:01, Chanwoo Choi wrote: Hi Lin, I'm glad to support the for dmc ddr clock scaling with devfreq/devfreq-event. But, I think that you have to use the standard interface. As I already mentioned[1] on previous mail, devfreq fwk support the standard DEVFREQ_TRANSITION_NOTIFIER notifier which has the two notifications. - DEVFREQ_PRECHANGE - DEVFREQ_POSTCHANGE [1] https://patchwork.kernel.org/patch/9194305/ You can use the DEVFREQ_PRECHANGE instead of DMCFREQ_ADJUST and use the DEVFREQ_POSTCHANGE instead of DMCFREQ_FINISH. On 2016년 07월 22일 18:07, Lin Huang wrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang <h...@rock-chips.com> --- Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 15 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 482 drivers/devfreq/rockchip/rockchip_dmc.c | 143 ++ include/soc/rockchip/rockchip_dmc.h | 45 +++ 7 files changed, 689 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index a5be56e..cb67246 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -101,5 +101,6 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" +source "drivers/devfreq/rockchip/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 09f11d9..48e2ae6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)+= governor_passive.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)+= exynos-bus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ)+= tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT)+= event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..7fb1cff --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,15 @@ +config ARM_ROCKCHIP_DMC_DEVFREQ +bool "ARM ROCKCHIP DMC DEVFREQ Driver" +depends on ARCH_ROCKCHIP +help + This adds the DEVFREQ driver framework for the rockchip dmc. + +config ARM_RK3399_DMC_DEVFREQ +bool "ARM RK3399 DMC DEVFREQ Driver" +depends on ARM_ROCKCHIP_DMC_DEVFREQ +select PM_OPP +select DEVFREQ_GOV_SIMPLE_ONDEMAND +help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency + for the memory controller and reads the usage counts from hardware. + diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile new file mode 100644 index 000..caca525 --- /dev/null +++ b/drivers/devfreq/rockchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ)+= rockchip_dmc.o +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)+= rk3399_dmc.o diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c new file mode 100644 index 000..f1d6120 --- /dev/null +++ b/drivers/devfreq/rockchip/rk3399_dmc.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang <h...@rock-chips.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../../firmware/rockchip_sip.h" + +struct dram_timing { +unsigned int ddr3_speed_bin; +unsigned int pd_idle; +unsigned int sr_idle; +
Re: [PATCH v3 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, On 2016年07月25日 17:45, Chanwoo Choi wrote: Hi Lin, On 2016년 07월 25일 17:47, hl wrote: Hi Chanwoo Choi, On 2016年07月25日 14:01, Chanwoo Choi wrote: Hi Lin, I'm glad to support the for dmc ddr clock scaling with devfreq/devfreq-event. But, I think that you have to use the standard interface. As I already mentioned[1] on previous mail, devfreq fwk support the standard DEVFREQ_TRANSITION_NOTIFIER notifier which has the two notifications. - DEVFREQ_PRECHANGE - DEVFREQ_POSTCHANGE [1] https://patchwork.kernel.org/patch/9194305/ You can use the DEVFREQ_PRECHANGE instead of DMCFREQ_ADJUST and use the DEVFREQ_POSTCHANGE instead of DMCFREQ_FINISH. On 2016년 07월 22일 18:07, Lin Huang wrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang --- Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 15 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 482 drivers/devfreq/rockchip/rockchip_dmc.c | 143 ++ include/soc/rockchip/rockchip_dmc.h | 45 +++ 7 files changed, 689 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index a5be56e..cb67246 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -101,5 +101,6 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" +source "drivers/devfreq/rockchip/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 09f11d9..48e2ae6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)+= governor_passive.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)+= exynos-bus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ)+= tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT)+= event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..7fb1cff --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,15 @@ +config ARM_ROCKCHIP_DMC_DEVFREQ +bool "ARM ROCKCHIP DMC DEVFREQ Driver" +depends on ARCH_ROCKCHIP +help + This adds the DEVFREQ driver framework for the rockchip dmc. + +config ARM_RK3399_DMC_DEVFREQ +bool "ARM RK3399 DMC DEVFREQ Driver" +depends on ARM_ROCKCHIP_DMC_DEVFREQ +select PM_OPP +select DEVFREQ_GOV_SIMPLE_ONDEMAND +help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency + for the memory controller and reads the usage counts from hardware. + diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile new file mode 100644 index 000..caca525 --- /dev/null +++ b/drivers/devfreq/rockchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ)+= rockchip_dmc.o +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)+= rk3399_dmc.o diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c new file mode 100644 index 000..f1d6120 --- /dev/null +++ b/drivers/devfreq/rockchip/rk3399_dmc.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../../firmware/rockchip_sip.h" + +struct dram_timing { +unsigned int ddr3_speed_bin; +unsigned int pd_idle; +unsigned int sr_idle; +unsigned int sr_mc_gate_idle; +unsigned int srpd_lite_idle;
Re: [PATCH v3 1/7] firmware: rockchip: sip: Add rockchip SIP runtime service
Hi Sudeep Holla, On 2016年07月26日 01:36, Sudeep Holla wrote: On 22/07/16 21:50, Heiko Stübner wrote: Hi again, one bigger thing I noticed only now. Am Freitag, 22. Juli 2016, 17:07:14 schrieben Sie: diff --git a/drivers/firmware/rockchip_sip.c b/drivers/firmware/rockchip_sip.c new file mode 100644 index 000..7756af9 --- /dev/null +++ b/drivers/firmware/rockchip_sip.c @@ -0,0 +1,64 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2016 ARM Limited + */ +#include +#include +#include +#include +#include +#include "rockchip_sip.h" + +typedef unsigned long (psci_fn)(unsigned long, unsigned long, +unsigned long, unsigned long); +asmlinkage psci_fn __invoke_psci_fn_smc; + +#define CONFIG_DRAM_INIT0x00 +#define CONFIG_DRAM_SET_RATE0x01 +#define CONFIG_DRAM_ROUND_RATE0x02 +#define CONFIG_DRAM_SET_AT_SR0x03 +#define CONFIG_DRAM_GET_BW0x04 +#define CONFIG_DRAM_GET_RATE0x05 +#define CONFIG_DRAM_CLR_IRQ0x06 +#define CONFIG_DRAM_SET_PARAM 0x07 + +uint64_t sip_smc_ddr_init(void) +{ +return __invoke_psci_fn_smc(SIP_DDR_FREQ, 0, +0, CONFIG_DRAM_INIT); I don't think that is legal to use. For one this function itself is declared static in the psci code - most likely for a specific reason. And also if anything invoke_psci_fn would hold the correct pointer depending on the calling method. But as said above, accessing psci static stuff is most likely wrong. Maybe the two psci people I've included can tell us how this is to be accessed. Thanks Heiko for looping us in this thread. The feature being added in this series is completely out of scope of PSCI specification and hence PSCI can't be used. Firstly we need to audit if these are need in Linux and why they can't be handled within the existing PSCI APIs. But yes, this series is misuse of PSCI. I also see to know that ARM Trusted Firmware community has not accepted this PSCI approach, so this patches are useless without that. If they are still needed they need to make use of SMC Calling Convention (arm_smccc_smc). Either make these smc function identifiers standard on their platforms and use them directly in the driver. If they tend to change too much across their platforms, use the DT approach with appropriate bindings. Thanks for your suggestion, i will update the code in next version. -- Lin Huang
Re: [PATCH v3 1/7] firmware: rockchip: sip: Add rockchip SIP runtime service
Hi Sudeep Holla, On 2016年07月26日 01:36, Sudeep Holla wrote: On 22/07/16 21:50, Heiko Stübner wrote: Hi again, one bigger thing I noticed only now. Am Freitag, 22. Juli 2016, 17:07:14 schrieben Sie: diff --git a/drivers/firmware/rockchip_sip.c b/drivers/firmware/rockchip_sip.c new file mode 100644 index 000..7756af9 --- /dev/null +++ b/drivers/firmware/rockchip_sip.c @@ -0,0 +1,64 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2016 ARM Limited + */ +#include +#include +#include +#include +#include +#include "rockchip_sip.h" + +typedef unsigned long (psci_fn)(unsigned long, unsigned long, +unsigned long, unsigned long); +asmlinkage psci_fn __invoke_psci_fn_smc; + +#define CONFIG_DRAM_INIT0x00 +#define CONFIG_DRAM_SET_RATE0x01 +#define CONFIG_DRAM_ROUND_RATE0x02 +#define CONFIG_DRAM_SET_AT_SR0x03 +#define CONFIG_DRAM_GET_BW0x04 +#define CONFIG_DRAM_GET_RATE0x05 +#define CONFIG_DRAM_CLR_IRQ0x06 +#define CONFIG_DRAM_SET_PARAM 0x07 + +uint64_t sip_smc_ddr_init(void) +{ +return __invoke_psci_fn_smc(SIP_DDR_FREQ, 0, +0, CONFIG_DRAM_INIT); I don't think that is legal to use. For one this function itself is declared static in the psci code - most likely for a specific reason. And also if anything invoke_psci_fn would hold the correct pointer depending on the calling method. But as said above, accessing psci static stuff is most likely wrong. Maybe the two psci people I've included can tell us how this is to be accessed. Thanks Heiko for looping us in this thread. The feature being added in this series is completely out of scope of PSCI specification and hence PSCI can't be used. Firstly we need to audit if these are need in Linux and why they can't be handled within the existing PSCI APIs. But yes, this series is misuse of PSCI. I also see to know that ARM Trusted Firmware community has not accepted this PSCI approach, so this patches are useless without that. If they are still needed they need to make use of SMC Calling Convention (arm_smccc_smc). Either make these smc function identifiers standard on their platforms and use them directly in the driver. If they tend to change too much across their platforms, use the DT approach with appropriate bindings. Thanks for your suggestion, i will update the code in next version. -- Lin Huang
Re: [PATCH v3 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, On 2016年07月25日 14:01, Chanwoo Choi wrote: Hi Lin, I'm glad to support the for dmc ddr clock scaling with devfreq/devfreq-event. But, I think that you have to use the standard interface. As I already mentioned[1] on previous mail, devfreq fwk support the standard DEVFREQ_TRANSITION_NOTIFIER notifier which has the two notifications. - DEVFREQ_PRECHANGE - DEVFREQ_POSTCHANGE [1] https://patchwork.kernel.org/patch/9194305/ You can use the DEVFREQ_PRECHANGE instead of DMCFREQ_ADJUST and use the DEVFREQ_POSTCHANGE instead of DMCFREQ_FINISH. On 2016년 07월 22일 18:07, Lin Huang wrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang--- Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 15 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 482 drivers/devfreq/rockchip/rockchip_dmc.c | 143 ++ include/soc/rockchip/rockchip_dmc.h | 45 +++ 7 files changed, 689 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index a5be56e..cb67246 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -101,5 +101,6 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" +source "drivers/devfreq/rockchip/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 09f11d9..48e2ae6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT)+= event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..7fb1cff --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,15 @@ +config ARM_ROCKCHIP_DMC_DEVFREQ + bool "ARM ROCKCHIP DMC DEVFREQ Driver" + depends on ARCH_ROCKCHIP + help + This adds the DEVFREQ driver framework for the rockchip dmc. + +config ARM_RK3399_DMC_DEVFREQ + bool "ARM RK3399 DMC DEVFREQ Driver" + depends on ARM_ROCKCHIP_DMC_DEVFREQ + select PM_OPP + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency + for the memory controller and reads the usage counts from hardware. + diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile new file mode 100644 index 000..caca525 --- /dev/null +++ b/drivers/devfreq/rockchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ) += rockchip_dmc.o +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c new file mode 100644 index 000..f1d6120 --- /dev/null +++ b/drivers/devfreq/rockchip/rk3399_dmc.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../../firmware/rockchip_sip.h" + +struct dram_timing { + unsigned int ddr3_speed_bin; + unsigned int pd_idle; + unsigned int sr_idle; + unsigned int sr_mc_gate_idle; + unsigned int srpd_lite_idle; + unsigned int standby_idle; + unsigned int
Re: [PATCH v3 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, On 2016年07月25日 14:01, Chanwoo Choi wrote: Hi Lin, I'm glad to support the for dmc ddr clock scaling with devfreq/devfreq-event. But, I think that you have to use the standard interface. As I already mentioned[1] on previous mail, devfreq fwk support the standard DEVFREQ_TRANSITION_NOTIFIER notifier which has the two notifications. - DEVFREQ_PRECHANGE - DEVFREQ_POSTCHANGE [1] https://patchwork.kernel.org/patch/9194305/ You can use the DEVFREQ_PRECHANGE instead of DMCFREQ_ADJUST and use the DEVFREQ_POSTCHANGE instead of DMCFREQ_FINISH. On 2016년 07월 22일 18:07, Lin Huang wrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang --- Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 15 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 482 drivers/devfreq/rockchip/rockchip_dmc.c | 143 ++ include/soc/rockchip/rockchip_dmc.h | 45 +++ 7 files changed, 689 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index a5be56e..cb67246 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -101,5 +101,6 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" +source "drivers/devfreq/rockchip/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 09f11d9..48e2ae6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT)+= event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..7fb1cff --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,15 @@ +config ARM_ROCKCHIP_DMC_DEVFREQ + bool "ARM ROCKCHIP DMC DEVFREQ Driver" + depends on ARCH_ROCKCHIP + help + This adds the DEVFREQ driver framework for the rockchip dmc. + +config ARM_RK3399_DMC_DEVFREQ + bool "ARM RK3399 DMC DEVFREQ Driver" + depends on ARM_ROCKCHIP_DMC_DEVFREQ + select PM_OPP + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency + for the memory controller and reads the usage counts from hardware. + diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile new file mode 100644 index 000..caca525 --- /dev/null +++ b/drivers/devfreq/rockchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ) += rockchip_dmc.o +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c new file mode 100644 index 000..f1d6120 --- /dev/null +++ b/drivers/devfreq/rockchip/rk3399_dmc.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../../firmware/rockchip_sip.h" + +struct dram_timing { + unsigned int ddr3_speed_bin; + unsigned int pd_idle; + unsigned int sr_idle; + unsigned int sr_mc_gate_idle; + unsigned int srpd_lite_idle; + unsigned int standby_idle; + unsigned int dram_dll_dis_freq; + unsigned int
Re: [PATCH v3 1/7] firmware: rockchip: sip: Add rockchip SIP runtime service
Hi Heiko, On 2016年07月23日 04:50, Heiko Stübner wrote: Hi again, one bigger thing I noticed only now. Am Freitag, 22. Juli 2016, 17:07:14 schrieben Sie: diff --git a/drivers/firmware/rockchip_sip.c b/drivers/firmware/rockchip_sip.c new file mode 100644 index 000..7756af9 --- /dev/null +++ b/drivers/firmware/rockchip_sip.c @@ -0,0 +1,64 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2016 ARM Limited + */ +#include +#include +#include +#include +#include +#include "rockchip_sip.h" + +typedef unsigned long (psci_fn)(unsigned long, unsigned long, + unsigned long, unsigned long); +asmlinkage psci_fn __invoke_psci_fn_smc; + +#define CONFIG_DRAM_INIT 0x00 +#define CONFIG_DRAM_SET_RATE 0x01 +#define CONFIG_DRAM_ROUND_RATE 0x02 +#define CONFIG_DRAM_SET_AT_SR 0x03 +#define CONFIG_DRAM_GET_BW 0x04 +#define CONFIG_DRAM_GET_RATE 0x05 +#define CONFIG_DRAM_CLR_IRQ0x06 +#define CONFIG_DRAM_SET_PARAM 0x07 + +uint64_t sip_smc_ddr_init(void) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, 0, + 0, CONFIG_DRAM_INIT); I don't think that is legal to use. For one this function itself is declared static in the psci code - most likely for a specific reason. And also if anything invoke_psci_fn would hold the correct pointer depending on the calling method. But as said above, accessing psci static stuff is most likely wrong. Maybe the two psci people I've included can tell us how this is to be accessed. Thanks Heiko. Hope Sudeep Holla and Lorenzo Pieralisi can give me advice. Heiko +} + +uint64_t sip_smc_set_ddr_param(uint64_t param) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, param, + 0, CONFIG_DRAM_SET_PARAM); +} + +uint64_t sip_smc_set_ddr_rate(uint64_t rate) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, rate, 0, + CONFIG_DRAM_SET_RATE); +} + +uint64_t sip_smc_get_ddr_rate(void) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, 0, 0, CONFIG_DRAM_GET_RATE); +} + +uint64_t sip_smc_clr_ddr_irq(void) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, 0, 0, CONFIG_DRAM_CLR_IRQ); +} + +uint64_t sip_smc_get_call_count(void) +{ + return __invoke_psci_fn_smc(SIP_SVC_CALL_COUNT, 0, 0, 0); +} ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang
Re: [PATCH v3 1/7] firmware: rockchip: sip: Add rockchip SIP runtime service
Hi Heiko, On 2016年07月23日 04:50, Heiko Stübner wrote: Hi again, one bigger thing I noticed only now. Am Freitag, 22. Juli 2016, 17:07:14 schrieben Sie: diff --git a/drivers/firmware/rockchip_sip.c b/drivers/firmware/rockchip_sip.c new file mode 100644 index 000..7756af9 --- /dev/null +++ b/drivers/firmware/rockchip_sip.c @@ -0,0 +1,64 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2016 ARM Limited + */ +#include +#include +#include +#include +#include +#include "rockchip_sip.h" + +typedef unsigned long (psci_fn)(unsigned long, unsigned long, + unsigned long, unsigned long); +asmlinkage psci_fn __invoke_psci_fn_smc; + +#define CONFIG_DRAM_INIT 0x00 +#define CONFIG_DRAM_SET_RATE 0x01 +#define CONFIG_DRAM_ROUND_RATE 0x02 +#define CONFIG_DRAM_SET_AT_SR 0x03 +#define CONFIG_DRAM_GET_BW 0x04 +#define CONFIG_DRAM_GET_RATE 0x05 +#define CONFIG_DRAM_CLR_IRQ0x06 +#define CONFIG_DRAM_SET_PARAM 0x07 + +uint64_t sip_smc_ddr_init(void) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, 0, + 0, CONFIG_DRAM_INIT); I don't think that is legal to use. For one this function itself is declared static in the psci code - most likely for a specific reason. And also if anything invoke_psci_fn would hold the correct pointer depending on the calling method. But as said above, accessing psci static stuff is most likely wrong. Maybe the two psci people I've included can tell us how this is to be accessed. Thanks Heiko. Hope Sudeep Holla and Lorenzo Pieralisi can give me advice. Heiko +} + +uint64_t sip_smc_set_ddr_param(uint64_t param) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, param, + 0, CONFIG_DRAM_SET_PARAM); +} + +uint64_t sip_smc_set_ddr_rate(uint64_t rate) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, rate, 0, + CONFIG_DRAM_SET_RATE); +} + +uint64_t sip_smc_get_ddr_rate(void) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, 0, 0, CONFIG_DRAM_GET_RATE); +} + +uint64_t sip_smc_clr_ddr_irq(void) +{ + return __invoke_psci_fn_smc(SIP_DDR_FREQ, 0, 0, CONFIG_DRAM_CLR_IRQ); +} + +uint64_t sip_smc_get_call_count(void) +{ + return __invoke_psci_fn_smc(SIP_SVC_CALL_COUNT, 0, 0, 0); +} ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang
Re: [PATCH v3 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Paul, On 2016年07月23日 04:24, Paul Gortmaker wrote: On Fri, Jul 22, 2016 at 5:07 AM, Lin Huangwrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang --- Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 15 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 482 drivers/devfreq/rockchip/rockchip_dmc.c | 143 ++ include/soc/rockchip/rockchip_dmc.h | 45 +++ 7 files changed, 689 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index a5be56e..cb67246 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -101,5 +101,6 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" +source "drivers/devfreq/rockchip/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 09f11d9..48e2ae6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ)+= tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..7fb1cff --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,15 @@ +config ARM_ROCKCHIP_DMC_DEVFREQ + bool "ARM ROCKCHIP DMC DEVFREQ Driver" + depends on ARCH_ROCKCHIP + help + This adds the DEVFREQ driver framework for the rockchip dmc. + +config ARM_RK3399_DMC_DEVFREQ + bool "ARM RK3399 DMC DEVFREQ Driver" Since you are using bool Kconfigs for your driver, please do not use module.h or MODULE_ tags in your driver, and use the builtin register function. Alternatively if there really is a use case for it to be a modular driver then use a tristate Kconfig. Thanks for pointing it, will fix it next version. THanks, Paul. -- + depends on ARM_ROCKCHIP_DMC_DEVFREQ + select PM_OPP + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency + for the memory controller and reads the usage counts from hardware. + ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang
Re: [PATCH v3 6/7] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Paul, On 2016年07月23日 04:24, Paul Gortmaker wrote: On Fri, Jul 22, 2016 at 5:07 AM, Lin Huang wrote: base on dfi result, we do ddr frequency scaling, register dmc driver to devfreq framework, and use simple-ondemand policy. Signed-off-by: Lin Huang --- Changes in v3: - operate dram setting through sip call - imporve set rate flow Changes in v2: - None Changes in v1: - move dfi controller to event - fix set voltage sequence when set rate fail - change Kconfig type from tristate to bool - move unuse EXPORT_SYMBOL_GPL() drivers/devfreq/Kconfig | 1 + drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 15 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 482 drivers/devfreq/rockchip/rockchip_dmc.c | 143 ++ include/soc/rockchip/rockchip_dmc.h | 45 +++ 7 files changed, 689 insertions(+) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index a5be56e..cb67246 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -101,5 +101,6 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" +source "drivers/devfreq/rockchip/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 09f11d9..48e2ae6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ)+= tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..7fb1cff --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,15 @@ +config ARM_ROCKCHIP_DMC_DEVFREQ + bool "ARM ROCKCHIP DMC DEVFREQ Driver" + depends on ARCH_ROCKCHIP + help + This adds the DEVFREQ driver framework for the rockchip dmc. + +config ARM_RK3399_DMC_DEVFREQ + bool "ARM RK3399 DMC DEVFREQ Driver" Since you are using bool Kconfigs for your driver, please do not use module.h or MODULE_ tags in your driver, and use the builtin register function. Alternatively if there really is a use case for it to be a modular driver then use a tristate Kconfig. Thanks for pointing it, will fix it next version. THanks, Paul. -- + depends on ARM_ROCKCHIP_DMC_DEVFREQ + select PM_OPP + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency + for the memory controller and reads the usage counts from hardware. + ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang
Re: [RFC PATCH v1 4/6] PM / devfreq: event: support rockchip dfi controller
Hi Thierry, On 2016年06月04日 00:54, Thierry Reding wrote: On Fri, Jun 03, 2016 at 05:55:17PM +0800, Lin Huang wrote: [...] + ret = clk_prepare_enable(data->clk); + if (ret) { + dev_err(>dev, "failed to enable clk: %d\n", ret); + clk_disable_unprepare(data->clk); + return ret; + } This is going to give you a large WARN. clk_prepare_enable() already leaves the clock in a proper state when it fails (i.e. it calls clk_unprepare() if the clk_enable() part failed), so calling clk_disable_unprepare() upon failure is going to unbalance the reference counts. Thanks for reminding, i will fix it next version. Thierry -- Lin Huang
Re: [RFC PATCH v1 4/6] PM / devfreq: event: support rockchip dfi controller
Hi Thierry, On 2016年06月04日 00:54, Thierry Reding wrote: On Fri, Jun 03, 2016 at 05:55:17PM +0800, Lin Huang wrote: [...] + ret = clk_prepare_enable(data->clk); + if (ret) { + dev_err(>dev, "failed to enable clk: %d\n", ret); + clk_disable_unprepare(data->clk); + return ret; + } This is going to give you a large WARN. clk_prepare_enable() already leaves the clock in a proper state when it fails (i.e. it calls clk_unprepare() if the clk_enable() part failed), so calling clk_disable_unprepare() upon failure is going to unbalance the reference counts. Thanks for reminding, i will fix it next version. Thierry -- Lin Huang
Re: [RFC PATCH v1 4/6] PM / devfreq: event: support rockchip dfi controller
On 2016年06月03日 18:26, Chanwoo Choi wrote: Hi Lin, I add the some comment on below. If you modify it, You can add my acked-by tag. Looks good to me. Thanks for you reviewing, i will update the code folloiwing your comment. Acked-by: Chanwoo ChoiAlso, I'd like you to add me to mail thread on next version because I'm supporter of devfreq-event. I am sorry for missing you mail in before patch:-[ , will add you to mail thread next vesion. On 2016년 06월 03일 18:55, Lin Huang wrote: on rk3399 platform, there is dfi conroller can monitor ddr load, base on this result, we can do ddr freqency scaling. Signed-off-by: Lin Huang --- Changes in v1: - NOne drivers/devfreq/event/Kconfig| 7 + drivers/devfreq/event/Makefile | 1 + drivers/devfreq/event/rockchip-dfi.c | 265 +++ 3 files changed, 273 insertions(+) create mode 100644 drivers/devfreq/event/rockchip-dfi.c diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig index 1e8b4f4..6ebdc13 100644 --- a/drivers/devfreq/event/Kconfig +++ b/drivers/devfreq/event/Kconfig @@ -30,4 +30,11 @@ config DEVFREQ_EVENT_EXYNOS_PPMU (Platform Performance Monitoring Unit) counters to estimate the utilization of each module. +config DEVFREQ_EVENT_ROCKCHIP_DFI + bool "ROCKCHIP DFI DEVFREQ event Driver" + depends on ARCH_ROCKCHIP + help + This add the devfreq-event driver for Rockchip SoC. It provides DFI You better to full name of 'DFI' abbreviation as following: - DFI (Dxxx Fxxx Ixxx) + driver to count ddr load. + endif # PM_DEVFREQ_EVENT diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile index 3d6afd3..dda7090 100644 --- a/drivers/devfreq/event/Makefile +++ b/drivers/devfreq/event/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP) += exynos-nocp.o obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o +obj-$(CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI) += rockchip-dfi.o diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c new file mode 100644 index 000..e3b020f9 --- /dev/null +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RK3399_DMC_NUM_CH 2 + +/* DDRMON_CTRL */ +#define DDRMON_CTRL0x04 +#define CLR_DDRMON_CTRL(0x1f << 0) +#define LPDDR4_EN (0x10001 << 4) +#define HARDWARE_EN(0x10001 << 3) +#define LPDDR3_EN (0x10001 << 2) +#define SOFTWARE_EN(0x10001 << 1) +#define TIME_CNT_EN(0x10001 << 0) + +#define DDRMON_CH0_COUNT_NUM 0x28 +#define DDRMON_CH0_DFI_ACCESS_NUM 0x2c +#define DDRMON_CH1_COUNT_NUM 0x3c +#define DDRMON_CH1_DFI_ACCESS_NUM 0x40 + +/* pmu grf */ +#define PMUGRF_OS_REG2 0x308 +#define DDRTYPE_SHIFT 13 +#define DDRTYPE_MASK 7 + +enum { + DDR3 = 3, + LPDDR3 = 6, + LPDDR4 = 7, + UNUSED = 0xFF +}; + +struct dmc_usage { + u32 access; + u32 total; +}; + +struct rockchip_dfi { + struct devfreq_event_dev *edev; + struct devfreq_event_desc *desc; + struct dmc_usage ch_usage[RK3399_DMC_NUM_CH]; + struct device *dev; + void __iomem *regs; + struct regmap *regmap_pmu; + struct clk *clk; +}; + +static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) +{ + struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); + void __iomem *dfi_regs = info->regs; + u32 val; + u32 ddr_type; + + /* get ddr type */ + regmap_read(info->regmap_pmu, PMUGRF_OS_REG2, ); + ddr_type = (val >> DDRTYPE_SHIFT) & DDRTYPE_MASK; + + /* clear DDRMON_CTRL setting */ + writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); + + /* set ddr type to dfi */ + if (ddr_type == LPDDR3) + writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL); + else if (ddr_type == LPDDR4) + writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL); + + /* enable count, use software mode */ + writel_relaxed(SOFTWARE_EN, dfi_regs + DDRMON_CTRL); +} + +static void rockchip_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) +{ + struct rockchip_dfi
Re: [RFC PATCH v1 4/6] PM / devfreq: event: support rockchip dfi controller
On 2016年06月03日 18:26, Chanwoo Choi wrote: Hi Lin, I add the some comment on below. If you modify it, You can add my acked-by tag. Looks good to me. Thanks for you reviewing, i will update the code folloiwing your comment. Acked-by: Chanwoo Choi Also, I'd like you to add me to mail thread on next version because I'm supporter of devfreq-event. I am sorry for missing you mail in before patch:-[ , will add you to mail thread next vesion. On 2016년 06월 03일 18:55, Lin Huang wrote: on rk3399 platform, there is dfi conroller can monitor ddr load, base on this result, we can do ddr freqency scaling. Signed-off-by: Lin Huang --- Changes in v1: - NOne drivers/devfreq/event/Kconfig| 7 + drivers/devfreq/event/Makefile | 1 + drivers/devfreq/event/rockchip-dfi.c | 265 +++ 3 files changed, 273 insertions(+) create mode 100644 drivers/devfreq/event/rockchip-dfi.c diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig index 1e8b4f4..6ebdc13 100644 --- a/drivers/devfreq/event/Kconfig +++ b/drivers/devfreq/event/Kconfig @@ -30,4 +30,11 @@ config DEVFREQ_EVENT_EXYNOS_PPMU (Platform Performance Monitoring Unit) counters to estimate the utilization of each module. +config DEVFREQ_EVENT_ROCKCHIP_DFI + bool "ROCKCHIP DFI DEVFREQ event Driver" + depends on ARCH_ROCKCHIP + help + This add the devfreq-event driver for Rockchip SoC. It provides DFI You better to full name of 'DFI' abbreviation as following: - DFI (Dxxx Fxxx Ixxx) + driver to count ddr load. + endif # PM_DEVFREQ_EVENT diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile index 3d6afd3..dda7090 100644 --- a/drivers/devfreq/event/Makefile +++ b/drivers/devfreq/event/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP) += exynos-nocp.o obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o +obj-$(CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI) += rockchip-dfi.o diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c new file mode 100644 index 000..e3b020f9 --- /dev/null +++ b/drivers/devfreq/event/rockchip-dfi.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RK3399_DMC_NUM_CH 2 + +/* DDRMON_CTRL */ +#define DDRMON_CTRL0x04 +#define CLR_DDRMON_CTRL(0x1f << 0) +#define LPDDR4_EN (0x10001 << 4) +#define HARDWARE_EN(0x10001 << 3) +#define LPDDR3_EN (0x10001 << 2) +#define SOFTWARE_EN(0x10001 << 1) +#define TIME_CNT_EN(0x10001 << 0) + +#define DDRMON_CH0_COUNT_NUM 0x28 +#define DDRMON_CH0_DFI_ACCESS_NUM 0x2c +#define DDRMON_CH1_COUNT_NUM 0x3c +#define DDRMON_CH1_DFI_ACCESS_NUM 0x40 + +/* pmu grf */ +#define PMUGRF_OS_REG2 0x308 +#define DDRTYPE_SHIFT 13 +#define DDRTYPE_MASK 7 + +enum { + DDR3 = 3, + LPDDR3 = 6, + LPDDR4 = 7, + UNUSED = 0xFF +}; + +struct dmc_usage { + u32 access; + u32 total; +}; + +struct rockchip_dfi { + struct devfreq_event_dev *edev; + struct devfreq_event_desc *desc; + struct dmc_usage ch_usage[RK3399_DMC_NUM_CH]; + struct device *dev; + void __iomem *regs; + struct regmap *regmap_pmu; + struct clk *clk; +}; + +static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) +{ + struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); + void __iomem *dfi_regs = info->regs; + u32 val; + u32 ddr_type; + + /* get ddr type */ + regmap_read(info->regmap_pmu, PMUGRF_OS_REG2, ); + ddr_type = (val >> DDRTYPE_SHIFT) & DDRTYPE_MASK; + + /* clear DDRMON_CTRL setting */ + writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); + + /* set ddr type to dfi */ + if (ddr_type == LPDDR3) + writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL); + else if (ddr_type == LPDDR4) + writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL); + + /* enable count, use software mode */ + writel_relaxed(SOFTWARE_EN, dfi_regs + DDRMON_CTRL); +} + +static void rockchip_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) +{ + struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); + void __iomem
Re: [RFC PATCH v1 1/6] rockchip: rockchip: add new clock-type for the ddrclk
Hi Heiko, On 2016年06月03日 20:51, Heiko Stübner wrote: Am Freitag, 3. Juni 2016, 17:55:14 schrieb Lin Huang: On new rockchip platform(rk3399 etc), there have dcf controller to do ddr frequency scaling, and this controller will implement in arm-trust-firmware. We add a special clock-type to handle that. Signed-off-by: Lin Huang--- Changes in v1: - None drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-ddr.c | 147 + drivers/clk/rockchip/clk.c | 9 +++ drivers/clk/rockchip/clk.h | 27 4 files changed, 184 insertions(+) create mode 100644 drivers/clk/rockchip/clk-ddr.c diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index f47a2fa..b5f2c8e 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,6 +8,7 @@ obj-y += clk-pll.o obj-y += clk-cpu.o obj-y += clk-inverter.o obj-y += clk-mmc-phase.o +obj-y += clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER)+= softrst.o obj-y += clk-rk3036.o diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c new file mode 100644 index 000..5b6630d --- /dev/null +++ b/drivers/clk/rockchip/clk-ddr.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "clk.h" + +struct rockchip_ddrclk { + struct clk_hw hw; + void __iomem*reg_base; + int mux_offset; + int mux_shift; + int mux_width; + int mux_flag; + int div_shift; + int div_width; + int div_flag; + spinlock_t *lock; +}; + +#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw) +#define val_mask(width)((1 << (width)) - 1) maybe use GENMASK? Oh, yes, we can use it. Will fix next version. + +static int rockchip_ddrclk_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + unsigned long flags; + + spin_lock_irqsave(ddrclk->lock, flags); + + /* TODO: set ddr rate in bl31 */ I expect this interface to be in existence and merged into the main ATF first. Right now the whole clock-type does nothing more than a simple COMPOSITE with added CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY. Also Mike is propably still working in the so called coordinated rate change for clocks needing special handling on rate changes, which might provide a second approach to this. You mean there is a patch set can handle it now? Can you tell me the ID, I want to check it. So please, first of all get the ATF-interface merged and meanwhile if you need to read the clock-rate, just use a regular composite, with the read-only flags. My colleague are wroking on ATF code now, I agree with you, We can not merge this patch set before ATF-interface merged. And we do not need to add a new code if we only want to read ddr clock rate(we can get the ddr rate to read dpll), so i prefer to keep this function for now, and do review first, once the ATF code ready, we can merge soon(i hope :-P ) . + spin_unlock_irqrestore(ddrclk->lock, flags); + + return 0; +} + +static unsigned long +rockchip_ddrclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + int val; + + val = clk_readl(ddrclk->reg_base + + ddrclk->mux_offset) >> ddrclk->div_shift; + val &= val_mask(ddrclk->div_width); + + return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); return divider_recalc_rate(...) got it , thank you. Heiko -- Lin Huang
Re: [RFC PATCH v1 1/6] rockchip: rockchip: add new clock-type for the ddrclk
Hi Heiko, On 2016年06月03日 20:51, Heiko Stübner wrote: Am Freitag, 3. Juni 2016, 17:55:14 schrieb Lin Huang: On new rockchip platform(rk3399 etc), there have dcf controller to do ddr frequency scaling, and this controller will implement in arm-trust-firmware. We add a special clock-type to handle that. Signed-off-by: Lin Huang --- Changes in v1: - None drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-ddr.c | 147 + drivers/clk/rockchip/clk.c | 9 +++ drivers/clk/rockchip/clk.h | 27 4 files changed, 184 insertions(+) create mode 100644 drivers/clk/rockchip/clk-ddr.c diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index f47a2fa..b5f2c8e 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,6 +8,7 @@ obj-y += clk-pll.o obj-y += clk-cpu.o obj-y += clk-inverter.o obj-y += clk-mmc-phase.o +obj-y += clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER)+= softrst.o obj-y += clk-rk3036.o diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c new file mode 100644 index 000..5b6630d --- /dev/null +++ b/drivers/clk/rockchip/clk-ddr.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "clk.h" + +struct rockchip_ddrclk { + struct clk_hw hw; + void __iomem*reg_base; + int mux_offset; + int mux_shift; + int mux_width; + int mux_flag; + int div_shift; + int div_width; + int div_flag; + spinlock_t *lock; +}; + +#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw) +#define val_mask(width)((1 << (width)) - 1) maybe use GENMASK? Oh, yes, we can use it. Will fix next version. + +static int rockchip_ddrclk_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + unsigned long flags; + + spin_lock_irqsave(ddrclk->lock, flags); + + /* TODO: set ddr rate in bl31 */ I expect this interface to be in existence and merged into the main ATF first. Right now the whole clock-type does nothing more than a simple COMPOSITE with added CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY. Also Mike is propably still working in the so called coordinated rate change for clocks needing special handling on rate changes, which might provide a second approach to this. You mean there is a patch set can handle it now? Can you tell me the ID, I want to check it. So please, first of all get the ATF-interface merged and meanwhile if you need to read the clock-rate, just use a regular composite, with the read-only flags. My colleague are wroking on ATF code now, I agree with you, We can not merge this patch set before ATF-interface merged. And we do not need to add a new code if we only want to read ddr clock rate(we can get the ddr rate to read dpll), so i prefer to keep this function for now, and do review first, once the ATF code ready, we can merge soon(i hope :-P ) . + spin_unlock_irqrestore(ddrclk->lock, flags); + + return 0; +} + +static unsigned long +rockchip_ddrclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + int val; + + val = clk_readl(ddrclk->reg_base + + ddrclk->mux_offset) >> ddrclk->div_shift; + val &= val_mask(ddrclk->div_width); + + return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); return divider_recalc_rate(...) got it , thank you. Heiko -- Lin Huang
Re: [RFC PATCH v1 3/6] clk: rockchip: rk3399: add ddrc clock support
Hi Heiko, On 2016年06月03日 20:56, Heiko Stübner wrote: Am Freitag, 3. Juni 2016, 17:55:16 schrieb Lin Huang: add ddrc clock setting, so we can do ddr frequency scaling on rk3399 platform in future. Signed-off-by: Lin Huang--- Changes in v1: - remove ddrc source CLK_IGNORE_UNUSED flag, Suggestion by Doug - move clk_ddrc and clk_ddrc_dpll_src to critical, Suggestion by Doug drivers/clk/rockchip/clk-rk3399.c | 20 1 file changed, 20 insertions(+) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index f1d8e44..29afb88 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c [...] @@ -1377,6 +1381,18 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED, RK3368_CLKSEL_CON(58), 0, 5, DFLAGS, RK3368_CLKGATE_CON(13), 11, GFLAGS), + + /* ddrc */ + GATE(0, "clk_ddrc_lpll_src", "lpll", 0, RK3399_CLKGATE_CON(3), +0, GFLAGS), + GATE(0, "clk_ddrc_bpll_src", "bpll", 0, RK3399_CLKGATE_CON(3), +1, GFLAGS), + GATE(0, "clk_ddrc_dpll_src", "dpll", 0, RK3399_CLKGATE_CON(3), +2, GFLAGS), + GATE(0, "clk_ddrc_gpll_src", "gpll", 0, RK3399_CLKGATE_CON(3), +3, GFLAGS), + COMPOSITE_DDRC(SCLK_DDRCLK, "clk_ddrc", mux_ddrclk_p, 0, + RK3399_CLKSEL_CON(6), 4, 2, MFLAGS, 0, 3, DFLAGS), }; as said in the other patch, just make this a regular COMPOSITE_NOGATE with CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY until that interface to the ATF exists and is approved. That way you can still read back the clock rate without anything changing the clock-rate, but we don't need to add duplicate code for it. static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { @@ -1487,6 +1503,10 @@ static const char *const rk3399_cru_critical_clocks[] __initconst = { "gpll_hclk_perilp1_src", "gpll_aclk_perilp0_src", "gpll_aclk_perihp_src", + + /* ddrc */ + "clk_ddrc_dpll_src", Why does your clk_ddrc_dpll_src need a separate critical entry. Any code changing the clk_ddrc parent should make sure the new parent is enabled. (The clock-framework of course does this already). Okay, thank you. + "clk_ddrc", }; static const char *const rk3399_pmucru_critical_clocks[] __initconst = { Heiko -- Lin Huang
Re: [RFC PATCH v1 3/6] clk: rockchip: rk3399: add ddrc clock support
Hi Heiko, On 2016年06月03日 20:56, Heiko Stübner wrote: Am Freitag, 3. Juni 2016, 17:55:16 schrieb Lin Huang: add ddrc clock setting, so we can do ddr frequency scaling on rk3399 platform in future. Signed-off-by: Lin Huang --- Changes in v1: - remove ddrc source CLK_IGNORE_UNUSED flag, Suggestion by Doug - move clk_ddrc and clk_ddrc_dpll_src to critical, Suggestion by Doug drivers/clk/rockchip/clk-rk3399.c | 20 1 file changed, 20 insertions(+) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index f1d8e44..29afb88 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c [...] @@ -1377,6 +1381,18 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED, RK3368_CLKSEL_CON(58), 0, 5, DFLAGS, RK3368_CLKGATE_CON(13), 11, GFLAGS), + + /* ddrc */ + GATE(0, "clk_ddrc_lpll_src", "lpll", 0, RK3399_CLKGATE_CON(3), +0, GFLAGS), + GATE(0, "clk_ddrc_bpll_src", "bpll", 0, RK3399_CLKGATE_CON(3), +1, GFLAGS), + GATE(0, "clk_ddrc_dpll_src", "dpll", 0, RK3399_CLKGATE_CON(3), +2, GFLAGS), + GATE(0, "clk_ddrc_gpll_src", "gpll", 0, RK3399_CLKGATE_CON(3), +3, GFLAGS), + COMPOSITE_DDRC(SCLK_DDRCLK, "clk_ddrc", mux_ddrclk_p, 0, + RK3399_CLKSEL_CON(6), 4, 2, MFLAGS, 0, 3, DFLAGS), }; as said in the other patch, just make this a regular COMPOSITE_NOGATE with CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY until that interface to the ATF exists and is approved. That way you can still read back the clock rate without anything changing the clock-rate, but we don't need to add duplicate code for it. static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { @@ -1487,6 +1503,10 @@ static const char *const rk3399_cru_critical_clocks[] __initconst = { "gpll_hclk_perilp1_src", "gpll_aclk_perilp0_src", "gpll_aclk_perihp_src", + + /* ddrc */ + "clk_ddrc_dpll_src", Why does your clk_ddrc_dpll_src need a separate critical entry. Any code changing the clk_ddrc parent should make sure the new parent is enabled. (The clock-framework of course does this already). Okay, thank you. + "clk_ddrc", }; static const char *const rk3399_pmucru_critical_clocks[] __initconst = { Heiko -- Lin Huang
Re: [RFC PATCH v1 1/6] rockchip: rockchip: add new clock-type for the ddrclk
Hi Heiko, On 2016年06月03日 20:51, Heiko Stübner wrote: Am Freitag, 3. Juni 2016, 17:55:14 schrieb Lin Huang: On new rockchip platform(rk3399 etc), there have dcf controller to do ddr frequency scaling, and this controller will implement in arm-trust-firmware. We add a special clock-type to handle that. Signed-off-by: Lin Huang--- Changes in v1: - None drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-ddr.c | 147 + drivers/clk/rockchip/clk.c | 9 +++ drivers/clk/rockchip/clk.h | 27 4 files changed, 184 insertions(+) create mode 100644 drivers/clk/rockchip/clk-ddr.c diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index f47a2fa..b5f2c8e 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,6 +8,7 @@ obj-y += clk-pll.o obj-y += clk-cpu.o obj-y += clk-inverter.o obj-y += clk-mmc-phase.o +obj-y += clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER)+= softrst.o obj-y += clk-rk3036.o diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c new file mode 100644 index 000..5b6630d --- /dev/null +++ b/drivers/clk/rockchip/clk-ddr.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "clk.h" + +struct rockchip_ddrclk { + struct clk_hw hw; + void __iomem*reg_base; + int mux_offset; + int mux_shift; + int mux_width; + int mux_flag; + int div_shift; + int div_width; + int div_flag; + spinlock_t *lock; +}; + +#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw) +#define val_mask(width)((1 << (width)) - 1) maybe use GENMASK? Oh, yes, we can use it. Will fix next version. + +static int rockchip_ddrclk_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + unsigned long flags; + + spin_lock_irqsave(ddrclk->lock, flags); + + /* TODO: set ddr rate in bl31 */ I expect this interface to be in existence and merged into the main ATF first. Right now the whole clock-type does nothing more than a simple COMPOSITE with added CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY. Also Mike is propably still working in the so called coordinated rate change for clocks needing special handling on rate changes, which might provide a second approach to this. You mean there is a patch set can handle it now? Can you tell me the ID, I want to check it. So please, first of all get the ATF-interface merged and meanwhile if you need to read the clock-rate, just use a regular composite, with the read-only flags. My colleague are wroking on ATF code now, I agree with you, We can not merge this patch set before ATF-interface merged. And we do not need to add a new code if we only want to read ddr clock rate(we can get the ddr rate to read dpll), so i prefer to keep this function for now, and do review first, once the ATF code ready, we can merge soon it(i hope :-P ) . + spin_unlock_irqrestore(ddrclk->lock, flags); + + return 0; +} + +static unsigned long +rockchip_ddrclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + int val; + + val = clk_readl(ddrclk->reg_base + + ddrclk->mux_offset) >> ddrclk->div_shift; + val &= val_mask(ddrclk->div_width); + + return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); return divider_recalc_rate(...) got it , thank you. Heiko -- Lin Huang
Re: [RFC PATCH v1 1/6] rockchip: rockchip: add new clock-type for the ddrclk
Hi Heiko, On 2016年06月03日 20:51, Heiko Stübner wrote: Am Freitag, 3. Juni 2016, 17:55:14 schrieb Lin Huang: On new rockchip platform(rk3399 etc), there have dcf controller to do ddr frequency scaling, and this controller will implement in arm-trust-firmware. We add a special clock-type to handle that. Signed-off-by: Lin Huang --- Changes in v1: - None drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-ddr.c | 147 + drivers/clk/rockchip/clk.c | 9 +++ drivers/clk/rockchip/clk.h | 27 4 files changed, 184 insertions(+) create mode 100644 drivers/clk/rockchip/clk-ddr.c diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index f47a2fa..b5f2c8e 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,6 +8,7 @@ obj-y += clk-pll.o obj-y += clk-cpu.o obj-y += clk-inverter.o obj-y += clk-mmc-phase.o +obj-y += clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER)+= softrst.o obj-y += clk-rk3036.o diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c new file mode 100644 index 000..5b6630d --- /dev/null +++ b/drivers/clk/rockchip/clk-ddr.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "clk.h" + +struct rockchip_ddrclk { + struct clk_hw hw; + void __iomem*reg_base; + int mux_offset; + int mux_shift; + int mux_width; + int mux_flag; + int div_shift; + int div_width; + int div_flag; + spinlock_t *lock; +}; + +#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw) +#define val_mask(width)((1 << (width)) - 1) maybe use GENMASK? Oh, yes, we can use it. Will fix next version. + +static int rockchip_ddrclk_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + unsigned long flags; + + spin_lock_irqsave(ddrclk->lock, flags); + + /* TODO: set ddr rate in bl31 */ I expect this interface to be in existence and merged into the main ATF first. Right now the whole clock-type does nothing more than a simple COMPOSITE with added CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY. Also Mike is propably still working in the so called coordinated rate change for clocks needing special handling on rate changes, which might provide a second approach to this. You mean there is a patch set can handle it now? Can you tell me the ID, I want to check it. So please, first of all get the ATF-interface merged and meanwhile if you need to read the clock-rate, just use a regular composite, with the read-only flags. My colleague are wroking on ATF code now, I agree with you, We can not merge this patch set before ATF-interface merged. And we do not need to add a new code if we only want to read ddr clock rate(we can get the ddr rate to read dpll), so i prefer to keep this function for now, and do review first, once the ATF code ready, we can merge soon it(i hope :-P ) . + spin_unlock_irqrestore(ddrclk->lock, flags); + + return 0; +} + +static unsigned long +rockchip_ddrclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); + int val; + + val = clk_readl(ddrclk->reg_base + + ddrclk->mux_offset) >> ddrclk->div_shift; + val &= val_mask(ddrclk->div_width); + + return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); return divider_recalc_rate(...) got it , thank you. Heiko -- Lin Huang
Re: [RFC PATCH v1 1/6] rockchip: rockchip: add new clock-type for the ddrclk
Hi Shawn, On 2016年06月03日 20:29, Shawn Lin wrote: Hi Lin, It looks good with only a few minor comments. On 2016/6/3 17:55, Lin Huang wrote: On new rockchip platform(rk3399 etc), there have dcf controller to do ddr frequency scaling, and this controller will implement in arm-trust-firmware. We add a special clock-type to handle that. Signed-off-by: Lin Huang--- Changes in v1: - None drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-ddr.c | 147 + drivers/clk/rockchip/clk.c | 9 +++ drivers/clk/rockchip/clk.h | 27 4 files changed, 184 insertions(+) create mode 100644 drivers/clk/rockchip/clk-ddr.c diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index f47a2fa..b5f2c8e 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,6 +8,7 @@ obj-y+= clk-pll.o obj-y+= clk-cpu.o obj-y+= clk-inverter.o obj-y+= clk-mmc-phase.o +obj-y+= clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER)+= softrst.o obj-y+= clk-rk3036.o diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c new file mode 100644 index 000..5b6630d --- /dev/null +++ b/drivers/clk/rockchip/clk-ddr.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "clk.h" + alphabetical order would be better. Okay, will fix next version, thank you. +struct rockchip_ddrclk { +struct clk_hwhw; +void __iomem*reg_base; +intmux_offset; +intmux_shift; +intmux_width; +intmux_flag; +intdiv_shift; +intdiv_width; +intdiv_flag; +spinlock_t*lock; +}; + +#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw) +#define val_mask(width)((1 << (width)) - 1) + +static int rockchip_ddrclk_set_rate(struct clk_hw *hw, unsigned long drate, +unsigned long prate) +{ +struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); +unsigned long flags; + +spin_lock_irqsave(ddrclk->lock, flags); + +/* TODO: set ddr rate in bl31 */ + +spin_unlock_irqrestore(ddrclk->lock, flags); + What do you wanna protect here? I am not sure for now, when i finish this function, if there nothing need protect i will remove it. Thank you. +return 0; +} + +static unsigned long +rockchip_ddrclk_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ +struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); +int val; + +val = clk_readl(ddrclk->reg_base + +ddrclk->mux_offset) >> ddrclk->div_shift; +val &= val_mask(ddrclk->div_width); + +return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); +} + +static long clk_ddrclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ +return rate; +} + +static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw) +{ +struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); +int num_parents = clk_hw_get_num_parents(hw); +u32 val; + +val = clk_readl(ddrclk->reg_base + +ddrclk->mux_offset) >> ddrclk->mux_shift; +val &= val_mask(ddrclk->mux_width); + +if (val >= num_parents) +return -EINVAL; + +return val; +} + +static const struct clk_ops rockchip_ddrclk_ops = { +.recalc_rate = rockchip_ddrclk_recalc_rate, +.set_rate = rockchip_ddrclk_set_rate, +.round_rate = clk_ddrclk_round_rate, +.get_parent = rockchip_ddrclk_get_parent, +}; + +struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, + const char *const *parent_names, + u8 num_parents, int mux_offset, + int mux_shift, int mux_width, + int mux_flag, int div_shift, + int div_width, int div_flag, + void __iomem *reg_base, + spinlock_t *lock) +{ +struct rockchip_ddrclk *ddrclk; +struct clk_init_data init; +struct clk *clk; +int ret; + +ddrclk = kzalloc(sizeof(*ddrclk), GFP_KERNEL); +if (!ddrclk) +return ERR_PTR(-ENOMEM); + +init.name = name; +init.parent_names = parent_names; +init.num_parents = num_parents; +init.ops =
Re: [RFC PATCH v1 1/6] rockchip: rockchip: add new clock-type for the ddrclk
Hi Shawn, On 2016年06月03日 20:29, Shawn Lin wrote: Hi Lin, It looks good with only a few minor comments. On 2016/6/3 17:55, Lin Huang wrote: On new rockchip platform(rk3399 etc), there have dcf controller to do ddr frequency scaling, and this controller will implement in arm-trust-firmware. We add a special clock-type to handle that. Signed-off-by: Lin Huang --- Changes in v1: - None drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-ddr.c | 147 + drivers/clk/rockchip/clk.c | 9 +++ drivers/clk/rockchip/clk.h | 27 4 files changed, 184 insertions(+) create mode 100644 drivers/clk/rockchip/clk-ddr.c diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index f47a2fa..b5f2c8e 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -8,6 +8,7 @@ obj-y+= clk-pll.o obj-y+= clk-cpu.o obj-y+= clk-inverter.o obj-y+= clk-mmc-phase.o +obj-y+= clk-ddr.o obj-$(CONFIG_RESET_CONTROLLER)+= softrst.o obj-y+= clk-rk3036.o diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c new file mode 100644 index 000..5b6630d --- /dev/null +++ b/drivers/clk/rockchip/clk-ddr.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 Rockchip Electronics Co. Ltd. + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "clk.h" + alphabetical order would be better. Okay, will fix next version, thank you. +struct rockchip_ddrclk { +struct clk_hwhw; +void __iomem*reg_base; +intmux_offset; +intmux_shift; +intmux_width; +intmux_flag; +intdiv_shift; +intdiv_width; +intdiv_flag; +spinlock_t*lock; +}; + +#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw) +#define val_mask(width)((1 << (width)) - 1) + +static int rockchip_ddrclk_set_rate(struct clk_hw *hw, unsigned long drate, +unsigned long prate) +{ +struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); +unsigned long flags; + +spin_lock_irqsave(ddrclk->lock, flags); + +/* TODO: set ddr rate in bl31 */ + +spin_unlock_irqrestore(ddrclk->lock, flags); + What do you wanna protect here? I am not sure for now, when i finish this function, if there nothing need protect i will remove it. Thank you. +return 0; +} + +static unsigned long +rockchip_ddrclk_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ +struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); +int val; + +val = clk_readl(ddrclk->reg_base + +ddrclk->mux_offset) >> ddrclk->div_shift; +val &= val_mask(ddrclk->div_width); + +return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1); +} + +static long clk_ddrclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ +return rate; +} + +static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw) +{ +struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw); +int num_parents = clk_hw_get_num_parents(hw); +u32 val; + +val = clk_readl(ddrclk->reg_base + +ddrclk->mux_offset) >> ddrclk->mux_shift; +val &= val_mask(ddrclk->mux_width); + +if (val >= num_parents) +return -EINVAL; + +return val; +} + +static const struct clk_ops rockchip_ddrclk_ops = { +.recalc_rate = rockchip_ddrclk_recalc_rate, +.set_rate = rockchip_ddrclk_set_rate, +.round_rate = clk_ddrclk_round_rate, +.get_parent = rockchip_ddrclk_get_parent, +}; + +struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, + const char *const *parent_names, + u8 num_parents, int mux_offset, + int mux_shift, int mux_width, + int mux_flag, int div_shift, + int div_width, int div_flag, + void __iomem *reg_base, + spinlock_t *lock) +{ +struct rockchip_ddrclk *ddrclk; +struct clk_init_data init; +struct clk *clk; +int ret; + +ddrclk = kzalloc(sizeof(*ddrclk), GFP_KERNEL); +if (!ddrclk) +return ERR_PTR(-ENOMEM); + +init.name = name; +init.parent_names = parent_names; +init.num_parents = num_parents; +init.ops = _ddrclk_ops; + +init.flags = flags; +
Re: [RFC PATCH 3/4] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, I just check the devfreq-event framework code, it is good, i will do more dig to see whether it can fit for rk3399 dmc, thank you. On 2016年06月01日 19:47, Chanwoo Choi wrote: Hi Lin, This patch include the two features as following: - Monitor the ddr load - Control the ddr's clock with ondemand governor based on load The "Monitor the ddr load" has the specific the address in SoC. Namely, it is separate the module. So, I implemented the devfreq-event framework[1] which was merged. It is right method to separate two feature from your device driver. You can refer to patch[2][3]. The patch[2] show how to implement the "monitor the ddr load" by using Devfreq-Event framework and the patch[3] include the method how to implement the rk3399 dmc driver. [1] Devfreq-Event framework - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=f262f28c147051e7aa6daaf4fb5996833ffadff4 [2] Exynos Noc probe driver by using Devfreq-Event framework - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0179a913875a8b39eaf5b848c876439a3a4650af [3] Exynos Busfreq driver using the devfreq-evnet framework to get the monitored data - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0722249ac1f3dcc3af9e9d7ed89792a68f00 If you have more information and help, please let me know. I'll help you. Thanks, Chanwoo Choi On Wed, Jun 1, 2016 at 6:35 PM, Lin Huangwrote: there is dfi controller on rk3399 platform, it can monitor ddr load, register this controller to devfreq framework, and default to use simple_ondeamnd policy, and do ddr frequency scaling base on this result. Signed-off-by: Lin Huang --- drivers/devfreq/Kconfig | 2 +- drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 14 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 438 drivers/devfreq/rockchip/rockchip_dmc.c | 132 ++ include/soc/rockchip/rockchip_dmc.h | 44 7 files changed, 632 insertions(+), 1 deletion(-) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 78dac0e..a883744 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -101,5 +101,5 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" - +source "drivers/devfreq/rockchip/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 09f11d9..48e2ae6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ)+= tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..617b5fe --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,14 @@ +config ARM_ROCKCHIP_DMC_DEVFREQ + tristate "ARM ROCKCHIP DMC DEVFREQ Driver" + depends on ARCH_ROCKCHIP + help + This adds the DEVFREQ driver framework for the rockchip dmc. + +config ARM_RK3399_DMC_DEVFREQ + tristate "ARM RK3399 DMC DEVFREQ Driver" + depends on ARM_ROCKCHIP_DMC_DEVFREQ + select PM_OPP + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency + for the memory controller and reads the usage counts from hardware. diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile new file mode 100644 index 000..caca525 --- /dev/null +++ b/drivers/devfreq/rockchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ) += rockchip_dmc.o +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c new file mode 100644 index 000..4907d38 --- /dev/null +++ b/drivers/devfreq/rockchip/rk3399_dmc.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed
Re: [RFC PATCH 3/4] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Chanwoo Choi, I just check the devfreq-event framework code, it is good, i will do more dig to see whether it can fit for rk3399 dmc, thank you. On 2016年06月01日 19:47, Chanwoo Choi wrote: Hi Lin, This patch include the two features as following: - Monitor the ddr load - Control the ddr's clock with ondemand governor based on load The "Monitor the ddr load" has the specific the address in SoC. Namely, it is separate the module. So, I implemented the devfreq-event framework[1] which was merged. It is right method to separate two feature from your device driver. You can refer to patch[2][3]. The patch[2] show how to implement the "monitor the ddr load" by using Devfreq-Event framework and the patch[3] include the method how to implement the rk3399 dmc driver. [1] Devfreq-Event framework - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=f262f28c147051e7aa6daaf4fb5996833ffadff4 [2] Exynos Noc probe driver by using Devfreq-Event framework - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0179a913875a8b39eaf5b848c876439a3a4650af [3] Exynos Busfreq driver using the devfreq-evnet framework to get the monitored data - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0722249ac1f3dcc3af9e9d7ed89792a68f00 If you have more information and help, please let me know. I'll help you. Thanks, Chanwoo Choi On Wed, Jun 1, 2016 at 6:35 PM, Lin Huang wrote: there is dfi controller on rk3399 platform, it can monitor ddr load, register this controller to devfreq framework, and default to use simple_ondeamnd policy, and do ddr frequency scaling base on this result. Signed-off-by: Lin Huang --- drivers/devfreq/Kconfig | 2 +- drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 14 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 438 drivers/devfreq/rockchip/rockchip_dmc.c | 132 ++ include/soc/rockchip/rockchip_dmc.h | 44 7 files changed, 632 insertions(+), 1 deletion(-) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 78dac0e..a883744 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -101,5 +101,5 @@ config ARM_TEGRA_DEVFREQ operating frequencies and voltages with OPP support. source "drivers/devfreq/event/Kconfig" - +source "drivers/devfreq/rockchip/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index 09f11d9..48e2ae6 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o # DEVFREQ Drivers obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ)+= tegra-devfreq.o +obj-$(CONFIG_ARCH_ROCKCHIP)+= rockchip/ # DEVFREQ Event Drivers obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ diff --git a/drivers/devfreq/rockchip/Kconfig b/drivers/devfreq/rockchip/Kconfig new file mode 100644 index 000..617b5fe --- /dev/null +++ b/drivers/devfreq/rockchip/Kconfig @@ -0,0 +1,14 @@ +config ARM_ROCKCHIP_DMC_DEVFREQ + tristate "ARM ROCKCHIP DMC DEVFREQ Driver" + depends on ARCH_ROCKCHIP + help + This adds the DEVFREQ driver framework for the rockchip dmc. + +config ARM_RK3399_DMC_DEVFREQ + tristate "ARM RK3399 DMC DEVFREQ Driver" + depends on ARM_ROCKCHIP_DMC_DEVFREQ + select PM_OPP + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for the RK3399 dmc. It sets the frequency + for the memory controller and reads the usage counts from hardware. diff --git a/drivers/devfreq/rockchip/Makefile b/drivers/devfreq/rockchip/Makefile new file mode 100644 index 000..caca525 --- /dev/null +++ b/drivers/devfreq/rockchip/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ) += rockchip_dmc.o +obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o diff --git a/drivers/devfreq/rockchip/rk3399_dmc.c b/drivers/devfreq/rockchip/rk3399_dmc.c new file mode 100644 index 000..4907d38 --- /dev/null +++ b/drivers/devfreq/rockchip/rk3399_dmc.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Author: Lin Huang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY;
Re: [RFC PATCH 3/4] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Myungloo Ham, On 2016年06月01日 18:47, MyungJoo Ham wrote: On Wed, Jun 1, 2016 at 6:35 PM, Lin Huangwrote: there is dfi controller on rk3399 platform, it can monitor ddr load, register this controller to devfreq framework, and default to use simple_ondeamnd policy, and do ddr frequency scaling base on this result. Signed-off-by: Lin Huang --- drivers/devfreq/Kconfig | 2 +- drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 14 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 438 drivers/devfreq/rockchip/rockchip_dmc.c | 132 ++ include/soc/rockchip/rockchip_dmc.h | 44 7 files changed, 632 insertions(+), 1 deletion(-) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h + + /* check the rate we get whether correct */ + dmcfreq->rate = clk_get_rate(dmcfreq->dmc_clk); + if (dmcfreq->rate != target_rate) { + dev_err(dev, "get wrong ddr frequency, Request freq %lu,\ + Current freq %lu\n", target_rate, dmcfreq->rate); + regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt, + dmcfreq->volt); Why do you need to check this and more importantly, why do you assume that dmvfreq->volt will be safe in this case? (what if the new dmcfreq->rate is larger than the old dmcfreq->rate after clk_get_rate?) Note that you didn't update dmcfreq->volt after clk_get_rate() Now we will set the ddr clock rate in bl31 use dcf controller(as i show in the patch cover letter), and there only two result we can get, set clock rate fail(ddr clock still in old rate) or set clock rate sucessful(use the new ddr rate), if the set rate fail, we should keep the voltage old value. Ah, you remind me, i should check clock rate before: if (old_clk_rate > target_rate) otherwise there have chance set high rate fail and use low voltage. And about the dmcfreq->volt, i will update this value when into the function, throuth opp = devfreq_recommended_opp(dev, >rate, flags); if (IS_ERR(opp)) { rcu_read_unlock(); return PTR_ERR(opp); } dmcfreq->volt = dev_pm_opp_get_voltage(opp); +EXPORT_SYMBOL_GPL(dmc_event); +EXPORT_SYMBOL_GPL(rockchip_dmc_enabled); +EXPORT_SYMBOL_GPL(rockchip_dmc_enable); +EXPORT_SYMBOL_GPL(rockchip_dmc_disable); +EXPORT_SYMBOL_GPL(dmc_register_notifier); +EXPORT_SYMBOL_GPL(dmc_unregister_notifier); +EXPORT_SYMBOL_GPL(rockchip_dmc_get); +EXPORT_SYMBOL_GPL(rockchip_dmc_put); Do you really need to export all these device driver specific functions? Looks like a design flaw here. there is some situation we need to disable ddr frequency scaling(connect two panel etc) on rk3399 platform, and it should be also needed on other rockchip platform, so i move these funticon as separate file. Cheers, MyungJoo -- Lin Huang
Re: [RFC PATCH 3/4] PM / devfreq: rockchip: add devfreq driver for rk3399 dmc
Hi Myungloo Ham, On 2016年06月01日 18:47, MyungJoo Ham wrote: On Wed, Jun 1, 2016 at 6:35 PM, Lin Huang wrote: there is dfi controller on rk3399 platform, it can monitor ddr load, register this controller to devfreq framework, and default to use simple_ondeamnd policy, and do ddr frequency scaling base on this result. Signed-off-by: Lin Huang --- drivers/devfreq/Kconfig | 2 +- drivers/devfreq/Makefile| 1 + drivers/devfreq/rockchip/Kconfig| 14 + drivers/devfreq/rockchip/Makefile | 2 + drivers/devfreq/rockchip/rk3399_dmc.c | 438 drivers/devfreq/rockchip/rockchip_dmc.c | 132 ++ include/soc/rockchip/rockchip_dmc.h | 44 7 files changed, 632 insertions(+), 1 deletion(-) create mode 100644 drivers/devfreq/rockchip/Kconfig create mode 100644 drivers/devfreq/rockchip/Makefile create mode 100644 drivers/devfreq/rockchip/rk3399_dmc.c create mode 100644 drivers/devfreq/rockchip/rockchip_dmc.c create mode 100644 include/soc/rockchip/rockchip_dmc.h + + /* check the rate we get whether correct */ + dmcfreq->rate = clk_get_rate(dmcfreq->dmc_clk); + if (dmcfreq->rate != target_rate) { + dev_err(dev, "get wrong ddr frequency, Request freq %lu,\ + Current freq %lu\n", target_rate, dmcfreq->rate); + regulator_set_voltage(dmcfreq->vdd_center, dmcfreq->volt, + dmcfreq->volt); Why do you need to check this and more importantly, why do you assume that dmvfreq->volt will be safe in this case? (what if the new dmcfreq->rate is larger than the old dmcfreq->rate after clk_get_rate?) Note that you didn't update dmcfreq->volt after clk_get_rate() Now we will set the ddr clock rate in bl31 use dcf controller(as i show in the patch cover letter), and there only two result we can get, set clock rate fail(ddr clock still in old rate) or set clock rate sucessful(use the new ddr rate), if the set rate fail, we should keep the voltage old value. Ah, you remind me, i should check clock rate before: if (old_clk_rate > target_rate) otherwise there have chance set high rate fail and use low voltage. And about the dmcfreq->volt, i will update this value when into the function, throuth opp = devfreq_recommended_opp(dev, >rate, flags); if (IS_ERR(opp)) { rcu_read_unlock(); return PTR_ERR(opp); } dmcfreq->volt = dev_pm_opp_get_voltage(opp); +EXPORT_SYMBOL_GPL(dmc_event); +EXPORT_SYMBOL_GPL(rockchip_dmc_enabled); +EXPORT_SYMBOL_GPL(rockchip_dmc_enable); +EXPORT_SYMBOL_GPL(rockchip_dmc_disable); +EXPORT_SYMBOL_GPL(dmc_register_notifier); +EXPORT_SYMBOL_GPL(dmc_unregister_notifier); +EXPORT_SYMBOL_GPL(rockchip_dmc_get); +EXPORT_SYMBOL_GPL(rockchip_dmc_put); Do you really need to export all these device driver specific functions? Looks like a design flaw here. there is some situation we need to disable ddr frequency scaling(connect two panel etc) on rk3399 platform, and it should be also needed on other rockchip platform, so i move these funticon as separate file. Cheers, MyungJoo -- Lin Huang
Re: [RFC PATCH 2/4] clk: rockchip: rk3399: add ddrc clock support
Hi Doug, On 2016年06月01日 23:46, Heiko Stübner wrote: Am Mittwoch, 1. Juni 2016, 08:24:48 schrieb Doug Anderson: Lin Huang, On Wed, Jun 1, 2016 at 2:35 AM, Lin Huangwrote: add ddrc clock setting, so we can do ddr frequency scaling on rk3399 platform in future. Signed-off-by: Lin Huang --- drivers/clk/rockchip/clk-rk3399.c | 16 include/dt-bindings/clock/rk3399-cru.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index f1d8e44..749ea59 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -118,6 +118,10 @@ PNAME(mux_armclkb_p) = { "clk_core_b_lpll_src",> "clk_core_b_bpll_src", "clk_core_b_dpll_src", "clk_core_b_gpll_src" }; +PNAME(mux_ddrclk_p)= { "clk_ddrc_lpll_src", + "clk_ddrc_bpll_src", + "clk_ddrc_dpll_src", + "clk_ddrc_gpll_src" }; PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", @@ -1377,6 +1381,18 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {> COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED, RK3368_CLKSEL_CON(58), 0, 5, DFLAGS, RK3368_CLKGATE_CON(13), 11, GFLAGS), + + /* ddrc */ + GATE(0, "clk_ddrc_lpll_src", "lpll", CLK_IGNORE_UNUSED, +RK3399_CLKGATE_CON(3), 0, GFLAGS), + GATE(0, "clk_ddrc_bpll_src", "bpll", CLK_IGNORE_UNUSED, +RK3399_CLKGATE_CON(3), 1, GFLAGS), + GATE(0, "clk_ddrc_dpll_src", "dpll", CLK_IGNORE_UNUSED, +RK3399_CLKGATE_CON(3), 2, GFLAGS), + GATE(0, "clk_ddrc_gpll_src", "gpll", CLK_IGNORE_UNUSED, +RK3399_CLKGATE_CON(3), 3, GFLAGS), + COMPOSITE_DDRC(SCLK_DDRCLK, "clk_ddrc", mux_ddrclk_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(6), 4, 2, MFLAGS, 0, 3, DFLAGS), It seems slightly unfortunate that we need CLK_IGNORE_UNUSED on these. Only one of these will ever be used at once and it would be awfully nice if the others could get gated, right? ...presumably this is needed because we might not have an actual driver for DDR Freq and we definitely want to make sure that clk_ddrc is enabled in that case. I guess what we really want is something like CLK_ENABLE_HAND_OFF eventually, but until then I think you might get slightly better behavior by getting rid of all of these CLK_IGNORE_UNUSED and setting "clk_ddrc" as a critical clock, either using the table in this file or the new flag. My current feeling is that staying with the homegrown solution for critical clocks might be preferable until the clk-handoff mechanism lands as well, as our critical clocks fall into both categories and I'd like to not touch everything twice. The clock above should be controlled by the dcf, so falls into the handoff category (critical until a driver picks up the clock). Also mixing both new and old approach might get confusing. But I'm definitly open to counter-arguments :-) I will remove CLK_IGNORE_UNUSED flag and set "clk_ddrc" as critical clock in next version. Besides, i think we should also set "clk_ddrc_dpll_src" as critical clock, since we always use dpll as ddr clock source, and it should always on. }; static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h index 50a44cf..8a0f0442 100644 --- a/include/dt-bindings/clock/rk3399-cru.h +++ b/include/dt-bindings/clock/rk3399-cru.h @@ -131,6 +131,7 @@ #define SCLK_DPHY_RX0_CFG 165 #define SCLK_RMII_SRC 166 #define SCLK_PCIEPHY_REF100M 167 +#define SCLK_DDRCLK168 Almost certainly you'll want to create a separate patch for the dt-bindings change since it will need to land in a different tree so it can be pulled into both Heiko's clock topic branch and dts64 topic branch. correct. will fix next version, thanks. ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang
Re: [RFC PATCH 2/4] clk: rockchip: rk3399: add ddrc clock support
Hi Doug, On 2016年06月01日 23:46, Heiko Stübner wrote: Am Mittwoch, 1. Juni 2016, 08:24:48 schrieb Doug Anderson: Lin Huang, On Wed, Jun 1, 2016 at 2:35 AM, Lin Huang wrote: add ddrc clock setting, so we can do ddr frequency scaling on rk3399 platform in future. Signed-off-by: Lin Huang --- drivers/clk/rockchip/clk-rk3399.c | 16 include/dt-bindings/clock/rk3399-cru.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index f1d8e44..749ea59 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -118,6 +118,10 @@ PNAME(mux_armclkb_p) = { "clk_core_b_lpll_src",> "clk_core_b_bpll_src", "clk_core_b_dpll_src", "clk_core_b_gpll_src" }; +PNAME(mux_ddrclk_p)= { "clk_ddrc_lpll_src", + "clk_ddrc_bpll_src", + "clk_ddrc_dpll_src", + "clk_ddrc_gpll_src" }; PNAME(mux_aclk_cci_p) = { "cpll_aclk_cci_src", "gpll_aclk_cci_src", "npll_aclk_cci_src", @@ -1377,6 +1381,18 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {> COMPOSITE_NOMUX(0, "clk_test", "clk_test_pre", CLK_IGNORE_UNUSED, RK3368_CLKSEL_CON(58), 0, 5, DFLAGS, RK3368_CLKGATE_CON(13), 11, GFLAGS), + + /* ddrc */ + GATE(0, "clk_ddrc_lpll_src", "lpll", CLK_IGNORE_UNUSED, +RK3399_CLKGATE_CON(3), 0, GFLAGS), + GATE(0, "clk_ddrc_bpll_src", "bpll", CLK_IGNORE_UNUSED, +RK3399_CLKGATE_CON(3), 1, GFLAGS), + GATE(0, "clk_ddrc_dpll_src", "dpll", CLK_IGNORE_UNUSED, +RK3399_CLKGATE_CON(3), 2, GFLAGS), + GATE(0, "clk_ddrc_gpll_src", "gpll", CLK_IGNORE_UNUSED, +RK3399_CLKGATE_CON(3), 3, GFLAGS), + COMPOSITE_DDRC(SCLK_DDRCLK, "clk_ddrc", mux_ddrclk_p, CLK_IGNORE_UNUSED, + RK3399_CLKSEL_CON(6), 4, 2, MFLAGS, 0, 3, DFLAGS), It seems slightly unfortunate that we need CLK_IGNORE_UNUSED on these. Only one of these will ever be used at once and it would be awfully nice if the others could get gated, right? ...presumably this is needed because we might not have an actual driver for DDR Freq and we definitely want to make sure that clk_ddrc is enabled in that case. I guess what we really want is something like CLK_ENABLE_HAND_OFF eventually, but until then I think you might get slightly better behavior by getting rid of all of these CLK_IGNORE_UNUSED and setting "clk_ddrc" as a critical clock, either using the table in this file or the new flag. My current feeling is that staying with the homegrown solution for critical clocks might be preferable until the clk-handoff mechanism lands as well, as our critical clocks fall into both categories and I'd like to not touch everything twice. The clock above should be controlled by the dcf, so falls into the handoff category (critical until a driver picks up the clock). Also mixing both new and old approach might get confusing. But I'm definitly open to counter-arguments :-) I will remove CLK_IGNORE_UNUSED flag and set "clk_ddrc" as critical clock in next version. Besides, i think we should also set "clk_ddrc_dpll_src" as critical clock, since we always use dpll as ddr clock source, and it should always on. }; static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = { diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h index 50a44cf..8a0f0442 100644 --- a/include/dt-bindings/clock/rk3399-cru.h +++ b/include/dt-bindings/clock/rk3399-cru.h @@ -131,6 +131,7 @@ #define SCLK_DPHY_RX0_CFG 165 #define SCLK_RMII_SRC 166 #define SCLK_PCIEPHY_REF100M 167 +#define SCLK_DDRCLK168 Almost certainly you'll want to create a separate patch for the dt-bindings change since it will need to land in a different tree so it can be pulled into both Heiko's clock topic branch and dts64 topic branch. correct. will fix next version, thanks. ___ Linux-rockchip mailing list linux-rockc...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip -- Lin Huang
Re: [PATCH 1/2] clk: rockchip: dmc: support rk3399 dmc clock driver
Hi MyungJoo, On 23/11/15 16:09, MyungJoo Ham wrote: +static unsigned long rk3399_dmcclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rk3399_dmcclk *dmc = to_rk3399_dmcclk(); + u32 val; + + /* +* Get parent rate since it changed in this clks set_rate op. The parent +* rate passed into this function is cached before set_rate is called in +* the common clk code, so we have to get it here. +*/ + parent_rate = clk_get_rate(clk_get_parent(hw->clk)); + + val = readl(dmc->cru + CRU_CLKSEL6_CON); + val = (val >> CLK_DDRC_DIV_CON_SHIFT) & CLK_DDRC_DIV_CON_MASK; + + return parent_rate / (val + 1); +} + +/* + * TODO: set ddr frequcney in dcf which run in ATF + */ +static int rk3399_dmcclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return 0; +} Is it correct that you didn't fill this up because your Trustzone driver (SMC) is not ready yet? Yep, the SMC is not ready yet. Then, why don't you fill that function assuming that TrustZone is not activated and add SMC call functions with if or #if after its TrustZone driver is ready? Or does your SoC mandate the usage ot TrustZone, restricting the usage of CRU_CLKSEL6_CON write? (I don't see why SoC vendors will do this..) I'll be ready to merge the RK3399 devfreq driver if you fill this up (assuming that TZ is not enabled) or add TZ driver and SMC calls. Thank you for your reply, it is good idea use if or #if to distinguish the TrustZone whether ready, i will handle it in next version. I may follow Heiko advice to do some modify in dmc clock and rk3399 devfreq driver, I will upload new version when it's ready. Cheers, MyungJoo ps. according to rk339_dmcclk_recalc_rate(), filling rk339_dmcclk_set_rate assuming that TZ is not enabled seems trivial. -- Lin Huang -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/2] clk: rockchip: dmc: support rk3399 dmc clock driver
Hi Heiko, On 22/11/15 02:30, Heiko Stuebner wrote: Hi Lin, Am Freitag, 20. November 2015, 09:37:15 schrieb hl: On 20/11/15 05:47, Heiko Stuebner wrote: Hi Lin, Am Donnerstag, 19. November 2015, 18:21:10 schrieb Lin Huang: support rk3399 dmc clock driver. Note, ddr set rate function will use dcf controller which run in ATF, it need to fishish it when rk3399 arm trust firmware ready. this unfinalized state is slightly unfortunate and I think this code will need to wait until CRU and DDRC specs are available. Because this is clearly part of the CRU (labeled CRU_CLKSEL6_CON etc) so shouldn't be a separate driver at all and also what your driver currently only does can still simply be described in the regular scheme as part of a full clock driver like PNAME(mux_ddrc_p) = { "pll_dpll", "pll_gpll", "pll_alpll", "pll_abpll" }; COMPOSITE_NOGATE(0, "ddrc", mux_ddrc_p, 0, RK3399_CLKSEL_CON(6), 4, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), So the code needs to actually demonstrate why a separate clock type is really necessary. I do understand that we will probably need a special way to talk to this dcf controller but seeing how this interaction will work is really a prequisite to finding a correct solution. if we can use common clock driver, i can put the dfi controller as a independent driver into devfreq, this is the best way. But how do we separate the ddr clk_set_rate() , so we can manipulate dcf controller(actually, we use SMC handle dcf controller in arm trust firmware ), i check clock driver code, it seem there is not way to do that for now. the core problem I have right now is, that I don't understand how the interaction with the dfi controller works at all :-) . One thing that might work, is that your dfi-driver takes the ddrc-clock from the clock controller and then registers a clock notifier to get notified before and after the clock-rate changes. But that depends as stated above on how the dfi-controller needs to be handled. For example the current armclk-handling uses a clock notifier around the actual rate change ... so you could use that as inspiration. Thank you for your inspiration. I think i can handle ddrc clk like the armclk. About the dfi, it will monitor ddr utilization, according this result to do ddr frequency scaling. I think i can implement a dfi drvier, and register it to devfreq, then call the dmc_set_rate fucntion in the dfi drvier, meanwhile i will implement a ddrc clk driver like the armclk, implement set rate funciton, and call the dcf(implement in ATF) in this function. Heiko -- Lin Huang -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/2] clk: rockchip: dmc: support rk3399 dmc clock driver
Hi Heiko, On 22/11/15 02:30, Heiko Stuebner wrote: Hi Lin, Am Freitag, 20. November 2015, 09:37:15 schrieb hl: On 20/11/15 05:47, Heiko Stuebner wrote: Hi Lin, Am Donnerstag, 19. November 2015, 18:21:10 schrieb Lin Huang: support rk3399 dmc clock driver. Note, ddr set rate function will use dcf controller which run in ATF, it need to fishish it when rk3399 arm trust firmware ready. this unfinalized state is slightly unfortunate and I think this code will need to wait until CRU and DDRC specs are available. Because this is clearly part of the CRU (labeled CRU_CLKSEL6_CON etc) so shouldn't be a separate driver at all and also what your driver currently only does can still simply be described in the regular scheme as part of a full clock driver like PNAME(mux_ddrc_p) = { "pll_dpll", "pll_gpll", "pll_alpll", "pll_abpll" }; COMPOSITE_NOGATE(0, "ddrc", mux_ddrc_p, 0, RK3399_CLKSEL_CON(6), 4, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), So the code needs to actually demonstrate why a separate clock type is really necessary. I do understand that we will probably need a special way to talk to this dcf controller but seeing how this interaction will work is really a prequisite to finding a correct solution. if we can use common clock driver, i can put the dfi controller as a independent driver into devfreq, this is the best way. But how do we separate the ddr clk_set_rate() , so we can manipulate dcf controller(actually, we use SMC handle dcf controller in arm trust firmware ), i check clock driver code, it seem there is not way to do that for now. the core problem I have right now is, that I don't understand how the interaction with the dfi controller works at all :-) . One thing that might work, is that your dfi-driver takes the ddrc-clock from the clock controller and then registers a clock notifier to get notified before and after the clock-rate changes. But that depends as stated above on how the dfi-controller needs to be handled. For example the current armclk-handling uses a clock notifier around the actual rate change ... so you could use that as inspiration. Thank you for your inspiration. I think i can handle ddrc clk like the armclk. About the dfi, it will monitor ddr utilization, according this result to do ddr frequency scaling. I think i can implement a dfi drvier, and register it to devfreq, then call the dmc_set_rate fucntion in the dfi drvier, meanwhile i will implement a ddrc clk driver like the armclk, implement set rate funciton, and call the dcf(implement in ATF) in this function. Heiko -- Lin Huang -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/2] clk: rockchip: dmc: support rk3399 dmc clock driver
Hi MyungJoo, On 23/11/15 16:09, MyungJoo Ham wrote: +static unsigned long rk3399_dmcclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rk3399_dmcclk *dmc = to_rk3399_dmcclk(); + u32 val; + + /* +* Get parent rate since it changed in this clks set_rate op. The parent +* rate passed into this function is cached before set_rate is called in +* the common clk code, so we have to get it here. +*/ + parent_rate = clk_get_rate(clk_get_parent(hw->clk)); + + val = readl(dmc->cru + CRU_CLKSEL6_CON); + val = (val >> CLK_DDRC_DIV_CON_SHIFT) & CLK_DDRC_DIV_CON_MASK; + + return parent_rate / (val + 1); +} + +/* + * TODO: set ddr frequcney in dcf which run in ATF + */ +static int rk3399_dmcclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return 0; +} Is it correct that you didn't fill this up because your Trustzone driver (SMC) is not ready yet? Yep, the SMC is not ready yet. Then, why don't you fill that function assuming that TrustZone is not activated and add SMC call functions with if or #if after its TrustZone driver is ready? Or does your SoC mandate the usage ot TrustZone, restricting the usage of CRU_CLKSEL6_CON write? (I don't see why SoC vendors will do this..) I'll be ready to merge the RK3399 devfreq driver if you fill this up (assuming that TZ is not enabled) or add TZ driver and SMC calls. Thank you for your reply, it is good idea use if or #if to distinguish the TrustZone whether ready, i will handle it in next version. I may follow Heiko advice to do some modify in dmc clock and rk3399 devfreq driver, I will upload new version when it's ready. Cheers, MyungJoo ps. according to rk339_dmcclk_recalc_rate(), filling rk339_dmcclk_set_rate assuming that TZ is not enabled seems trivial. -- Lin Huang -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/2] clk: rockchip: dmc: support rk3399 dmc clock driver
Hi Heiko, On 20/11/15 05:47, Heiko Stuebner wrote: Hi Lin, Am Donnerstag, 19. November 2015, 18:21:10 schrieb Lin Huang: support rk3399 dmc clock driver. Note, ddr set rate function will use dcf controller which run in ATF, it need to fishish it when rk3399 arm trust firmware ready. this unfinalized state is slightly unfortunate and I think this code will need to wait until CRU and DDRC specs are available. Because this is clearly part of the CRU (labeled CRU_CLKSEL6_CON etc) so shouldn't be a separate driver at all and also what your driver currently only does can still simply be described in the regular scheme as part of a full clock driver like PNAME(mux_ddrc_p) = { "pll_dpll", "pll_gpll", "pll_alpll", "pll_abpll" }; COMPOSITE_NOGATE(0, "ddrc", mux_ddrc_p, 0, RK3399_CLKSEL_CON(6), 4, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), So the code needs to actually demonstrate why a separate clock type is really necessary. I do understand that we will probably need a special way to talk to this dcf controller but seeing how this interaction will work is really a prequisite to finding a correct solution. if we can use common clock driver, i can put the dfi controller as a independent driver into devfreq, this is the best way. But how do we separate the ddr clk_set_rate() , so we can manipulate dcf controller(actually, we use SMC handle dcf controller in arm trust firmware ), i check clock driver code, it seem there is not way to do that for now. Heiko --- drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-rk3399-dmc.c | 196 ++ include/soc/rockchip/rk3399-dmc-clk.h | 36 +++ 3 files changed, 233 insertions(+) create mode 100644 drivers/clk/rockchip/clk-rk3399-dmc.c create mode 100644 include/soc/rockchip/rk3399-dmc-clk.h diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index b27edd6..98bd955 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_RESET_CONTROLLER)+= softrst.o obj-y += clk-rk3188.o obj-y += clk-rk3288.o obj-y += clk-rk3368.o +obj-y += clk-rk3399-dmc.o diff --git a/drivers/clk/rockchip/clk-rk3399-dmc.c b/drivers/clk/rockchip/clk-rk3399-dmc.c new file mode 100644 index 000..03cc044 --- /dev/null +++ b/drivers/clk/rockchip/clk-rk3399-dmc.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define to_rk3399_dmcclk(obj) container_of(obj, struct rk3399_dmcclk, hw) + +/* CRU_CLKSEL6_CON*/ +#define CRU_CLKSEL6_CON0x118 +#define CLK_DDRC_PLL_SEL_SHIFT 0x4 +#define CLK_DDRC_PLL_SEL_MASK 0x3 +#define CLK_DDRC_DIV_CON_SHIFT 0 +#define CLK_DDRC_DIV_CON_MASK 0x07 + +static unsigned long rk3399_dmcclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rk3399_dmcclk *dmc = to_rk3399_dmcclk(); + u32 val; + + /* +* Get parent rate since it changed in this clks set_rate op. The parent +* rate passed into this function is cached before set_rate is called in +* the common clk code, so we have to get it here. +*/ + parent_rate = clk_get_rate(clk_get_parent(hw->clk)); + + val = readl(dmc->cru + CRU_CLKSEL6_CON); + val = (val >> CLK_DDRC_DIV_CON_SHIFT) & CLK_DDRC_DIV_CON_MASK; + + return parent_rate / (val + 1); +} + +/* + * TODO: set ddr frequcney in dcf which run in ATF + */ +static int rk3399_dmcclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return 0; +} + +static u8 rk3399_dmcclk_get_parent(struct clk_hw *hw) +{ + struct rk3399_dmcclk *dmc = to_rk3399_dmcclk(); + u32 val; + + val = readl(dmc->cru + CRU_CLKSEL6_CON); + + return (val >> CLK_DDRC_PLL_SEL_SHIFT) & + CLK_DDRC_PLL_SEL_MASK; +} + +static const struct clk_ops rk3399_dmcclk_ops = { + .recalc_rate = rk3399_dmcclk_recalc_rate, + .set_rate = rk3399_dmcclk_set_rate, + .get_parent = rk3399_dmcclk_get_parent, +}; + +static const char *parent_clk_names[] = { + "pll_dpll", + "pll_gpll", + "pll_alpll", + "pll_abpll", +}; + +static int
Re: [PATCH 1/2] clk: rockchip: dmc: support rk3399 dmc clock driver
Hi Heiko, On 20/11/15 05:47, Heiko Stuebner wrote: Hi Lin, Am Donnerstag, 19. November 2015, 18:21:10 schrieb Lin Huang: support rk3399 dmc clock driver. Note, ddr set rate function will use dcf controller which run in ATF, it need to fishish it when rk3399 arm trust firmware ready. this unfinalized state is slightly unfortunate and I think this code will need to wait until CRU and DDRC specs are available. Because this is clearly part of the CRU (labeled CRU_CLKSEL6_CON etc) so shouldn't be a separate driver at all and also what your driver currently only does can still simply be described in the regular scheme as part of a full clock driver like PNAME(mux_ddrc_p) = { "pll_dpll", "pll_gpll", "pll_alpll", "pll_abpll" }; COMPOSITE_NOGATE(0, "ddrc", mux_ddrc_p, 0, RK3399_CLKSEL_CON(6), 4, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), So the code needs to actually demonstrate why a separate clock type is really necessary. I do understand that we will probably need a special way to talk to this dcf controller but seeing how this interaction will work is really a prequisite to finding a correct solution. if we can use common clock driver, i can put the dfi controller as a independent driver into devfreq, this is the best way. But how do we separate the ddr clk_set_rate() , so we can manipulate dcf controller(actually, we use SMC handle dcf controller in arm trust firmware ), i check clock driver code, it seem there is not way to do that for now. Heiko --- drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-rk3399-dmc.c | 196 ++ include/soc/rockchip/rk3399-dmc-clk.h | 36 +++ 3 files changed, 233 insertions(+) create mode 100644 drivers/clk/rockchip/clk-rk3399-dmc.c create mode 100644 include/soc/rockchip/rk3399-dmc-clk.h diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index b27edd6..98bd955 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_RESET_CONTROLLER)+= softrst.o obj-y += clk-rk3188.o obj-y += clk-rk3288.o obj-y += clk-rk3368.o +obj-y += clk-rk3399-dmc.o diff --git a/drivers/clk/rockchip/clk-rk3399-dmc.c b/drivers/clk/rockchip/clk-rk3399-dmc.c new file mode 100644 index 000..03cc044 --- /dev/null +++ b/drivers/clk/rockchip/clk-rk3399-dmc.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define to_rk3399_dmcclk(obj) container_of(obj, struct rk3399_dmcclk, hw) + +/* CRU_CLKSEL6_CON*/ +#define CRU_CLKSEL6_CON0x118 +#define CLK_DDRC_PLL_SEL_SHIFT 0x4 +#define CLK_DDRC_PLL_SEL_MASK 0x3 +#define CLK_DDRC_DIV_CON_SHIFT 0 +#define CLK_DDRC_DIV_CON_MASK 0x07 + +static unsigned long rk3399_dmcclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rk3399_dmcclk *dmc = to_rk3399_dmcclk(); + u32 val; + + /* +* Get parent rate since it changed in this clks set_rate op. The parent +* rate passed into this function is cached before set_rate is called in +* the common clk code, so we have to get it here. +*/ + parent_rate = clk_get_rate(clk_get_parent(hw->clk)); + + val = readl(dmc->cru + CRU_CLKSEL6_CON); + val = (val >> CLK_DDRC_DIV_CON_SHIFT) & CLK_DDRC_DIV_CON_MASK; + + return parent_rate / (val + 1); +} + +/* + * TODO: set ddr frequcney in dcf which run in ATF + */ +static int rk3399_dmcclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return 0; +} + +static u8 rk3399_dmcclk_get_parent(struct clk_hw *hw) +{ + struct rk3399_dmcclk *dmc = to_rk3399_dmcclk(); + u32 val; + + val = readl(dmc->cru + CRU_CLKSEL6_CON); + + return (val >> CLK_DDRC_PLL_SEL_SHIFT) & + CLK_DDRC_PLL_SEL_MASK; +} + +static const struct clk_ops rk3399_dmcclk_ops = { + .recalc_rate = rk3399_dmcclk_recalc_rate, + .set_rate = rk3399_dmcclk_set_rate, + .get_parent = rk3399_dmcclk_get_parent, +}; + +static const char *parent_clk_names[] = { + "pll_dpll", + "pll_gpll", + "pll_alpll", + "pll_abpll", +}; + +static int