@@ -306,6 +306,8 @@ CONFIG_DRM=y
CONFIG_DRM_CMA_FBDEV_BUFFER_NUM=2
CONFIG_DRM_I2C_ADV7511=y
CONFIG_DRM_HISI=y
+CONFIG_DRM_HISI_KIRIN=y
+CONFIG_HISI_KIRIN_DW_DSI=y
CONFIG_FB_ARMCLCD=y
CONFIG_FB_SIMPLE=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
@@ -8,3 +8,8 @@ config DRM_HISI
help
Choose this option if you have a hisilicon chipsets(hi6220).
If M is selected the module will be called hisi-drm.
+#
+# hisilicon drm device configuration.
+# Please keep this list sorted alphabetically
+
+source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
@@ -1,5 +1,5 @@
-hisi-drm-y := hisi_drm_drv.o \
- hisi_drm_ade.o \
- hisi_drm_dsi.o
+#
+# Makefile for hisilicon drm drivers.
+# Please keep this list sorted alphabetically
-obj-$(CONFIG_DRM_HISI) += hisi-drm.o
+obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
deleted file mode 100644
@@ -1,494 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
- *
- * 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.
- *
- */
-
-#ifndef __HISI_ADE_REG_H__
-#define __HISI_ADE_REG_H__
-
-/*
- * ADE Registers Offset
- */
-#define ADE_CTRL (0x4)
-#define ADE_CTRL1 (0x8C)
-#define ADE_ROT_SRC_CFG (0x10)
-#define ADE_DISP_SRC_CFG (0x18)
-#define ADE_WDMA2_SRC_CFG (0x1C)
-#define ADE_SEC_OVLY_SRC_CFG (0x20)
-#define ADE_WDMA3_SRC_CFG (0x24)
-#define ADE_OVLY1_TRANS_CFG (0x2C)
-#define ADE_EN (0x100)
-#define INTR_MASK_CPU_0 (0xC10)
-#define INTR_MASK_CPU_1 (0xC14)
-#define ADE_FRM_DISGARD_CTRL (0xA4)
-/* reset and reload regs */
-#define ADE_SOFT_RST_SEL0 (0x78)
-#define ADE_SOFT_RST_SEL1 (0x7C)
-#define ADE_RELOAD_DIS0 (0xAC)
-#define ADE_RELOAD_DIS1 (0xB0)
-#define ADE_CH_RDMA_BIT_OFST (0)
-#define ADE_CLIP_BIT_OFST (15)
-#define ADE_SCL_BIT_OFST (21)
-#define ADE_CTRAN_BIT_OFST (24)
-#define ADE_OVLY_BIT_OFST (37) /* 32+5 */
-/* channel regs */
-#define RD_CH_PE(x) (0x1000 + (x) * 0x80)
-#define RD_CH_CTRL(x) (0x1004 + (x) * 0x80)
-#define RD_CH_ADDR(x) (0x1008 + (x) * 0x80)
-#define RD_CH_SIZE(x) (0x100C + (x) * 0x80)
-#define RD_CH_STRIDE(x) (0x1010 + (x) * 0x80)
-#define RD_CH_SPACE(x) (0x1014 + (x) * 0x80)
-#define RD_CH_PARTIAL_SIZE(x) (0x1018 + (x) * 0x80)
-#define RD_CH_PARTIAL_SPACE(x) (0x101C + (x) * 0x80)
-#define RD_CH_EN(x) (0x1020 + (x) * 0x80)
-#define RD_CH_STATUS(x) (0x1024 + (x) * 0x80)
-#define RD_CH_DISP_CTRL (0x1404)
-#define RD_CH_DISP_ADDR (0x1408)
-#define RD_CH_DISP_SIZE (0x140C)
-#define RD_CH_DISP_STRIDE (0x1410)
-#define RD_CH_DISP_SPACE (0x1414)
-#define RD_CH_DISP_EN (0x142C)
-/* clip regs */
-#define ADE_CLIP_DISABLE(x) (0x6800 + (x) * 0x100)
-#define ADE_CLIP_SIZE0(x) (0x6804 + (x) * 0x100)
-#define ADE_CLIP_SIZE1(x) (0x6808 + (x) * 0x100)
-#define ADE_CLIP_SIZE2(x) (0x680C + (x) * 0x100)
-#define ADE_CLIP_CFG_OK(x) (0x6810 + (x) * 0x100)
-/* scale regs */
-#define ADE_SCL1_MUX_CFG (0xC)
-#define ADE_SCL2_SRC_CFG (0x14)
-#define ADE_SCL3_MUX_CFG (0x8)
-#define ADE_SCL_CTRL(x) (0x3000 + (x) * 0x800)
-#define ADE_SCL_HSP(x) (0x3004 + (x) * 0x800)
-#define ADE_SCL_UV_HSP(x) (0x3008 + (x) * 0x800)
-#define ADE_SCL_VSP(x) (0x300C + (x) * 0x800)
-#define ADE_SCL_UV_VSP(x) (0x3010 + (x) * 0x800)
-#define ADE_SCL_ORES(x) (0x3014 + (x) * 0x800)
-#define ADE_SCL_IRES(x) (0x3018 + (x) * 0x800)
-#define ADE_SCL_START(x) (0x301C + (x) * 0x800)
-#define ADE_SCL_ERR(x) (0x3020 + (x) * 0x800)
-#define ADE_SCL_PIX_OFST(x) (0x3024 + (x) * 0x800)
-#define ADE_SCL_UV_PIX_OFST(x) (0x3028 + (x) * 0x800)
-#define ADE_SCL_COEF_CLR(x) (0x3030 + (x) * 0x800)
-#define ADE_SCL_HCOEF(x, m, n) (0x3100 + (x) * 0x800 + \
- 12 * (m) + 4 * (n))
-#define ADE_SCL_VCOEF(x, i, j) (0x340C + (x) * 0x800 + \
- 12 * (i) + 4 * (j))
-/* ctran regs */
-#define ADE_CTRAN5_TRANS_CFG (0x40)
-#define ADE_CTRAN_DIS(x) (0x5004 + (x) * 0x100)
-#define ADE_CTRAN_MODE_CHOOSE(x) (0x5008 + (x) * 0x100)
-#define ADE_CTRAN_STAT(x) (0x500C + (x) * 0x100)
-#define ADE_CTRAN_CHDC0(x) (0x5010 + (x) * 0x100)
-#define ADE_CTRAN_CHDC1(x) (0x5014 + (x) * 0x100)
-#define ADE_CTRAN_CHDC2(x) (0x5018 + (x) * 0x100)
-#define ADE_CTRAN_CHDC3(x) (0x501C + (x) * 0x100)
-#define ADE_CTRAN_CHDC4(x) (0x5020 + (x) * 0x100)
-#define ADE_CTRAN_CHDC5(x) (0x5024 + (x) * 0x100)
-#define ADE_CTRAN_CSC0(x) (0x5028 + (x) * 0x100)
-#define ADE_CTRAN_CSC1(x) (0x502C + (x) * 0x100)
-#define ADE_CTRAN_CSC2(x) (0x5030 + (x) * 0x100)
-#define ADE_CTRAN_CSC3(x) (0x5034 + (x) * 0x100)
-#define ADE_CTRAN_CSC4(x) (0x5038 + (x) * 0x100)
-#define ADE_CTRAN_IMAGE_SIZE(x) (0x503C + (x) * 0x100)
-#define ADE_CTRAN_CFG_OK(x) (0x5040 + (x) * 0x100)
-/* overlay regs */
-#define ADE_OVLY_ALPHA_ST (0x2000)
-#define ADE_OVLY_CH_XY0(x) (0x2004 + (x) * 4)
-#define ADE_OVLY_CH_XY1(x) (0x2024 + (x) * 4)
-#define ADE_OVLY_CH_CTL(x) (0x204C + (x) * 4)
-#define ADE_OVLY_OUTPUT_SIZE(x) (0x2070 + (x) * 8)
-#define ADE_OVLY_BASE_COLOR(x) (0x2074 + (x) * 8)
-#define ADE_OVLYX_CTL(x) (0x209C + (x) * 4)
-#define ADE_OVLY_CTL (0x98)
-#define ADE_OVLY_CH_ALP_MODE_OFST (0)
-#define ADE_OVLY_CH_ALP_SEL_OFST (2)
-#define ADE_OVLY_CH_UNDER_ALP_SEL_OFST (4)
-#define ADE_OVLY_CH_EN_OFST (6)
-#define ADE_OVLY_CH_ALP_GBL_OFST (15)
-#define ADE_OVLY_CH_SEL_OFST (28)
-
-/*
- * media regs
- */
-#define SC_MEDIA_RSTDIS (0x530)
-#define SC_MEDIA_RSTEN (0x52C)
-#define NOC_ADE0_QOSGENERATOR_MODE 0x010C
-#define NOC_ADE0_QOSGENERATOR_EXTCONTROL 0x0118
-#define NOC_ADE1_QOSGENERATOR_MODE 0x020C
-#define NOC_ADE1_QOSGENERATOR_EXTCONTROL 0x0218
-
-/*
- * regs relevant enum
- */
-enum {
- LDI_TEST = 0,
- LDI_WORK
-};
-
-enum {
- LDI_ISR_FRAME_END_INT = 0x2,
- LDI_ISR_UNDER_FLOW_INT = 0x4
-};
-
-enum {
- ADE_ISR1_RES_SWITCH_CMPL = 0x80000000
-};
-
-enum {
- LDI_DISP_MODE_NOT_3D_FBF = 0,
- LDI_DISP_MODE_3D_FBF
-};
-
-enum {
- ADE_RGB = 0,
- ADE_BGR
-};
-
-enum {
- ADE_DISABLE = 0,
- ADE_ENABLE
-};
-
-enum {
- ADE_OUT_RGB_565 = 0,
- ADE_OUT_RGB_666,
- ADE_OUT_RGB_888
-};
-
-/*
- * ADE read as big-endian, so revert the
- * rgb order described in the SoC datasheet
- */
-enum ADE_FORMAT {
- ADE_RGB_565 = 0,
- ADE_BGR_565,
- ADE_XRGB_8888,
- ADE_XBGR_8888,
- ADE_ARGB_8888,
- ADE_ABGR_8888,
- ADE_RGBA_8888,
- ADE_BGRA_8888,
- ADE_RGB_888,
- ADE_BGR_888 = 9,
- ADE_FORMAT_NOT_SUPPORT = 800
-};
-
-/* ldi src cfg */
-enum {
- TOP_DISP_SRC_NONE = 0,
- TOP_DISP_SRC_OVLY2,
- TOP_DISP_SRC_DISP,
- TOP_DISP_SRC_ROT,
- TOP_DISP_SRC_SCL2
-};
-
-enum {
- ADE_ISR_DMA_ERROR = 0x2000000
-};
-
-enum ade_channel {
- ADE_CH1 = 0, /* channel 1 for primary plane */
- ADE_CH_NUM
-};
-
-enum ade_scale {
- ADE_SCL1 = 0,
- ADE_SCL2,
- ADE_SCL3,
- ADE_SCL_NUM
-};
-
-enum ade_ctran {
- ADE_CTRAN1 = 0,
- ADE_CTRAN2,
- ADE_CTRAN3,
- ADE_CTRAN4,
- ADE_CTRAN5,
- ADE_CTRAN6,
- ADE_CTRAN_NUM
-};
-
-enum ade_overlay {
- ADE_OVLY1 = 0,
- ADE_OVLY2,
- ADE_OVLY3,
- ADE_OVLY_NUM
-};
-
-enum {
- ADE_ALP_GLOBAL = 0,
- ADE_ALP_PIXEL,
- ADE_ALP_PIXEL_AND_GLB
-};
-
-enum {
- ADE_ALP_MUL_COEFF_0 = 0, /* alpha */
- ADE_ALP_MUL_COEFF_1, /* 1-alpha */
- ADE_ALP_MUL_COEFF_2, /* 0 */
- ADE_ALP_MUL_COEFF_3 /* 1 */
-};
-
-/*
- * ADE Register Union Struct
- */
-union U_ADE_CTRL1 {
-struct {
- unsigned int auto_clk_gate_en :1;
- unsigned int rot_buf_shr_out :1;
- unsigned int reserved_44 :30;
- } bits;
- unsigned int u32;
-};
-
-union U_ADE_SOFT_RST_SEL0 {
-struct {
- unsigned int ch1_rdma_srst_sel :1;
- unsigned int ch2_rdma_srst_sel :1;
- unsigned int ch3_rdma_srst_sel :1;
- unsigned int ch4_rdma_srst_sel :1;
- unsigned int ch5_rdma_srst_sel :1;
- unsigned int ch6_rdma_srst_sel :1;
- unsigned int disp_rdma_srst_sel :1;
- unsigned int cmdq1_rdma_srst_sel :1;
- unsigned int cmdq2_rdma_srst_sel :1;
- unsigned int reserved_29 :1;
- unsigned int ch1_wdma_srst_sel :1;
- unsigned int ch2_wdma_srst_sel :1;
- unsigned int ch3_wdma_srst_sel :1;
- unsigned int reserved_28 :1;
- unsigned int cmdq_wdma_srst_sel :1;
- unsigned int clip1_srst_sel :1;
- unsigned int clip2_srst_sel :1;
- unsigned int clip3_srst_sel :1;
- unsigned int clip4_srst_sel :1;
- unsigned int clip5_srst_sel :1;
- unsigned int clip6_srst_sel :1;
- unsigned int scl1_srst_sel :1;
- unsigned int scl2_srst_sel :1;
- unsigned int scl3_srst_sel :1;
- unsigned int ctran1_srst_sel :1;
- unsigned int ctran2_srst_sel :1;
- unsigned int ctran3_srst_sel :1;
- unsigned int ctran4_srst_sel :1;
- unsigned int ctran5_srst_sel :1;
- unsigned int ctran6_srst_sel :1;
- unsigned int rot_srst_sel :1;
- unsigned int reserved_27 :1;
- } bits;
- unsigned int u32;
-};
-
-union U_ADE_CTRL {
-struct {
- unsigned int frm_end_start :2;
- unsigned int dfs_buf_cfg :1;
- unsigned int rot_buf_cfg :3;
- unsigned int rd_ch5_nv :1;
- unsigned int rd_ch6_nv :1;
- unsigned int dfs_buf_unflow_lev1 :13;
- unsigned int dfs_buf_unflow_lev2 :11;
- } bits;
- unsigned int u32;
-};
-
-/*
- * ADE Register Write/Read functions
- */
-static inline void set_TOP_CTL_clk_gate_en(u8 *base, u32 val)
-{
- union U_ADE_CTRL1 ade_ctrl1;
- u8 *reg_addr = base + ADE_CTRL1;
-
- ade_ctrl1.u32 = readl(reg_addr);
- ade_ctrl1.bits.auto_clk_gate_en = val;
- writel(ade_ctrl1.u32, reg_addr);
-}
-
-static inline void set_TOP_SOFT_RST_SEL0_disp_rdma(u8 *base, u32 val)
-{
- union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
- u8 *addr = base + ADE_SOFT_RST_SEL0;
-
- ade_soft_rst.u32 = readl(addr);
- ade_soft_rst.bits.disp_rdma_srst_sel = val;
- writel(ade_soft_rst.u32, addr);
-}
-
-static inline void set_TOP_SOFT_RST_SEL0_ctran5(u8 *base, u32 val)
-{
- union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
- u8 *addr = base + ADE_SOFT_RST_SEL0;
-
- ade_soft_rst.u32 = readl(addr);
- ade_soft_rst.bits.ctran5_srst_sel = val;
- writel(ade_soft_rst.u32, addr);
-}
-
-static inline void set_TOP_SOFT_RST_SEL0_ctran6(u8 *base, u32 val)
-{
- union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
- u8 *addr = base + ADE_SOFT_RST_SEL0;
-
- ade_soft_rst.u32 = readl(addr);
- ade_soft_rst.bits.ctran6_srst_sel = val;
- writel(ade_soft_rst.u32, addr);
-}
-
-static inline void set_TOP_CTL_frm_end_start(u8 *base, u32 val)
-{
- union U_ADE_CTRL ade_ctrl;
- u8 *reg_addr = base + ADE_CTRL;
-
- ade_ctrl.u32 = readl(reg_addr);
- ade_ctrl.bits.frm_end_start = val;
- writel(ade_ctrl.u32, reg_addr);
-}
-
-/*
- * LDI Registers Offset
- */
-#define LDI_HRZ_CTRL0 (0x7400)
-#define LDI_HRZ_CTRL1 (0x7404)
-#define LDI_VRT_CTRL0 (0x7408)
-#define LDI_VRT_CTRL1 (0x740C)
-#define LDI_PLR_CTRL (0x7410)
-#define LDI_DSP_SIZE (0x7414)
-#define LDI_INT_EN (0x741C)
-#define LDI_CTRL (0x7420)
-#define LDI_ORG_INT (0x7424)
-#define LDI_MSK_INT (0x7428)
-#define LDI_INT_CLR (0x742C)
-#define LDI_WORK_MODE (0x7430)
-#define LDI_DE_SPACE_LOW (0x7438)
-#define LDI_MCU_INTS (0x7450)
-#define LDI_MCU_INTE (0x7454)
-#define LDI_MCU_INTC (0x7458)
-#define LDI_HDMI_DSI_GT (0x7434)
-
-/*
- * LDI Timing Polarity defines
- */
-#define HISI_LDI_FLAG_NVSYNC BIT(0)
-#define HISI_LDI_FLAG_NHSYNC BIT(1)
-#define HISI_LDI_FLAG_NPIXCLK BIT(2)
-#define HISI_LDI_FLAG_NDE BIT(3)
-
-/*
- * LDI Register Union Struct
- */
-union U_LDI_CTRL {
-struct {
- unsigned int ldi_en :1;
- unsigned int disp_mode_buf :1;
- unsigned int date_gate_en :1;
- unsigned int bpp :2;
- unsigned int wait_vsync_en :1;
- unsigned int corlorbar_width :7;
- unsigned int bgr :1;
- unsigned int color_mode :1;
- unsigned int shutdown :1;
- unsigned int vactive_line :12;
- unsigned int ldi_en_self_clr :1;
- unsigned int reserved_573 :3;
- } bits;
- unsigned int u32;
-};
-
-union U_LDI_WORK_MODE {
-struct {
- unsigned int work_mode :1;
- unsigned int wback_en :1;
- unsigned int colorbar_en :1;
- unsigned int reserved_577 :29;
- } bits;
- unsigned int u32;
-};
-
-/*
- * LDI Register Write/Read Helper functions
- */
-static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs)
-{
- u32 mask = (1 << bw) - 1;
- u32 tmp = readl(addr);
-
- tmp &= ~(mask << bs);
- writel(tmp | ((val & mask) << bs), addr);
-}
-
-static inline void set_LDI_CTRL_ldi_en(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.ldi_en = val;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_disp_mode(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.disp_mode_buf = val;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_bpp(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.bpp = val;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_corlorbar_width(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.corlorbar_width = (val > 0) ? val - 1 : 0;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_bgr(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.bgr = val;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_WORK_MODE_work_mode(u8 *base, u32 val)
-{
- union U_LDI_WORK_MODE ldi_work_mode;
- u8 *addr = base + LDI_WORK_MODE;
-
- ldi_work_mode.u32 = readl(addr);
- ldi_work_mode.bits.work_mode = val;
- writel(ldi_work_mode.u32, addr);
-}
-
-static inline void set_LDI_WORK_MODE_colorbar_en(u8 *base, u32 val)
-{
- union U_LDI_WORK_MODE ldi_work_mode;
- u8 *addr = base + LDI_WORK_MODE;
-
- ldi_work_mode.u32 = readl(addr);
- ldi_work_mode.bits.colorbar_en = val;
- writel(ldi_work_mode.u32, addr);
-}
-
-#endif
deleted file mode 100644
@@ -1,1100 +0,0 @@
-/*
- * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
- *
- * Copyright (c) 2014-2015 Hisilicon Limited.
- * Author:
- * Xinliang Liu <xinliang.liu@linaro.org>
- * Xinliang Liu <z.liuxinliang@hisilicon.com>
- * Xinwei Kong <kong.kongxinwei@hisilicon.com>
- *
- * 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.
- *
- */
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/component.h>
-#include <video/display_timing.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "hisi_drm_drv.h"
-#include "hisi_ade_reg.h"
-
-#define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
-#define PRIMARY_CH (ADE_CH1)
-
-#define to_ade_crtc(crtc) \
- container_of(crtc, struct ade_crtc, base)
-
-#define to_ade_plane(plane) \
- container_of(plane, struct ade_plane, base)
-
-struct ade_hw_ctx {
- void __iomem *base;
- void __iomem *media_base;
- void __iomem *media_noc_base;
-
- int irq;
- u32 ade_core_rate;
- u32 media_noc_rate;
-
- struct clk *ade_core_clk;
- struct clk *media_noc_clk;
- struct clk *ade_pix_clk;
- bool power_on;
-};
-
-struct ade_crtc {
- struct drm_crtc base;
- struct ade_hw_ctx *ctx;
- bool enable;
- u64 use_mask;
-};
-
-struct ade_plane {
- struct drm_plane base;
- void *ctx;
- u8 ch; /* channel */
-};
-
-struct ade_data {
- struct ade_crtc acrtc;
- struct ade_plane aplane[ADE_CH_NUM];
- struct ade_hw_ctx ctx;
-};
-
-/* ade-format info: */
-struct ade_format {
- u32 pixel_format;
- enum ADE_FORMAT ade_format;
-};
-
-static const struct ade_format ade_formats[] = {
- /* 16bpp RGB: */
- { DRM_FORMAT_RGB565, ADE_RGB_565 },
- { DRM_FORMAT_BGR565, ADE_BGR_565 },
- /* 24bpp RGB: */
- { DRM_FORMAT_RGB888, ADE_RGB_888 },
- { DRM_FORMAT_BGR888, ADE_BGR_888 },
- /* 32bpp [A]RGB: */
- { DRM_FORMAT_XRGB8888, ADE_XRGB_8888 },
- { DRM_FORMAT_XBGR8888, ADE_XBGR_8888 },
- { DRM_FORMAT_RGBA8888, ADE_RGBA_8888 },
- { DRM_FORMAT_BGRA8888, ADE_BGRA_8888 },
- { DRM_FORMAT_ARGB8888, ADE_ARGB_8888 },
- { DRM_FORMAT_ABGR8888, ADE_ABGR_8888 },
-};
-
-static const u32 channel_formats1[] = {
- /* channel 1,2,3,4 */
- DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
- DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
- DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
- DRM_FORMAT_ABGR8888
-};
-
-u32 ade_get_channel_formats(u8 ch, const u32 **formats)
-{
- switch (ch) {
- case ADE_CH1:
- *formats = channel_formats1;
- return ARRAY_SIZE(channel_formats1);
- default:
- DRM_ERROR("no this channel %d\n", ch);
- *formats = NULL;
- return 0;
- }
-}
-
-/* convert from fourcc format to ade format */
-static u32 ade_get_format(u32 pixel_format)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ade_formats); i++)
- if (ade_formats[i].pixel_format == pixel_format)
- return ade_formats[i].ade_format;
-
- /* not found */
- DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", pixel_format);
- return ADE_FORMAT_NOT_SUPPORT;
-}
-
-static void ade_init(struct ade_hw_ctx *ctx)
-{
- void __iomem *base = ctx->base;
-
- /* enable clk gate */
- set_TOP_CTL_clk_gate_en(base, 1);
- /* clear overlay */
- writel(0, base + ADE_OVLY1_TRANS_CFG);
- writel(0, base + ADE_OVLY_CTL);
- writel(0, base + ADE_OVLYX_CTL(ADE_OVLY2));
- /* clear reset and reload regs */
- writel(0, base + ADE_SOFT_RST_SEL0);
- writel(0, base + ADE_SOFT_RST_SEL1);
- writel(0xFFFFFFFF, base + ADE_RELOAD_DIS0);
- writel(0xFFFFFFFF, base + ADE_RELOAD_DIS1);
- /* for video set to 1, means that ade registers
- * became effective at frame end
- */
- set_TOP_CTL_frm_end_start(base, 1);
-}
-
-static void ade_ldi_set_mode(struct ade_crtc *acrtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adj_mode)
-{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u32 out_w = mode->hdisplay;
- u32 out_h = mode->vdisplay;
- u32 hfp, hbp, hsw, vfp, vbp, vsw;
- u32 plr_flags;
- int ret;
-
- plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
- ? HISI_LDI_FLAG_NVSYNC : 0;
- plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
- ? HISI_LDI_FLAG_NHSYNC : 0;
- hfp = mode->hsync_start - mode->hdisplay;
- hbp = mode->htotal - mode->hsync_end;
- hsw = mode->hsync_end - mode->hsync_start;
- vfp = mode->vsync_start - mode->vdisplay;
- vbp = mode->vtotal - mode->vsync_end;
- vsw = mode->vsync_end - mode->vsync_start;
- if (vsw > 15) {
- DRM_INFO("vsw exceeded 15\n");
- vsw = 15;
- }
-
- writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
- /* p3-73 6220V100 pdf:
- * "The configured value is the actual width - 1"
- */
- writel(hsw - 1, base + LDI_HRZ_CTRL1);
- writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
- /* p3-74 6220V100 pdf:
- * "The configured value is the actual width - 1"
- */
- writel(vsw - 1, base + LDI_VRT_CTRL1);
-
- /* p3-75 6220V100 pdf:
- * "The configured value is the actual width - 1"
- */
- writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
- base + LDI_DSP_SIZE);
- writel(plr_flags, base + LDI_PLR_CTRL);
-
- ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
- /* Success should be guaranteed in aotomic_check
- * failer shouldn't happen here
- */
- if (ret)
- DRM_ERROR("set ade_pixel_clk_rate fail\n");
- adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
-
- /* ctran6 setting */
- writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
- writel(out_w * out_h - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
- acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
- DRM_INFO("set mode: %dx%d\n", out_w, out_h);
-
- /*
- * other parameters setting
- */
- writel(BIT(0), base + LDI_WORK_MODE);
- writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
- base + LDI_CTRL);
- set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
-}
-
-static int ade_power_up(struct ade_hw_ctx *ctx)
-{
- void __iomem *media_base = ctx->media_base;
- int ret;
-
- ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
- if (ret) {
- DRM_ERROR("clk_set_rate ade_core_rate error\n");
- return ret;
- }
- ret = clk_set_rate(ctx->media_noc_clk, ctx->media_noc_rate);
- if (ret) {
- DRM_ERROR("media_noc_clk media_noc_rate error\n");
- return ret;
- }
- ret = clk_prepare_enable(ctx->media_noc_clk);
- if (ret) {
- DRM_ERROR("fail to clk_prepare_enable media_noc_clk\n");
- return ret;
- }
-
- writel(0x20, media_base + SC_MEDIA_RSTDIS);
-
- ret = clk_prepare_enable(ctx->ade_core_clk);
- if (ret) {
- DRM_ERROR("fail to clk_prepare_enable ade_core_clk\n");
- return ret;
- }
-
- ade_init(ctx);
- ctx->power_on = true;
- return 0;
-}
-
-static void ade_power_down(struct ade_hw_ctx *ctx)
-{
- void __iomem *base = ctx->base;
- void __iomem *media_base = ctx->media_base;
-
- set_LDI_CTRL_ldi_en(base, ADE_DISABLE);
- /* dsi pixel off */
- set_reg(base + LDI_HDMI_DSI_GT, 0x1, 1, 0);
-
- clk_disable_unprepare(ctx->ade_core_clk);
- writel(0x20, media_base + SC_MEDIA_RSTEN);
- clk_disable_unprepare(ctx->media_noc_clk);
- ctx->power_on = false;
-}
-
-static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
- unsigned int index)
-{
- unsigned int index_tmp = 0;
- struct drm_crtc *crtc;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- if (index_tmp == index)
- return crtc;
-
- index_tmp++;
- }
-
- WARN_ON(true);
- return NULL;
-}
-
-int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
- struct ade_crtc *acrtc = to_ade_crtc(crtc);
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u32 intr_en;
-
- DRM_INFO("enable_vblank enter.\n");
- if (!ctx->power_on)
- (void)ade_power_up(ctx);
-
- intr_en = readl(base + LDI_INT_EN);
- intr_en |= LDI_ISR_FRAME_END_INT;
- writel(intr_en, base + LDI_INT_EN);
-
- return 0;
-}
-
-void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
-{
- struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
- struct ade_crtc *acrtc = to_ade_crtc(crtc);
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u32 intr_en;
-
- DRM_INFO("disable_vblank enter.\n");
- if (!ctx->power_on) {
- DRM_ERROR("power is down! vblank disable fail\n");
- return;
- }
- intr_en = readl(base + LDI_INT_EN);
- intr_en &= ~LDI_ISR_FRAME_END_INT;
- writel(intr_en, base + LDI_INT_EN);
-}
-
-static irqreturn_t ade_irq_handler(int irq, void *data)
-{
- struct ade_crtc *acrtc = data;
- struct ade_hw_ctx *ctx = acrtc->ctx;
- struct drm_crtc *crtc = &acrtc->base;
- struct drm_device *dev = crtc->dev;
- void __iomem *base = ctx->base;
- u32 status;
-
- status = readl(base + LDI_MSK_INT);
- /* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
-
- /* vblank irq */
- if (status & LDI_ISR_FRAME_END_INT) {
- writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
- drm_handle_vblank(dev, drm_crtc_index(crtc));
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * set modules' reset mode: by software or hardware
- * set modules' reload enable/disable
- */
-static void ade_set_reset_and_reload(struct ade_crtc *acrtc)
-{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u32 mask0 = (u32)acrtc->use_mask;
- u32 mask1 = (u32)(acrtc->use_mask >> 32);
-
- DRM_DEBUG_DRIVER("mask=0x%llX, mask0=0x%X, mask1=0x%X\n",
- acrtc->use_mask, mask0, mask1);
-
- writel(mask0, base + ADE_SOFT_RST_SEL0);
- writel(mask1, base + ADE_SOFT_RST_SEL1);
- writel(~mask0, base + ADE_RELOAD_DIS0);
- writel(~mask1, base + ADE_RELOAD_DIS1);
-}
-
-void ade_set_medianoc_qos(struct ade_crtc *acrtc)
-{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->media_noc_base;
- void __iomem *reg;
- u32 val;
-
- reg = base + NOC_ADE0_QOSGENERATOR_MODE;
- val = (readl(reg) & 0xfffffffc) | 0x2;
- writel(val, reg);
-
- reg = base + NOC_ADE0_QOSGENERATOR_EXTCONTROL;
- val = readl(reg) | 0x1;
- writel(val, reg);
-
- reg = base + NOC_ADE1_QOSGENERATOR_MODE;
- val = (readl(reg) & 0xfffffffc) | 0x2;
- writel(val, reg);
-
- reg = base + NOC_ADE1_QOSGENERATOR_EXTCONTROL;
- val = readl(reg) | 0x1;
- writel(val, reg);
-}
-
-/*
- * commit to ldi to display
- */
-static void ade_display_commit(struct ade_crtc *acrtc)
-{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
-
- /* TODO: set rotator after overlay */
-
- /* TODO: set scale after overlay */
-
- /* display source setting */
- writel(TOP_DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
-
- /* set reset mode:soft or hw, and reload modules */
- ade_set_reset_and_reload(acrtc);
-
- DRM_INFO("ADE GO\n");
- /* enable ade */
- wmb();
- writel(ADE_ENABLE, base + ADE_EN);
- /* enable ldi */
- wmb();
- set_LDI_CTRL_ldi_en(base, ADE_ENABLE);
- /* dsi pixel on */
- set_reg(base + LDI_HDMI_DSI_GT, 0x0, 1, 0);
-}
-
-static void ade_crtc_enable(struct drm_crtc *crtc)
-{
- struct ade_crtc *acrtc = to_ade_crtc(crtc);
- struct ade_hw_ctx *ctx = acrtc->ctx;
- int ret;
-
- DRM_DEBUG_DRIVER("enter.\n");
- if (acrtc->enable)
- return;
-
- if (!ctx->power_on) {
- ret = ade_power_up(ctx);
- if (ret) {
- DRM_ERROR("failed to initialize ade clk\n");
- return;
- }
- }
-
- ade_set_medianoc_qos(acrtc);
- ade_display_commit(acrtc);
- acrtc->enable = true;
-
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void ade_crtc_disable(struct drm_crtc *crtc)
-{
- struct ade_crtc *acrtc = to_ade_crtc(crtc);
- struct ade_hw_ctx *ctx = acrtc->ctx;
-
- DRM_DEBUG_DRIVER("enter.\n");
-
- if (!acrtc->enable)
- return;
-
- ade_power_down(ctx);
- acrtc->use_mask = 0;
- acrtc->enable = false;
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-int ade_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
-{
- DRM_DEBUG_DRIVER("enter.\n");
- DRM_DEBUG_DRIVER("exit success.\n");
- /* do nothing */
- return 0;
-}
-
-static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
-{
- struct ade_crtc *acrtc = to_ade_crtc(crtc);
- struct ade_hw_ctx *ctx = acrtc->ctx;
- struct drm_display_mode *mode = &crtc->state->mode;
- struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
-
- DRM_DEBUG_DRIVER("enter.\n");
- if (!ctx->power_on)
- (void)ade_power_up(ctx);
- ade_ldi_set_mode(acrtc, mode, adj_mode);
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state)
-{
- struct ade_crtc *acrtc = to_ade_crtc(crtc);
- struct ade_hw_ctx *ctx = acrtc->ctx;
-
- DRM_DEBUG_DRIVER("enter.\n");
- if (!ctx->power_on)
- (void)ade_power_up(ctx);
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
- struct drm_crtc_state *old_state)
-
-{
- struct ade_crtc *acrtc = to_ade_crtc(crtc);
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
-
- DRM_DEBUG_DRIVER("enter.\n");
- /* commit to display: LDI input setting */
- if (acrtc->enable) {
- /* set reset and reload */
- ade_set_reset_and_reload(acrtc);
- /* flush ade regitsters */
- wmb();
- writel(ADE_ENABLE, base + ADE_EN);
- }
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
- .enable = ade_crtc_enable,
- .disable = ade_crtc_disable,
- .atomic_check = ade_crtc_atomic_check,
- .mode_set_nofb = ade_crtc_mode_set_nofb,
- .atomic_begin = ade_crtc_atomic_begin,
- .atomic_flush = ade_crtc_atomic_flush,
-};
-
-static const struct drm_crtc_funcs ade_crtc_funcs = {
- .destroy = drm_crtc_cleanup,
- .set_config = drm_atomic_helper_set_config,
- .page_flip = drm_atomic_helper_page_flip,
- .reset = drm_atomic_helper_crtc_reset,
- .set_property = drm_atomic_helper_crtc_set_property,
- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
-};
-
-static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
- struct drm_plane *plane)
-{
- int ret;
-
- ret = drm_crtc_init_with_planes(dev, crtc, plane,
- NULL, &ade_crtc_funcs);
- if (ret) {
- DRM_ERROR("failed to init crtc.\n");
- return ret;
- }
-
- drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
-
- return 0;
-}
-
-static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
- u32 ch, u32 y, u32 in_h, u32 fmt)
-{
- u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
- struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u32 stride = fb->pitches[0];
- u32 addr = (u32)obj->paddr + y * stride;
-
- DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x, \
- addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
- ch + 1, y, in_h, stride, (u32)obj->paddr,
- addr, fb->width, fb->height,
- fmt, drm_get_format_name(fb->pixel_format));
-
- /* get reg offset */
- reg_ctrl = RD_CH_CTRL(ch);
- reg_addr = RD_CH_ADDR(ch);
- reg_size = RD_CH_SIZE(ch);
- reg_stride = RD_CH_STRIDE(ch);
- reg_space = RD_CH_SPACE(ch);
- reg_en = RD_CH_EN(ch);
-
- /*
- * TODO: set rotation
- */
- writel((fmt << 16) & 0x1f0000, base + reg_ctrl);
- writel(addr, base + reg_addr);
- writel((in_h << 16) | stride, base + reg_size);
- writel(stride, base + reg_stride);
- writel(in_h * stride, base + reg_space);
- writel(1, base + reg_en);
-
- acrtc->use_mask |= BIT(ADE_CH_RDMA_BIT_OFST + ch);
-}
-
-static void ade_rdma_disable(struct ade_crtc *acrtc, u32 ch)
-{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u32 reg_en;
-
- /* get reg offset */
- reg_en = RD_CH_EN(ch);
-
- writel(0, base + reg_en);
- acrtc->use_mask &= ~BIT(ADE_CH_RDMA_BIT_OFST + ch);
-}
-
-static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
- u32 in_w, u32 in_h)
-{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u32 disable_val;
- u32 clip_left;
- u32 clip_right;
-
- /*
- * clip width, no need to clip height
- */
- if (fb_w == in_w) { /* bypass */
- disable_val = 1;
- clip_left = 0;
- clip_right = 0;
- } else {
- disable_val = 0;
- clip_left = x;
- clip_right = fb_w - (x + in_w) - 1;
- }
-
- DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n",
- ch + 1, clip_left, clip_right);
-
- writel(disable_val, base + ADE_CLIP_DISABLE(ch));
- writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch));
- writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch));
-
- acrtc->use_mask |= BIT(ADE_CLIP_BIT_OFST + ch);
-}
-
-static void ade_clip_disable(struct ade_crtc *acrtc, u32 ch)
-{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
-
- writel(1, base + ADE_CLIP_DISABLE(ch));
- acrtc->use_mask &= ~BIT(ADE_CLIP_BIT_OFST + ch);
-}
-
-static bool has_Alpha_channel(int format)
-{
- switch (format) {
- case ADE_ARGB_8888:
- case ADE_ABGR_8888:
- case ADE_RGBA_8888:
- case ADE_BGRA_8888:
- return true;
- default:
- return false;
- }
-}
-
-static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
- u8 *alp_sel, u8 *under_alp_sel)
-{
- bool has_alpha = has_Alpha_channel(fmt);
-
- /*
- * get alp_mode
- */
- if (has_alpha && glb_alpha < 255)
- *alp_mode = ADE_ALP_PIXEL_AND_GLB;
- else if (has_alpha)
- *alp_mode = ADE_ALP_PIXEL;
- else
- *alp_mode = ADE_ALP_GLOBAL;
-
- /*
- * get alp sel
- */
- *alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */
- *under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
-}
-
-static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u32 x0, u32 y0,
- u32 in_w, u32 in_h, u32 fmt)
-{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u8 ovly_ch = 0;
- u8 x = ADE_OVLY2;
- u8 glb_alpha = 255;
- u32 x1 = x0 + in_w - 1;
- u32 y1 = y0 + in_h - 1;
- u32 val;
- u8 alp_sel;
- u8 under_alp_sel;
- u8 alp_mode;
-
- ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
- &under_alp_sel);
-
- /* overlay routing setting */
- writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch));
- writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch));
- val = (ch + 1) << ADE_OVLY_CH_SEL_OFST | BIT(ADE_OVLY_CH_EN_OFST) |
- alp_sel << ADE_OVLY_CH_ALP_SEL_OFST |
- under_alp_sel << ADE_OVLY_CH_UNDER_ALP_SEL_OFST |
- glb_alpha << ADE_OVLY_CH_ALP_GBL_OFST |
- alp_mode << ADE_OVLY_CH_ALP_MODE_OFST;
- DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
- writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
- val = (x + 1) << (ovly_ch * 4) | readl(base + ADE_OVLY_CTL);
- DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
- writel(val, base + ADE_OVLY_CTL);
-
- /* when primary is enable, indicate that it's ready to output. */
- if (ch == PRIMARY_CH) {
- val = (in_w - 1) << 16 | (in_h - 1);
- writel(val, base + ADE_OVLY_OUTPUT_SIZE(x));
- writel(1, base + ADE_OVLYX_CTL(x));
- acrtc->use_mask |= BIT(ADE_OVLY_BIT_OFST + x);
- }
-}
-
-static void ade_overlay_disable(struct ade_crtc *acrtc, u32 ch)
-{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u8 ovly_ch = 0;
- u32 val;
-
- val = ~BIT(6) & readl(base + ADE_OVLY_CH_CTL(ovly_ch));
- DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
- writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
- val = ~(0x3 << (ovly_ch * 4)) & readl(base + ADE_OVLY_CTL);
-
- DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
- writel(val, base + ADE_OVLY_CTL);
-}
-
-/*
- * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->overlay
- */
-static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
- struct drm_framebuffer *fb, int crtc_x,
- int crtc_y, unsigned int crtc_w,
- unsigned int crtc_h, u32 src_x,
- u32 src_y, u32 src_w, u32 src_h)
-{
- u8 ch = aplane->ch;
- u32 fmt = ade_get_format(fb->pixel_format);
- u32 in_w;
- u32 in_h;
-
- DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d",
- ch + 1, src_x, src_y, src_w, src_h,
- crtc_x, crtc_y, crtc_w, crtc_h);
-
- /* 1) DMA setting */
- in_w = src_w;
- in_h = src_h;
- ade_rdma_set(acrtc, fb, ch, src_y, in_h, fmt);
-
- /* 2) clip setting */
- ade_clip_set(acrtc, ch, fb->width, src_x, in_w, in_h);
-
- /* 3) TODO: scale setting for overlay planes */
-
- /* 4) TODO: ctran/csc setting for overlay planes */
-
- /* 5) overlay/compositor routing setting */
- ade_overlay_set(acrtc, ch, crtc_x, crtc_y, in_w, in_h, fmt);
-
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void ade_disable_channel(struct ade_plane *aplane,
- struct ade_crtc *acrtc)
-{
- u32 ch = aplane->ch;
-
- DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1);
-
- /*
- * when primary is disable, power is down
- * so no need to disable this channel.
- */
- if (ch == PRIMARY_CH)
- return;
-
- /* disable read DMA */
- ade_rdma_disable(acrtc, ch);
-
- /* disable clip */
- ade_clip_disable(acrtc, ch);
-
- /* disable overlay routing */
- ade_overlay_disable(acrtc, ch);
-
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static int ade_plane_prepare_fb(struct drm_plane *plane,
- const struct drm_plane_state *new_state)
-{
- DRM_DEBUG_DRIVER("enter.\n");
- DRM_DEBUG_DRIVER("exit success.\n");
- return 0;
-}
-
-static void ade_plane_cleanup_fb(struct drm_plane *plane,
- const struct drm_plane_state *old_state)
-{
- DRM_DEBUG_DRIVER("enter.\n");
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static int ade_plane_atomic_check(struct drm_plane *plane,
- struct drm_plane_state *state)
-{
- struct drm_framebuffer *fb = state->fb;
- struct drm_crtc *crtc = state->crtc;
- struct drm_crtc_state *crtc_state;
- u32 src_x = state->src_x >> 16;
- u32 src_y = state->src_y >> 16;
- u32 src_w = state->src_w >> 16;
- u32 src_h = state->src_h >> 16;
- int crtc_x = state->crtc_x;
- int crtc_y = state->crtc_y;
- u32 crtc_w = state->crtc_w;
- u32 crtc_h = state->crtc_h;
-
- if (!crtc || !fb)
- return 0;
-
- crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
-
- if (src_w != crtc_w || src_h != crtc_h) {
- DRM_ERROR("Scale not support!!!\n");
- return -EINVAL;
- }
-
- if (src_x + src_w > fb->width ||
- src_y + src_h > fb->height)
- return -EINVAL;
-
- if (crtc_x < 0 || crtc_y < 0)
- return -EINVAL;
-
- if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
- crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
- return -EINVAL;
-
- return 0;
-}
-
-static void ade_plane_atomic_update(struct drm_plane *plane,
- struct drm_plane_state *old_state)
-{
- struct drm_plane_state *state = plane->state;
- struct ade_plane *aplane = to_ade_plane(plane);
- struct ade_crtc *acrtc;
-
- if (!state->crtc)
- return;
-
- acrtc = to_ade_crtc(state->crtc);
- ade_update_channel(aplane, acrtc, state->fb,
- state->crtc_x, state->crtc_y,
- state->crtc_w, state->crtc_h,
- state->src_x >> 16, state->src_y >> 16,
- state->src_w >> 16, state->src_h >> 16);
-}
-
-static void ade_plane_atomic_disable(struct drm_plane *plane,
- struct drm_plane_state *old_state)
-{
- struct ade_plane *aplane = to_ade_plane(plane);
- struct ade_crtc *acrtc;
-
- if (!old_state->crtc)
- return;
- acrtc = to_ade_crtc(old_state->crtc);
- ade_disable_channel(aplane, acrtc);
-}
-
-static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
- .prepare_fb = ade_plane_prepare_fb,
- .cleanup_fb = ade_plane_cleanup_fb,
- .atomic_check = ade_plane_atomic_check,
- .atomic_update = ade_plane_atomic_update,
- .atomic_disable = ade_plane_atomic_disable,
-};
-
-static struct drm_plane_funcs ade_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
- .set_property = drm_atomic_helper_plane_set_property,
- .destroy = drm_plane_cleanup,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
-};
-
-static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
- enum drm_plane_type type)
-{
- const u32 *fmts;
- u32 fmts_cnt;
- int ret = 0;
-
- /* get properties */
- fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts);
- if (ret)
- return ret;
-
- ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs,
- fmts, fmts_cnt, type);
- if (ret) {
- DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch);
- return ret;
- }
-
- drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs);
-
- return 0;
-}
-
-static int ade_bind(struct device *dev, struct device *master, void *data)
-{
- struct ade_data *ade = dev_get_drvdata(dev);
- struct ade_hw_ctx *ctx = &ade->ctx;
- struct ade_crtc *acrtc = &ade->acrtc;
- struct drm_device *drm_dev = (struct drm_device *)data;
- struct ade_plane *aplane;
- enum drm_plane_type type;
- int ret;
- int i;
-
- /*
- * plane init
- * TODO: Now only support primary plane, overlay planes
- * need to do.
- */
- for (i = 0; i < ADE_CH_NUM; i++) {
- aplane = &ade->aplane[i];
- aplane->ch = i;
- aplane->ctx = ctx;
- type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
- DRM_PLANE_TYPE_OVERLAY;
-
- ret = ade_plane_init(drm_dev, aplane, type);
- if (ret)
- return ret;
- }
-
- /* crtc init */
- acrtc->ctx = ctx;
- ret = ade_crtc_init(drm_dev, &acrtc->base,
- &ade->aplane[PRIMARY_CH].base);
- if (ret)
- return ret;
-
- /* vblank irq init */
- ret = request_irq(ctx->irq, ade_irq_handler, DRIVER_IRQ_SHARED,
- drm_dev->driver->name, acrtc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void ade_unbind(struct device *dev, struct device *master, void *data)
-{
- /* do nothing */
-}
-
-static const struct component_ops ade_ops = {
- .bind = ade_bind,
- .unbind = ade_unbind,
-};
-
-static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx)
-{
- struct resource *res;
- struct device *dev;
- struct device_node *np;
- int ret;
-
- dev = &pdev->dev;
- np = dev->of_node;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ade_base");
- ctx->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ctx->base)) {
- DRM_ERROR("failed to remap ade io base\n");
- return PTR_ERR(ctx->base);
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_base");
- ctx->media_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ctx->media_base)) {
- DRM_ERROR("failed to remap media io base\n");
- return PTR_ERR(ctx->media_base);
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_noc_base");
- ctx->media_noc_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ctx->media_noc_base)) {
- DRM_ERROR("failed to remap media noc base\n");
- return PTR_ERR(ctx->media_noc_base);
- }
-
- ctx->irq = platform_get_irq(pdev, 0);
- if (ctx->irq < 0) {
- DRM_ERROR("failed to parse the irq\n");
- return -ENODEV;
- }
-
- ctx->ade_core_clk = devm_clk_get(&pdev->dev, "clk_ade_core");
- if (!ctx->ade_core_clk) {
- DRM_ERROR("failed to parse the ADE_CORE\n");
- return -ENODEV;
- }
- ctx->media_noc_clk = devm_clk_get(&pdev->dev,
- "aclk_codec_jpeg_src");
- if (!ctx->media_noc_clk) {
- DRM_ERROR("failed to parse the CODEC_JPEG\n");
- return -ENODEV;
- }
- ctx->ade_pix_clk = devm_clk_get(&pdev->dev, "clk_ade_pix");
- if (!ctx->ade_pix_clk) {
- DRM_ERROR("failed to parse the ADE_PIX_SRC\n");
- return -ENODEV;
- }
-
- ret = of_property_read_u32(np, "ade_core_clk_rate",
- &ctx->ade_core_rate);
- if (ret) {
- DRM_ERROR("failed to parse the ade_core_clk_rate\n");
- return -ENODEV;
- }
- ret = of_property_read_u32(np, "media_noc_clk_rate",
- &ctx->media_noc_rate);
- if (ret) {
- DRM_ERROR("failed to parse the media_noc_clk_rate\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int ade_probe(struct platform_device *pdev)
-{
- struct ade_data *ade;
- int ret;
-
- DRM_DEBUG_DRIVER("enter.\n");
-
- ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
- if (!ade) {
- DRM_ERROR("failed to alloc ade_data\n");
- return -ENOMEM;
- }
-
- ret = ade_dts_parse(pdev, &ade->ctx);
- if (ret) {
- DRM_ERROR("failed to parse dts!!\n");
- return ret;
- }
-
- platform_set_drvdata(pdev, ade);
-
- return component_add(&pdev->dev, &ade_ops);
-}
-
-static int ade_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &ade_ops);
-
- return 0;
-}
-
-static const struct of_device_id ade_of_match[] = {
- { .compatible = "hisilicon,hi6220-ade" },
- { }
-};
-MODULE_DEVICE_TABLE(of, ade_of_match);
-
-static struct platform_driver ade_driver = {
- .probe = ade_probe,
- .remove = ade_remove,
- .driver = {
- .name = "hisi-ade",
- .owner = THIS_MODULE,
- .of_match_table = ade_of_match,
- },
-};
-
-module_platform_driver(ade_driver);
-
-MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
-MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
-MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
-MODULE_DESCRIPTION("Hisilicon DRM ADE(crtc/plane) Driver");
-MODULE_LICENSE("GPL v2");
deleted file mode 100644
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
- *
- * 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.
- *
- */
-
-#ifndef __HISI_DRM_ADE_H__
-#define __HISI_DRM_ADE_H__
-
-int ade_enable_vblank(struct drm_device *dev, unsigned int pipe);
-void ade_disable_vblank(struct drm_device *dev, unsigned int pipe);
-
-#endif
deleted file mode 100644
@@ -1,280 +0,0 @@
-/*
- * Hisilicon SoCs drm master driver
- *
- * Copyright (c) 2014-2015 Hisilicon Limited.
- * Author:
- * Xinliang Liu <xinliang.liu@linaro.org>
- * Xinliang Liu <z.liuxinliang@hisilicon.com>
- * Xinwei Kong <kong.kongxinwei@hisilicon.com>
- *
- * 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.
- *
- */
-
-#include <linux/of_platform.h>
-#include <linux/component.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
-
-#include "hisi_drm_ade.h"
-#include "hisi_drm_drv.h"
-
-#define DRIVER_NAME "hisi-drm"
-
-static int hisi_drm_unload(struct drm_device *dev)
-{
- struct hisi_drm_private *priv = dev->dev_private;
-
-#ifdef CONFIG_DRM_FBDEV_EMULATION
- if (priv->fbdev) {
- drm_fbdev_cma_fini(priv->fbdev);
- priv->fbdev = NULL;
- }
-#endif
- drm_kms_helper_poll_fini(dev);
- drm_vblank_cleanup(dev);
- drm_mode_config_cleanup(dev);
- devm_kfree(dev->dev, priv);
- dev->dev_private = NULL;
-
- return 0;
-}
-
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-static void hisi_fbdev_output_poll_changed(struct drm_device *dev)
-{
- struct hisi_drm_private *priv = dev->dev_private;
-
- if (priv->fbdev) {
- drm_fbdev_cma_hotplug_event(priv->fbdev);
- } else {
- priv->fbdev = drm_fbdev_cma_init(dev, 32,
- dev->mode_config.num_crtc,
- dev->mode_config.num_connector);
- if (IS_ERR(priv->fbdev))
- priv->fbdev = NULL;
- }
-}
-#endif
-
-static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
- .fb_create = drm_fb_cma_create,
-#ifdef CONFIG_DRM_FBDEV_EMULATION
- .output_poll_changed = hisi_fbdev_output_poll_changed,
-#endif
- .atomic_check = drm_atomic_helper_check,
- .atomic_commit = drm_atomic_helper_commit,
-};
-
-static void hisi_drm_mode_config_init(struct drm_device *dev)
-{
- dev->mode_config.min_width = 0;
- dev->mode_config.min_height = 0;
-
- dev->mode_config.max_width = 2048;
- dev->mode_config.max_height = 2048;
-
- dev->mode_config.funcs = &hisi_drm_mode_config_funcs;
-}
-
-static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
-{
- struct hisi_drm_private *priv;
- int ret;
-
- priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- dev->dev_private = priv;
- dev_set_drvdata(dev->dev, dev);
-
- /* dev->mode_config initialization */
- drm_mode_config_init(dev);
- hisi_drm_mode_config_init(dev);
-
- /* bind and init sub drivers */
- ret = component_bind_all(dev->dev, dev);
- if (ret) {
- DRM_ERROR("failed to bind all component.\n");
- goto err_mode_config_cleanup;
- }
-
- /* vblank init */
- ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
- if (ret) {
- DRM_ERROR("failed to initialize vblank.\n");
- goto err_unbind_all;
- }
- /* with irq_enabled = true, we can use the vblank feature. */
- dev->irq_enabled = true;
-
- /* reset all the states of crtc/plane/encoder/connector */
- drm_mode_config_reset(dev);
-
- /* init kms poll for handling hpd */
- drm_kms_helper_poll_init(dev);
-
- /* force detection after connectors init */
- (void)drm_helper_hpd_irq_event(dev);
-
- return 0;
-
-err_unbind_all:
- component_unbind_all(dev->dev, dev);
-err_mode_config_cleanup:
- drm_mode_config_cleanup(dev);
- devm_kfree(dev->dev, priv);
- dev->dev_private = NULL;
-
- return ret;
-}
-
-static const struct file_operations hisi_drm_fops = {
- .owner = THIS_MODULE,
- .open = drm_open,
- .release = drm_release,
- .unlocked_ioctl = drm_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = drm_compat_ioctl,
-#endif
- .poll = drm_poll,
- .read = drm_read,
- .llseek = no_llseek,
- .mmap = drm_gem_cma_mmap,
-};
-
-static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
- struct drm_gem_object *obj,
- int flags)
-{
- /* we want to be able to write in mmapped buffer */
- flags |= O_RDWR;
- return drm_gem_prime_export(dev, obj, flags);
-}
-
-static int hisi_gem_cma_dumb_create(struct drm_file *file,
- struct drm_device *dev,
- struct drm_mode_create_dumb *args)
-{
- int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
-
- /* mali gpu need pitch 8 bytes alignment for 32bpp */
- args->pitch = roundup(min_pitch, 8);
-
- return drm_gem_cma_dumb_create_internal(file, dev, args);
-}
-
-static struct drm_driver hisi_drm_driver = {
- .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
- DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
- .load = hisi_drm_load,
- .unload = hisi_drm_unload,
- .fops = &hisi_drm_fops,
- .set_busid = drm_platform_set_busid,
-
- .gem_free_object = drm_gem_cma_free_object,
- .gem_vm_ops = &drm_gem_cma_vm_ops,
- .dumb_create = hisi_gem_cma_dumb_create,
- .dumb_map_offset = drm_gem_cma_dumb_map_offset,
- .dumb_destroy = drm_gem_dumb_destroy,
-
- .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
- .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
- .gem_prime_export = hisi_gem_prime_export,
- .gem_prime_import = drm_gem_prime_import,
- .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
- .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
- .gem_prime_vmap = drm_gem_cma_prime_vmap,
- .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
- .gem_prime_mmap = drm_gem_cma_prime_mmap,
-
- .get_vblank_counter = drm_vblank_count,
- .enable_vblank = ade_enable_vblank,
- .disable_vblank = ade_disable_vblank,
-
- .name = "hisi",
- .desc = "Hisilicon SoCs' DRM Driver",
- .date = "20150718",
- .major = 1,
- .minor = 0,
-};
-
-static int compare_of(struct device *dev, void *data)
-{
- return dev->of_node == data;
-}
-
-static int hisi_drm_bind(struct device *dev)
-{
- dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
- return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
-}
-
-static void hisi_drm_unbind(struct device *dev)
-{
- drm_put_dev(dev_get_drvdata(dev));
-}
-
-static const struct component_master_ops hisi_drm_ops = {
- .bind = hisi_drm_bind,
- .unbind = hisi_drm_unbind,
-};
-
-static int hisi_drm_platform_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *node = dev->of_node;
- struct device_node *child_np;
- struct component_match *match = NULL;
-
- of_platform_populate(node, NULL, NULL, dev);
-
- child_np = of_get_next_available_child(node, NULL);
- while (child_np) {
- component_match_add(dev, &match, compare_of, child_np);
- of_node_put(child_np);
- child_np = of_get_next_available_child(node, child_np);
- }
-
- return component_master_add_with_match(dev, &hisi_drm_ops, match);
-
- return 0;
-}
-
-static int hisi_drm_platform_remove(struct platform_device *pdev)
-{
- component_master_del(&pdev->dev, &hisi_drm_ops);
- of_platform_depopulate(&pdev->dev);
- return 0;
-}
-
-static const struct of_device_id hisi_drm_dt_ids[] = {
- { .compatible = "hisilicon,hi6220-dss", },
- { /* end node */ },
-};
-MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
-
-static struct platform_driver hisi_drm_platform_driver = {
- .probe = hisi_drm_platform_probe,
- .remove = hisi_drm_platform_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME,
- .of_match_table = hisi_drm_dt_ids,
- },
-};
-
-module_platform_driver(hisi_drm_platform_driver);
-
-MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
-MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
-MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
-MODULE_DESCRIPTION("hisilicon SoCs' DRM master driver");
-MODULE_LICENSE("GPL v2");
deleted file mode 100644
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
- *
- * 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.
- *
- */
-
-#ifndef __HISI_DRM_DRV_H__
-#define __HISI_DRM_DRV_H__
-
-struct hisi_drm_private {
-#ifdef CONFIG_DRM_FBDEV_EMULATION
- struct drm_fbdev_cma *fbdev;
-#endif
-};
-
-#endif /* __HISI_DRM_DRV_H__ */
deleted file mode 100644
@@ -1,832 +0,0 @@
-/*
- * Hisilicon hi6220 SoC dsi driver
- *
- * Copyright (c) 2014-2015 Hisilicon Limited.
- * Author:
- * Xinliang Liu <xinliang.liu@linaro.org>
- * Xinliang Liu <z.liuxinliang@hisilicon.com>
- * Xinwei Kong <kong.kongxinwei@hisilicon.com>
- *
- * 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.
- *
- */
-
-#include <linux/clk.h>
-#include <linux/component.h>
-#include <linux/of_graph.h>
-
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_encoder_slave.h>
-#include <drm/drm_atomic_helper.h>
-
-#include "hisi_dsi_reg.h"
-
-#define MAX_TX_ESC_CLK (10)
-#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
-#define DEFAULT_MIPI_CLK_RATE 19200000
-#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000))
-#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
- phy->lane_byte_clk_kHz)))
-
-#define encoder_to_dsi(encoder) \
- container_of(encoder, struct hisi_dsi, encoder)
-#define host_to_dsi(host) \
- container_of(host, struct hisi_dsi, host)
-
-struct mipi_phy_register {
- u32 clk_t_lpx;
- u32 clk_t_hs_prepare;
- u32 clk_t_hs_zero;
- u32 clk_t_hs_trial;
- u32 clk_t_wakeup;
- u32 data_t_lpx;
- u32 data_t_hs_prepare;
- u32 data_t_hs_zero;
- u32 data_t_hs_trial;
- u32 data_t_ta_go;
- u32 data_t_ta_get;
- u32 data_t_wakeup;
- u32 hstx_ckg_sel;
- u32 pll_fbd_div5f;
- u32 pll_fbd_div1f;
- u32 pll_fbd_2p;
- u32 pll_enbwt;
- u32 pll_fbd_p;
- u32 pll_fbd_s;
- u32 pll_pre_div1p;
- u32 pll_pre_p;
- u32 pll_vco_750M;
- u32 pll_lpf_rs;
- u32 pll_lpf_cs;
- u32 clklp2hs_time;
- u32 clkhs2lp_time;
- u32 lp2hs_time;
- u32 hs2lp_time;
- u32 clk_to_data_delay;
- u32 data_to_clk_delay;
- u32 lane_byte_clk_kHz;
- u32 clk_division;
-};
-
-struct dsi_hw_ctx {
- void __iomem *base;
- struct clk *dsi_cfg_clk;
-};
-
-struct hisi_dsi {
- struct drm_encoder encoder;
- struct drm_bridge *bridge;
- struct mipi_dsi_host host;
- struct drm_display_mode cur_mode;
- struct dsi_hw_ctx *ctx;
- struct mipi_phy_register phy;
-
- u32 lanes;
- enum mipi_dsi_pixel_format format;
- unsigned long mode_flags;
- bool enable;
-};
-
-struct dsi_data {
- struct hisi_dsi dsi;
- struct dsi_hw_ctx ctx;
-};
-
-struct dsi_phy_seq_info {
- u32 min_range_kHz;
- u32 max_range_kHz;
- u32 pll_vco_750M;
- u32 hstx_ckg_sel;
-};
-
-static const struct dsi_phy_seq_info dphy_seq_info[] = {
- { 46000, 62000, 1, 7 },
- { 62000, 93000, 0, 7 },
- { 93000, 125000, 1, 6 },
- { 125000, 187000, 0, 6 },
- { 187000, 250000, 1, 5 },
- { 250000, 375000, 0, 5 },
- { 375000, 500000, 1, 4 },
- { 500000, 750000, 0, 4 },
- { 750000, 1000000, 1, 0 },
- { 1000000, 1500000, 0, 0 }
-};
-
-static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
- struct mipi_phy_register *phy)
-{
- u32 ui = 0;
- u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
- u32 i = 0;
- u32 q_pll = 1;
- u32 m_pll = 0;
- u32 n_pll = 0;
- u32 r_pll = 1;
- u32 m_n = 0;
- u32 m_n_int = 0;
- u64 f_kHz;
- u64 temp;
- u64 tmp_kHz = phy_freq_kHz;
-
- do {
- f_kHz = tmp_kHz;
-
- /* Find the PLL clock range from the table */
- for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
- if (f_kHz > dphy_seq_info[i].min_range_kHz &&
- f_kHz <= dphy_seq_info[i].max_range_kHz)
- break;
-
- if (i == ARRAY_SIZE(dphy_seq_info)) {
- DRM_ERROR("%lldkHz out of range\n", f_kHz);
- return;
- }
-
- phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
- phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
-
- if (phy->hstx_ckg_sel <= 7 &&
- phy->hstx_ckg_sel >= 4)
- q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
-
- temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
- m_n_int = temp / (u64)1000000000;
- m_n = (temp % (u64)1000000000) / (u64)100000000;
-
- if (m_n_int % 2 == 0) {
- if (m_n * 6 >= 50) {
- n_pll = 2;
- m_pll = (m_n_int + 1) * n_pll;
- } else if (m_n * 6 >= 30) {
- n_pll = 3;
- m_pll = m_n_int * n_pll + 2;
- } else {
- n_pll = 1;
- m_pll = m_n_int * n_pll;
- }
- } else {
- if (m_n * 6 >= 50) {
- n_pll = 1;
- m_pll = (m_n_int + 1) * n_pll;
- } else if (m_n * 6 >= 30) {
- n_pll = 1;
- m_pll = (m_n_int + 1) * n_pll;
- } else if (m_n * 6 >= 10) {
- n_pll = 3;
- m_pll = m_n_int * n_pll + 1;
- } else {
- n_pll = 2;
- m_pll = m_n_int * n_pll;
- }
- }
-
- if (n_pll == 1) {
- phy->pll_fbd_p = 0;
- phy->pll_pre_div1p = 1;
- } else {
- phy->pll_fbd_p = n_pll;
- phy->pll_pre_div1p = 0;
- }
-
- if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
- r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
-
- if (m_pll == 2) {
- phy->pll_pre_p = 0;
- phy->pll_fbd_s = 0;
- phy->pll_fbd_div1f = 0;
- phy->pll_fbd_div5f = 1;
- } else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) {
- phy->pll_pre_p = m_pll / (2 * r_pll);
- phy->pll_fbd_s = 0;
- phy->pll_fbd_div1f = 1;
- phy->pll_fbd_div5f = 0;
- } else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) {
- if (((m_pll / (2 * r_pll)) % 2) == 0) {
- phy->pll_pre_p =
- (m_pll / (2 * r_pll)) / 2 - 1;
- phy->pll_fbd_s =
- (m_pll / (2 * r_pll)) % 2 + 2;
- } else {
- phy->pll_pre_p =
- (m_pll / (2 * r_pll)) / 2;
- phy->pll_fbd_s =
- (m_pll / (2 * r_pll)) % 2;
- }
- phy->pll_fbd_div1f = 0;
- phy->pll_fbd_div5f = 0;
- } else {
- phy->pll_pre_p = 0;
- phy->pll_fbd_s = 0;
- phy->pll_fbd_div1f = 0;
- phy->pll_fbd_div5f = 1;
- }
-
- f_kHz = (u64)1000000000 * (u64)m_pll /
- ((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
-
- if (f_kHz >= phy_freq_kHz)
- break;
-
- tmp_kHz += 10;
-
- } while (1);
-
- ui = 1000000 / f_kHz;
-
- phy->clk_t_lpx = ROUND(50, 8 * ui);
- phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
-
- phy->clk_t_hs_zero = ROUND(262, 8 * ui);
- phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
- phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
- if (phy->clk_t_wakeup > 0xff)
- phy->clk_t_wakeup = 0xff;
- phy->data_t_wakeup = phy->clk_t_wakeup;
- phy->data_t_lpx = phy->clk_t_lpx;
- phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
- phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
- phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
- phy->data_t_ta_go = 3;
- phy->data_t_ta_get = 4;
-
- phy->pll_enbwt = 1;
- phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
- phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
- phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
- phy->hs2lp_time = phy->clkhs2lp_time;
- phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
- phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
- phy->clkhs2lp_time;
-
- phy->lane_byte_clk_kHz = f_kHz / 8;
- phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
- if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
- phy->clk_division++;
-}
-
-static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
-{
- u32 val;
-
- /* TODO: only support RGB888 now, to support more */
- switch (format) {
- case MIPI_DSI_FMT_RGB888:
- val = DSI_24BITS_1;
- break;
- default:
- val = DSI_24BITS_1;
- break;
- }
-
- return val;
-}
-
-static void dsi_mipi_phy_clks(void __iomem *base,
- struct mipi_phy_register *phy,
- u32 lanes)
-{
- u32 delay_count;
- bool is_ready;
- u32 val;
- u32 i;
-
- /* set lanes value */
- val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
- writel(val, base + PHY_IF_CFG);
-
- /* set phy clk division */
- val = readl(base + CLKMGR_CFG) | phy->clk_division;
- writel(val, base + CLKMGR_CFG);
-
- /* clean up phy set param */
- writel(0, base + PHY_RSTZ);
- writel(0, base + PHY_TST_CTRL0);
- writel(1, base + PHY_TST_CTRL0);
- writel(0, base + PHY_TST_CTRL0);
-
- /* clock lane Timing control - TLPX */
- dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
-
- /* clock lane Timing control - THS-PREPARE */
- dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
-
- /* clock lane Timing control - THS-ZERO */
- dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
-
- /* clock lane Timing control - THS-TRAIL */
- dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
-
- /* clock lane Timing control - TWAKEUP */
- dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
-
- /* data lane */
- for (i = 0; i < lanes; i++) {
- /* Timing control - TLPX*/
- dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx);
-
- /* Timing control - THS-PREPARE */
- dsi_phy_tst_set(base, 0x10021 + (i << 4),
- phy->data_t_hs_prepare);
-
- /* Timing control - THS-ZERO */
- dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero);
-
- /* Timing control - THS-TRAIL */
- dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial);
-
- /* Timing control - TTA-GO */
- dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go);
-
- /* Timing control - TTA-GET */
- dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get);
-
- /* Timing control - TWAKEUP */
- dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup);
- }
-
- /* physical configuration I */
- dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
-
- /* physical configuration pll II */
- val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
- (phy->pll_fbd_2p << 1) + phy->pll_enbwt;
- dsi_phy_tst_set(base, 0x10063, val);
-
- /* physical configuration pll II */
- dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
-
- /* physical configuration pll III */
- dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
-
- /*physical configuration pll IV*/
- val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
- dsi_phy_tst_set(base, 0x10066, val);
-
- /*physical configuration pll V*/
- val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
- phy->pll_lpf_cs + BIT(5);
- dsi_phy_tst_set(base, 0x10067, val);
-
- writel(BIT(2), base + PHY_RSTZ);
- udelay(1);
- writel(BIT(2) | BIT(0), base + PHY_RSTZ);
- udelay(1);
- writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
- usleep_range(1000, 1500);
-
- /* wait for phy's clock ready */
- delay_count = 0;
- is_ready = false;
- while (1) {
- val = readl(base + PHY_STATUS);
- if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
- is_ready = (delay_count < 100) ? true : false;
- delay_count = 0;
- break;
- }
-
- udelay(1);
- ++delay_count;
- }
-
- if (!is_ready)
- DRM_INFO("phylock and phystopstateclklane is not ready.\n");
-}
-
-static void dsi_set_mode_timing(void __iomem *base,
- struct mipi_phy_register *phy,
- struct drm_display_mode *mode,
- enum mipi_dsi_pixel_format format)
-{
- u32 hfp, hbp, hsw, vfp, vbp, vsw;
- u32 hline_time;
- u32 hsa_time;
- u32 hbp_time;
- u32 pixel_clk_kHz;
- int htot, vtot;
- u32 val;
-
- /* DSI color coding setting */
- val = dsi_get_dpi_color_coding(format);
- writel(val, base + DPI_COLOR_CODING);
-
- /* DSI format and pol setting */
- val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
- val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
- writel(val, base + DPI_CFG_POL);
-
- /*
- * The DSI IP accepts vertical timing using lines as normal,
- * but horizontal timing is a mixture of pixel-clocks for the
- * active region and byte-lane clocks for the blanking-related
- * timings. hfp is specified as the total hline_time in byte-
- * lane clocks minus hsa, hbp and active.
- */
- pixel_clk_kHz = mode->clock;
- htot = mode->htotal;
- vtot = mode->vtotal;
- hfp = mode->hsync_start - mode->hdisplay;
- hbp = mode->htotal - mode->hsync_end;
- hsw = mode->hsync_end - mode->hsync_start;
- vfp = mode->vsync_start - mode->vdisplay;
- vbp = mode->vtotal - mode->vsync_end;
- vsw = mode->vsync_end - mode->vsync_start;
- if (vsw > 15) {
- DRM_INFO("vsw exceeded 15\n");
- vtot -= vsw - 15;
- vsw = 15;
- }
-
- hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
- hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
- hline_time = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
- pixel_clk_kHz;
-
- if ((R(hline_time) / 1000) > htot) {
- DRM_INFO("--: hline_time=%d\n", hline_time);
- hline_time--;
- }
-
- if ((R(hline_time) / 1000) < htot) {
- DRM_INFO("++: hline_time=%d\n", hline_time);
- hline_time++;
- }
-
- /* all specified in byte-lane clocks */
- writel(hsa_time, base + VID_HSA_TIME);
- writel(hbp_time, base + VID_HBP_TIME);
- writel(hline_time, base + VID_HLINE_TIME);
-
- writel(vsw, base + VID_VSA_LINES);
- writel(vbp, base + VID_VBP_LINES);
- writel(vfp, base + VID_VFP_LINES);
- writel(mode->vdisplay, base + VID_VACTIVE_LINES);
- writel(mode->hdisplay, base + VID_PKT_SIZE);
-}
-
-static void dsi_set_video_mode_type(void __iomem *base,
- struct mipi_phy_register *phy,
- unsigned long flags)
-{
- u32 val;
- u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
- MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
- u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
- MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
- u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
-
- /*
- * choose video type
- */
- if ((flags & mode_mask) == non_burst_sync_pulse)
- val = DSI_NON_BURST_SYNC_PULSES;
- else if ((flags & mode_mask) == non_burst_sync_event)
- val = DSI_NON_BURST_SYNC_EVENTS;
- else
- val = DSI_BURST_SYNC_PULSES_1;
-
- writel(val, base + VID_MODE_CFG);
- /* TODO: to support LCD panel need to set LP command transfer */
-}
-
-static void dsi_mipi_init(struct hisi_dsi *dsi)
-{
- struct dsi_hw_ctx *ctx = dsi->ctx;
- struct mipi_phy_register *phy = &dsi->phy;
- struct drm_display_mode *mode = &dsi->cur_mode;
- void __iomem *base = ctx->base;
- u32 dphy_freq_kHz;
-
- /* count phy params */
- dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
- set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
-
- /* reset Core */
- writel(0, base + PWR_UP);
-
- /* set phy clocks */
- dsi_mipi_phy_clks(base, phy, dsi->lanes);
-
- /* set dsi mode */
- dsi_set_mode_timing(base, phy, mode, dsi->format);
-
- /* set video mode type and low power */
- dsi_set_video_mode_type(base, phy, dsi->mode_flags);
-
- /* DSI and D-PHY Initialization */
- writel(DSI_VIDEO_MODE, base + MODE_CFG);
- writel(BIT(0), base + LPCLK_CTRL);
- writel(BIT(0), base + PWR_UP);
-
- DRM_INFO("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n",
- dsi->lanes, mode->clock, phy->lane_byte_clk_kHz);
-}
-
-static void dsi_encoder_disable(struct drm_encoder *encoder)
-{
- struct hisi_dsi *dsi = encoder_to_dsi(encoder);
- struct dsi_hw_ctx *ctx = dsi->ctx;
- void __iomem *base = ctx->base;
-
- DRM_DEBUG_DRIVER("enter\n");
- if (!dsi->enable)
- return;
-
- writel(0, base + PWR_UP);
- writel(0, base + LPCLK_CTRL);
- writel(0, base + PHY_RSTZ);
- clk_disable_unprepare(ctx->dsi_cfg_clk);
-
- dsi->enable = false;
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void dsi_encoder_enable(struct drm_encoder *encoder)
-{
- struct hisi_dsi *dsi = encoder_to_dsi(encoder);
- struct dsi_hw_ctx *ctx = dsi->ctx;
- int ret;
-
- DRM_DEBUG_DRIVER("enter.\n");
- if (dsi->enable)
- return;
-
- /* mipi dphy clock enable */
- ret = clk_prepare_enable(ctx->dsi_cfg_clk);
- if (ret) {
- DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
- return;
- }
-
- dsi_mipi_init(dsi);
-
- dsi->enable = true;
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void dsi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adj_mode)
-{
- struct hisi_dsi *dsi = encoder_to_dsi(encoder);
-
- DRM_DEBUG_DRIVER("enter.\n");
- drm_mode_copy(&dsi->cur_mode, adj_mode);
- DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
-{
- struct drm_display_mode *mode = &crtc_state->mode;
-
- DRM_DEBUG_DRIVER("enter.\n");
- if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
- DRM_ERROR("not support INTERLACE mode\n");
- return MODE_NO_INTERLACE;
- }
-
- /* pixel clock support range is (1190494208/64, 1190494208)Hz */
- if (mode->clock < 18602 || mode->clock > 1190494) {
- DRM_ERROR("mode clock not support\n");
- return MODE_CLOCK_RANGE;
- }
-
- DRM_DEBUG_DRIVER("exit success.\n");
- return 0;
-}
-
-static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
- .atomic_check = dsi_encoder_atomic_check,
- .mode_set = dsi_encoder_mode_set,
- .enable = dsi_encoder_enable,
- .disable = dsi_encoder_disable
-};
-
-static const struct drm_encoder_funcs hisi_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-};
-
-static int hisi_drm_encoder_init(struct drm_device *dev,
- struct drm_encoder *encoder)
-{
- int ret;
-
- encoder->possible_crtcs = 1;
- ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
- if (ret) {
- DRM_ERROR("failed to init dsi encoder\n");
- return ret;
- }
-
- drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
-
- return 0;
-}
-
-static int dsi_host_attach(struct mipi_dsi_host *host,
- struct mipi_dsi_device *mdsi)
-{
- struct hisi_dsi *dsi = host_to_dsi(host);
-
- if (mdsi->lanes < 1 || mdsi->lanes > 4) {
- DRM_ERROR("dsi device params invalid\n");
- return -EINVAL;
- }
-
- dsi->lanes = mdsi->lanes;
- dsi->format = mdsi->format;
- dsi->mode_flags = mdsi->mode_flags;
-
- return 0;
-}
-
-static int dsi_host_detach(struct mipi_dsi_host *host,
- struct mipi_dsi_device *mdsi)
-{
- /* do nothing */
- return 0;
-}
-
-static struct mipi_dsi_host_ops dsi_host_ops = {
- .attach = dsi_host_attach,
- .detach = dsi_host_detach,
-};
-
-static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
-{
- struct mipi_dsi_host *host = &dsi->host;
- int ret;
-
- host->dev = dev;
- host->ops = &dsi_host_ops;
- ret = mipi_dsi_host_register(host);
- if (ret) {
- DRM_ERROR("failed to register dsi host\n");
- return ret;
- }
-
- return 0;
-}
-
-static int dsi_bridge_init(struct drm_device *dev, struct hisi_dsi *dsi)
-{
- struct drm_encoder *encoder = &dsi->encoder;
- struct drm_bridge *bridge = dsi->bridge;
- int ret;
-
- /* associate the bridge to dsi encoder */
- encoder->bridge = bridge;
- bridge->encoder = encoder;
-
- ret = drm_bridge_attach(dev, bridge);
- if (ret) {
- DRM_ERROR("failed to attach exteranl bridge\n");
- return ret;
- }
-
- return 0;
-}
-
-static int dsi_bind(struct device *dev, struct device *master, void *data)
-{
- struct dsi_data *ddata = dev_get_drvdata(dev);
- struct hisi_dsi *dsi = &ddata->dsi;
- struct drm_device *drm_dev = data;
- int ret;
-
- ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
- if (ret)
- return ret;
-
- ret = dsi_host_init(dev, dsi);
- if (ret)
- return ret;
-
- ret = dsi_bridge_init(drm_dev, dsi);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void dsi_unbind(struct device *dev, struct device *master, void *data)
-{
- /* do nothing */
-}
-
-static const struct component_ops dsi_ops = {
- .bind = dsi_bind,
- .unbind = dsi_unbind,
-};
-
-static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
-{
- struct dsi_hw_ctx *ctx = dsi->ctx;
- struct device_node *np = pdev->dev.of_node;
- struct device_node *endpoint, *bridge_node;
- struct drm_bridge *bridge;
- struct resource *res;
-
- /*
- * Get the endpoint node. In our case, dsi has one output port
- * to which the external HDMI bridge is connected.
- */
- endpoint = of_graph_get_next_endpoint(np, NULL);
- if (!endpoint) {
- DRM_ERROR("no valid endpoint node\n");
- return -ENODEV;
- }
- of_node_put(endpoint);
-
- bridge_node = of_graph_get_remote_port_parent(endpoint);
- if (!bridge_node) {
- DRM_ERROR("no valid bridge node\n");
- return -ENODEV;
- }
- of_node_put(bridge_node);
-
- bridge = of_drm_find_bridge(bridge_node);
- if (!bridge) {
- DRM_INFO("wait for external HDMI bridge driver.\n");
- return -EPROBE_DEFER;
- }
- dsi->bridge = bridge;
-
- ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
- if (IS_ERR(ctx->dsi_cfg_clk)) {
- DRM_ERROR("failed to get dsi plck clock\n");
- return PTR_ERR(ctx->dsi_cfg_clk);
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ctx->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ctx->base)) {
- DRM_ERROR("failed to remap dsi io region\n");
- return PTR_ERR(ctx->base);
- }
-
- return 0;
-}
-
-static int dsi_probe(struct platform_device *pdev)
-{
- struct dsi_data *data;
- struct hisi_dsi *dsi;
- struct dsi_hw_ctx *ctx;
- int ret;
-
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data) {
- DRM_ERROR("failed to allocate dsi data.\n");
- return -ENOMEM;
- }
- dsi = &data->dsi;
- ctx = &data->ctx;
- dsi->ctx = ctx;
-
- ret = dsi_parse_dt(pdev, dsi);
- if (ret)
- return ret;
-
- platform_set_drvdata(pdev, data);
-
- return component_add(&pdev->dev, &dsi_ops);
-}
-
-static int dsi_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &dsi_ops);
-
- return 0;
-}
-
-static const struct of_device_id dsi_of_match[] = {
- {.compatible = "hisilicon,hi6220-dsi"},
- { }
-};
-MODULE_DEVICE_TABLE(of, dsi_of_match);
-
-static struct platform_driver dsi_driver = {
- .probe = dsi_probe,
- .remove = dsi_remove,
- .driver = {
- .name = "hisi-dsi",
- .owner = THIS_MODULE,
- .of_match_table = dsi_of_match,
- },
-};
-
-module_platform_driver(dsi_driver);
-
-MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
-MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
-MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
-MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
-MODULE_LICENSE("GPL v2");
deleted file mode 100644
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
- *
- * 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.
- *
- */
-
-#ifndef __HISI_DSI_REG_H__
-#define __HISI_DSI_REG_H__
-
-/*
- * regs
- */
-#define PWR_UP (0x4) /* Core power-up */
-#define PHY_IF_CFG (0xA4) /* D-PHY interface configuration */
-#define CLKMGR_CFG (0x8) /* the internal clock dividers */
-#define PHY_RSTZ (0xA0) /* D-PHY reset control */
-#define PHY_TST_CTRL0 (0xB4) /* D-PHY test interface control 0 */
-#define PHY_TST_CTRL1 (0xB8) /* D-PHY test interface control 1 */
-#define DPI_VCID (0xC) /* DPI virtual channel id */
-#define DPI_COLOR_CODING (0x10) /* DPI color coding */
-#define DPI_CFG_POL (0x14) /* DPI polarity configuration */
-#define VID_HSA_TIME (0x48) /* Horizontal Sync Active time */
-#define VID_HBP_TIME (0x4C) /* Horizontal Back Porch time */
-#define VID_HLINE_TIME (0x50) /* Line time */
-#define VID_VSA_LINES (0x54) /* Vertical Sync Active period */
-#define VID_VBP_LINES (0x58) /* Vertical Back Porch period */
-#define VID_VFP_LINES (0x5C) /* Vertical Front Porch period */
-#define VID_VACTIVE_LINES (0x60) /* Vertical resolution */
-#define VID_PKT_SIZE (0x3C) /* Video packet size */
-#define VID_MODE_CFG (0x38) /* Video mode configuration */
-#define DPI_LP_CMD_TIM (0x18) /* Low-power command timing config */
-#define PHY_TMR_CFG (0x9C) /* Data lanes timing configuration */
-#define BTA_TO_CNT (0x8C) /* Response timeout definition */
-#define PHY_TMR_LPCLK_CFG (0x98) /* clock lane timing configuration */
-#define CLK_DATA_TMR_CFG (0xCC)
-#define LPCLK_CTRL (0x94) /* Low-power in clock lane */
-#define PCKHDL_CFG (0x2C) /* Packet handler configuration */
-#define EDPI_CMD_SIZE (0x64) /* Size for eDPI packets */
-#define MODE_CFG (0x34) /* Video or Command mode selection */
-#define PHY_STATUS (0xB0) /* D-PHY PPI status interface */
-
-#define PHY_STOP_WAIT_TIME (0x30)
-
-/*
- * regs relevant enum
- */
-enum dpi_color_coding {
- DSI_24BITS_1 = 5,
-};
-
-enum dsi_video_mode_type {
- DSI_NON_BURST_SYNC_PULSES = 0,
- DSI_NON_BURST_SYNC_EVENTS,
- DSI_BURST_SYNC_PULSES_1,
- DSI_BURST_SYNC_PULSES_2
-};
-
-enum dsi_work_mode {
- DSI_VIDEO_MODE = 0,
- DSI_COMMAND_MODE
-};
-
-/*
- * regs Write/Read functions
- */
-static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
-{
- writel(reg, base + PHY_TST_CTRL1);
- /* reg addr written at first */
- wmb();
- writel(0x02, base + PHY_TST_CTRL0);
- /* cmd1 sent for write */
- wmb();
- writel(0x00, base + PHY_TST_CTRL0);
- /* cmd2 sent for write */
- wmb();
- writel(val, base + PHY_TST_CTRL1);
- /* Then write data */
- wmb();
- writel(0x02, base + PHY_TST_CTRL0);
- /* cmd2 sent for write */
- wmb();
- writel(0x00, base + PHY_TST_CTRL0);
-}
-
-#endif /* __HISI_DRM_DSI_H__ */
new file mode 100644
@@ -0,0 +1,19 @@
+config DRM_HISI_KIRIN
+ tristate "DRM Support for Hisilicon Kirin series SoCs Platform"
+ depends on DRM && OF && ARM64
+ select DRM_KMS_HELPER
+ select DRM_GEM_CMA_HELPER
+ select DRM_KMS_CMA_HELPER
+ help
+ Choose this option if you have a hisilicon Kirin chipsets(hi6220).
+ If M is selected the module will be called kirin-drm.
+
+config HISI_KIRIN_DW_DSI
+ tristate "HiSilicon Kirin specific extensions for Synopsys DW MIPI DSI"
+ depends on DRM_HISI_KIRIN
+ select DRM_MIPI_DSI
+ select DRM_PANEL
+ help
+ This selects support for HiSilicon Kirin SoC specific extensions for
+ the Synopsys DesignWare DSI driver. If you want to enable MIPI DSI on
+ hi6220 based SoC, you should selet this option.
new file mode 100644
@@ -0,0 +1,6 @@
+kirin-drm-y := kirin_drm_drv.o \
+ kirin_drm_ade.o
+
+obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o
+
+obj-$(CONFIG_HISI_KIRIN_DW_DSI) += dw_drm_dsi.o
new file mode 100644
@@ -0,0 +1,832 @@
+/*
+ * Hisilicon hi6220 SoC dsi driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ * Xinliang Liu <xinliang.liu@linaro.org>
+ * Xinliang Liu <z.liuxinliang@hisilicon.com>
+ * Xinwei Kong <kong.kongxinwei@hisilicon.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_graph.h>
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "dw_dsi_reg.h"
+
+#define MAX_TX_ESC_CLK (10)
+#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
+#define DEFAULT_MIPI_CLK_RATE 19200000
+#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000))
+#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
+ phy->lane_byte_clk_kHz)))
+
+#define encoder_to_dsi(encoder) \
+ container_of(encoder, struct hisi_dsi, encoder)
+#define host_to_dsi(host) \
+ container_of(host, struct hisi_dsi, host)
+
+struct mipi_phy_register {
+ u32 clk_t_lpx;
+ u32 clk_t_hs_prepare;
+ u32 clk_t_hs_zero;
+ u32 clk_t_hs_trial;
+ u32 clk_t_wakeup;
+ u32 data_t_lpx;
+ u32 data_t_hs_prepare;
+ u32 data_t_hs_zero;
+ u32 data_t_hs_trial;
+ u32 data_t_ta_go;
+ u32 data_t_ta_get;
+ u32 data_t_wakeup;
+ u32 hstx_ckg_sel;
+ u32 pll_fbd_div5f;
+ u32 pll_fbd_div1f;
+ u32 pll_fbd_2p;
+ u32 pll_enbwt;
+ u32 pll_fbd_p;
+ u32 pll_fbd_s;
+ u32 pll_pre_div1p;
+ u32 pll_pre_p;
+ u32 pll_vco_750M;
+ u32 pll_lpf_rs;
+ u32 pll_lpf_cs;
+ u32 clklp2hs_time;
+ u32 clkhs2lp_time;
+ u32 lp2hs_time;
+ u32 hs2lp_time;
+ u32 clk_to_data_delay;
+ u32 data_to_clk_delay;
+ u32 lane_byte_clk_kHz;
+ u32 clk_division;
+};
+
+struct dsi_hw_ctx {
+ void __iomem *base;
+ struct clk *dsi_cfg_clk;
+};
+
+struct hisi_dsi {
+ struct drm_encoder encoder;
+ struct drm_bridge *bridge;
+ struct mipi_dsi_host host;
+ struct drm_display_mode cur_mode;
+ struct dsi_hw_ctx *ctx;
+ struct mipi_phy_register phy;
+
+ u32 lanes;
+ enum mipi_dsi_pixel_format format;
+ unsigned long mode_flags;
+ bool enable;
+};
+
+struct dsi_data {
+ struct hisi_dsi dsi;
+ struct dsi_hw_ctx ctx;
+};
+
+struct dsi_phy_seq_info {
+ u32 min_range_kHz;
+ u32 max_range_kHz;
+ u32 pll_vco_750M;
+ u32 hstx_ckg_sel;
+};
+
+static const struct dsi_phy_seq_info dphy_seq_info[] = {
+ { 46000, 62000, 1, 7 },
+ { 62000, 93000, 0, 7 },
+ { 93000, 125000, 1, 6 },
+ { 125000, 187000, 0, 6 },
+ { 187000, 250000, 1, 5 },
+ { 250000, 375000, 0, 5 },
+ { 375000, 500000, 1, 4 },
+ { 500000, 750000, 0, 4 },
+ { 750000, 1000000, 1, 0 },
+ { 1000000, 1500000, 0, 0 }
+};
+
+static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
+ struct mipi_phy_register *phy)
+{
+ u32 ui = 0;
+ u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
+ u32 i = 0;
+ u32 q_pll = 1;
+ u32 m_pll = 0;
+ u32 n_pll = 0;
+ u32 r_pll = 1;
+ u32 m_n = 0;
+ u32 m_n_int = 0;
+ u64 f_kHz;
+ u64 temp;
+ u64 tmp_kHz = phy_freq_kHz;
+
+ do {
+ f_kHz = tmp_kHz;
+
+ /* Find the PLL clock range from the table */
+ for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
+ if (f_kHz > dphy_seq_info[i].min_range_kHz &&
+ f_kHz <= dphy_seq_info[i].max_range_kHz)
+ break;
+
+ if (i == ARRAY_SIZE(dphy_seq_info)) {
+ DRM_ERROR("%lldkHz out of range\n", f_kHz);
+ return;
+ }
+
+ phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
+ phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
+
+ if (phy->hstx_ckg_sel <= 7 &&
+ phy->hstx_ckg_sel >= 4)
+ q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
+
+ temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
+ m_n_int = temp / (u64)1000000000;
+ m_n = (temp % (u64)1000000000) / (u64)100000000;
+
+ if (m_n_int % 2 == 0) {
+ if (m_n * 6 >= 50) {
+ n_pll = 2;
+ m_pll = (m_n_int + 1) * n_pll;
+ } else if (m_n * 6 >= 30) {
+ n_pll = 3;
+ m_pll = m_n_int * n_pll + 2;
+ } else {
+ n_pll = 1;
+ m_pll = m_n_int * n_pll;
+ }
+ } else {
+ if (m_n * 6 >= 50) {
+ n_pll = 1;
+ m_pll = (m_n_int + 1) * n_pll;
+ } else if (m_n * 6 >= 30) {
+ n_pll = 1;
+ m_pll = (m_n_int + 1) * n_pll;
+ } else if (m_n * 6 >= 10) {
+ n_pll = 3;
+ m_pll = m_n_int * n_pll + 1;
+ } else {
+ n_pll = 2;
+ m_pll = m_n_int * n_pll;
+ }
+ }
+
+ if (n_pll == 1) {
+ phy->pll_fbd_p = 0;
+ phy->pll_pre_div1p = 1;
+ } else {
+ phy->pll_fbd_p = n_pll;
+ phy->pll_pre_div1p = 0;
+ }
+
+ if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
+ r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
+
+ if (m_pll == 2) {
+ phy->pll_pre_p = 0;
+ phy->pll_fbd_s = 0;
+ phy->pll_fbd_div1f = 0;
+ phy->pll_fbd_div5f = 1;
+ } else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) {
+ phy->pll_pre_p = m_pll / (2 * r_pll);
+ phy->pll_fbd_s = 0;
+ phy->pll_fbd_div1f = 1;
+ phy->pll_fbd_div5f = 0;
+ } else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) {
+ if (((m_pll / (2 * r_pll)) % 2) == 0) {
+ phy->pll_pre_p =
+ (m_pll / (2 * r_pll)) / 2 - 1;
+ phy->pll_fbd_s =
+ (m_pll / (2 * r_pll)) % 2 + 2;
+ } else {
+ phy->pll_pre_p =
+ (m_pll / (2 * r_pll)) / 2;
+ phy->pll_fbd_s =
+ (m_pll / (2 * r_pll)) % 2;
+ }
+ phy->pll_fbd_div1f = 0;
+ phy->pll_fbd_div5f = 0;
+ } else {
+ phy->pll_pre_p = 0;
+ phy->pll_fbd_s = 0;
+ phy->pll_fbd_div1f = 0;
+ phy->pll_fbd_div5f = 1;
+ }
+
+ f_kHz = (u64)1000000000 * (u64)m_pll /
+ ((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
+
+ if (f_kHz >= phy_freq_kHz)
+ break;
+
+ tmp_kHz += 10;
+
+ } while (1);
+
+ ui = 1000000 / f_kHz;
+
+ phy->clk_t_lpx = ROUND(50, 8 * ui);
+ phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
+
+ phy->clk_t_hs_zero = ROUND(262, 8 * ui);
+ phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
+ phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
+ if (phy->clk_t_wakeup > 0xff)
+ phy->clk_t_wakeup = 0xff;
+ phy->data_t_wakeup = phy->clk_t_wakeup;
+ phy->data_t_lpx = phy->clk_t_lpx;
+ phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
+ phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
+ phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
+ phy->data_t_ta_go = 3;
+ phy->data_t_ta_get = 4;
+
+ phy->pll_enbwt = 1;
+ phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
+ phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
+ phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
+ phy->hs2lp_time = phy->clkhs2lp_time;
+ phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
+ phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
+ phy->clkhs2lp_time;
+
+ phy->lane_byte_clk_kHz = f_kHz / 8;
+ phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
+ if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
+ phy->clk_division++;
+}
+
+static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
+{
+ u32 val;
+
+ /* TODO: only support RGB888 now, to support more */
+ switch (format) {
+ case MIPI_DSI_FMT_RGB888:
+ val = DSI_24BITS_1;
+ break;
+ default:
+ val = DSI_24BITS_1;
+ break;
+ }
+
+ return val;
+}
+
+static void dsi_mipi_phy_clks(void __iomem *base,
+ struct mipi_phy_register *phy,
+ u32 lanes)
+{
+ u32 delay_count;
+ bool is_ready;
+ u32 val;
+ u32 i;
+
+ /* set lanes value */
+ val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
+ writel(val, base + PHY_IF_CFG);
+
+ /* set phy clk division */
+ val = readl(base + CLKMGR_CFG) | phy->clk_division;
+ writel(val, base + CLKMGR_CFG);
+
+ /* clean up phy set param */
+ writel(0, base + PHY_RSTZ);
+ writel(0, base + PHY_TST_CTRL0);
+ writel(1, base + PHY_TST_CTRL0);
+ writel(0, base + PHY_TST_CTRL0);
+
+ /* clock lane Timing control - TLPX */
+ dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
+
+ /* clock lane Timing control - THS-PREPARE */
+ dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
+
+ /* clock lane Timing control - THS-ZERO */
+ dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
+
+ /* clock lane Timing control - THS-TRAIL */
+ dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
+
+ /* clock lane Timing control - TWAKEUP */
+ dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
+
+ /* data lane */
+ for (i = 0; i < lanes; i++) {
+ /* Timing control - TLPX*/
+ dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx);
+
+ /* Timing control - THS-PREPARE */
+ dsi_phy_tst_set(base, 0x10021 + (i << 4),
+ phy->data_t_hs_prepare);
+
+ /* Timing control - THS-ZERO */
+ dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero);
+
+ /* Timing control - THS-TRAIL */
+ dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial);
+
+ /* Timing control - TTA-GO */
+ dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go);
+
+ /* Timing control - TTA-GET */
+ dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get);
+
+ /* Timing control - TWAKEUP */
+ dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup);
+ }
+
+ /* physical configuration I */
+ dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
+
+ /* physical configuration pll II */
+ val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
+ (phy->pll_fbd_2p << 1) + phy->pll_enbwt;
+ dsi_phy_tst_set(base, 0x10063, val);
+
+ /* physical configuration pll II */
+ dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
+
+ /* physical configuration pll III */
+ dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
+
+ /*physical configuration pll IV*/
+ val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
+ dsi_phy_tst_set(base, 0x10066, val);
+
+ /*physical configuration pll V*/
+ val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
+ phy->pll_lpf_cs + BIT(5);
+ dsi_phy_tst_set(base, 0x10067, val);
+
+ writel(BIT(2), base + PHY_RSTZ);
+ udelay(1);
+ writel(BIT(2) | BIT(0), base + PHY_RSTZ);
+ udelay(1);
+ writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
+ usleep_range(1000, 1500);
+
+ /* wait for phy's clock ready */
+ delay_count = 0;
+ is_ready = false;
+ while (1) {
+ val = readl(base + PHY_STATUS);
+ if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
+ is_ready = (delay_count < 100) ? true : false;
+ delay_count = 0;
+ break;
+ }
+
+ udelay(1);
+ ++delay_count;
+ }
+
+ if (!is_ready)
+ DRM_INFO("phylock and phystopstateclklane is not ready.\n");
+}
+
+static void dsi_set_mode_timing(void __iomem *base,
+ struct mipi_phy_register *phy,
+ struct drm_display_mode *mode,
+ enum mipi_dsi_pixel_format format)
+{
+ u32 hfp, hbp, hsw, vfp, vbp, vsw;
+ u32 hline_time;
+ u32 hsa_time;
+ u32 hbp_time;
+ u32 pixel_clk_kHz;
+ int htot, vtot;
+ u32 val;
+
+ /* DSI color coding setting */
+ val = dsi_get_dpi_color_coding(format);
+ writel(val, base + DPI_COLOR_CODING);
+
+ /* DSI format and pol setting */
+ val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
+ val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
+ writel(val, base + DPI_CFG_POL);
+
+ /*
+ * The DSI IP accepts vertical timing using lines as normal,
+ * but horizontal timing is a mixture of pixel-clocks for the
+ * active region and byte-lane clocks for the blanking-related
+ * timings. hfp is specified as the total hline_time in byte-
+ * lane clocks minus hsa, hbp and active.
+ */
+ pixel_clk_kHz = mode->clock;
+ htot = mode->htotal;
+ vtot = mode->vtotal;
+ hfp = mode->hsync_start - mode->hdisplay;
+ hbp = mode->htotal - mode->hsync_end;
+ hsw = mode->hsync_end - mode->hsync_start;
+ vfp = mode->vsync_start - mode->vdisplay;
+ vbp = mode->vtotal - mode->vsync_end;
+ vsw = mode->vsync_end - mode->vsync_start;
+ if (vsw > 15) {
+ DRM_INFO("vsw exceeded 15\n");
+ vtot -= vsw - 15;
+ vsw = 15;
+ }
+
+ hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
+ hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
+ hline_time = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
+ pixel_clk_kHz;
+
+ if ((R(hline_time) / 1000) > htot) {
+ DRM_INFO("--: hline_time=%d\n", hline_time);
+ hline_time--;
+ }
+
+ if ((R(hline_time) / 1000) < htot) {
+ DRM_INFO("++: hline_time=%d\n", hline_time);
+ hline_time++;
+ }
+
+ /* all specified in byte-lane clocks */
+ writel(hsa_time, base + VID_HSA_TIME);
+ writel(hbp_time, base + VID_HBP_TIME);
+ writel(hline_time, base + VID_HLINE_TIME);
+
+ writel(vsw, base + VID_VSA_LINES);
+ writel(vbp, base + VID_VBP_LINES);
+ writel(vfp, base + VID_VFP_LINES);
+ writel(mode->vdisplay, base + VID_VACTIVE_LINES);
+ writel(mode->hdisplay, base + VID_PKT_SIZE);
+}
+
+static void dsi_set_video_mode_type(void __iomem *base,
+ struct mipi_phy_register *phy,
+ unsigned long flags)
+{
+ u32 val;
+ u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
+
+ /*
+ * choose video type
+ */
+ if ((flags & mode_mask) == non_burst_sync_pulse)
+ val = DSI_NON_BURST_SYNC_PULSES;
+ else if ((flags & mode_mask) == non_burst_sync_event)
+ val = DSI_NON_BURST_SYNC_EVENTS;
+ else
+ val = DSI_BURST_SYNC_PULSES_1;
+
+ writel(val, base + VID_MODE_CFG);
+ /* TODO: to support LCD panel need to set LP command transfer */
+}
+
+static void dsi_mipi_init(struct hisi_dsi *dsi)
+{
+ struct dsi_hw_ctx *ctx = dsi->ctx;
+ struct mipi_phy_register *phy = &dsi->phy;
+ struct drm_display_mode *mode = &dsi->cur_mode;
+ void __iomem *base = ctx->base;
+ u32 dphy_freq_kHz;
+
+ /* count phy params */
+ dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
+ set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
+
+ /* reset Core */
+ writel(0, base + PWR_UP);
+
+ /* set phy clocks */
+ dsi_mipi_phy_clks(base, phy, dsi->lanes);
+
+ /* set dsi mode */
+ dsi_set_mode_timing(base, phy, mode, dsi->format);
+
+ /* set video mode type and low power */
+ dsi_set_video_mode_type(base, phy, dsi->mode_flags);
+
+ /* DSI and D-PHY Initialization */
+ writel(DSI_VIDEO_MODE, base + MODE_CFG);
+ writel(BIT(0), base + LPCLK_CTRL);
+ writel(BIT(0), base + PWR_UP);
+
+ DRM_INFO("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n",
+ dsi->lanes, mode->clock, phy->lane_byte_clk_kHz);
+}
+
+static void dsi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+ struct dsi_hw_ctx *ctx = dsi->ctx;
+ void __iomem *base = ctx->base;
+
+ DRM_DEBUG_DRIVER("enter\n");
+ if (!dsi->enable)
+ return;
+
+ writel(0, base + PWR_UP);
+ writel(0, base + LPCLK_CTRL);
+ writel(0, base + PHY_RSTZ);
+ clk_disable_unprepare(ctx->dsi_cfg_clk);
+
+ dsi->enable = false;
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void dsi_encoder_enable(struct drm_encoder *encoder)
+{
+ struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+ struct dsi_hw_ctx *ctx = dsi->ctx;
+ int ret;
+
+ DRM_DEBUG_DRIVER("enter.\n");
+ if (dsi->enable)
+ return;
+
+ /* mipi dphy clock enable */
+ ret = clk_prepare_enable(ctx->dsi_cfg_clk);
+ if (ret) {
+ DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
+ return;
+ }
+
+ dsi_mipi_init(dsi);
+
+ dsi->enable = true;
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void dsi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+
+ DRM_DEBUG_DRIVER("enter.\n");
+ drm_mode_copy(&dsi->cur_mode, adj_mode);
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct drm_display_mode *mode = &crtc_state->mode;
+
+ DRM_DEBUG_DRIVER("enter.\n");
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ DRM_ERROR("not support INTERLACE mode\n");
+ return MODE_NO_INTERLACE;
+ }
+
+ /* pixel clock support range is (1190494208/64, 1190494208)Hz */
+ if (mode->clock < 18602 || mode->clock > 1190494) {
+ DRM_ERROR("mode clock not support\n");
+ return MODE_CLOCK_RANGE;
+ }
+
+ DRM_DEBUG_DRIVER("exit success.\n");
+ return 0;
+}
+
+static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
+ .atomic_check = dsi_encoder_atomic_check,
+ .mode_set = dsi_encoder_mode_set,
+ .enable = dsi_encoder_enable,
+ .disable = dsi_encoder_disable
+};
+
+static const struct drm_encoder_funcs hisi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int hisi_drm_encoder_init(struct drm_device *dev,
+ struct drm_encoder *encoder)
+{
+ int ret;
+
+ encoder->possible_crtcs = 1;
+ ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+ if (ret) {
+ DRM_ERROR("failed to init dsi encoder\n");
+ return ret;
+ }
+
+ drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
+
+ return 0;
+}
+
+static int dsi_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *mdsi)
+{
+ struct hisi_dsi *dsi = host_to_dsi(host);
+
+ if (mdsi->lanes < 1 || mdsi->lanes > 4) {
+ DRM_ERROR("dsi device params invalid\n");
+ return -EINVAL;
+ }
+
+ dsi->lanes = mdsi->lanes;
+ dsi->format = mdsi->format;
+ dsi->mode_flags = mdsi->mode_flags;
+
+ return 0;
+}
+
+static int dsi_host_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *mdsi)
+{
+ /* do nothing */
+ return 0;
+}
+
+static struct mipi_dsi_host_ops dsi_host_ops = {
+ .attach = dsi_host_attach,
+ .detach = dsi_host_detach,
+};
+
+static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
+{
+ struct mipi_dsi_host *host = &dsi->host;
+ int ret;
+
+ host->dev = dev;
+ host->ops = &dsi_host_ops;
+ ret = mipi_dsi_host_register(host);
+ if (ret) {
+ DRM_ERROR("failed to register dsi host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dsi_bridge_init(struct drm_device *dev, struct hisi_dsi *dsi)
+{
+ struct drm_encoder *encoder = &dsi->encoder;
+ struct drm_bridge *bridge = dsi->bridge;
+ int ret;
+
+ /* associate the bridge to dsi encoder */
+ encoder->bridge = bridge;
+ bridge->encoder = encoder;
+
+ ret = drm_bridge_attach(dev, bridge);
+ if (ret) {
+ DRM_ERROR("failed to attach exteranl bridge\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dsi_bind(struct device *dev, struct device *master, void *data)
+{
+ struct dsi_data *ddata = dev_get_drvdata(dev);
+ struct hisi_dsi *dsi = &ddata->dsi;
+ struct drm_device *drm_dev = data;
+ int ret;
+
+ ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
+ if (ret)
+ return ret;
+
+ ret = dsi_host_init(dev, dsi);
+ if (ret)
+ return ret;
+
+ ret = dsi_bridge_init(drm_dev, dsi);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void dsi_unbind(struct device *dev, struct device *master, void *data)
+{
+ /* do nothing */
+}
+
+static const struct component_ops dsi_ops = {
+ .bind = dsi_bind,
+ .unbind = dsi_unbind,
+};
+
+static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
+{
+ struct dsi_hw_ctx *ctx = dsi->ctx;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *endpoint, *bridge_node;
+ struct drm_bridge *bridge;
+ struct resource *res;
+
+ /*
+ * Get the endpoint node. In our case, dsi has one output port
+ * to which the external HDMI bridge is connected.
+ */
+ endpoint = of_graph_get_next_endpoint(np, NULL);
+ if (!endpoint) {
+ DRM_ERROR("no valid endpoint node\n");
+ return -ENODEV;
+ }
+ of_node_put(endpoint);
+
+ bridge_node = of_graph_get_remote_port_parent(endpoint);
+ if (!bridge_node) {
+ DRM_ERROR("no valid bridge node\n");
+ return -ENODEV;
+ }
+ of_node_put(bridge_node);
+
+ bridge = of_drm_find_bridge(bridge_node);
+ if (!bridge) {
+ DRM_INFO("wait for external HDMI bridge driver.\n");
+ return -EPROBE_DEFER;
+ }
+ dsi->bridge = bridge;
+
+ ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
+ if (IS_ERR(ctx->dsi_cfg_clk)) {
+ DRM_ERROR("failed to get dsi plck clock\n");
+ return PTR_ERR(ctx->dsi_cfg_clk);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ctx->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ctx->base)) {
+ DRM_ERROR("failed to remap dsi io region\n");
+ return PTR_ERR(ctx->base);
+ }
+
+ return 0;
+}
+
+static int dsi_probe(struct platform_device *pdev)
+{
+ struct dsi_data *data;
+ struct hisi_dsi *dsi;
+ struct dsi_hw_ctx *ctx;
+ int ret;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ DRM_ERROR("failed to allocate dsi data.\n");
+ return -ENOMEM;
+ }
+ dsi = &data->dsi;
+ ctx = &data->ctx;
+ dsi->ctx = ctx;
+
+ ret = dsi_parse_dt(pdev, dsi);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return component_add(&pdev->dev, &dsi_ops);
+}
+
+static int dsi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dsi_ops);
+
+ return 0;
+}
+
+static const struct of_device_id dsi_of_match[] = {
+ {.compatible = "hisilicon,hi6220-dsi"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, dsi_of_match);
+
+static struct platform_driver dsi_driver = {
+ .probe = dsi_probe,
+ .remove = dsi_remove,
+ .driver = {
+ .name = "hisi-dsi",
+ .owner = THIS_MODULE,
+ .of_match_table = dsi_of_match,
+ },
+};
+
+module_platform_driver(dsi_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
+MODULE_LICENSE("GPL v2");
new file mode 100644
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HISI_DSI_REG_H__
+#define __HISI_DSI_REG_H__
+
+/*
+ * regs
+ */
+#define PWR_UP (0x4) /* Core power-up */
+#define PHY_IF_CFG (0xA4) /* D-PHY interface configuration */
+#define CLKMGR_CFG (0x8) /* the internal clock dividers */
+#define PHY_RSTZ (0xA0) /* D-PHY reset control */
+#define PHY_TST_CTRL0 (0xB4) /* D-PHY test interface control 0 */
+#define PHY_TST_CTRL1 (0xB8) /* D-PHY test interface control 1 */
+#define DPI_VCID (0xC) /* DPI virtual channel id */
+#define DPI_COLOR_CODING (0x10) /* DPI color coding */
+#define DPI_CFG_POL (0x14) /* DPI polarity configuration */
+#define VID_HSA_TIME (0x48) /* Horizontal Sync Active time */
+#define VID_HBP_TIME (0x4C) /* Horizontal Back Porch time */
+#define VID_HLINE_TIME (0x50) /* Line time */
+#define VID_VSA_LINES (0x54) /* Vertical Sync Active period */
+#define VID_VBP_LINES (0x58) /* Vertical Back Porch period */
+#define VID_VFP_LINES (0x5C) /* Vertical Front Porch period */
+#define VID_VACTIVE_LINES (0x60) /* Vertical resolution */
+#define VID_PKT_SIZE (0x3C) /* Video packet size */
+#define VID_MODE_CFG (0x38) /* Video mode configuration */
+#define DPI_LP_CMD_TIM (0x18) /* Low-power command timing config */
+#define PHY_TMR_CFG (0x9C) /* Data lanes timing configuration */
+#define BTA_TO_CNT (0x8C) /* Response timeout definition */
+#define PHY_TMR_LPCLK_CFG (0x98) /* clock lane timing configuration */
+#define CLK_DATA_TMR_CFG (0xCC)
+#define LPCLK_CTRL (0x94) /* Low-power in clock lane */
+#define PCKHDL_CFG (0x2C) /* Packet handler configuration */
+#define EDPI_CMD_SIZE (0x64) /* Size for eDPI packets */
+#define MODE_CFG (0x34) /* Video or Command mode selection */
+#define PHY_STATUS (0xB0) /* D-PHY PPI status interface */
+
+#define PHY_STOP_WAIT_TIME (0x30)
+
+/*
+ * regs relevant enum
+ */
+enum dpi_color_coding {
+ DSI_24BITS_1 = 5,
+};
+
+enum dsi_video_mode_type {
+ DSI_NON_BURST_SYNC_PULSES = 0,
+ DSI_NON_BURST_SYNC_EVENTS,
+ DSI_BURST_SYNC_PULSES_1,
+ DSI_BURST_SYNC_PULSES_2
+};
+
+enum dsi_work_mode {
+ DSI_VIDEO_MODE = 0,
+ DSI_COMMAND_MODE
+};
+
+/*
+ * regs Write/Read functions
+ */
+static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
+{
+ writel(reg, base + PHY_TST_CTRL1);
+ /* reg addr written at first */
+ wmb();
+ writel(0x02, base + PHY_TST_CTRL0);
+ /* cmd1 sent for write */
+ wmb();
+ writel(0x00, base + PHY_TST_CTRL0);
+ /* cmd2 sent for write */
+ wmb();
+ writel(val, base + PHY_TST_CTRL1);
+ /* Then write data */
+ wmb();
+ writel(0x02, base + PHY_TST_CTRL0);
+ /* cmd2 sent for write */
+ wmb();
+ writel(0x00, base + PHY_TST_CTRL0);
+}
+
+#endif /* __HISI_DRM_DSI_H__ */
new file mode 100644
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HISI_DRM_ADE_H__
+#define __HISI_DRM_ADE_H__
+
+int ade_enable_vblank(struct drm_device *dev, unsigned int pipe);
+void ade_disable_vblank(struct drm_device *dev, unsigned int pipe);
+
+#endif
new file mode 100644
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HISI_ADE_REG_H__
+#define __HISI_ADE_REG_H__
+
+/*
+ * ADE Registers Offset
+ */
+#define ADE_CTRL (0x4)
+#define ADE_CTRL1 (0x8C)
+#define ADE_ROT_SRC_CFG (0x10)
+#define ADE_DISP_SRC_CFG (0x18)
+#define ADE_WDMA2_SRC_CFG (0x1C)
+#define ADE_SEC_OVLY_SRC_CFG (0x20)
+#define ADE_WDMA3_SRC_CFG (0x24)
+#define ADE_OVLY1_TRANS_CFG (0x2C)
+#define ADE_EN (0x100)
+#define INTR_MASK_CPU_0 (0xC10)
+#define INTR_MASK_CPU_1 (0xC14)
+#define ADE_FRM_DISGARD_CTRL (0xA4)
+/* reset and reload regs */
+#define ADE_SOFT_RST_SEL0 (0x78)
+#define ADE_SOFT_RST_SEL1 (0x7C)
+#define ADE_RELOAD_DIS0 (0xAC)
+#define ADE_RELOAD_DIS1 (0xB0)
+#define ADE_CH_RDMA_BIT_OFST (0)
+#define ADE_CLIP_BIT_OFST (15)
+#define ADE_SCL_BIT_OFST (21)
+#define ADE_CTRAN_BIT_OFST (24)
+#define ADE_OVLY_BIT_OFST (37) /* 32+5 */
+/* channel regs */
+#define RD_CH_PE(x) (0x1000 + (x) * 0x80)
+#define RD_CH_CTRL(x) (0x1004 + (x) * 0x80)
+#define RD_CH_ADDR(x) (0x1008 + (x) * 0x80)
+#define RD_CH_SIZE(x) (0x100C + (x) * 0x80)
+#define RD_CH_STRIDE(x) (0x1010 + (x) * 0x80)
+#define RD_CH_SPACE(x) (0x1014 + (x) * 0x80)
+#define RD_CH_PARTIAL_SIZE(x) (0x1018 + (x) * 0x80)
+#define RD_CH_PARTIAL_SPACE(x) (0x101C + (x) * 0x80)
+#define RD_CH_EN(x) (0x1020 + (x) * 0x80)
+#define RD_CH_STATUS(x) (0x1024 + (x) * 0x80)
+#define RD_CH_DISP_CTRL (0x1404)
+#define RD_CH_DISP_ADDR (0x1408)
+#define RD_CH_DISP_SIZE (0x140C)
+#define RD_CH_DISP_STRIDE (0x1410)
+#define RD_CH_DISP_SPACE (0x1414)
+#define RD_CH_DISP_EN (0x142C)
+/* clip regs */
+#define ADE_CLIP_DISABLE(x) (0x6800 + (x) * 0x100)
+#define ADE_CLIP_SIZE0(x) (0x6804 + (x) * 0x100)
+#define ADE_CLIP_SIZE1(x) (0x6808 + (x) * 0x100)
+#define ADE_CLIP_SIZE2(x) (0x680C + (x) * 0x100)
+#define ADE_CLIP_CFG_OK(x) (0x6810 + (x) * 0x100)
+/* scale regs */
+#define ADE_SCL1_MUX_CFG (0xC)
+#define ADE_SCL2_SRC_CFG (0x14)
+#define ADE_SCL3_MUX_CFG (0x8)
+#define ADE_SCL_CTRL(x) (0x3000 + (x) * 0x800)
+#define ADE_SCL_HSP(x) (0x3004 + (x) * 0x800)
+#define ADE_SCL_UV_HSP(x) (0x3008 + (x) * 0x800)
+#define ADE_SCL_VSP(x) (0x300C + (x) * 0x800)
+#define ADE_SCL_UV_VSP(x) (0x3010 + (x) * 0x800)
+#define ADE_SCL_ORES(x) (0x3014 + (x) * 0x800)
+#define ADE_SCL_IRES(x) (0x3018 + (x) * 0x800)
+#define ADE_SCL_START(x) (0x301C + (x) * 0x800)
+#define ADE_SCL_ERR(x) (0x3020 + (x) * 0x800)
+#define ADE_SCL_PIX_OFST(x) (0x3024 + (x) * 0x800)
+#define ADE_SCL_UV_PIX_OFST(x) (0x3028 + (x) * 0x800)
+#define ADE_SCL_COEF_CLR(x) (0x3030 + (x) * 0x800)
+#define ADE_SCL_HCOEF(x, m, n) (0x3100 + (x) * 0x800 + \
+ 12 * (m) + 4 * (n))
+#define ADE_SCL_VCOEF(x, i, j) (0x340C + (x) * 0x800 + \
+ 12 * (i) + 4 * (j))
+/* ctran regs */
+#define ADE_CTRAN5_TRANS_CFG (0x40)
+#define ADE_CTRAN_DIS(x) (0x5004 + (x) * 0x100)
+#define ADE_CTRAN_MODE_CHOOSE(x) (0x5008 + (x) * 0x100)
+#define ADE_CTRAN_STAT(x) (0x500C + (x) * 0x100)
+#define ADE_CTRAN_CHDC0(x) (0x5010 + (x) * 0x100)
+#define ADE_CTRAN_CHDC1(x) (0x5014 + (x) * 0x100)
+#define ADE_CTRAN_CHDC2(x) (0x5018 + (x) * 0x100)
+#define ADE_CTRAN_CHDC3(x) (0x501C + (x) * 0x100)
+#define ADE_CTRAN_CHDC4(x) (0x5020 + (x) * 0x100)
+#define ADE_CTRAN_CHDC5(x) (0x5024 + (x) * 0x100)
+#define ADE_CTRAN_CSC0(x) (0x5028 + (x) * 0x100)
+#define ADE_CTRAN_CSC1(x) (0x502C + (x) * 0x100)
+#define ADE_CTRAN_CSC2(x) (0x5030 + (x) * 0x100)
+#define ADE_CTRAN_CSC3(x) (0x5034 + (x) * 0x100)
+#define ADE_CTRAN_CSC4(x) (0x5038 + (x) * 0x100)
+#define ADE_CTRAN_IMAGE_SIZE(x) (0x503C + (x) * 0x100)
+#define ADE_CTRAN_CFG_OK(x) (0x5040 + (x) * 0x100)
+/* overlay regs */
+#define ADE_OVLY_ALPHA_ST (0x2000)
+#define ADE_OVLY_CH_XY0(x) (0x2004 + (x) * 4)
+#define ADE_OVLY_CH_XY1(x) (0x2024 + (x) * 4)
+#define ADE_OVLY_CH_CTL(x) (0x204C + (x) * 4)
+#define ADE_OVLY_OUTPUT_SIZE(x) (0x2070 + (x) * 8)
+#define ADE_OVLY_BASE_COLOR(x) (0x2074 + (x) * 8)
+#define ADE_OVLYX_CTL(x) (0x209C + (x) * 4)
+#define ADE_OVLY_CTL (0x98)
+#define ADE_OVLY_CH_ALP_MODE_OFST (0)
+#define ADE_OVLY_CH_ALP_SEL_OFST (2)
+#define ADE_OVLY_CH_UNDER_ALP_SEL_OFST (4)
+#define ADE_OVLY_CH_EN_OFST (6)
+#define ADE_OVLY_CH_ALP_GBL_OFST (15)
+#define ADE_OVLY_CH_SEL_OFST (28)
+
+/*
+ * media regs
+ */
+#define SC_MEDIA_RSTDIS (0x530)
+#define SC_MEDIA_RSTEN (0x52C)
+#define NOC_ADE0_QOSGENERATOR_MODE 0x010C
+#define NOC_ADE0_QOSGENERATOR_EXTCONTROL 0x0118
+#define NOC_ADE1_QOSGENERATOR_MODE 0x020C
+#define NOC_ADE1_QOSGENERATOR_EXTCONTROL 0x0218
+
+/*
+ * regs relevant enum
+ */
+enum {
+ LDI_TEST = 0,
+ LDI_WORK
+};
+
+enum {
+ LDI_ISR_FRAME_END_INT = 0x2,
+ LDI_ISR_UNDER_FLOW_INT = 0x4
+};
+
+enum {
+ ADE_ISR1_RES_SWITCH_CMPL = 0x80000000
+};
+
+enum {
+ LDI_DISP_MODE_NOT_3D_FBF = 0,
+ LDI_DISP_MODE_3D_FBF
+};
+
+enum {
+ ADE_RGB = 0,
+ ADE_BGR
+};
+
+enum {
+ ADE_DISABLE = 0,
+ ADE_ENABLE
+};
+
+enum {
+ ADE_OUT_RGB_565 = 0,
+ ADE_OUT_RGB_666,
+ ADE_OUT_RGB_888
+};
+
+/*
+ * ADE read as big-endian, so revert the
+ * rgb order described in the SoC datasheet
+ */
+enum ADE_FORMAT {
+ ADE_RGB_565 = 0,
+ ADE_BGR_565,
+ ADE_XRGB_8888,
+ ADE_XBGR_8888,
+ ADE_ARGB_8888,
+ ADE_ABGR_8888,
+ ADE_RGBA_8888,
+ ADE_BGRA_8888,
+ ADE_RGB_888,
+ ADE_BGR_888 = 9,
+ ADE_FORMAT_NOT_SUPPORT = 800
+};
+
+/* ldi src cfg */
+enum {
+ TOP_DISP_SRC_NONE = 0,
+ TOP_DISP_SRC_OVLY2,
+ TOP_DISP_SRC_DISP,
+ TOP_DISP_SRC_ROT,
+ TOP_DISP_SRC_SCL2
+};
+
+enum {
+ ADE_ISR_DMA_ERROR = 0x2000000
+};
+
+enum ade_channel {
+ ADE_CH1 = 0, /* channel 1 for primary plane */
+ ADE_CH_NUM
+};
+
+enum ade_scale {
+ ADE_SCL1 = 0,
+ ADE_SCL2,
+ ADE_SCL3,
+ ADE_SCL_NUM
+};
+
+enum ade_ctran {
+ ADE_CTRAN1 = 0,
+ ADE_CTRAN2,
+ ADE_CTRAN3,
+ ADE_CTRAN4,
+ ADE_CTRAN5,
+ ADE_CTRAN6,
+ ADE_CTRAN_NUM
+};
+
+enum ade_overlay {
+ ADE_OVLY1 = 0,
+ ADE_OVLY2,
+ ADE_OVLY3,
+ ADE_OVLY_NUM
+};
+
+enum {
+ ADE_ALP_GLOBAL = 0,
+ ADE_ALP_PIXEL,
+ ADE_ALP_PIXEL_AND_GLB
+};
+
+enum {
+ ADE_ALP_MUL_COEFF_0 = 0, /* alpha */
+ ADE_ALP_MUL_COEFF_1, /* 1-alpha */
+ ADE_ALP_MUL_COEFF_2, /* 0 */
+ ADE_ALP_MUL_COEFF_3 /* 1 */
+};
+
+/*
+ * ADE Register Union Struct
+ */
+union U_ADE_CTRL1 {
+struct {
+ unsigned int auto_clk_gate_en :1;
+ unsigned int rot_buf_shr_out :1;
+ unsigned int reserved_44 :30;
+ } bits;
+ unsigned int u32;
+};
+
+union U_ADE_SOFT_RST_SEL0 {
+struct {
+ unsigned int ch1_rdma_srst_sel :1;
+ unsigned int ch2_rdma_srst_sel :1;
+ unsigned int ch3_rdma_srst_sel :1;
+ unsigned int ch4_rdma_srst_sel :1;
+ unsigned int ch5_rdma_srst_sel :1;
+ unsigned int ch6_rdma_srst_sel :1;
+ unsigned int disp_rdma_srst_sel :1;
+ unsigned int cmdq1_rdma_srst_sel :1;
+ unsigned int cmdq2_rdma_srst_sel :1;
+ unsigned int reserved_29 :1;
+ unsigned int ch1_wdma_srst_sel :1;
+ unsigned int ch2_wdma_srst_sel :1;
+ unsigned int ch3_wdma_srst_sel :1;
+ unsigned int reserved_28 :1;
+ unsigned int cmdq_wdma_srst_sel :1;
+ unsigned int clip1_srst_sel :1;
+ unsigned int clip2_srst_sel :1;
+ unsigned int clip3_srst_sel :1;
+ unsigned int clip4_srst_sel :1;
+ unsigned int clip5_srst_sel :1;
+ unsigned int clip6_srst_sel :1;
+ unsigned int scl1_srst_sel :1;
+ unsigned int scl2_srst_sel :1;
+ unsigned int scl3_srst_sel :1;
+ unsigned int ctran1_srst_sel :1;
+ unsigned int ctran2_srst_sel :1;
+ unsigned int ctran3_srst_sel :1;
+ unsigned int ctran4_srst_sel :1;
+ unsigned int ctran5_srst_sel :1;
+ unsigned int ctran6_srst_sel :1;
+ unsigned int rot_srst_sel :1;
+ unsigned int reserved_27 :1;
+ } bits;
+ unsigned int u32;
+};
+
+union U_ADE_CTRL {
+struct {
+ unsigned int frm_end_start :2;
+ unsigned int dfs_buf_cfg :1;
+ unsigned int rot_buf_cfg :3;
+ unsigned int rd_ch5_nv :1;
+ unsigned int rd_ch6_nv :1;
+ unsigned int dfs_buf_unflow_lev1 :13;
+ unsigned int dfs_buf_unflow_lev2 :11;
+ } bits;
+ unsigned int u32;
+};
+
+/*
+ * ADE Register Write/Read functions
+ */
+static inline void set_TOP_CTL_clk_gate_en(u8 *base, u32 val)
+{
+ union U_ADE_CTRL1 ade_ctrl1;
+ u8 *reg_addr = base + ADE_CTRL1;
+
+ ade_ctrl1.u32 = readl(reg_addr);
+ ade_ctrl1.bits.auto_clk_gate_en = val;
+ writel(ade_ctrl1.u32, reg_addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_disp_rdma(u8 *base, u32 val)
+{
+ union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+ u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+ ade_soft_rst.u32 = readl(addr);
+ ade_soft_rst.bits.disp_rdma_srst_sel = val;
+ writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_ctran5(u8 *base, u32 val)
+{
+ union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+ u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+ ade_soft_rst.u32 = readl(addr);
+ ade_soft_rst.bits.ctran5_srst_sel = val;
+ writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_ctran6(u8 *base, u32 val)
+{
+ union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+ u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+ ade_soft_rst.u32 = readl(addr);
+ ade_soft_rst.bits.ctran6_srst_sel = val;
+ writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_CTL_frm_end_start(u8 *base, u32 val)
+{
+ union U_ADE_CTRL ade_ctrl;
+ u8 *reg_addr = base + ADE_CTRL;
+
+ ade_ctrl.u32 = readl(reg_addr);
+ ade_ctrl.bits.frm_end_start = val;
+ writel(ade_ctrl.u32, reg_addr);
+}
+
+/*
+ * LDI Registers Offset
+ */
+#define LDI_HRZ_CTRL0 (0x7400)
+#define LDI_HRZ_CTRL1 (0x7404)
+#define LDI_VRT_CTRL0 (0x7408)
+#define LDI_VRT_CTRL1 (0x740C)
+#define LDI_PLR_CTRL (0x7410)
+#define LDI_DSP_SIZE (0x7414)
+#define LDI_INT_EN (0x741C)
+#define LDI_CTRL (0x7420)
+#define LDI_ORG_INT (0x7424)
+#define LDI_MSK_INT (0x7428)
+#define LDI_INT_CLR (0x742C)
+#define LDI_WORK_MODE (0x7430)
+#define LDI_DE_SPACE_LOW (0x7438)
+#define LDI_MCU_INTS (0x7450)
+#define LDI_MCU_INTE (0x7454)
+#define LDI_MCU_INTC (0x7458)
+#define LDI_HDMI_DSI_GT (0x7434)
+
+/*
+ * LDI Timing Polarity defines
+ */
+#define HISI_LDI_FLAG_NVSYNC BIT(0)
+#define HISI_LDI_FLAG_NHSYNC BIT(1)
+#define HISI_LDI_FLAG_NPIXCLK BIT(2)
+#define HISI_LDI_FLAG_NDE BIT(3)
+
+/*
+ * LDI Register Union Struct
+ */
+union U_LDI_CTRL {
+struct {
+ unsigned int ldi_en :1;
+ unsigned int disp_mode_buf :1;
+ unsigned int date_gate_en :1;
+ unsigned int bpp :2;
+ unsigned int wait_vsync_en :1;
+ unsigned int corlorbar_width :7;
+ unsigned int bgr :1;
+ unsigned int color_mode :1;
+ unsigned int shutdown :1;
+ unsigned int vactive_line :12;
+ unsigned int ldi_en_self_clr :1;
+ unsigned int reserved_573 :3;
+ } bits;
+ unsigned int u32;
+};
+
+union U_LDI_WORK_MODE {
+struct {
+ unsigned int work_mode :1;
+ unsigned int wback_en :1;
+ unsigned int colorbar_en :1;
+ unsigned int reserved_577 :29;
+ } bits;
+ unsigned int u32;
+};
+
+/*
+ * LDI Register Write/Read Helper functions
+ */
+static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs)
+{
+ u32 mask = (1 << bw) - 1;
+ u32 tmp = readl(addr);
+
+ tmp &= ~(mask << bs);
+ writel(tmp | ((val & mask) << bs), addr);
+}
+
+static inline void set_LDI_CTRL_ldi_en(u8 *base, u32 val)
+{
+ union U_LDI_CTRL ldi_ctrl;
+ u8 *addr = base + LDI_CTRL;
+
+ ldi_ctrl.u32 = readl(addr);
+ ldi_ctrl.bits.ldi_en = val;
+ writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_disp_mode(u8 *base, u32 val)
+{
+ union U_LDI_CTRL ldi_ctrl;
+ u8 *addr = base + LDI_CTRL;
+
+ ldi_ctrl.u32 = readl(addr);
+ ldi_ctrl.bits.disp_mode_buf = val;
+ writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_bpp(u8 *base, u32 val)
+{
+ union U_LDI_CTRL ldi_ctrl;
+ u8 *addr = base + LDI_CTRL;
+
+ ldi_ctrl.u32 = readl(addr);
+ ldi_ctrl.bits.bpp = val;
+ writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_corlorbar_width(u8 *base, u32 val)
+{
+ union U_LDI_CTRL ldi_ctrl;
+ u8 *addr = base + LDI_CTRL;
+
+ ldi_ctrl.u32 = readl(addr);
+ ldi_ctrl.bits.corlorbar_width = (val > 0) ? val - 1 : 0;
+ writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_bgr(u8 *base, u32 val)
+{
+ union U_LDI_CTRL ldi_ctrl;
+ u8 *addr = base + LDI_CTRL;
+
+ ldi_ctrl.u32 = readl(addr);
+ ldi_ctrl.bits.bgr = val;
+ writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_WORK_MODE_work_mode(u8 *base, u32 val)
+{
+ union U_LDI_WORK_MODE ldi_work_mode;
+ u8 *addr = base + LDI_WORK_MODE;
+
+ ldi_work_mode.u32 = readl(addr);
+ ldi_work_mode.bits.work_mode = val;
+ writel(ldi_work_mode.u32, addr);
+}
+
+static inline void set_LDI_WORK_MODE_colorbar_en(u8 *base, u32 val)
+{
+ union U_LDI_WORK_MODE ldi_work_mode;
+ u8 *addr = base + LDI_WORK_MODE;
+
+ ldi_work_mode.u32 = readl(addr);
+ ldi_work_mode.bits.colorbar_en = val;
+ writel(ldi_work_mode.u32, addr);
+}
+
+#endif
new file mode 100644
@@ -0,0 +1,1100 @@
+/*
+ * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ * Xinliang Liu <xinliang.liu@linaro.org>
+ * Xinliang Liu <z.liuxinliang@hisilicon.com>
+ * Xinwei Kong <kong.kongxinwei@hisilicon.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <video/display_timing.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "kirin_drm_drv.h"
+#include "kirin_ade_reg.h"
+
+#define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
+#define PRIMARY_CH (ADE_CH1)
+
+#define to_ade_crtc(crtc) \
+ container_of(crtc, struct ade_crtc, base)
+
+#define to_ade_plane(plane) \
+ container_of(plane, struct ade_plane, base)
+
+struct ade_hw_ctx {
+ void __iomem *base;
+ void __iomem *media_base;
+ void __iomem *media_noc_base;
+
+ int irq;
+ u32 ade_core_rate;
+ u32 media_noc_rate;
+
+ struct clk *ade_core_clk;
+ struct clk *media_noc_clk;
+ struct clk *ade_pix_clk;
+ bool power_on;
+};
+
+struct ade_crtc {
+ struct drm_crtc base;
+ struct ade_hw_ctx *ctx;
+ bool enable;
+ u64 use_mask;
+};
+
+struct ade_plane {
+ struct drm_plane base;
+ void *ctx;
+ u8 ch; /* channel */
+};
+
+struct ade_data {
+ struct ade_crtc acrtc;
+ struct ade_plane aplane[ADE_CH_NUM];
+ struct ade_hw_ctx ctx;
+};
+
+/* ade-format info: */
+struct ade_format {
+ u32 pixel_format;
+ enum ADE_FORMAT ade_format;
+};
+
+static const struct ade_format ade_formats[] = {
+ /* 16bpp RGB: */
+ { DRM_FORMAT_RGB565, ADE_RGB_565 },
+ { DRM_FORMAT_BGR565, ADE_BGR_565 },
+ /* 24bpp RGB: */
+ { DRM_FORMAT_RGB888, ADE_RGB_888 },
+ { DRM_FORMAT_BGR888, ADE_BGR_888 },
+ /* 32bpp [A]RGB: */
+ { DRM_FORMAT_XRGB8888, ADE_XRGB_8888 },
+ { DRM_FORMAT_XBGR8888, ADE_XBGR_8888 },
+ { DRM_FORMAT_RGBA8888, ADE_RGBA_8888 },
+ { DRM_FORMAT_BGRA8888, ADE_BGRA_8888 },
+ { DRM_FORMAT_ARGB8888, ADE_ARGB_8888 },
+ { DRM_FORMAT_ABGR8888, ADE_ABGR_8888 },
+};
+
+static const u32 channel_formats1[] = {
+ /* channel 1,2,3,4 */
+ DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
+ DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_ABGR8888
+};
+
+u32 ade_get_channel_formats(u8 ch, const u32 **formats)
+{
+ switch (ch) {
+ case ADE_CH1:
+ *formats = channel_formats1;
+ return ARRAY_SIZE(channel_formats1);
+ default:
+ DRM_ERROR("no this channel %d\n", ch);
+ *formats = NULL;
+ return 0;
+ }
+}
+
+/* convert from fourcc format to ade format */
+static u32 ade_get_format(u32 pixel_format)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ade_formats); i++)
+ if (ade_formats[i].pixel_format == pixel_format)
+ return ade_formats[i].ade_format;
+
+ /* not found */
+ DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", pixel_format);
+ return ADE_FORMAT_NOT_SUPPORT;
+}
+
+static void ade_init(struct ade_hw_ctx *ctx)
+{
+ void __iomem *base = ctx->base;
+
+ /* enable clk gate */
+ set_TOP_CTL_clk_gate_en(base, 1);
+ /* clear overlay */
+ writel(0, base + ADE_OVLY1_TRANS_CFG);
+ writel(0, base + ADE_OVLY_CTL);
+ writel(0, base + ADE_OVLYX_CTL(ADE_OVLY2));
+ /* clear reset and reload regs */
+ writel(0, base + ADE_SOFT_RST_SEL0);
+ writel(0, base + ADE_SOFT_RST_SEL1);
+ writel(0xFFFFFFFF, base + ADE_RELOAD_DIS0);
+ writel(0xFFFFFFFF, base + ADE_RELOAD_DIS1);
+ /* for video set to 1, means that ade registers
+ * became effective at frame end
+ */
+ set_TOP_CTL_frm_end_start(base, 1);
+}
+
+static void ade_ldi_set_mode(struct ade_crtc *acrtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+ u32 out_w = mode->hdisplay;
+ u32 out_h = mode->vdisplay;
+ u32 hfp, hbp, hsw, vfp, vbp, vsw;
+ u32 plr_flags;
+ int ret;
+
+ plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ ? HISI_LDI_FLAG_NVSYNC : 0;
+ plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ ? HISI_LDI_FLAG_NHSYNC : 0;
+ hfp = mode->hsync_start - mode->hdisplay;
+ hbp = mode->htotal - mode->hsync_end;
+ hsw = mode->hsync_end - mode->hsync_start;
+ vfp = mode->vsync_start - mode->vdisplay;
+ vbp = mode->vtotal - mode->vsync_end;
+ vsw = mode->vsync_end - mode->vsync_start;
+ if (vsw > 15) {
+ DRM_INFO("vsw exceeded 15\n");
+ vsw = 15;
+ }
+
+ writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
+ /* p3-73 6220V100 pdf:
+ * "The configured value is the actual width - 1"
+ */
+ writel(hsw - 1, base + LDI_HRZ_CTRL1);
+ writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
+ /* p3-74 6220V100 pdf:
+ * "The configured value is the actual width - 1"
+ */
+ writel(vsw - 1, base + LDI_VRT_CTRL1);
+
+ /* p3-75 6220V100 pdf:
+ * "The configured value is the actual width - 1"
+ */
+ writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
+ base + LDI_DSP_SIZE);
+ writel(plr_flags, base + LDI_PLR_CTRL);
+
+ ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
+ /* Success should be guaranteed in aotomic_check
+ * failer shouldn't happen here
+ */
+ if (ret)
+ DRM_ERROR("set ade_pixel_clk_rate fail\n");
+ adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
+
+ /* ctran6 setting */
+ writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
+ writel(out_w * out_h - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
+ acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
+ DRM_INFO("set mode: %dx%d\n", out_w, out_h);
+
+ /*
+ * other parameters setting
+ */
+ writel(BIT(0), base + LDI_WORK_MODE);
+ writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
+ base + LDI_CTRL);
+ set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
+}
+
+static int ade_power_up(struct ade_hw_ctx *ctx)
+{
+ void __iomem *media_base = ctx->media_base;
+ int ret;
+
+ ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
+ if (ret) {
+ DRM_ERROR("clk_set_rate ade_core_rate error\n");
+ return ret;
+ }
+ ret = clk_set_rate(ctx->media_noc_clk, ctx->media_noc_rate);
+ if (ret) {
+ DRM_ERROR("media_noc_clk media_noc_rate error\n");
+ return ret;
+ }
+ ret = clk_prepare_enable(ctx->media_noc_clk);
+ if (ret) {
+ DRM_ERROR("fail to clk_prepare_enable media_noc_clk\n");
+ return ret;
+ }
+
+ writel(0x20, media_base + SC_MEDIA_RSTDIS);
+
+ ret = clk_prepare_enable(ctx->ade_core_clk);
+ if (ret) {
+ DRM_ERROR("fail to clk_prepare_enable ade_core_clk\n");
+ return ret;
+ }
+
+ ade_init(ctx);
+ ctx->power_on = true;
+ return 0;
+}
+
+static void ade_power_down(struct ade_hw_ctx *ctx)
+{
+ void __iomem *base = ctx->base;
+ void __iomem *media_base = ctx->media_base;
+
+ set_LDI_CTRL_ldi_en(base, ADE_DISABLE);
+ /* dsi pixel off */
+ set_reg(base + LDI_HDMI_DSI_GT, 0x1, 1, 0);
+
+ clk_disable_unprepare(ctx->ade_core_clk);
+ writel(0x20, media_base + SC_MEDIA_RSTEN);
+ clk_disable_unprepare(ctx->media_noc_clk);
+ ctx->power_on = false;
+}
+
+static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
+ unsigned int index)
+{
+ unsigned int index_tmp = 0;
+ struct drm_crtc *crtc;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ if (index_tmp == index)
+ return crtc;
+
+ index_tmp++;
+ }
+
+ WARN_ON(true);
+ return NULL;
+}
+
+int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+ struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
+ struct ade_crtc *acrtc = to_ade_crtc(crtc);
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+ u32 intr_en;
+
+ DRM_INFO("enable_vblank enter.\n");
+ if (!ctx->power_on)
+ (void)ade_power_up(ctx);
+
+ intr_en = readl(base + LDI_INT_EN);
+ intr_en |= LDI_ISR_FRAME_END_INT;
+ writel(intr_en, base + LDI_INT_EN);
+
+ return 0;
+}
+
+void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+ struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
+ struct ade_crtc *acrtc = to_ade_crtc(crtc);
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+ u32 intr_en;
+
+ DRM_INFO("disable_vblank enter.\n");
+ if (!ctx->power_on) {
+ DRM_ERROR("power is down! vblank disable fail\n");
+ return;
+ }
+ intr_en = readl(base + LDI_INT_EN);
+ intr_en &= ~LDI_ISR_FRAME_END_INT;
+ writel(intr_en, base + LDI_INT_EN);
+}
+
+static irqreturn_t ade_irq_handler(int irq, void *data)
+{
+ struct ade_crtc *acrtc = data;
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ struct drm_crtc *crtc = &acrtc->base;
+ struct drm_device *dev = crtc->dev;
+ void __iomem *base = ctx->base;
+ u32 status;
+
+ status = readl(base + LDI_MSK_INT);
+ /* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
+
+ /* vblank irq */
+ if (status & LDI_ISR_FRAME_END_INT) {
+ writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
+ drm_handle_vblank(dev, drm_crtc_index(crtc));
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * set modules' reset mode: by software or hardware
+ * set modules' reload enable/disable
+ */
+static void ade_set_reset_and_reload(struct ade_crtc *acrtc)
+{
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+ u32 mask0 = (u32)acrtc->use_mask;
+ u32 mask1 = (u32)(acrtc->use_mask >> 32);
+
+ DRM_DEBUG_DRIVER("mask=0x%llX, mask0=0x%X, mask1=0x%X\n",
+ acrtc->use_mask, mask0, mask1);
+
+ writel(mask0, base + ADE_SOFT_RST_SEL0);
+ writel(mask1, base + ADE_SOFT_RST_SEL1);
+ writel(~mask0, base + ADE_RELOAD_DIS0);
+ writel(~mask1, base + ADE_RELOAD_DIS1);
+}
+
+void ade_set_medianoc_qos(struct ade_crtc *acrtc)
+{
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->media_noc_base;
+ void __iomem *reg;
+ u32 val;
+
+ reg = base + NOC_ADE0_QOSGENERATOR_MODE;
+ val = (readl(reg) & 0xfffffffc) | 0x2;
+ writel(val, reg);
+
+ reg = base + NOC_ADE0_QOSGENERATOR_EXTCONTROL;
+ val = readl(reg) | 0x1;
+ writel(val, reg);
+
+ reg = base + NOC_ADE1_QOSGENERATOR_MODE;
+ val = (readl(reg) & 0xfffffffc) | 0x2;
+ writel(val, reg);
+
+ reg = base + NOC_ADE1_QOSGENERATOR_EXTCONTROL;
+ val = readl(reg) | 0x1;
+ writel(val, reg);
+}
+
+/*
+ * commit to ldi to display
+ */
+static void ade_display_commit(struct ade_crtc *acrtc)
+{
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+
+ /* TODO: set rotator after overlay */
+
+ /* TODO: set scale after overlay */
+
+ /* display source setting */
+ writel(TOP_DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
+
+ /* set reset mode:soft or hw, and reload modules */
+ ade_set_reset_and_reload(acrtc);
+
+ DRM_INFO("ADE GO\n");
+ /* enable ade */
+ wmb();
+ writel(ADE_ENABLE, base + ADE_EN);
+ /* enable ldi */
+ wmb();
+ set_LDI_CTRL_ldi_en(base, ADE_ENABLE);
+ /* dsi pixel on */
+ set_reg(base + LDI_HDMI_DSI_GT, 0x0, 1, 0);
+}
+
+static void ade_crtc_enable(struct drm_crtc *crtc)
+{
+ struct ade_crtc *acrtc = to_ade_crtc(crtc);
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ int ret;
+
+ DRM_DEBUG_DRIVER("enter.\n");
+ if (acrtc->enable)
+ return;
+
+ if (!ctx->power_on) {
+ ret = ade_power_up(ctx);
+ if (ret) {
+ DRM_ERROR("failed to initialize ade clk\n");
+ return;
+ }
+ }
+
+ ade_set_medianoc_qos(acrtc);
+ ade_display_commit(acrtc);
+ acrtc->enable = true;
+
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_disable(struct drm_crtc *crtc)
+{
+ struct ade_crtc *acrtc = to_ade_crtc(crtc);
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+
+ DRM_DEBUG_DRIVER("enter.\n");
+
+ if (!acrtc->enable)
+ return;
+
+ ade_power_down(ctx);
+ acrtc->use_mask = 0;
+ acrtc->enable = false;
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+int ade_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
+{
+ DRM_DEBUG_DRIVER("enter.\n");
+ DRM_DEBUG_DRIVER("exit success.\n");
+ /* do nothing */
+ return 0;
+}
+
+static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+ struct ade_crtc *acrtc = to_ade_crtc(crtc);
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ struct drm_display_mode *mode = &crtc->state->mode;
+ struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
+
+ DRM_DEBUG_DRIVER("enter.\n");
+ if (!ctx->power_on)
+ (void)ade_power_up(ctx);
+ ade_ldi_set_mode(acrtc, mode, adj_mode);
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct ade_crtc *acrtc = to_ade_crtc(crtc);
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+
+ DRM_DEBUG_DRIVER("enter.\n");
+ if (!ctx->power_on)
+ (void)ade_power_up(ctx);
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+
+{
+ struct ade_crtc *acrtc = to_ade_crtc(crtc);
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+
+ DRM_DEBUG_DRIVER("enter.\n");
+ /* commit to display: LDI input setting */
+ if (acrtc->enable) {
+ /* set reset and reload */
+ ade_set_reset_and_reload(acrtc);
+ /* flush ade regitsters */
+ wmb();
+ writel(ADE_ENABLE, base + ADE_EN);
+ }
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
+ .enable = ade_crtc_enable,
+ .disable = ade_crtc_disable,
+ .atomic_check = ade_crtc_atomic_check,
+ .mode_set_nofb = ade_crtc_mode_set_nofb,
+ .atomic_begin = ade_crtc_atomic_begin,
+ .atomic_flush = ade_crtc_atomic_flush,
+};
+
+static const struct drm_crtc_funcs ade_crtc_funcs = {
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = drm_atomic_helper_crtc_reset,
+ .set_property = drm_atomic_helper_crtc_set_property,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+ struct drm_plane *plane)
+{
+ int ret;
+
+ ret = drm_crtc_init_with_planes(dev, crtc, plane,
+ NULL, &ade_crtc_funcs);
+ if (ret) {
+ DRM_ERROR("failed to init crtc.\n");
+ return ret;
+ }
+
+ drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
+
+ return 0;
+}
+
+static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
+ u32 ch, u32 y, u32 in_h, u32 fmt)
+{
+ u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
+ struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+ u32 stride = fb->pitches[0];
+ u32 addr = (u32)obj->paddr + y * stride;
+
+ DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x, \
+ addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
+ ch + 1, y, in_h, stride, (u32)obj->paddr,
+ addr, fb->width, fb->height,
+ fmt, drm_get_format_name(fb->pixel_format));
+
+ /* get reg offset */
+ reg_ctrl = RD_CH_CTRL(ch);
+ reg_addr = RD_CH_ADDR(ch);
+ reg_size = RD_CH_SIZE(ch);
+ reg_stride = RD_CH_STRIDE(ch);
+ reg_space = RD_CH_SPACE(ch);
+ reg_en = RD_CH_EN(ch);
+
+ /*
+ * TODO: set rotation
+ */
+ writel((fmt << 16) & 0x1f0000, base + reg_ctrl);
+ writel(addr, base + reg_addr);
+ writel((in_h << 16) | stride, base + reg_size);
+ writel(stride, base + reg_stride);
+ writel(in_h * stride, base + reg_space);
+ writel(1, base + reg_en);
+
+ acrtc->use_mask |= BIT(ADE_CH_RDMA_BIT_OFST + ch);
+}
+
+static void ade_rdma_disable(struct ade_crtc *acrtc, u32 ch)
+{
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+ u32 reg_en;
+
+ /* get reg offset */
+ reg_en = RD_CH_EN(ch);
+
+ writel(0, base + reg_en);
+ acrtc->use_mask &= ~BIT(ADE_CH_RDMA_BIT_OFST + ch);
+}
+
+static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
+ u32 in_w, u32 in_h)
+{
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+ u32 disable_val;
+ u32 clip_left;
+ u32 clip_right;
+
+ /*
+ * clip width, no need to clip height
+ */
+ if (fb_w == in_w) { /* bypass */
+ disable_val = 1;
+ clip_left = 0;
+ clip_right = 0;
+ } else {
+ disable_val = 0;
+ clip_left = x;
+ clip_right = fb_w - (x + in_w) - 1;
+ }
+
+ DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n",
+ ch + 1, clip_left, clip_right);
+
+ writel(disable_val, base + ADE_CLIP_DISABLE(ch));
+ writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch));
+ writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch));
+
+ acrtc->use_mask |= BIT(ADE_CLIP_BIT_OFST + ch);
+}
+
+static void ade_clip_disable(struct ade_crtc *acrtc, u32 ch)
+{
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+
+ writel(1, base + ADE_CLIP_DISABLE(ch));
+ acrtc->use_mask &= ~BIT(ADE_CLIP_BIT_OFST + ch);
+}
+
+static bool has_Alpha_channel(int format)
+{
+ switch (format) {
+ case ADE_ARGB_8888:
+ case ADE_ABGR_8888:
+ case ADE_RGBA_8888:
+ case ADE_BGRA_8888:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
+ u8 *alp_sel, u8 *under_alp_sel)
+{
+ bool has_alpha = has_Alpha_channel(fmt);
+
+ /*
+ * get alp_mode
+ */
+ if (has_alpha && glb_alpha < 255)
+ *alp_mode = ADE_ALP_PIXEL_AND_GLB;
+ else if (has_alpha)
+ *alp_mode = ADE_ALP_PIXEL;
+ else
+ *alp_mode = ADE_ALP_GLOBAL;
+
+ /*
+ * get alp sel
+ */
+ *alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */
+ *under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
+}
+
+static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u32 x0, u32 y0,
+ u32 in_w, u32 in_h, u32 fmt)
+{
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+ u8 ovly_ch = 0;
+ u8 x = ADE_OVLY2;
+ u8 glb_alpha = 255;
+ u32 x1 = x0 + in_w - 1;
+ u32 y1 = y0 + in_h - 1;
+ u32 val;
+ u8 alp_sel;
+ u8 under_alp_sel;
+ u8 alp_mode;
+
+ ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
+ &under_alp_sel);
+
+ /* overlay routing setting */
+ writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch));
+ writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch));
+ val = (ch + 1) << ADE_OVLY_CH_SEL_OFST | BIT(ADE_OVLY_CH_EN_OFST) |
+ alp_sel << ADE_OVLY_CH_ALP_SEL_OFST |
+ under_alp_sel << ADE_OVLY_CH_UNDER_ALP_SEL_OFST |
+ glb_alpha << ADE_OVLY_CH_ALP_GBL_OFST |
+ alp_mode << ADE_OVLY_CH_ALP_MODE_OFST;
+ DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
+ writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+ val = (x + 1) << (ovly_ch * 4) | readl(base + ADE_OVLY_CTL);
+ DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
+ writel(val, base + ADE_OVLY_CTL);
+
+ /* when primary is enable, indicate that it's ready to output. */
+ if (ch == PRIMARY_CH) {
+ val = (in_w - 1) << 16 | (in_h - 1);
+ writel(val, base + ADE_OVLY_OUTPUT_SIZE(x));
+ writel(1, base + ADE_OVLYX_CTL(x));
+ acrtc->use_mask |= BIT(ADE_OVLY_BIT_OFST + x);
+ }
+}
+
+static void ade_overlay_disable(struct ade_crtc *acrtc, u32 ch)
+{
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ void __iomem *base = ctx->base;
+ u8 ovly_ch = 0;
+ u32 val;
+
+ val = ~BIT(6) & readl(base + ADE_OVLY_CH_CTL(ovly_ch));
+ DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
+ writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+ val = ~(0x3 << (ovly_ch * 4)) & readl(base + ADE_OVLY_CTL);
+
+ DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
+ writel(val, base + ADE_OVLY_CTL);
+}
+
+/*
+ * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->overlay
+ */
+static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
+ struct drm_framebuffer *fb, int crtc_x,
+ int crtc_y, unsigned int crtc_w,
+ unsigned int crtc_h, u32 src_x,
+ u32 src_y, u32 src_w, u32 src_h)
+{
+ u8 ch = aplane->ch;
+ u32 fmt = ade_get_format(fb->pixel_format);
+ u32 in_w;
+ u32 in_h;
+
+ DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d",
+ ch + 1, src_x, src_y, src_w, src_h,
+ crtc_x, crtc_y, crtc_w, crtc_h);
+
+ /* 1) DMA setting */
+ in_w = src_w;
+ in_h = src_h;
+ ade_rdma_set(acrtc, fb, ch, src_y, in_h, fmt);
+
+ /* 2) clip setting */
+ ade_clip_set(acrtc, ch, fb->width, src_x, in_w, in_h);
+
+ /* 3) TODO: scale setting for overlay planes */
+
+ /* 4) TODO: ctran/csc setting for overlay planes */
+
+ /* 5) overlay/compositor routing setting */
+ ade_overlay_set(acrtc, ch, crtc_x, crtc_y, in_w, in_h, fmt);
+
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_disable_channel(struct ade_plane *aplane,
+ struct ade_crtc *acrtc)
+{
+ u32 ch = aplane->ch;
+
+ DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1);
+
+ /*
+ * when primary is disable, power is down
+ * so no need to disable this channel.
+ */
+ if (ch == PRIMARY_CH)
+ return;
+
+ /* disable read DMA */
+ ade_rdma_disable(acrtc, ch);
+
+ /* disable clip */
+ ade_clip_disable(acrtc, ch);
+
+ /* disable overlay routing */
+ ade_overlay_disable(acrtc, ch);
+
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int ade_plane_prepare_fb(struct drm_plane *plane,
+ const struct drm_plane_state *new_state)
+{
+ DRM_DEBUG_DRIVER("enter.\n");
+ DRM_DEBUG_DRIVER("exit success.\n");
+ return 0;
+}
+
+static void ade_plane_cleanup_fb(struct drm_plane *plane,
+ const struct drm_plane_state *old_state)
+{
+ DRM_DEBUG_DRIVER("enter.\n");
+ DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int ade_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_crtc *crtc = state->crtc;
+ struct drm_crtc_state *crtc_state;
+ u32 src_x = state->src_x >> 16;
+ u32 src_y = state->src_y >> 16;
+ u32 src_w = state->src_w >> 16;
+ u32 src_h = state->src_h >> 16;
+ int crtc_x = state->crtc_x;
+ int crtc_y = state->crtc_y;
+ u32 crtc_w = state->crtc_w;
+ u32 crtc_h = state->crtc_h;
+
+ if (!crtc || !fb)
+ return 0;
+
+ crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ if (src_w != crtc_w || src_h != crtc_h) {
+ DRM_ERROR("Scale not support!!!\n");
+ return -EINVAL;
+ }
+
+ if (src_x + src_w > fb->width ||
+ src_y + src_h > fb->height)
+ return -EINVAL;
+
+ if (crtc_x < 0 || crtc_y < 0)
+ return -EINVAL;
+
+ if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
+ crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void ade_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct drm_plane_state *state = plane->state;
+ struct ade_plane *aplane = to_ade_plane(plane);
+ struct ade_crtc *acrtc;
+
+ if (!state->crtc)
+ return;
+
+ acrtc = to_ade_crtc(state->crtc);
+ ade_update_channel(aplane, acrtc, state->fb,
+ state->crtc_x, state->crtc_y,
+ state->crtc_w, state->crtc_h,
+ state->src_x >> 16, state->src_y >> 16,
+ state->src_w >> 16, state->src_h >> 16);
+}
+
+static void ade_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct ade_plane *aplane = to_ade_plane(plane);
+ struct ade_crtc *acrtc;
+
+ if (!old_state->crtc)
+ return;
+ acrtc = to_ade_crtc(old_state->crtc);
+ ade_disable_channel(aplane, acrtc);
+}
+
+static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
+ .prepare_fb = ade_plane_prepare_fb,
+ .cleanup_fb = ade_plane_cleanup_fb,
+ .atomic_check = ade_plane_atomic_check,
+ .atomic_update = ade_plane_atomic_update,
+ .atomic_disable = ade_plane_atomic_disable,
+};
+
+static struct drm_plane_funcs ade_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .set_property = drm_atomic_helper_plane_set_property,
+ .destroy = drm_plane_cleanup,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
+ enum drm_plane_type type)
+{
+ const u32 *fmts;
+ u32 fmts_cnt;
+ int ret = 0;
+
+ /* get properties */
+ fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts);
+ if (ret)
+ return ret;
+
+ ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs,
+ fmts, fmts_cnt, type);
+ if (ret) {
+ DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch);
+ return ret;
+ }
+
+ drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs);
+
+ return 0;
+}
+
+static int ade_bind(struct device *dev, struct device *master, void *data)
+{
+ struct ade_data *ade = dev_get_drvdata(dev);
+ struct ade_hw_ctx *ctx = &ade->ctx;
+ struct ade_crtc *acrtc = &ade->acrtc;
+ struct drm_device *drm_dev = (struct drm_device *)data;
+ struct ade_plane *aplane;
+ enum drm_plane_type type;
+ int ret;
+ int i;
+
+ /*
+ * plane init
+ * TODO: Now only support primary plane, overlay planes
+ * need to do.
+ */
+ for (i = 0; i < ADE_CH_NUM; i++) {
+ aplane = &ade->aplane[i];
+ aplane->ch = i;
+ aplane->ctx = ctx;
+ type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
+ DRM_PLANE_TYPE_OVERLAY;
+
+ ret = ade_plane_init(drm_dev, aplane, type);
+ if (ret)
+ return ret;
+ }
+
+ /* crtc init */
+ acrtc->ctx = ctx;
+ ret = ade_crtc_init(drm_dev, &acrtc->base,
+ &ade->aplane[PRIMARY_CH].base);
+ if (ret)
+ return ret;
+
+ /* vblank irq init */
+ ret = request_irq(ctx->irq, ade_irq_handler, DRIVER_IRQ_SHARED,
+ drm_dev->driver->name, acrtc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void ade_unbind(struct device *dev, struct device *master, void *data)
+{
+ /* do nothing */
+}
+
+static const struct component_ops ade_ops = {
+ .bind = ade_bind,
+ .unbind = ade_unbind,
+};
+
+static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx)
+{
+ struct resource *res;
+ struct device *dev;
+ struct device_node *np;
+ int ret;
+
+ dev = &pdev->dev;
+ np = dev->of_node;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ade_base");
+ ctx->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ctx->base)) {
+ DRM_ERROR("failed to remap ade io base\n");
+ return PTR_ERR(ctx->base);
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_base");
+ ctx->media_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ctx->media_base)) {
+ DRM_ERROR("failed to remap media io base\n");
+ return PTR_ERR(ctx->media_base);
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_noc_base");
+ ctx->media_noc_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ctx->media_noc_base)) {
+ DRM_ERROR("failed to remap media noc base\n");
+ return PTR_ERR(ctx->media_noc_base);
+ }
+
+ ctx->irq = platform_get_irq(pdev, 0);
+ if (ctx->irq < 0) {
+ DRM_ERROR("failed to parse the irq\n");
+ return -ENODEV;
+ }
+
+ ctx->ade_core_clk = devm_clk_get(&pdev->dev, "clk_ade_core");
+ if (!ctx->ade_core_clk) {
+ DRM_ERROR("failed to parse the ADE_CORE\n");
+ return -ENODEV;
+ }
+ ctx->media_noc_clk = devm_clk_get(&pdev->dev,
+ "aclk_codec_jpeg_src");
+ if (!ctx->media_noc_clk) {
+ DRM_ERROR("failed to parse the CODEC_JPEG\n");
+ return -ENODEV;
+ }
+ ctx->ade_pix_clk = devm_clk_get(&pdev->dev, "clk_ade_pix");
+ if (!ctx->ade_pix_clk) {
+ DRM_ERROR("failed to parse the ADE_PIX_SRC\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(np, "ade_core_clk_rate",
+ &ctx->ade_core_rate);
+ if (ret) {
+ DRM_ERROR("failed to parse the ade_core_clk_rate\n");
+ return -ENODEV;
+ }
+ ret = of_property_read_u32(np, "media_noc_clk_rate",
+ &ctx->media_noc_rate);
+ if (ret) {
+ DRM_ERROR("failed to parse the media_noc_clk_rate\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int ade_probe(struct platform_device *pdev)
+{
+ struct ade_data *ade;
+ int ret;
+
+ DRM_DEBUG_DRIVER("enter.\n");
+
+ ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
+ if (!ade) {
+ DRM_ERROR("failed to alloc ade_data\n");
+ return -ENOMEM;
+ }
+
+ ret = ade_dts_parse(pdev, &ade->ctx);
+ if (ret) {
+ DRM_ERROR("failed to parse dts!!\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, ade);
+
+ return component_add(&pdev->dev, &ade_ops);
+}
+
+static int ade_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &ade_ops);
+
+ return 0;
+}
+
+static const struct of_device_id ade_of_match[] = {
+ { .compatible = "hisilicon,hi6220-ade" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ade_of_match);
+
+static struct platform_driver ade_driver = {
+ .probe = ade_probe,
+ .remove = ade_remove,
+ .driver = {
+ .name = "hisi-ade",
+ .owner = THIS_MODULE,
+ .of_match_table = ade_of_match,
+ },
+};
+
+module_platform_driver(ade_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("Hisilicon DRM ADE(crtc/plane) Driver");
+MODULE_LICENSE("GPL v2");
new file mode 100644
@@ -0,0 +1,280 @@
+/*
+ * Hisilicon SoCs drm master driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ * Xinliang Liu <xinliang.liu@linaro.org>
+ * Xinliang Liu <z.liuxinliang@hisilicon.com>
+ * Xinwei Kong <kong.kongxinwei@hisilicon.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/of_platform.h>
+#include <linux/component.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "hisi_drm_ade.h"
+#include "kirin_drm_drv.h"
+
+#define DRIVER_NAME "hisi-drm"
+
+static int hisi_drm_unload(struct drm_device *dev)
+{
+ struct hisi_drm_private *priv = dev->dev_private;
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+ if (priv->fbdev) {
+ drm_fbdev_cma_fini(priv->fbdev);
+ priv->fbdev = NULL;
+ }
+#endif
+ drm_kms_helper_poll_fini(dev);
+ drm_vblank_cleanup(dev);
+ drm_mode_config_cleanup(dev);
+ devm_kfree(dev->dev, priv);
+ dev->dev_private = NULL;
+
+ return 0;
+}
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+static void hisi_fbdev_output_poll_changed(struct drm_device *dev)
+{
+ struct hisi_drm_private *priv = dev->dev_private;
+
+ if (priv->fbdev) {
+ drm_fbdev_cma_hotplug_event(priv->fbdev);
+ } else {
+ priv->fbdev = drm_fbdev_cma_init(dev, 32,
+ dev->mode_config.num_crtc,
+ dev->mode_config.num_connector);
+ if (IS_ERR(priv->fbdev))
+ priv->fbdev = NULL;
+ }
+}
+#endif
+
+static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+ .output_poll_changed = hisi_fbdev_output_poll_changed,
+#endif
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static void hisi_drm_mode_config_init(struct drm_device *dev)
+{
+ dev->mode_config.min_width = 0;
+ dev->mode_config.min_height = 0;
+
+ dev->mode_config.max_width = 2048;
+ dev->mode_config.max_height = 2048;
+
+ dev->mode_config.funcs = &hisi_drm_mode_config_funcs;
+}
+
+static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
+{
+ struct hisi_drm_private *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev->dev_private = priv;
+ dev_set_drvdata(dev->dev, dev);
+
+ /* dev->mode_config initialization */
+ drm_mode_config_init(dev);
+ hisi_drm_mode_config_init(dev);
+
+ /* bind and init sub drivers */
+ ret = component_bind_all(dev->dev, dev);
+ if (ret) {
+ DRM_ERROR("failed to bind all component.\n");
+ goto err_mode_config_cleanup;
+ }
+
+ /* vblank init */
+ ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ if (ret) {
+ DRM_ERROR("failed to initialize vblank.\n");
+ goto err_unbind_all;
+ }
+ /* with irq_enabled = true, we can use the vblank feature. */
+ dev->irq_enabled = true;
+
+ /* reset all the states of crtc/plane/encoder/connector */
+ drm_mode_config_reset(dev);
+
+ /* init kms poll for handling hpd */
+ drm_kms_helper_poll_init(dev);
+
+ /* force detection after connectors init */
+ (void)drm_helper_hpd_irq_event(dev);
+
+ return 0;
+
+err_unbind_all:
+ component_unbind_all(dev->dev, dev);
+err_mode_config_cleanup:
+ drm_mode_config_cleanup(dev);
+ devm_kfree(dev->dev, priv);
+ dev->dev_private = NULL;
+
+ return ret;
+}
+
+static const struct file_operations hisi_drm_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .poll = drm_poll,
+ .read = drm_read,
+ .llseek = no_llseek,
+ .mmap = drm_gem_cma_mmap,
+};
+
+static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj,
+ int flags)
+{
+ /* we want to be able to write in mmapped buffer */
+ flags |= O_RDWR;
+ return drm_gem_prime_export(dev, obj, flags);
+}
+
+static int hisi_gem_cma_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+ /* mali gpu need pitch 8 bytes alignment for 32bpp */
+ args->pitch = roundup(min_pitch, 8);
+
+ return drm_gem_cma_dumb_create_internal(file, dev, args);
+}
+
+static struct drm_driver hisi_drm_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
+ DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
+ .load = hisi_drm_load,
+ .unload = hisi_drm_unload,
+ .fops = &hisi_drm_fops,
+ .set_busid = drm_platform_set_busid,
+
+ .gem_free_object = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = hisi_gem_cma_dumb_create,
+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+ .dumb_destroy = drm_gem_dumb_destroy,
+
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = hisi_gem_prime_export,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+ .gem_prime_vmap = drm_gem_cma_prime_vmap,
+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+ .gem_prime_mmap = drm_gem_cma_prime_mmap,
+
+ .get_vblank_counter = drm_vblank_count,
+ .enable_vblank = ade_enable_vblank,
+ .disable_vblank = ade_disable_vblank,
+
+ .name = "hisi",
+ .desc = "Hisilicon SoCs' DRM Driver",
+ .date = "20150718",
+ .major = 1,
+ .minor = 0,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static int hisi_drm_bind(struct device *dev)
+{
+ dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+ return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
+}
+
+static void hisi_drm_unbind(struct device *dev)
+{
+ drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops hisi_drm_ops = {
+ .bind = hisi_drm_bind,
+ .unbind = hisi_drm_unbind,
+};
+
+static int hisi_drm_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct device_node *child_np;
+ struct component_match *match = NULL;
+
+ of_platform_populate(node, NULL, NULL, dev);
+
+ child_np = of_get_next_available_child(node, NULL);
+ while (child_np) {
+ component_match_add(dev, &match, compare_of, child_np);
+ of_node_put(child_np);
+ child_np = of_get_next_available_child(node, child_np);
+ }
+
+ return component_master_add_with_match(dev, &hisi_drm_ops, match);
+
+ return 0;
+}
+
+static int hisi_drm_platform_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &hisi_drm_ops);
+ of_platform_depopulate(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id hisi_drm_dt_ids[] = {
+ { .compatible = "hisilicon,hi6220-dss", },
+ { /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
+
+static struct platform_driver hisi_drm_platform_driver = {
+ .probe = hisi_drm_platform_probe,
+ .remove = hisi_drm_platform_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .of_match_table = hisi_drm_dt_ids,
+ },
+};
+
+module_platform_driver(hisi_drm_platform_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("hisilicon SoCs' DRM master driver");
+MODULE_LICENSE("GPL v2");
new file mode 100644
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HISI_DRM_DRV_H__
+#define __HISI_DRM_DRV_H__
+
+struct hisi_drm_private {
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+ struct drm_fbdev_cma *fbdev;
+#endif
+};
+
+#endif /* __HISI_DRM_DRV_H__ */
In preparation to sync with the driver that ended upstream, as well as what is used in Guodong's RPB builds, move the hisi_drm driver over to kirin. The only changes in the source are to include filenames, which changed in the move. Signed-off-by: John Stultz <john.stultz@linaro.org> --- arch/arm64/configs/hikey_defconfig | 2 + drivers/gpu/drm/hisilicon/Kconfig | 5 + drivers/gpu/drm/hisilicon/Makefile | 8 +- drivers/gpu/drm/hisilicon/hisi_ade_reg.h | 494 ---------- drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 1100 ----------------------- drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 - drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 280 ------ drivers/gpu/drm/hisilicon/hisi_drm_drv.h | 19 - drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 832 ----------------- drivers/gpu/drm/hisilicon/hisi_dsi_reg.h | 89 -- drivers/gpu/drm/hisilicon/kirin/Kconfig | 19 + drivers/gpu/drm/hisilicon/kirin/Makefile | 6 + drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 832 +++++++++++++++++ drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h | 89 ++ drivers/gpu/drm/hisilicon/kirin/hisi_drm_ade.h | 16 + drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h | 494 ++++++++++ drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 1100 +++++++++++++++++++++++ drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 280 ++++++ drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h | 19 + 19 files changed, 2866 insertions(+), 2834 deletions(-) delete mode 100644 drivers/gpu/drm/hisilicon/hisi_ade_reg.h delete mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.c delete mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h delete mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c delete mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.h delete mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c delete mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h create mode 100644 drivers/gpu/drm/hisilicon/kirin/Kconfig create mode 100644 drivers/gpu/drm/hisilicon/kirin/Makefile create mode 100644 drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c create mode 100644 drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h create mode 100644 drivers/gpu/drm/hisilicon/kirin/hisi_drm_ade.h create mode 100644 drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h create mode 100644 drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c create mode 100644 drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c create mode 100644 drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h -- 1.9.1