drm: zte: add function to configure vou_ctrl dividers
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.guo@linaro.org> Reviewed-by: Sean Paul <seanpaul@chromium.org>
This commit is contained in:
Родитель
831a8d5e0b
Коммит
9cc2a68519
|
@ -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 @@ static const struct zx_crtc_bits main_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 @@ static const struct zx_crtc_bits aux_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 {
|
||||
|
@ -236,6 +257,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);
|
||||
|
|
|
@ -36,6 +36,31 @@ void vou_inf_hdmi_audio_sel(struct drm_crtc *crtc,
|
|||
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);
|
||||
|
||||
|
|
|
@ -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
|
||||
#define VOU_INF_HDMI_CTRL 0x30
|
||||
|
|
Загрузка…
Ссылка в новой задаче