18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2016 Linaro Ltd.
48c2ecf20Sopenharmony_ci * Copyright 2016 ZTE Corporation.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/clk.h>
88c2ecf20Sopenharmony_ci#include <linux/component.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/of_address.h>
118c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <video/videomode.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
168c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h>
178c2ecf20Sopenharmony_ci#include <drm/drm_fb_cma_helper.h>
188c2ecf20Sopenharmony_ci#include <drm/drm_fb_helper.h>
198c2ecf20Sopenharmony_ci#include <drm/drm_gem_cma_helper.h>
208c2ecf20Sopenharmony_ci#include <drm/drm_of.h>
218c2ecf20Sopenharmony_ci#include <drm/drm_plane_helper.h>
228c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h>
238c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "zx_common_regs.h"
268c2ecf20Sopenharmony_ci#include "zx_drm_drv.h"
278c2ecf20Sopenharmony_ci#include "zx_plane.h"
288c2ecf20Sopenharmony_ci#include "zx_vou.h"
298c2ecf20Sopenharmony_ci#include "zx_vou_regs.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define GL_NUM	2
328c2ecf20Sopenharmony_ci#define VL_NUM	3
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cienum vou_chn_type {
358c2ecf20Sopenharmony_ci	VOU_CHN_MAIN,
368c2ecf20Sopenharmony_ci	VOU_CHN_AUX,
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistruct zx_crtc_regs {
408c2ecf20Sopenharmony_ci	u32 fir_active;
418c2ecf20Sopenharmony_ci	u32 fir_htiming;
428c2ecf20Sopenharmony_ci	u32 fir_vtiming;
438c2ecf20Sopenharmony_ci	u32 sec_vtiming;
448c2ecf20Sopenharmony_ci	u32 timing_shift;
458c2ecf20Sopenharmony_ci	u32 timing_pi_shift;
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic const struct zx_crtc_regs main_crtc_regs = {
498c2ecf20Sopenharmony_ci	.fir_active = FIR_MAIN_ACTIVE,
508c2ecf20Sopenharmony_ci	.fir_htiming = FIR_MAIN_H_TIMING,
518c2ecf20Sopenharmony_ci	.fir_vtiming = FIR_MAIN_V_TIMING,
528c2ecf20Sopenharmony_ci	.sec_vtiming = SEC_MAIN_V_TIMING,
538c2ecf20Sopenharmony_ci	.timing_shift = TIMING_MAIN_SHIFT,
548c2ecf20Sopenharmony_ci	.timing_pi_shift = TIMING_MAIN_PI_SHIFT,
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic const struct zx_crtc_regs aux_crtc_regs = {
588c2ecf20Sopenharmony_ci	.fir_active = FIR_AUX_ACTIVE,
598c2ecf20Sopenharmony_ci	.fir_htiming = FIR_AUX_H_TIMING,
608c2ecf20Sopenharmony_ci	.fir_vtiming = FIR_AUX_V_TIMING,
618c2ecf20Sopenharmony_ci	.sec_vtiming = SEC_AUX_V_TIMING,
628c2ecf20Sopenharmony_ci	.timing_shift = TIMING_AUX_SHIFT,
638c2ecf20Sopenharmony_ci	.timing_pi_shift = TIMING_AUX_PI_SHIFT,
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistruct zx_crtc_bits {
678c2ecf20Sopenharmony_ci	u32 polarity_mask;
688c2ecf20Sopenharmony_ci	u32 polarity_shift;
698c2ecf20Sopenharmony_ci	u32 int_frame_mask;
708c2ecf20Sopenharmony_ci	u32 tc_enable;
718c2ecf20Sopenharmony_ci	u32 sec_vactive_shift;
728c2ecf20Sopenharmony_ci	u32 sec_vactive_mask;
738c2ecf20Sopenharmony_ci	u32 interlace_select;
748c2ecf20Sopenharmony_ci	u32 pi_enable;
758c2ecf20Sopenharmony_ci	u32 div_vga_shift;
768c2ecf20Sopenharmony_ci	u32 div_pic_shift;
778c2ecf20Sopenharmony_ci	u32 div_tvenc_shift;
788c2ecf20Sopenharmony_ci	u32 div_hdmi_pnx_shift;
798c2ecf20Sopenharmony_ci	u32 div_hdmi_shift;
808c2ecf20Sopenharmony_ci	u32 div_inf_shift;
818c2ecf20Sopenharmony_ci	u32 div_layer_shift;
828c2ecf20Sopenharmony_ci};
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic const struct zx_crtc_bits main_crtc_bits = {
858c2ecf20Sopenharmony_ci	.polarity_mask = MAIN_POL_MASK,
868c2ecf20Sopenharmony_ci	.polarity_shift = MAIN_POL_SHIFT,
878c2ecf20Sopenharmony_ci	.int_frame_mask = TIMING_INT_MAIN_FRAME,
888c2ecf20Sopenharmony_ci	.tc_enable = MAIN_TC_EN,
898c2ecf20Sopenharmony_ci	.sec_vactive_shift = SEC_VACT_MAIN_SHIFT,
908c2ecf20Sopenharmony_ci	.sec_vactive_mask = SEC_VACT_MAIN_MASK,
918c2ecf20Sopenharmony_ci	.interlace_select = MAIN_INTERLACE_SEL,
928c2ecf20Sopenharmony_ci	.pi_enable = MAIN_PI_EN,
938c2ecf20Sopenharmony_ci	.div_vga_shift = VGA_MAIN_DIV_SHIFT,
948c2ecf20Sopenharmony_ci	.div_pic_shift = PIC_MAIN_DIV_SHIFT,
958c2ecf20Sopenharmony_ci	.div_tvenc_shift = TVENC_MAIN_DIV_SHIFT,
968c2ecf20Sopenharmony_ci	.div_hdmi_pnx_shift = HDMI_MAIN_PNX_DIV_SHIFT,
978c2ecf20Sopenharmony_ci	.div_hdmi_shift = HDMI_MAIN_DIV_SHIFT,
988c2ecf20Sopenharmony_ci	.div_inf_shift = INF_MAIN_DIV_SHIFT,
998c2ecf20Sopenharmony_ci	.div_layer_shift = LAYER_MAIN_DIV_SHIFT,
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic const struct zx_crtc_bits aux_crtc_bits = {
1038c2ecf20Sopenharmony_ci	.polarity_mask = AUX_POL_MASK,
1048c2ecf20Sopenharmony_ci	.polarity_shift = AUX_POL_SHIFT,
1058c2ecf20Sopenharmony_ci	.int_frame_mask = TIMING_INT_AUX_FRAME,
1068c2ecf20Sopenharmony_ci	.tc_enable = AUX_TC_EN,
1078c2ecf20Sopenharmony_ci	.sec_vactive_shift = SEC_VACT_AUX_SHIFT,
1088c2ecf20Sopenharmony_ci	.sec_vactive_mask = SEC_VACT_AUX_MASK,
1098c2ecf20Sopenharmony_ci	.interlace_select = AUX_INTERLACE_SEL,
1108c2ecf20Sopenharmony_ci	.pi_enable = AUX_PI_EN,
1118c2ecf20Sopenharmony_ci	.div_vga_shift = VGA_AUX_DIV_SHIFT,
1128c2ecf20Sopenharmony_ci	.div_pic_shift = PIC_AUX_DIV_SHIFT,
1138c2ecf20Sopenharmony_ci	.div_tvenc_shift = TVENC_AUX_DIV_SHIFT,
1148c2ecf20Sopenharmony_ci	.div_hdmi_pnx_shift = HDMI_AUX_PNX_DIV_SHIFT,
1158c2ecf20Sopenharmony_ci	.div_hdmi_shift = HDMI_AUX_DIV_SHIFT,
1168c2ecf20Sopenharmony_ci	.div_inf_shift = INF_AUX_DIV_SHIFT,
1178c2ecf20Sopenharmony_ci	.div_layer_shift = LAYER_AUX_DIV_SHIFT,
1188c2ecf20Sopenharmony_ci};
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistruct zx_crtc {
1218c2ecf20Sopenharmony_ci	struct drm_crtc crtc;
1228c2ecf20Sopenharmony_ci	struct drm_plane *primary;
1238c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou;
1248c2ecf20Sopenharmony_ci	void __iomem *chnreg;
1258c2ecf20Sopenharmony_ci	void __iomem *chncsc;
1268c2ecf20Sopenharmony_ci	void __iomem *dither;
1278c2ecf20Sopenharmony_ci	const struct zx_crtc_regs *regs;
1288c2ecf20Sopenharmony_ci	const struct zx_crtc_bits *bits;
1298c2ecf20Sopenharmony_ci	enum vou_chn_type chn_type;
1308c2ecf20Sopenharmony_ci	struct clk *pixclk;
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc)
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistruct vou_layer_bits {
1368c2ecf20Sopenharmony_ci	u32 enable;
1378c2ecf20Sopenharmony_ci	u32 chnsel;
1388c2ecf20Sopenharmony_ci	u32 clksel;
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic const struct vou_layer_bits zx_gl_bits[GL_NUM] = {
1428c2ecf20Sopenharmony_ci	{
1438c2ecf20Sopenharmony_ci		.enable = OSD_CTRL0_GL0_EN,
1448c2ecf20Sopenharmony_ci		.chnsel = OSD_CTRL0_GL0_SEL,
1458c2ecf20Sopenharmony_ci		.clksel = VOU_CLK_GL0_SEL,
1468c2ecf20Sopenharmony_ci	}, {
1478c2ecf20Sopenharmony_ci		.enable = OSD_CTRL0_GL1_EN,
1488c2ecf20Sopenharmony_ci		.chnsel = OSD_CTRL0_GL1_SEL,
1498c2ecf20Sopenharmony_ci		.clksel = VOU_CLK_GL1_SEL,
1508c2ecf20Sopenharmony_ci	},
1518c2ecf20Sopenharmony_ci};
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic const struct vou_layer_bits zx_vl_bits[VL_NUM] = {
1548c2ecf20Sopenharmony_ci	{
1558c2ecf20Sopenharmony_ci		.enable = OSD_CTRL0_VL0_EN,
1568c2ecf20Sopenharmony_ci		.chnsel = OSD_CTRL0_VL0_SEL,
1578c2ecf20Sopenharmony_ci		.clksel = VOU_CLK_VL0_SEL,
1588c2ecf20Sopenharmony_ci	}, {
1598c2ecf20Sopenharmony_ci		.enable = OSD_CTRL0_VL1_EN,
1608c2ecf20Sopenharmony_ci		.chnsel = OSD_CTRL0_VL1_SEL,
1618c2ecf20Sopenharmony_ci		.clksel = VOU_CLK_VL1_SEL,
1628c2ecf20Sopenharmony_ci	}, {
1638c2ecf20Sopenharmony_ci		.enable = OSD_CTRL0_VL2_EN,
1648c2ecf20Sopenharmony_ci		.chnsel = OSD_CTRL0_VL2_SEL,
1658c2ecf20Sopenharmony_ci		.clksel = VOU_CLK_VL2_SEL,
1668c2ecf20Sopenharmony_ci	},
1678c2ecf20Sopenharmony_ci};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistruct zx_vou_hw {
1708c2ecf20Sopenharmony_ci	struct device *dev;
1718c2ecf20Sopenharmony_ci	void __iomem *osd;
1728c2ecf20Sopenharmony_ci	void __iomem *timing;
1738c2ecf20Sopenharmony_ci	void __iomem *vouctl;
1748c2ecf20Sopenharmony_ci	void __iomem *otfppu;
1758c2ecf20Sopenharmony_ci	void __iomem *dtrc;
1768c2ecf20Sopenharmony_ci	struct clk *axi_clk;
1778c2ecf20Sopenharmony_ci	struct clk *ppu_clk;
1788c2ecf20Sopenharmony_ci	struct clk *main_clk;
1798c2ecf20Sopenharmony_ci	struct clk *aux_clk;
1808c2ecf20Sopenharmony_ci	struct zx_crtc *main_crtc;
1818c2ecf20Sopenharmony_ci	struct zx_crtc *aux_crtc;
1828c2ecf20Sopenharmony_ci};
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cienum vou_inf_data_sel {
1858c2ecf20Sopenharmony_ci	VOU_YUV444	= 0,
1868c2ecf20Sopenharmony_ci	VOU_RGB_101010	= 1,
1878c2ecf20Sopenharmony_ci	VOU_RGB_888	= 2,
1888c2ecf20Sopenharmony_ci	VOU_RGB_666	= 3,
1898c2ecf20Sopenharmony_ci};
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistruct vou_inf {
1928c2ecf20Sopenharmony_ci	enum vou_inf_id id;
1938c2ecf20Sopenharmony_ci	enum vou_inf_data_sel data_sel;
1948c2ecf20Sopenharmony_ci	u32 clocks_en_bits;
1958c2ecf20Sopenharmony_ci	u32 clocks_sel_bits;
1968c2ecf20Sopenharmony_ci};
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic struct vou_inf vou_infs[] = {
1998c2ecf20Sopenharmony_ci	[VOU_HDMI] = {
2008c2ecf20Sopenharmony_ci		.data_sel = VOU_YUV444,
2018c2ecf20Sopenharmony_ci		.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
2028c2ecf20Sopenharmony_ci		.clocks_sel_bits = BIT(13) | BIT(2),
2038c2ecf20Sopenharmony_ci	},
2048c2ecf20Sopenharmony_ci	[VOU_TV_ENC] = {
2058c2ecf20Sopenharmony_ci		.data_sel = VOU_YUV444,
2068c2ecf20Sopenharmony_ci		.clocks_en_bits = BIT(15),
2078c2ecf20Sopenharmony_ci		.clocks_sel_bits = BIT(11) | BIT(0),
2088c2ecf20Sopenharmony_ci	},
2098c2ecf20Sopenharmony_ci	[VOU_VGA] = {
2108c2ecf20Sopenharmony_ci		.data_sel = VOU_RGB_888,
2118c2ecf20Sopenharmony_ci		.clocks_en_bits = BIT(1),
2128c2ecf20Sopenharmony_ci		.clocks_sel_bits = BIT(10),
2138c2ecf20Sopenharmony_ci	},
2148c2ecf20Sopenharmony_ci};
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	return zcrtc->vou;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_civoid vou_inf_hdmi_audio_sel(struct drm_crtc *crtc,
2248c2ecf20Sopenharmony_ci			    enum vou_inf_hdmi_audio aud)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
2278c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = zcrtc->vou;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_INF_HDMI_CTRL, VOU_HDMI_AUD_MASK, aud);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_civoid vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
2358c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = zcrtc->vou;
2368c2ecf20Sopenharmony_ci	struct vou_inf *inf = &vou_infs[id];
2378c2ecf20Sopenharmony_ci	void __iomem *dither = zcrtc->dither;
2388c2ecf20Sopenharmony_ci	void __iomem *csc = zcrtc->chncsc;
2398c2ecf20Sopenharmony_ci	bool is_main = zcrtc->chn_type == VOU_CHN_MAIN;
2408c2ecf20Sopenharmony_ci	u32 data_sel_shift = id << 1;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (inf->data_sel != VOU_YUV444) {
2438c2ecf20Sopenharmony_ci		/* Enable channel CSC for RGB output */
2448c2ecf20Sopenharmony_ci		zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
2458c2ecf20Sopenharmony_ci			       CSC_BT709_IMAGE_YCBCR2RGB << CSC_COV_MODE_SHIFT);
2468c2ecf20Sopenharmony_ci		zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE,
2478c2ecf20Sopenharmony_ci			       CSC_WORK_ENABLE);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		/* Bypass Dither block for RGB output */
2508c2ecf20Sopenharmony_ci		zx_writel_mask(dither + OSD_DITHER_CTRL0, DITHER_BYSPASS,
2518c2ecf20Sopenharmony_ci			       DITHER_BYSPASS);
2528c2ecf20Sopenharmony_ci	} else {
2538c2ecf20Sopenharmony_ci		zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, 0);
2548c2ecf20Sopenharmony_ci		zx_writel_mask(dither + OSD_DITHER_CTRL0, DITHER_BYSPASS, 0);
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/* Select data format */
2588c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift,
2598c2ecf20Sopenharmony_ci		       inf->data_sel << data_sel_shift);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	/* Select channel */
2628c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << id,
2638c2ecf20Sopenharmony_ci		       zcrtc->chn_type << id);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	/* Select interface clocks */
2668c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits,
2678c2ecf20Sopenharmony_ci		       is_main ? 0 : inf->clocks_sel_bits);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* Enable interface clocks */
2708c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits,
2718c2ecf20Sopenharmony_ci		       inf->clocks_en_bits);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* Enable the device */
2748c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 1 << id);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_civoid vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = crtc_to_vou(crtc);
2808c2ecf20Sopenharmony_ci	struct vou_inf *inf = &vou_infs[id];
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	/* Disable the device */
2838c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 0);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* Disable interface clocks */
2868c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_civoid zx_vou_config_dividers(struct drm_crtc *crtc,
2908c2ecf20Sopenharmony_ci			    struct vou_div_config *configs, int num)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
2938c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = zcrtc->vou;
2948c2ecf20Sopenharmony_ci	const struct zx_crtc_bits *bits = zcrtc->bits;
2958c2ecf20Sopenharmony_ci	int i;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/* Clear update flag bit */
2988c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, 0);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
3018c2ecf20Sopenharmony_ci		struct vou_div_config *cfg = configs + i;
3028c2ecf20Sopenharmony_ci		u32 reg, shift;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		switch (cfg->id) {
3058c2ecf20Sopenharmony_ci		case VOU_DIV_VGA:
3068c2ecf20Sopenharmony_ci			reg = VOU_CLK_SEL;
3078c2ecf20Sopenharmony_ci			shift = bits->div_vga_shift;
3088c2ecf20Sopenharmony_ci			break;
3098c2ecf20Sopenharmony_ci		case VOU_DIV_PIC:
3108c2ecf20Sopenharmony_ci			reg = VOU_CLK_SEL;
3118c2ecf20Sopenharmony_ci			shift = bits->div_pic_shift;
3128c2ecf20Sopenharmony_ci			break;
3138c2ecf20Sopenharmony_ci		case VOU_DIV_TVENC:
3148c2ecf20Sopenharmony_ci			reg = VOU_DIV_PARA;
3158c2ecf20Sopenharmony_ci			shift = bits->div_tvenc_shift;
3168c2ecf20Sopenharmony_ci			break;
3178c2ecf20Sopenharmony_ci		case VOU_DIV_HDMI_PNX:
3188c2ecf20Sopenharmony_ci			reg = VOU_DIV_PARA;
3198c2ecf20Sopenharmony_ci			shift = bits->div_hdmi_pnx_shift;
3208c2ecf20Sopenharmony_ci			break;
3218c2ecf20Sopenharmony_ci		case VOU_DIV_HDMI:
3228c2ecf20Sopenharmony_ci			reg = VOU_DIV_PARA;
3238c2ecf20Sopenharmony_ci			shift = bits->div_hdmi_shift;
3248c2ecf20Sopenharmony_ci			break;
3258c2ecf20Sopenharmony_ci		case VOU_DIV_INF:
3268c2ecf20Sopenharmony_ci			reg = VOU_DIV_PARA;
3278c2ecf20Sopenharmony_ci			shift = bits->div_inf_shift;
3288c2ecf20Sopenharmony_ci			break;
3298c2ecf20Sopenharmony_ci		case VOU_DIV_LAYER:
3308c2ecf20Sopenharmony_ci			reg = VOU_DIV_PARA;
3318c2ecf20Sopenharmony_ci			shift = bits->div_layer_shift;
3328c2ecf20Sopenharmony_ci			break;
3338c2ecf20Sopenharmony_ci		default:
3348c2ecf20Sopenharmony_ci			continue;
3358c2ecf20Sopenharmony_ci		}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		/* Each divider occupies 3 bits */
3388c2ecf20Sopenharmony_ci		zx_writel_mask(vou->vouctl + reg, 0x7 << shift,
3398c2ecf20Sopenharmony_ci			       cfg->val << shift);
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* Set update flag bit to get dividers effected */
3438c2ecf20Sopenharmony_ci	zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE,
3448c2ecf20Sopenharmony_ci		       DIV_PARA_UPDATE);
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic inline void vou_chn_set_update(struct zx_crtc *zcrtc)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	zx_writel(zcrtc->chnreg + CHN_UPDATE, 1);
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic void zx_crtc_atomic_enable(struct drm_crtc *crtc,
3538c2ecf20Sopenharmony_ci				  struct drm_crtc_state *old_state)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
3568c2ecf20Sopenharmony_ci	bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
3578c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
3588c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = zcrtc->vou;
3598c2ecf20Sopenharmony_ci	const struct zx_crtc_regs *regs = zcrtc->regs;
3608c2ecf20Sopenharmony_ci	const struct zx_crtc_bits *bits = zcrtc->bits;
3618c2ecf20Sopenharmony_ci	struct videomode vm;
3628c2ecf20Sopenharmony_ci	u32 scan_mask;
3638c2ecf20Sopenharmony_ci	u32 pol = 0;
3648c2ecf20Sopenharmony_ci	u32 val;
3658c2ecf20Sopenharmony_ci	int ret;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	drm_display_mode_to_videomode(mode, &vm);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* Set up timing parameters */
3708c2ecf20Sopenharmony_ci	val = V_ACTIVE((interlaced ? vm.vactive / 2 : vm.vactive) - 1);
3718c2ecf20Sopenharmony_ci	val |= H_ACTIVE(vm.hactive - 1);
3728c2ecf20Sopenharmony_ci	zx_writel(vou->timing + regs->fir_active, val);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	val = SYNC_WIDE(vm.hsync_len - 1);
3758c2ecf20Sopenharmony_ci	val |= BACK_PORCH(vm.hback_porch - 1);
3768c2ecf20Sopenharmony_ci	val |= FRONT_PORCH(vm.hfront_porch - 1);
3778c2ecf20Sopenharmony_ci	zx_writel(vou->timing + regs->fir_htiming, val);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	val = SYNC_WIDE(vm.vsync_len - 1);
3808c2ecf20Sopenharmony_ci	val |= BACK_PORCH(vm.vback_porch - 1);
3818c2ecf20Sopenharmony_ci	val |= FRONT_PORCH(vm.vfront_porch - 1);
3828c2ecf20Sopenharmony_ci	zx_writel(vou->timing + regs->fir_vtiming, val);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (interlaced) {
3858c2ecf20Sopenharmony_ci		u32 shift = bits->sec_vactive_shift;
3868c2ecf20Sopenharmony_ci		u32 mask = bits->sec_vactive_mask;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci		val = zx_readl(vou->timing + SEC_V_ACTIVE);
3898c2ecf20Sopenharmony_ci		val &= ~mask;
3908c2ecf20Sopenharmony_ci		val |= ((vm.vactive / 2 - 1) << shift) & mask;
3918c2ecf20Sopenharmony_ci		zx_writel(vou->timing + SEC_V_ACTIVE, val);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		val = SYNC_WIDE(vm.vsync_len - 1);
3948c2ecf20Sopenharmony_ci		/*
3958c2ecf20Sopenharmony_ci		 * The vback_porch for the second field needs to shift one on
3968c2ecf20Sopenharmony_ci		 * the value for the first field.
3978c2ecf20Sopenharmony_ci		 */
3988c2ecf20Sopenharmony_ci		val |= BACK_PORCH(vm.vback_porch);
3998c2ecf20Sopenharmony_ci		val |= FRONT_PORCH(vm.vfront_porch - 1);
4008c2ecf20Sopenharmony_ci		zx_writel(vou->timing + regs->sec_vtiming, val);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* Set up polarities */
4048c2ecf20Sopenharmony_ci	if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
4058c2ecf20Sopenharmony_ci		pol |= 1 << POL_VSYNC_SHIFT;
4068c2ecf20Sopenharmony_ci	if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW)
4078c2ecf20Sopenharmony_ci		pol |= 1 << POL_HSYNC_SHIFT;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	zx_writel_mask(vou->timing + TIMING_CTRL, bits->polarity_mask,
4108c2ecf20Sopenharmony_ci		       pol << bits->polarity_shift);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* Setup SHIFT register by following what ZTE BSP does */
4138c2ecf20Sopenharmony_ci	val = H_SHIFT_VAL;
4148c2ecf20Sopenharmony_ci	if (interlaced)
4158c2ecf20Sopenharmony_ci		val |= V_SHIFT_VAL << 16;
4168c2ecf20Sopenharmony_ci	zx_writel(vou->timing + regs->timing_shift, val);
4178c2ecf20Sopenharmony_ci	zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/* Progressive or interlace scan select */
4208c2ecf20Sopenharmony_ci	scan_mask = bits->interlace_select | bits->pi_enable;
4218c2ecf20Sopenharmony_ci	zx_writel_mask(vou->timing + SCAN_CTRL, scan_mask,
4228c2ecf20Sopenharmony_ci		       interlaced ? scan_mask : 0);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/* Enable TIMING_CTRL */
4258c2ecf20Sopenharmony_ci	zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable,
4268c2ecf20Sopenharmony_ci		       bits->tc_enable);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* Configure channel screen size */
4298c2ecf20Sopenharmony_ci	zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_W_MASK,
4308c2ecf20Sopenharmony_ci		       vm.hactive << CHN_SCREEN_W_SHIFT);
4318c2ecf20Sopenharmony_ci	zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK,
4328c2ecf20Sopenharmony_ci		       vm.vactive << CHN_SCREEN_H_SHIFT);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* Configure channel interlace buffer control */
4358c2ecf20Sopenharmony_ci	zx_writel_mask(zcrtc->chnreg + CHN_INTERLACE_BUF_CTRL, CHN_INTERLACE_EN,
4368c2ecf20Sopenharmony_ci		       interlaced ? CHN_INTERLACE_EN : 0);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	/* Update channel */
4398c2ecf20Sopenharmony_ci	vou_chn_set_update(zcrtc);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	/* Enable channel */
4428c2ecf20Sopenharmony_ci	zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, CHN_ENABLE);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	drm_crtc_vblank_on(crtc);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	ret = clk_set_rate(zcrtc->pixclk, mode->clock * 1000);
4478c2ecf20Sopenharmony_ci	if (ret) {
4488c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(vou->dev, "failed to set pixclk rate: %d\n", ret);
4498c2ecf20Sopenharmony_ci		return;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(zcrtc->pixclk);
4538c2ecf20Sopenharmony_ci	if (ret)
4548c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(vou->dev, "failed to enable pixclk: %d\n", ret);
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic void zx_crtc_atomic_disable(struct drm_crtc *crtc,
4588c2ecf20Sopenharmony_ci				   struct drm_crtc_state *old_state)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
4618c2ecf20Sopenharmony_ci	const struct zx_crtc_bits *bits = zcrtc->bits;
4628c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = zcrtc->vou;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	clk_disable_unprepare(zcrtc->pixclk);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	drm_crtc_vblank_off(crtc);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	/* Disable channel */
4698c2ecf20Sopenharmony_ci	zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, 0);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* Disable TIMING_CTRL */
4728c2ecf20Sopenharmony_ci	zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable, 0);
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic void zx_crtc_atomic_flush(struct drm_crtc *crtc,
4768c2ecf20Sopenharmony_ci				  struct drm_crtc_state *old_state)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct drm_pending_vblank_event *event = crtc->state->event;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	if (!event)
4818c2ecf20Sopenharmony_ci		return;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	crtc->state->event = NULL;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	spin_lock_irq(&crtc->dev->event_lock);
4868c2ecf20Sopenharmony_ci	if (drm_crtc_vblank_get(crtc) == 0)
4878c2ecf20Sopenharmony_ci		drm_crtc_arm_vblank_event(crtc, event);
4888c2ecf20Sopenharmony_ci	else
4898c2ecf20Sopenharmony_ci		drm_crtc_send_vblank_event(crtc, event);
4908c2ecf20Sopenharmony_ci	spin_unlock_irq(&crtc->dev->event_lock);
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic const struct drm_crtc_helper_funcs zx_crtc_helper_funcs = {
4948c2ecf20Sopenharmony_ci	.atomic_flush = zx_crtc_atomic_flush,
4958c2ecf20Sopenharmony_ci	.atomic_enable = zx_crtc_atomic_enable,
4968c2ecf20Sopenharmony_ci	.atomic_disable = zx_crtc_atomic_disable,
4978c2ecf20Sopenharmony_ci};
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_cistatic int zx_vou_enable_vblank(struct drm_crtc *crtc)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
5028c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = crtc_to_vou(crtc);
5038c2ecf20Sopenharmony_ci	u32 int_frame_mask = zcrtc->bits->int_frame_mask;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	zx_writel_mask(vou->timing + TIMING_INT_CTRL, int_frame_mask,
5068c2ecf20Sopenharmony_ci		       int_frame_mask);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	return 0;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cistatic void zx_vou_disable_vblank(struct drm_crtc *crtc)
5128c2ecf20Sopenharmony_ci{
5138c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
5148c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = crtc_to_vou(crtc);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	zx_writel_mask(vou->timing + TIMING_INT_CTRL,
5178c2ecf20Sopenharmony_ci		       zcrtc->bits->int_frame_mask, 0);
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic const struct drm_crtc_funcs zx_crtc_funcs = {
5218c2ecf20Sopenharmony_ci	.destroy = drm_crtc_cleanup,
5228c2ecf20Sopenharmony_ci	.set_config = drm_atomic_helper_set_config,
5238c2ecf20Sopenharmony_ci	.page_flip = drm_atomic_helper_page_flip,
5248c2ecf20Sopenharmony_ci	.reset = drm_atomic_helper_crtc_reset,
5258c2ecf20Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
5268c2ecf20Sopenharmony_ci	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
5278c2ecf20Sopenharmony_ci	.enable_vblank = zx_vou_enable_vblank,
5288c2ecf20Sopenharmony_ci	.disable_vblank = zx_vou_disable_vblank,
5298c2ecf20Sopenharmony_ci};
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
5328c2ecf20Sopenharmony_ci			enum vou_chn_type chn_type)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct device *dev = vou->dev;
5358c2ecf20Sopenharmony_ci	struct zx_plane *zplane;
5368c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc;
5378c2ecf20Sopenharmony_ci	int ret;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	zcrtc = devm_kzalloc(dev, sizeof(*zcrtc), GFP_KERNEL);
5408c2ecf20Sopenharmony_ci	if (!zcrtc)
5418c2ecf20Sopenharmony_ci		return -ENOMEM;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	zcrtc->vou = vou;
5448c2ecf20Sopenharmony_ci	zcrtc->chn_type = chn_type;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
5478c2ecf20Sopenharmony_ci	if (!zplane)
5488c2ecf20Sopenharmony_ci		return -ENOMEM;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	zplane->dev = dev;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	if (chn_type == VOU_CHN_MAIN) {
5538c2ecf20Sopenharmony_ci		zplane->layer = vou->osd + MAIN_GL_OFFSET;
5548c2ecf20Sopenharmony_ci		zplane->csc = vou->osd + MAIN_GL_CSC_OFFSET;
5558c2ecf20Sopenharmony_ci		zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET;
5568c2ecf20Sopenharmony_ci		zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET;
5578c2ecf20Sopenharmony_ci		zplane->bits = &zx_gl_bits[0];
5588c2ecf20Sopenharmony_ci		zcrtc->chnreg = vou->osd + OSD_MAIN_CHN;
5598c2ecf20Sopenharmony_ci		zcrtc->chncsc = vou->osd + MAIN_CHN_CSC_OFFSET;
5608c2ecf20Sopenharmony_ci		zcrtc->dither = vou->osd + MAIN_DITHER_OFFSET;
5618c2ecf20Sopenharmony_ci		zcrtc->regs = &main_crtc_regs;
5628c2ecf20Sopenharmony_ci		zcrtc->bits = &main_crtc_bits;
5638c2ecf20Sopenharmony_ci	} else {
5648c2ecf20Sopenharmony_ci		zplane->layer = vou->osd + AUX_GL_OFFSET;
5658c2ecf20Sopenharmony_ci		zplane->csc = vou->osd + AUX_GL_CSC_OFFSET;
5668c2ecf20Sopenharmony_ci		zplane->hbsc = vou->osd + AUX_HBSC_OFFSET;
5678c2ecf20Sopenharmony_ci		zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET;
5688c2ecf20Sopenharmony_ci		zplane->bits = &zx_gl_bits[1];
5698c2ecf20Sopenharmony_ci		zcrtc->chnreg = vou->osd + OSD_AUX_CHN;
5708c2ecf20Sopenharmony_ci		zcrtc->chncsc = vou->osd + AUX_CHN_CSC_OFFSET;
5718c2ecf20Sopenharmony_ci		zcrtc->dither = vou->osd + AUX_DITHER_OFFSET;
5728c2ecf20Sopenharmony_ci		zcrtc->regs = &aux_crtc_regs;
5738c2ecf20Sopenharmony_ci		zcrtc->bits = &aux_crtc_bits;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	zcrtc->pixclk = devm_clk_get(dev, (chn_type == VOU_CHN_MAIN) ?
5778c2ecf20Sopenharmony_ci					  "main_wclk" : "aux_wclk");
5788c2ecf20Sopenharmony_ci	if (IS_ERR(zcrtc->pixclk)) {
5798c2ecf20Sopenharmony_ci		ret = PTR_ERR(zcrtc->pixclk);
5808c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to get pix clk: %d\n", ret);
5818c2ecf20Sopenharmony_ci		return ret;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_PRIMARY);
5858c2ecf20Sopenharmony_ci	if (ret) {
5868c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to init primary plane: %d\n", ret);
5878c2ecf20Sopenharmony_ci		return ret;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	zcrtc->primary = &zplane->plane;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL,
5938c2ecf20Sopenharmony_ci					&zx_crtc_funcs, NULL);
5948c2ecf20Sopenharmony_ci	if (ret) {
5958c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to init drm crtc: %d\n", ret);
5968c2ecf20Sopenharmony_ci		return ret;
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	drm_crtc_helper_add(&zcrtc->crtc, &zx_crtc_helper_funcs);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (chn_type == VOU_CHN_MAIN)
6028c2ecf20Sopenharmony_ci		vou->main_crtc = zcrtc;
6038c2ecf20Sopenharmony_ci	else
6048c2ecf20Sopenharmony_ci		vou->aux_crtc = zcrtc;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	return 0;
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_civoid zx_vou_layer_enable(struct drm_plane *plane)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(plane->state->crtc);
6128c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = zcrtc->vou;
6138c2ecf20Sopenharmony_ci	struct zx_plane *zplane = to_zx_plane(plane);
6148c2ecf20Sopenharmony_ci	const struct vou_layer_bits *bits = zplane->bits;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (zcrtc->chn_type == VOU_CHN_MAIN) {
6178c2ecf20Sopenharmony_ci		zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel, 0);
6188c2ecf20Sopenharmony_ci		zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel, 0);
6198c2ecf20Sopenharmony_ci	} else {
6208c2ecf20Sopenharmony_ci		zx_writel_mask(vou->osd + OSD_CTRL0, bits->chnsel,
6218c2ecf20Sopenharmony_ci			       bits->chnsel);
6228c2ecf20Sopenharmony_ci		zx_writel_mask(vou->vouctl + VOU_CLK_SEL, bits->clksel,
6238c2ecf20Sopenharmony_ci			       bits->clksel);
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, bits->enable);
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_civoid zx_vou_layer_disable(struct drm_plane *plane,
6308c2ecf20Sopenharmony_ci			  struct drm_plane_state *old_state)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	struct zx_crtc *zcrtc = to_zx_crtc(old_state->crtc);
6338c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = zcrtc->vou;
6348c2ecf20Sopenharmony_ci	struct zx_plane *zplane = to_zx_plane(plane);
6358c2ecf20Sopenharmony_ci	const struct vou_layer_bits *bits = zplane->bits;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	zx_writel_mask(vou->osd + OSD_CTRL0, bits->enable, 0);
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_cistatic void zx_overlay_init(struct drm_device *drm, struct zx_vou_hw *vou)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	struct device *dev = vou->dev;
6438c2ecf20Sopenharmony_ci	struct zx_plane *zplane;
6448c2ecf20Sopenharmony_ci	int i;
6458c2ecf20Sopenharmony_ci	int ret;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	/*
6488c2ecf20Sopenharmony_ci	 * VL0 has some quirks on scaling support which need special handling.
6498c2ecf20Sopenharmony_ci	 * Let's leave it out for now.
6508c2ecf20Sopenharmony_ci	 */
6518c2ecf20Sopenharmony_ci	for (i = 1; i < VL_NUM; i++) {
6528c2ecf20Sopenharmony_ci		zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
6538c2ecf20Sopenharmony_ci		if (!zplane) {
6548c2ecf20Sopenharmony_ci			DRM_DEV_ERROR(dev, "failed to allocate zplane %d\n", i);
6558c2ecf20Sopenharmony_ci			return;
6568c2ecf20Sopenharmony_ci		}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci		zplane->layer = vou->osd + OSD_VL_OFFSET(i);
6598c2ecf20Sopenharmony_ci		zplane->hbsc = vou->osd + HBSC_VL_OFFSET(i);
6608c2ecf20Sopenharmony_ci		zplane->rsz = vou->otfppu + RSZ_VL_OFFSET(i);
6618c2ecf20Sopenharmony_ci		zplane->bits = &zx_vl_bits[i];
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		ret = zx_plane_init(drm, zplane, DRM_PLANE_TYPE_OVERLAY);
6648c2ecf20Sopenharmony_ci		if (ret) {
6658c2ecf20Sopenharmony_ci			DRM_DEV_ERROR(dev, "failed to init overlay %d\n", i);
6668c2ecf20Sopenharmony_ci			continue;
6678c2ecf20Sopenharmony_ci		}
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic inline void zx_osd_int_update(struct zx_crtc *zcrtc)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	struct drm_crtc *crtc = &zcrtc->crtc;
6748c2ecf20Sopenharmony_ci	struct drm_plane *plane;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	vou_chn_set_update(zcrtc);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	drm_for_each_plane_mask(plane, crtc->dev, crtc->state->plane_mask)
6798c2ecf20Sopenharmony_ci		zx_plane_set_update(plane);
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic irqreturn_t vou_irq_handler(int irq, void *dev_id)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = dev_id;
6858c2ecf20Sopenharmony_ci	u32 state;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	/* Handle TIMING_CTRL frame interrupts */
6888c2ecf20Sopenharmony_ci	state = zx_readl(vou->timing + TIMING_INT_STATE);
6898c2ecf20Sopenharmony_ci	zx_writel(vou->timing + TIMING_INT_STATE, state);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (state & TIMING_INT_MAIN_FRAME)
6928c2ecf20Sopenharmony_ci		drm_crtc_handle_vblank(&vou->main_crtc->crtc);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	if (state & TIMING_INT_AUX_FRAME)
6958c2ecf20Sopenharmony_ci		drm_crtc_handle_vblank(&vou->aux_crtc->crtc);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	/* Handle OSD interrupts */
6988c2ecf20Sopenharmony_ci	state = zx_readl(vou->osd + OSD_INT_STA);
6998c2ecf20Sopenharmony_ci	zx_writel(vou->osd + OSD_INT_CLRSTA, state);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	if (state & OSD_INT_MAIN_UPT)
7028c2ecf20Sopenharmony_ci		zx_osd_int_update(vou->main_crtc);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	if (state & OSD_INT_AUX_UPT)
7058c2ecf20Sopenharmony_ci		zx_osd_int_update(vou->aux_crtc);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (state & OSD_INT_ERROR)
7088c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(vou->dev, "OSD ERROR: 0x%08x!\n", state);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic void vou_dtrc_init(struct zx_vou_hw *vou)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	/* Clear bit for bypass by ID */
7168c2ecf20Sopenharmony_ci	zx_writel_mask(vou->dtrc + DTRC_DETILE_CTRL,
7178c2ecf20Sopenharmony_ci		       TILE2RASTESCAN_BYPASS_MODE, 0);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	/* Select ARIDR mode */
7208c2ecf20Sopenharmony_ci	zx_writel_mask(vou->dtrc + DTRC_DETILE_CTRL, DETILE_ARIDR_MODE_MASK,
7218c2ecf20Sopenharmony_ci		       DETILE_ARID_IN_ARIDR);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	/* Bypass decompression for both frames */
7248c2ecf20Sopenharmony_ci	zx_writel_mask(vou->dtrc + DTRC_F0_CTRL, DTRC_DECOMPRESS_BYPASS,
7258c2ecf20Sopenharmony_ci		       DTRC_DECOMPRESS_BYPASS);
7268c2ecf20Sopenharmony_ci	zx_writel_mask(vou->dtrc + DTRC_F1_CTRL, DTRC_DECOMPRESS_BYPASS,
7278c2ecf20Sopenharmony_ci		       DTRC_DECOMPRESS_BYPASS);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	/* Set up ARID register */
7308c2ecf20Sopenharmony_ci	zx_writel(vou->dtrc + DTRC_ARID, DTRC_ARID3(0xf) | DTRC_ARID2(0xe) |
7318c2ecf20Sopenharmony_ci		  DTRC_ARID1(0xf) | DTRC_ARID0(0xe));
7328c2ecf20Sopenharmony_ci}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_cistatic void vou_hw_init(struct zx_vou_hw *vou)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	/* Release reset for all VOU modules */
7378c2ecf20Sopenharmony_ci	zx_writel(vou->vouctl + VOU_SOFT_RST, ~0);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	/* Enable all VOU module clocks */
7408c2ecf20Sopenharmony_ci	zx_writel(vou->vouctl + VOU_CLK_EN, ~0);
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	/* Clear both OSD and TIMING_CTRL interrupt state */
7438c2ecf20Sopenharmony_ci	zx_writel(vou->osd + OSD_INT_CLRSTA, ~0);
7448c2ecf20Sopenharmony_ci	zx_writel(vou->timing + TIMING_INT_STATE, ~0);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	/* Enable OSD and TIMING_CTRL interrrupts */
7478c2ecf20Sopenharmony_ci	zx_writel(vou->osd + OSD_INT_MSK, OSD_INT_ENABLE);
7488c2ecf20Sopenharmony_ci	zx_writel(vou->timing + TIMING_INT_CTRL, TIMING_INT_ENABLE);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/* Select GPC as input to gl/vl scaler as a sane default setting */
7518c2ecf20Sopenharmony_ci	zx_writel(vou->otfppu + OTFPPU_RSZ_DATA_SOURCE, 0x2a);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	/*
7548c2ecf20Sopenharmony_ci	 * Needs to reset channel and layer logic per frame when frame starts
7558c2ecf20Sopenharmony_ci	 * to get VOU work properly.
7568c2ecf20Sopenharmony_ci	 */
7578c2ecf20Sopenharmony_ci	zx_writel_mask(vou->osd + OSD_RST_CLR, RST_PER_FRAME, RST_PER_FRAME);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	vou_dtrc_init(vou);
7608c2ecf20Sopenharmony_ci}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_cistatic int zx_crtc_bind(struct device *dev, struct device *master, void *data)
7638c2ecf20Sopenharmony_ci{
7648c2ecf20Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
7658c2ecf20Sopenharmony_ci	struct drm_device *drm = data;
7668c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou;
7678c2ecf20Sopenharmony_ci	struct resource *res;
7688c2ecf20Sopenharmony_ci	int irq;
7698c2ecf20Sopenharmony_ci	int ret;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	vou = devm_kzalloc(dev, sizeof(*vou), GFP_KERNEL);
7728c2ecf20Sopenharmony_ci	if (!vou)
7738c2ecf20Sopenharmony_ci		return -ENOMEM;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "osd");
7768c2ecf20Sopenharmony_ci	vou->osd = devm_ioremap_resource(dev, res);
7778c2ecf20Sopenharmony_ci	if (IS_ERR(vou->osd)) {
7788c2ecf20Sopenharmony_ci		ret = PTR_ERR(vou->osd);
7798c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to remap osd region: %d\n", ret);
7808c2ecf20Sopenharmony_ci		return ret;
7818c2ecf20Sopenharmony_ci	}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "timing_ctrl");
7848c2ecf20Sopenharmony_ci	vou->timing = devm_ioremap_resource(dev, res);
7858c2ecf20Sopenharmony_ci	if (IS_ERR(vou->timing)) {
7868c2ecf20Sopenharmony_ci		ret = PTR_ERR(vou->timing);
7878c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to remap timing_ctrl region: %d\n",
7888c2ecf20Sopenharmony_ci			      ret);
7898c2ecf20Sopenharmony_ci		return ret;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dtrc");
7938c2ecf20Sopenharmony_ci	vou->dtrc = devm_ioremap_resource(dev, res);
7948c2ecf20Sopenharmony_ci	if (IS_ERR(vou->dtrc)) {
7958c2ecf20Sopenharmony_ci		ret = PTR_ERR(vou->dtrc);
7968c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to remap dtrc region: %d\n", ret);
7978c2ecf20Sopenharmony_ci		return ret;
7988c2ecf20Sopenharmony_ci	}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vou_ctrl");
8018c2ecf20Sopenharmony_ci	vou->vouctl = devm_ioremap_resource(dev, res);
8028c2ecf20Sopenharmony_ci	if (IS_ERR(vou->vouctl)) {
8038c2ecf20Sopenharmony_ci		ret = PTR_ERR(vou->vouctl);
8048c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to remap vou_ctrl region: %d\n",
8058c2ecf20Sopenharmony_ci			      ret);
8068c2ecf20Sopenharmony_ci		return ret;
8078c2ecf20Sopenharmony_ci	}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otfppu");
8108c2ecf20Sopenharmony_ci	vou->otfppu = devm_ioremap_resource(dev, res);
8118c2ecf20Sopenharmony_ci	if (IS_ERR(vou->otfppu)) {
8128c2ecf20Sopenharmony_ci		ret = PTR_ERR(vou->otfppu);
8138c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to remap otfppu region: %d\n", ret);
8148c2ecf20Sopenharmony_ci		return ret;
8158c2ecf20Sopenharmony_ci	}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
8188c2ecf20Sopenharmony_ci	if (irq < 0)
8198c2ecf20Sopenharmony_ci		return irq;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	vou->axi_clk = devm_clk_get(dev, "aclk");
8228c2ecf20Sopenharmony_ci	if (IS_ERR(vou->axi_clk)) {
8238c2ecf20Sopenharmony_ci		ret = PTR_ERR(vou->axi_clk);
8248c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to get axi_clk: %d\n", ret);
8258c2ecf20Sopenharmony_ci		return ret;
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	vou->ppu_clk = devm_clk_get(dev, "ppu_wclk");
8298c2ecf20Sopenharmony_ci	if (IS_ERR(vou->ppu_clk)) {
8308c2ecf20Sopenharmony_ci		ret = PTR_ERR(vou->ppu_clk);
8318c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to get ppu_clk: %d\n", ret);
8328c2ecf20Sopenharmony_ci		return ret;
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(vou->axi_clk);
8368c2ecf20Sopenharmony_ci	if (ret) {
8378c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to enable axi_clk: %d\n", ret);
8388c2ecf20Sopenharmony_ci		return ret;
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	clk_prepare_enable(vou->ppu_clk);
8428c2ecf20Sopenharmony_ci	if (ret) {
8438c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to enable ppu_clk: %d\n", ret);
8448c2ecf20Sopenharmony_ci		goto disable_axi_clk;
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	vou->dev = dev;
8488c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, vou);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	vou_hw_init(vou);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	ret = devm_request_irq(dev, irq, vou_irq_handler, 0, "zx_vou", vou);
8538c2ecf20Sopenharmony_ci	if (ret < 0) {
8548c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to request vou irq: %d\n", ret);
8558c2ecf20Sopenharmony_ci		goto disable_ppu_clk;
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	ret = zx_crtc_init(drm, vou, VOU_CHN_MAIN);
8598c2ecf20Sopenharmony_ci	if (ret) {
8608c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to init main channel crtc: %d\n",
8618c2ecf20Sopenharmony_ci			      ret);
8628c2ecf20Sopenharmony_ci		goto disable_ppu_clk;
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	ret = zx_crtc_init(drm, vou, VOU_CHN_AUX);
8668c2ecf20Sopenharmony_ci	if (ret) {
8678c2ecf20Sopenharmony_ci		DRM_DEV_ERROR(dev, "failed to init aux channel crtc: %d\n",
8688c2ecf20Sopenharmony_ci			      ret);
8698c2ecf20Sopenharmony_ci		goto disable_ppu_clk;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	zx_overlay_init(drm, vou);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	return 0;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_cidisable_ppu_clk:
8778c2ecf20Sopenharmony_ci	clk_disable_unprepare(vou->ppu_clk);
8788c2ecf20Sopenharmony_cidisable_axi_clk:
8798c2ecf20Sopenharmony_ci	clk_disable_unprepare(vou->axi_clk);
8808c2ecf20Sopenharmony_ci	return ret;
8818c2ecf20Sopenharmony_ci}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistatic void zx_crtc_unbind(struct device *dev, struct device *master,
8848c2ecf20Sopenharmony_ci			   void *data)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct zx_vou_hw *vou = dev_get_drvdata(dev);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	clk_disable_unprepare(vou->axi_clk);
8898c2ecf20Sopenharmony_ci	clk_disable_unprepare(vou->ppu_clk);
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic const struct component_ops zx_crtc_component_ops = {
8938c2ecf20Sopenharmony_ci	.bind = zx_crtc_bind,
8948c2ecf20Sopenharmony_ci	.unbind = zx_crtc_unbind,
8958c2ecf20Sopenharmony_ci};
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic int zx_crtc_probe(struct platform_device *pdev)
8988c2ecf20Sopenharmony_ci{
8998c2ecf20Sopenharmony_ci	return component_add(&pdev->dev, &zx_crtc_component_ops);
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_cistatic int zx_crtc_remove(struct platform_device *pdev)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	component_del(&pdev->dev, &zx_crtc_component_ops);
9058c2ecf20Sopenharmony_ci	return 0;
9068c2ecf20Sopenharmony_ci}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistatic const struct of_device_id zx_crtc_of_match[] = {
9098c2ecf20Sopenharmony_ci	{ .compatible = "zte,zx296718-dpc", },
9108c2ecf20Sopenharmony_ci	{ /* end */ },
9118c2ecf20Sopenharmony_ci};
9128c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, zx_crtc_of_match);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cistruct platform_driver zx_crtc_driver = {
9158c2ecf20Sopenharmony_ci	.probe = zx_crtc_probe,
9168c2ecf20Sopenharmony_ci	.remove = zx_crtc_remove,
9178c2ecf20Sopenharmony_ci	.driver	= {
9188c2ecf20Sopenharmony_ci		.name = "zx-crtc",
9198c2ecf20Sopenharmony_ci		.of_match_table	= zx_crtc_of_match,
9208c2ecf20Sopenharmony_ci	},
9218c2ecf20Sopenharmony_ci};
922