From: Shawn Guo <shawn....@linaro.org>

The clock control module (CRM) cannot always provide desired frequency
for all VOU output devices.  That's why VOU integrates a few dividers
to further divide the clocks from CRM.  Let's add an interface for
configuring these dividers.

Signed-off-by: Shawn Guo <shawn....@linaro.org>
Reviewed-by: Sean Paul <seanp...@chromium.org>
---
 drivers/gpu/drm/zte/zx_vou.c      | 79 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/zte/zx_vou.h      | 25 +++++++++++++
 drivers/gpu/drm/zte/zx_vou_regs.h | 16 ++++++++
 3 files changed, 120 insertions(+)

diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
index a82ba294c7e1..823b74ea758a 100644
--- a/drivers/gpu/drm/zte/zx_vou.c
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -72,6 +72,13 @@ struct zx_crtc_bits {
        u32 sec_vactive_mask;
        u32 interlace_select;
        u32 pi_enable;
+       u32 div_vga_shift;
+       u32 div_pic_shift;
+       u32 div_tvenc_shift;
+       u32 div_hdmi_pnx_shift;
+       u32 div_hdmi_shift;
+       u32 div_inf_shift;
+       u32 div_layer_shift;
 };
 
 static const struct zx_crtc_bits main_crtc_bits = {
@@ -83,6 +90,13 @@ struct zx_crtc_bits {
        .sec_vactive_mask = SEC_VACT_MAIN_MASK,
        .interlace_select = MAIN_INTERLACE_SEL,
        .pi_enable = MAIN_PI_EN,
+       .div_vga_shift = VGA_MAIN_DIV_SHIFT,
+       .div_pic_shift = PIC_MAIN_DIV_SHIFT,
+       .div_tvenc_shift = TVENC_MAIN_DIV_SHIFT,
+       .div_hdmi_pnx_shift = HDMI_MAIN_PNX_DIV_SHIFT,
+       .div_hdmi_shift = HDMI_MAIN_DIV_SHIFT,
+       .div_inf_shift = INF_MAIN_DIV_SHIFT,
+       .div_layer_shift = LAYER_MAIN_DIV_SHIFT,
 };
 
 static const struct zx_crtc_bits aux_crtc_bits = {
@@ -94,6 +108,13 @@ struct zx_crtc_bits {
        .sec_vactive_mask = SEC_VACT_AUX_MASK,
        .interlace_select = AUX_INTERLACE_SEL,
        .pi_enable = AUX_PI_EN,
+       .div_vga_shift = VGA_AUX_DIV_SHIFT,
+       .div_pic_shift = PIC_AUX_DIV_SHIFT,
+       .div_tvenc_shift = TVENC_AUX_DIV_SHIFT,
+       .div_hdmi_pnx_shift = HDMI_AUX_PNX_DIV_SHIFT,
+       .div_hdmi_shift = HDMI_AUX_DIV_SHIFT,
+       .div_inf_shift = INF_AUX_DIV_SHIFT,
+       .div_layer_shift = LAYER_AUX_DIV_SHIFT,
 };
 
 struct zx_crtc {
@@ -220,6 +241,64 @@ void vou_inf_disable(enum vou_inf_id id, struct drm_crtc 
*crtc)
        zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0);
 }
 
+void zx_vou_config_dividers(struct drm_crtc *crtc,
+                           struct vou_div_config *configs, int num)
+{
+       struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+       struct zx_vou_hw *vou = zcrtc->vou;
+       const struct zx_crtc_bits *bits = zcrtc->bits;
+       int i;
+
+       /* Clear update flag bit */
+       zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, 0);
+
+       for (i = 0; i < num; i++) {
+               struct vou_div_config *cfg = configs + i;
+               u32 reg, shift;
+
+               switch (cfg->id) {
+               case VOU_DIV_VGA:
+                       reg = VOU_CLK_SEL;
+                       shift = bits->div_vga_shift;
+                       break;
+               case VOU_DIV_PIC:
+                       reg = VOU_CLK_SEL;
+                       shift = bits->div_pic_shift;
+                       break;
+               case VOU_DIV_TVENC:
+                       reg = VOU_DIV_PARA;
+                       shift = bits->div_tvenc_shift;
+                       break;
+               case VOU_DIV_HDMI_PNX:
+                       reg = VOU_DIV_PARA;
+                       shift = bits->div_hdmi_pnx_shift;
+                       break;
+               case VOU_DIV_HDMI:
+                       reg = VOU_DIV_PARA;
+                       shift = bits->div_hdmi_shift;
+                       break;
+               case VOU_DIV_INF:
+                       reg = VOU_DIV_PARA;
+                       shift = bits->div_inf_shift;
+                       break;
+               case VOU_DIV_LAYER:
+                       reg = VOU_DIV_PARA;
+                       shift = bits->div_layer_shift;
+                       break;
+               default:
+                       continue;
+               }
+
+               /* Each divider occupies 3 bits */
+               zx_writel_mask(vou->vouctl + reg, 0x7 << shift,
+                              cfg->val << shift);
+       }
+
+       /* Set update flag bit to get dividers effected */
+       zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE,
+                      DIV_PARA_UPDATE);
+}
+
 static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
 {
        zx_writel(zcrtc->chnreg + CHN_UPDATE, 1);
diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
index a41a0ad49857..0dae4faefac4 100644
--- a/drivers/gpu/drm/zte/zx_vou.h
+++ b/drivers/gpu/drm/zte/zx_vou.h
@@ -33,6 +33,31 @@ enum vou_inf_data_sel {
 void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc);
 void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc);
 
+enum vou_div_id {
+       VOU_DIV_VGA,
+       VOU_DIV_PIC,
+       VOU_DIV_TVENC,
+       VOU_DIV_HDMI_PNX,
+       VOU_DIV_HDMI,
+       VOU_DIV_INF,
+       VOU_DIV_LAYER,
+};
+
+enum vou_div_val {
+       VOU_DIV_1 = 0,
+       VOU_DIV_2 = 1,
+       VOU_DIV_4 = 3,
+       VOU_DIV_8 = 7,
+};
+
+struct vou_div_config {
+       enum vou_div_id id;
+       enum vou_div_val val;
+};
+
+void zx_vou_config_dividers(struct drm_crtc *crtc,
+                           struct vou_div_config *configs, int num);
+
 int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
 void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
 
diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h 
b/drivers/gpu/drm/zte/zx_vou_regs.h
index e6ed844e068a..552772137cf0 100644
--- a/drivers/gpu/drm/zte/zx_vou_regs.h
+++ b/drivers/gpu/drm/zte/zx_vou_regs.h
@@ -176,11 +176,27 @@
 #define VOU_INF_DATA_SEL               0x08
 #define VOU_SOFT_RST                   0x14
 #define VOU_CLK_SEL                    0x18
+#define VGA_AUX_DIV_SHIFT              29
+#define VGA_MAIN_DIV_SHIFT             26
+#define PIC_MAIN_DIV_SHIFT             23
+#define PIC_AUX_DIV_SHIFT              20
 #define VOU_CLK_VL2_SEL                        BIT(8)
 #define VOU_CLK_VL1_SEL                        BIT(7)
 #define VOU_CLK_VL0_SEL                        BIT(6)
 #define VOU_CLK_GL1_SEL                        BIT(5)
 #define VOU_CLK_GL0_SEL                        BIT(4)
+#define VOU_DIV_PARA                   0x1c
+#define DIV_PARA_UPDATE                        BIT(31)
+#define TVENC_AUX_DIV_SHIFT            28
+#define HDMI_AUX_PNX_DIV_SHIFT         25
+#define HDMI_MAIN_PNX_DIV_SHIFT                22
+#define HDMI_AUX_DIV_SHIFT             19
+#define HDMI_MAIN_DIV_SHIFT            16
+#define TVENC_MAIN_DIV_SHIFT           13
+#define INF_AUX_DIV_SHIFT              9
+#define INF_MAIN_DIV_SHIFT             6
+#define LAYER_AUX_DIV_SHIFT            3
+#define LAYER_MAIN_DIV_SHIFT           0
 #define VOU_CLK_REQEN                  0x20
 #define VOU_CLK_EN                     0x24
 
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to