mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 05:55:44 +02:00
ANDROID: drm: kirin: Introduce kirin960
Add initial kirin960 support files. Signed-off-by: Xu YiPing <xuyiping@hisilicon.com> [jstultz: Fold in some minor cleanups] [jstultz: Folded in a export symbol fix by Greg Kroah-Hartman] Signed-off-by: John Stultz <john.stultz@linaro.org> Bug: 146450171 Change-Id: I934004f4a15e1bba341807f6c63c13bf6c661698
This commit is contained in:
parent
5cf9a844f6
commit
34ebaf13be
|
|
@ -6,7 +6,37 @@ config DRM_HISI_KIRIN
|
|||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_KMS_CMA_HELPER
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_PANEL
|
||||
help
|
||||
Choose this option if you have a hisilicon Kirin chipsets(hi6220).
|
||||
Choose this option if you have a hisilicon Kirin chipsets.
|
||||
If M is selected the module will be called kirin-drm.
|
||||
|
||||
if DRM_HISI_KIRIN
|
||||
config DRM_HISI_KIRIN620
|
||||
bool "DRM Support for Hisilicon Kirin620 Platform"
|
||||
default n
|
||||
depends on DRM_HISI_KIRIN
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_KMS_CMA_HELPER
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_PANEL
|
||||
help
|
||||
Choose this option if you have hisilicon Kirin Chipset(kirin620).
|
||||
It includes kirin620 ade and dsi drivers.
|
||||
If y is to build kirin620 drm into kirin drm drivers.
|
||||
|
||||
config DRM_HISI_KIRIN960
|
||||
bool "DRM Support for Hisilicon Kirin960 Platform"
|
||||
default n
|
||||
depends on DRM_HISI_KIRIN
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_KMS_CMA_HELPER
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_PANEL
|
||||
help
|
||||
Choose this option if you have hisilicon Kirin Chipset(kirin960), such
|
||||
as hikey board. It includes kirin620 dpe and dsi drivers.
|
||||
If y is to build kirin960 drm into kirin drm drivers.
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
kirin-drm-y := kirin_drm_drv.o \
|
||||
kirin_drm_ade.o
|
||||
EXTRA_CFLAGS += \
|
||||
-Iinclude/drm
|
||||
|
||||
obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o dw_drm_dsi.o
|
||||
kirin-drm-y := kirin_drm_drv.o
|
||||
kirin-drm-$(CONFIG_DRM_HISI_KIRIN620) += kirin_drm_ade.o
|
||||
|
||||
kirin-dsi-y := kirin_drm_dsi.o
|
||||
kirin-dsi-$(CONFIG_DRM_HISI_KIRIN620) += kirin/dw_drm_dsi.o
|
||||
kirin-dsi-$(CONFIG_DRM_HISI_KIRIN960) += kirin960/dw_drm_dsi.o
|
||||
|
||||
obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o kirin-dsi.o
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#define __DW_DSI_REG_H__
|
||||
|
||||
#define MASK(x) (BIT(x) - 1)
|
||||
|
||||
#define DEFAULT_MAX_TX_ESC_CLK (10 * 1000000UL) //for hikey960
|
||||
/*
|
||||
* regs
|
||||
*/
|
||||
|
|
@ -52,6 +52,50 @@
|
|||
#define VID_VACTIVE_LINES 0x60 /* Vertical resolution */
|
||||
#define VID_PKT_SIZE 0x3C /* Video packet size */
|
||||
#define VID_MODE_CFG 0x38 /* Video mode configuration */
|
||||
/***************************for hikey960***********************************/
|
||||
#define GEN_HDR 0x6c
|
||||
#define GEN_HDATA(data) (((data) & 0xffff) << 8)
|
||||
#define GEN_HDATA_MASK (0xffff << 8)
|
||||
#define GEN_HTYPE(type) (((type) & 0xff) << 0)
|
||||
#define GEN_HTYPE_MASK 0xff
|
||||
#define GEN_PLD_DATA 0x70
|
||||
#define CMD_PKT_STATUS 0x74
|
||||
#define GEN_CMD_EMPTY BIT(0)
|
||||
#define GEN_CMD_FULL BIT(1)
|
||||
#define GEN_PLD_W_EMPTY BIT(2)
|
||||
#define GEN_PLD_W_FULL BIT(3)
|
||||
#define GEN_PLD_R_EMPTY BIT(4)
|
||||
#define GEN_PLD_R_FULL BIT(5)
|
||||
#define GEN_RD_CMD_BUSY BIT(6)
|
||||
#define CMD_MODE_CFG 0x68
|
||||
#define MAX_RD_PKT_SIZE_LP BIT(24)
|
||||
#define DCS_LW_TX_LP BIT(19)
|
||||
#define DCS_SR_0P_TX_LP BIT(18)
|
||||
#define DCS_SW_1P_TX_LP BIT(17)
|
||||
#define DCS_SW_0P_TX_LP BIT(16)
|
||||
#define GEN_LW_TX_LP BIT(14)
|
||||
#define GEN_SR_2P_TX_LP BIT(13)
|
||||
#define GEN_SR_1P_TX_LP BIT(12)
|
||||
#define GEN_SR_0P_TX_LP BIT(11)
|
||||
#define GEN_SW_2P_TX_LP BIT(10)
|
||||
#define GEN_SW_1P_TX_LP BIT(9)
|
||||
#define GEN_SW_0P_TX_LP BIT(8)
|
||||
#define EN_ACK_RQST BIT(1)
|
||||
#define EN_TEAR_FX BIT(0)
|
||||
#define CMD_PKT_STATUS_TIMEOUT_US 20000
|
||||
#define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \
|
||||
DCS_LW_TX_LP | \
|
||||
DCS_SR_0P_TX_LP | \
|
||||
DCS_SW_1P_TX_LP | \
|
||||
DCS_SW_0P_TX_LP | \
|
||||
GEN_LW_TX_LP | \
|
||||
GEN_SR_2P_TX_LP | \
|
||||
GEN_SR_1P_TX_LP | \
|
||||
GEN_SR_0P_TX_LP | \
|
||||
GEN_SW_2P_TX_LP | \
|
||||
GEN_SW_1P_TX_LP | \
|
||||
GEN_SW_0P_TX_LP)
|
||||
/***************************for hikey960***********************************/
|
||||
#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 */
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
* Xinliang Liu <z.liuxinliang@hisilicon.com>
|
||||
* Xinliang Liu <xinliang.liu@linaro.org>
|
||||
* Xinwei Kong <kong.kongxinwei@hisilicon.com>
|
||||
* Da Lv <lvda3@hisilicon.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
|
@ -26,97 +27,10 @@
|
|||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
||||
#include "dw_dsi_reg.h"
|
||||
#include "../kirin_drm_dsi.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 PHY_REF_CLK_RATE 19200000
|
||||
#define PHY_REF_CLK_PERIOD_PS (1000000000 / (PHY_REF_CLK_RATE / 1000))
|
||||
|
||||
#define encoder_to_dsi(encoder) \
|
||||
container_of(encoder, struct dw_dsi, encoder)
|
||||
#define host_to_dsi(host) \
|
||||
container_of(host, struct dw_dsi, host)
|
||||
|
||||
struct mipi_phy_params {
|
||||
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 *pclk;
|
||||
};
|
||||
|
||||
struct dw_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_params phy;
|
||||
|
||||
u32 lanes;
|
||||
enum mipi_dsi_pixel_format format;
|
||||
unsigned long mode_flags;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
struct dsi_data {
|
||||
struct dw_dsi dsi;
|
||||
struct dsi_hw_ctx ctx;
|
||||
};
|
||||
|
||||
struct dsi_phy_range {
|
||||
u32 min_range_kHz;
|
||||
u32 max_range_kHz;
|
||||
u32 pll_vco_750M;
|
||||
u32 hstx_ckg_sel;
|
||||
};
|
||||
|
||||
static const struct dsi_phy_range dphy_range_info[] = {
|
||||
{ 46875, 62500, 1, 7 },
|
||||
{ 62500, 93750, 0, 7 },
|
||||
{ 93750, 125000, 1, 6 },
|
||||
{ 125000, 187500, 0, 6 },
|
||||
{ 187500, 250000, 1, 5 },
|
||||
{ 250000, 375000, 0, 5 },
|
||||
{ 375000, 500000, 1, 4 },
|
||||
{ 500000, 750000, 0, 4 },
|
||||
{ 750000, 1000000, 1, 0 },
|
||||
{ 1000000, 1500000, 0, 0 }
|
||||
};
|
||||
|
||||
static u32 dsi_calc_phy_rate(u32 req_kHz, struct mipi_phy_params *phy)
|
||||
{
|
||||
|
|
@ -568,24 +482,7 @@ static void dsi_mipi_init(struct dw_dsi *dsi)
|
|||
dsi->lanes, mode->clock, phy->lane_byte_clk_kHz);
|
||||
}
|
||||
|
||||
static void dsi_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct dw_dsi *dsi = encoder_to_dsi(encoder);
|
||||
struct dsi_hw_ctx *ctx = dsi->ctx;
|
||||
void __iomem *base = ctx->base;
|
||||
|
||||
if (!dsi->enable)
|
||||
return;
|
||||
|
||||
writel(0, base + PWR_UP);
|
||||
writel(0, base + LPCLK_CTRL);
|
||||
writel(0, base + PHY_RSTZ);
|
||||
clk_disable_unprepare(ctx->pclk);
|
||||
|
||||
dsi->enable = false;
|
||||
}
|
||||
|
||||
static void dsi_encoder_enable(struct drm_encoder *encoder)
|
||||
static void dsi_encoder_enable_sub(struct drm_encoder *encoder)
|
||||
{
|
||||
struct dw_dsi *dsi = encoder_to_dsi(encoder);
|
||||
struct dsi_hw_ctx *ctx = dsi->ctx;
|
||||
|
|
@ -601,8 +498,6 @@ static void dsi_encoder_enable(struct drm_encoder *encoder)
|
|||
}
|
||||
|
||||
dsi_mipi_init(dsi);
|
||||
|
||||
dsi->enable = true;
|
||||
}
|
||||
|
||||
static enum drm_mode_status dsi_encoder_phy_mode_valid(
|
||||
|
|
@ -844,54 +739,13 @@ static int dsi_parse_dt(struct platform_device *pdev, struct dw_dsi *dsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dsi_data *data;
|
||||
struct dw_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"},
|
||||
{ }
|
||||
const struct kirin_dsi_ops kirin_dsi_620 = {
|
||||
.version = KIRIN620_DSI,
|
||||
.parse_dt = dsi_parse_dt,
|
||||
.host_init = dsi_host_init,
|
||||
.encoder_enable = dsi_encoder_enable_sub,
|
||||
.encoder_valid = dsi_encoder_mode_valid
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dsi_of_match);
|
||||
|
||||
static struct platform_driver dsi_driver = {
|
||||
.probe = dsi_probe,
|
||||
.remove = dsi_remove,
|
||||
.driver = {
|
||||
.name = "dw-dsi",
|
||||
.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>");
|
||||
1269
drivers/gpu/drm/hisilicon/kirin/kirin960/dw_drm_dsi.c
Normal file
1269
drivers/gpu/drm/hisilicon/kirin/kirin960/dw_drm_dsi.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -1,7 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016 Linaro Limited.
|
||||
* Copyright (c) 2014-2016 Hisilicon Limited.
|
||||
* Copyright (c) 2016,2019 Linaro Limited.
|
||||
* Copyright (c) 2014-2016,2019 Hisilicon Limited.
|
||||
*/
|
||||
|
||||
#ifndef __KIRIN_ADE_REG_H__
|
||||
|
|
|
|||
393
drivers/gpu/drm/hisilicon/kirin/kirin_dpe_reg.h
Normal file
393
drivers/gpu/drm/hisilicon/kirin/kirin_dpe_reg.h
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Copyright (c) 2016 Linaro Limited.
|
||||
* Copyright (c) 2014-2016 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 __KIRIN_DPE_REG_H__
|
||||
#define __KIRIN_DPE_REG_H__
|
||||
|
||||
#define BIT_MMU_IRPT_NS BIT(28)
|
||||
#define BIT_ITF0_INTS BIT(16)
|
||||
#define BIT_DPP_INTS BIT(15)
|
||||
#define BIT_VACTIVE0_END BIT(8)
|
||||
#define BIT_VACTIVE0_START BIT(7)
|
||||
#define BIT_VSYNC BIT(4)
|
||||
#define BIT_LDI_UNFLOW BIT(2)
|
||||
|
||||
#define DFS_TIME (80)
|
||||
#define DFS_TIME_MIN (50)
|
||||
#define DFS_TIME_MIN_4K (10)
|
||||
#define DBUF0_DEPTH (1408)
|
||||
#define DBUF_WIDTH_BIT (144)
|
||||
#define PERRSTDIS3 (0x088)
|
||||
|
||||
#define DPE_GLB0_OFFSET (0x12000)
|
||||
#define DPE_DBG_OFFSET (0x11000)
|
||||
#define DPE_CMDLIST_OFFSET (0x02000)
|
||||
#define DPE_SMMU_OFFSET (0x08000)
|
||||
#define DPE_MIF_OFFSET (0x0A000)
|
||||
#define DPE_MCTRL_SYS_OFFSET (0x10000)
|
||||
#define DPE_MCTRL_CTL0_OFFSET (0x10800)
|
||||
#define DPE_RCH_VG0_DMA_OFFSET (0x20000)
|
||||
#define DPE_RCH_VG0_SCL_OFFSET (0x20200)
|
||||
#define DPE_RCH_VG0_ARSR_OFFSET (0x20300)
|
||||
#define DPE_RCH_VG1_DMA_OFFSET (0x28000)
|
||||
#define DPE_RCH_VG1_SCL_OFFSET (0x28200)
|
||||
#define DPE_RCH_VG2_DMA_OFFSET (0x30000)
|
||||
#define DPE_RCH_VG2_SCL_OFFSET (0x30200)
|
||||
#define DPE_RCH_G0_DMA_OFFSET (0x38000)
|
||||
#define DPE_RCH_G0_SCL_OFFSET (0x38200)
|
||||
#define DPE_RCH_G1_DMA_OFFSET (0x40000)
|
||||
#define DPE_RCH_G1_SCL_OFFSET (0x40200)
|
||||
#define DPE_RCH_D2_DMA_OFFSET (0x50000)
|
||||
#define DPE_RCH_D3_DMA_OFFSET (0x51000)
|
||||
#define DPE_RCH_D0_DMA_OFFSET (0x52000)
|
||||
#define DPE_RCH_D0_DFC_OFFSET (0x52100)
|
||||
#define DPE_RCH_D1_DMA_OFFSET (0x53000)
|
||||
#define DPE_WCH0_DMA_OFFSET (0x5A000)
|
||||
#define DPE_WCH1_DMA_OFFSET (0x5C000)
|
||||
#define DPE_WCH2_DMA_OFFSET (0x5E000)
|
||||
#define DPE_WCH2_DFC_OFFSET (0x5E100)
|
||||
#define DPE_OVL0_OFFSET (0x60000)
|
||||
#define DPE_DBUF0_OFFSET (0x6D000)
|
||||
#define DPE_DPP_OFFSET (0x70000)
|
||||
#define DPE_DPP_DITHER_OFFSET (0x70200)
|
||||
#define DPE_LDI0_OFFSET (0x7D000)
|
||||
#define DPE_IFBC_OFFSET (0x7D800)
|
||||
#define DPE_DSC_OFFSET (0x7DC00)
|
||||
|
||||
#define GLB_CPU_PDP_INTS (DPE_GLB0_OFFSET + 0x224)
|
||||
#define GLB_CPU_PDP_INT_MSK (DPE_GLB0_OFFSET + 0x228)
|
||||
#define GLB_CPU_SDP_INTS (DPE_GLB0_OFFSET + 0x22C)
|
||||
#define GLB_CPU_SDP_INT_MSK (DPE_GLB0_OFFSET + 0x230)
|
||||
|
||||
#define DBG_MCTL_INTS (0x023C)
|
||||
#define DBG_MCTL_INT_MSK (0x0240)
|
||||
#define DBG_WCH0_INTS (0x0244)
|
||||
#define DBG_WCH0_INT_MSK (0x0248)
|
||||
#define DBG_WCH1_INTS (0x024C)
|
||||
#define DBG_WCH1_INT_MSK (0x0250)
|
||||
#define DBG_RCH0_INTS (0x0254)
|
||||
#define DBG_RCH0_INT_MSK (0x0258)
|
||||
#define DBG_RCH1_INTS (0x025C)
|
||||
#define DBG_RCH1_INT_MSK (0x0260)
|
||||
#define DBG_RCH2_INTS (0x0264)
|
||||
#define DBG_RCH2_INT_MSK (0x0268)
|
||||
#define DBG_RCH3_INTS (0x026C)
|
||||
#define DBG_RCH3_INT_MSK (0x0270)
|
||||
#define DBG_RCH4_INTS (0x0274)
|
||||
#define DBG_RCH4_INT_MSK (0x0278)
|
||||
#define DBG_RCH5_INTS (0x027C)
|
||||
#define DBG_RCH5_INT_MSK (0x0280)
|
||||
#define DBG_RCH6_INTS (0x0284)
|
||||
#define DBG_RCH6_INT_MSK (0x0288)
|
||||
#define DBG_RCH7_INTS (0x028C)
|
||||
#define DBG_RCH7_INT_MSK (0x0290)
|
||||
#define DBG_DPE_GLB_INTS (0x0294)
|
||||
#define DBG_DPE_GLB_INT_MSK (0x0298)
|
||||
|
||||
#define AIF0_CH0_OFFSET (0x7000)
|
||||
#define AIF0_CH0_ADD_OFFSET (0x7004)
|
||||
|
||||
#define MIF_ENABLE (0x0000)
|
||||
#define MIF_MEM_CTRL (0x0004)
|
||||
#define MIF_CTRL0 (0x0000)
|
||||
#define MIF_CTRL1 (0x0004)
|
||||
#define MIF_CTRL2 (0x0008)
|
||||
#define MIF_CTRL3 (0x000C)
|
||||
#define MIF_CTRL4 (0x0010)
|
||||
#define MIF_CTRL5 (0x0014)
|
||||
#define MIF_CTRL_OFFSET (0x0020)
|
||||
#define MIF_CH0_OFFSET (DPE_MIF_OFFSET + MIF_CTRL_OFFSET * 1)
|
||||
|
||||
#define SMMU_SCR (0x0000)
|
||||
#define SMMU_MEMCTRL (0x0004)
|
||||
#define SMMU_LP_CTRL (0x0008)
|
||||
#define SMMU_INTMASK_NS (0x0010)
|
||||
#define SMMU_INTRAW_NS (0x0014)
|
||||
#define SMMU_INTSTAT_NS (0x0018)
|
||||
#define SMMU_INTCLR_NS (0x001C)
|
||||
#define SMMU_SMRx_NS (0x0020)
|
||||
|
||||
#define DMA_OFT_X0 (0x0000)
|
||||
#define DMA_OFT_Y0 (0x0004)
|
||||
#define DMA_OFT_X1 (0x0008)
|
||||
#define DMA_OFT_Y1 (0x000C)
|
||||
#define DMA_MASK0 (0x0010)
|
||||
#define DMA_MASK1 (0x0014)
|
||||
#define DMA_STRETCH_SIZE_VRT (0x0018)
|
||||
#define DMA_CTRL (0x001C)
|
||||
#define DMA_TILE_SCRAM (0x0020)
|
||||
#define DMA_PULSE (0x0028)
|
||||
#define DMA_CORE_GT (0x002C)
|
||||
#define DMA_DATA_ADDR0 (0x0060)
|
||||
#define DMA_STRIDE0 (0x0064)
|
||||
#define DMA_STRETCH_STRIDE0 (0x0068)
|
||||
#define DMA_DATA_NUM0 (0x006C)
|
||||
#define DMA_CH_CTL (0x00D4)
|
||||
#define DMA_CH_REG_DEFAULT (0x0A00)
|
||||
#define DMA_ALIGN_BYTES (128 / BITS_PER_BYTE)
|
||||
#define DMA_ADDR_ALIGN (128 / BITS_PER_BYTE)
|
||||
#define DMA_STRIDE_ALIGN (128 / BITS_PER_BYTE)
|
||||
|
||||
#define DFC_DISP_SIZE (0x0000)
|
||||
#define DFC_PIX_IN_NUM (0x0004)
|
||||
#define DFC_GLB_ALPHA (0x0008)
|
||||
#define DFC_DISP_FMT (0x000C)
|
||||
#define DFC_CLIP_CTL_HRZ (0x0010)
|
||||
#define DFC_CLIP_CTL_VRZ (0x0014)
|
||||
#define DFC_CTL_CLIP_EN (0x0018)
|
||||
#define DFC_ICG_MODULE (0x001C)
|
||||
#define DFC_DITHER_ENABLE (0x0020)
|
||||
#define DFC_PADDING_CTL (0x0024)
|
||||
|
||||
#define MCTL_CTL_EN (0x0000)
|
||||
#define MCTL_CTL_MUTEX (0x0004)
|
||||
#define MCTL_CTL_MUTEX_STATUS (0x0008)
|
||||
#define MCTL_CTL_MUTEX_ITF (0x000C)
|
||||
#define MCTL_CTL_MUTEX_DBUF (0x0010)
|
||||
#define MCTL_CTL_MUTEX_SCF (0x0014)
|
||||
#define MCTL_CTL_MUTEX_OV (0x0018)
|
||||
#define MCTL_CTL_MUTEX_WCH0 (0x0020)
|
||||
#define MCTL_CTL_MUTEX_RCH0 (0x0030)
|
||||
#define MCTL_CTL_TOP (0x0050)
|
||||
#define MCTL_CTL_DBG (0x00E0)
|
||||
#define MCTL_RCH0_FLUSH_EN (0x0100)
|
||||
#define MCTL_OV0_FLUSH_EN (0x0128)
|
||||
#define MCTL_RCH0_OV_OEN (0x0160)
|
||||
#define MCTL_RCH_OV0_SEL (0x0180)
|
||||
|
||||
#define OVL_SIZE (0x0000)
|
||||
#define OVL_BG_COLOR (0x0004)
|
||||
#define OVL_DST_STARTPOS (0x0008)
|
||||
#define OVL_DST_ENDPOS (0x000C)
|
||||
#define OVL_GCFG (0x0010)
|
||||
#define OVL_LAYER0_POS (0x0014)
|
||||
#define OVL_LAYER0_SIZE (0x0018)
|
||||
#define OVL_LAYER0_ALPHA (0x0030)
|
||||
#define OVL_LAYER0_CFG (0x0034)
|
||||
#define OVL6_REG_DEFAULT (0x01A8)
|
||||
|
||||
#define DBUF_FRM_SIZE (0x0000)
|
||||
#define DBUF_FRM_HSIZE (0x0004)
|
||||
#define DBUF_SRAM_VALID_NUM (0x0008)
|
||||
#define DBUF_WBE_EN (0x000C)
|
||||
#define DBUF_THD_FILL_LEV0 (0x0010)
|
||||
#define DBUF_DFS_FILL_LEV1 (0x0014)
|
||||
#define DBUF_THD_RQOS (0x0018)
|
||||
#define DBUF_THD_WQOS (0x001C)
|
||||
#define DBUF_THD_CG (0x0020)
|
||||
#define DBUF_THD_OTHER (0x0024)
|
||||
#define DBUF_ONLINE_FILL_LEVEL (0x003C)
|
||||
#define DBUF_WB_FILL_LEVEL (0x0040)
|
||||
#define DBUF_DFS_STATUS (0x0044)
|
||||
#define DBUF_THD_FLUX_REQ_BEF (0x0048)
|
||||
#define DBUF_DFS_LP_CTRL (0x004C)
|
||||
#define DBUF_RD_SHADOW_SEL (0x0050)
|
||||
#define DBUF_MEM_CTRL (0x0054)
|
||||
#define DBUF_THD_FLUX_REQ_AFT (0x0064)
|
||||
#define DBUF_THD_DFS_OK (0x0068)
|
||||
#define DBUF_FLUX_REQ_CTRL (0x006C)
|
||||
#define DBUF_REG_DEFAULT (0x00A4)
|
||||
|
||||
#define DPP_IMG_SIZE_BEF_SR (0x000C)
|
||||
#define DPP_IMG_SIZE_AFT_SR (0x0010)
|
||||
#define DPP_INTS (0x0040)
|
||||
#define DPP_INT_MSK (0x0044)
|
||||
|
||||
#define SCF_COEF_MEM_CTRL (0x0018)
|
||||
#define IFBC_MEM_CTRL (0x001C)
|
||||
#define DITHER_MEM_CTRL (0x002C)
|
||||
#define DSC_MEM_CTRL (0x0084)
|
||||
#define ARSR2P_LB_MEM_CTRL (0x0084)
|
||||
#define SCF_LB_MEM_CTRL (0x0090)
|
||||
#define ROT_MEM_CTRL (0x0538)
|
||||
#define VPP_MEM_CTRL (0x0704)
|
||||
#define CMD_MEM_CTRL (0x073C)
|
||||
#define DMA_BUF_MEM_CTRL (0x0854)
|
||||
#define AFBCD_MEM_CTRL (0x093C)
|
||||
#define AFBCE_MEM_CTRL (0x0924)
|
||||
|
||||
#define LDI_DPI0_HRZ_CTRL0 (0x0000)
|
||||
#define LDI_DPI0_HRZ_CTRL1 (0x0004)
|
||||
#define LDI_DPI0_HRZ_CTRL2 (0x0008)
|
||||
#define LDI_VRT_CTRL0 (0x000C)
|
||||
#define LDI_VRT_CTRL1 (0x0010)
|
||||
#define LDI_VRT_CTRL2 (0x0014)
|
||||
#define LDI_PLR_CTRL (0x0018)
|
||||
#define LDI_CTRL (0x0024)
|
||||
#define LDI_WORK_MODE (0x0028)
|
||||
#define LDI_DSI_CMD_MOD_CTRL (0x0030)
|
||||
#define LDI_VINACT_MSK_LEN (0x0050)
|
||||
#define LDI_CMD_EVENT_SEL (0x0060)
|
||||
#define LDI_MEM_CTRL (0x0100)
|
||||
#define LDI_PXL0_DIV2_GT_EN (0x0210)
|
||||
#define LDI_PXL0_DIV4_GT_EN (0x0214)
|
||||
#define LDI_PXL0_GT_EN (0x0218)
|
||||
#define LDI_PXL0_DSI_GT_EN (0x021C)
|
||||
#define LDI_PXL0_DIVXCFG (0x0220)
|
||||
#define LDI_VESA_CLK_SEL (0x0228)
|
||||
#define LDI_CPU_ITF_INTS (0x0248)
|
||||
#define LDI_CPU_ITF_INT_MSK (0x024C)
|
||||
|
||||
#define MIPIDSI_VERSION_OFFSET (0x0000)
|
||||
#define MIPIDSI_PWR_UP_OFFSET (0x0004)
|
||||
#define MIPIDSI_CLKMGR_CFG_OFFSET (0x0008)
|
||||
#define MIPIDSI_DPI_VCID_OFFSET (0x000c)
|
||||
#define MIPIDSI_DPI_COLOR_CODING_OFFSET (0x0010)
|
||||
#define MIPIDSI_DPI_CFG_POL_OFFSET (0x0014)
|
||||
#define MIPIDSI_DPI_LP_CMD_TIM_OFFSET (0x0018)
|
||||
#define MIPIDSI_PCKHDL_CFG_OFFSET (0x002c)
|
||||
#define MIPIDSI_GEN_VCID_OFFSET (0x0030)
|
||||
#define MIPIDSI_MODE_CFG_OFFSET (0x0034)
|
||||
#define MIPIDSI_VID_MODE_CFG_OFFSET (0x0038)
|
||||
#define MIPIDSI_VID_PKT_SIZE_OFFSET (0x003c)
|
||||
#define MIPIDSI_VID_NUM_CHUNKS_OFFSET (0x0040)
|
||||
#define MIPIDSI_VID_NULL_SIZE_OFFSET (0x0044)
|
||||
#define MIPIDSI_VID_HSA_TIME_OFFSET (0x0048)
|
||||
#define MIPIDSI_VID_HBP_TIME_OFFSET (0x004c)
|
||||
#define MIPIDSI_VID_HLINE_TIME_OFFSET (0x0050)
|
||||
#define MIPIDSI_VID_VSA_LINES_OFFSET (0x0054)
|
||||
#define MIPIDSI_VID_VBP_LINES_OFFSET (0x0058)
|
||||
#define MIPIDSI_VID_VFP_LINES_OFFSET (0x005c)
|
||||
#define MIPIDSI_VID_VACTIVE_LINES_OFFSET (0x0060)
|
||||
#define MIPIDSI_EDPI_CMD_SIZE_OFFSET (0x0064)
|
||||
#define MIPIDSI_CMD_MODE_CFG_OFFSET (0x0068)
|
||||
#define MIPIDSI_GEN_HDR_OFFSET (0x006c)
|
||||
#define MIPIDSI_GEN_PLD_DATA_OFFSET (0x0070)
|
||||
#define MIPIDSI_CMD_PKT_STATUS_OFFSET (0x0074)
|
||||
#define MIPIDSI_TO_CNT_CFG_OFFSET (0x0078)
|
||||
#define MIPIDSI_BTA_TO_CNT_OFFSET (0x008C)
|
||||
#define MIPIDSI_SDF_3D_OFFSET (0x0090)
|
||||
#define MIPIDSI_LPCLK_CTRL_OFFSET (0x0094)
|
||||
#define MIPIDSI_PHY_TMR_LPCLK_CFG_OFFSET (0x0098)
|
||||
#define MIPIDSI_PHY_TMR_CFG_OFFSET (0x009c)
|
||||
#define MIPIDSI_PHY_RSTZ_OFFSET (0x00a0)
|
||||
#define MIPIDSI_PHY_IF_CFG_OFFSET (0x00a4)
|
||||
#define MIPIDSI_PHY_ULPS_CTRL_OFFSET (0x00a8)
|
||||
#define MIPIDSI_PHY_TX_TRIGGERS_OFFSET (0x00ac)
|
||||
#define MIPIDSI_PHY_STATUS_OFFSET (0x00b0)
|
||||
#define MIPIDSI_PHY_TST_CTRL0_OFFSET (0x00b4)
|
||||
#define MIPIDSI_PHY_TST_CTRL1_OFFSET (0x00b8)
|
||||
#define MIPIDSI_PHY_TMR_RD_CFG_OFFSET (0x00f4)
|
||||
|
||||
enum XRES_DIV {
|
||||
XRES_DIV_1 = 1,
|
||||
XRES_DIV_2,
|
||||
};
|
||||
|
||||
enum YRES_DIV {
|
||||
YRES_DIV_1 = 1,
|
||||
YRES_DIV_2,
|
||||
};
|
||||
|
||||
enum PXL0_DIVCFG {
|
||||
PXL0_DIVCFG_0 = 0,
|
||||
PXL0_DIVCFG_1,
|
||||
};
|
||||
|
||||
enum PXL0_DIV2_GT_EN {
|
||||
PXL0_DIV2_GT_EN_CLOSE = 0,
|
||||
PXL0_DIV2_GT_EN_OPEN,
|
||||
};
|
||||
|
||||
enum PXL0_DIV4_GT_EN {
|
||||
PXL0_DIV4_GT_EN_CLOSE = 0,
|
||||
PXL0_DIV4_GT_EN_OPEN,
|
||||
};
|
||||
|
||||
enum PXL0_DSI_GT_EN {
|
||||
PXL0_DSI_GT_EN_0 = 0,
|
||||
PXL0_DSI_GT_EN_1,
|
||||
};
|
||||
|
||||
enum lcd_format {
|
||||
LCD_RGB888 = 0,
|
||||
LCD_RGB101010,
|
||||
LCD_RGB565,
|
||||
};
|
||||
|
||||
enum lcd_rgb_order {
|
||||
LCD_RGB = 0,
|
||||
LCD_BGR,
|
||||
};
|
||||
|
||||
enum dpe_dfc_format {
|
||||
DFC_PIXEL_FORMAT_RGB_565 = 0,
|
||||
DFC_PIXEL_FORMAT_XRGB_4444,
|
||||
DFC_PIXEL_FORMAT_ARGB_4444,
|
||||
DFC_PIXEL_FORMAT_XRGB_5551,
|
||||
DFC_PIXEL_FORMAT_ARGB_5551,
|
||||
DFC_PIXEL_FORMAT_XRGB_8888,
|
||||
DFC_PIXEL_FORMAT_ARGB_8888,
|
||||
DFC_PIXEL_FORMAT_BGR_565,
|
||||
DFC_PIXEL_FORMAT_XBGR_4444,
|
||||
DFC_PIXEL_FORMAT_ABGR_4444,
|
||||
DFC_PIXEL_FORMAT_XBGR_5551,
|
||||
DFC_PIXEL_FORMAT_ABGR_5551,
|
||||
DFC_PIXEL_FORMAT_XBGR_8888,
|
||||
DFC_PIXEL_FORMAT_ABGR_8888,
|
||||
DFC_PIXEL_FORMAT_YUV444,
|
||||
DFC_PIXEL_FORMAT_YVU444,
|
||||
DFC_PIXEL_FORMAT_YUYV422,
|
||||
DFC_PIXEL_FORMAT_YVYU422,
|
||||
DFC_PIXEL_FORMAT_VYUY422,
|
||||
DFC_PIXEL_FORMAT_UYVY422,
|
||||
};
|
||||
|
||||
enum dpe_dma_format {
|
||||
DMA_PIXEL_FORMAT_RGB_565 = 0,
|
||||
DMA_PIXEL_FORMAT_ARGB_4444,
|
||||
DMA_PIXEL_FORMAT_XRGB_4444,
|
||||
DMA_PIXEL_FORMAT_ARGB_5551,
|
||||
DMA_PIXEL_FORMAT_XRGB_5551,
|
||||
DMA_PIXEL_FORMAT_ARGB_8888,
|
||||
DMA_PIXEL_FORMAT_XRGB_8888,
|
||||
DMA_PIXEL_FORMAT_RESERVED0,
|
||||
DMA_PIXEL_FORMAT_YUYV_422_Pkg,
|
||||
DMA_PIXEL_FORMAT_YUV_420_SP_HP,
|
||||
DMA_PIXEL_FORMAT_YUV_420_P_HP,
|
||||
DMA_PIXEL_FORMAT_YUV_422_SP_HP,
|
||||
DMA_PIXEL_FORMAT_YUV_422_P_HP,
|
||||
DMA_PIXEL_FORMAT_AYUV_4444,
|
||||
};
|
||||
|
||||
enum dpe_fb_format {
|
||||
DPE_RGB_565 = 0,
|
||||
DPE_RGBX_4444,
|
||||
DPE_RGBA_4444,
|
||||
DPE_RGBX_5551,
|
||||
DPE_RGBA_5551,
|
||||
DPE_RGBX_8888,
|
||||
DPE_RGBA_8888,
|
||||
DPE_BGR_565,
|
||||
DPE_BGRX_4444,
|
||||
DPE_BGRA_4444,
|
||||
DPE_BGRX_5551,
|
||||
DPE_BGRA_5551,
|
||||
DPE_BGRX_8888,
|
||||
DPE_BGRA_8888,
|
||||
DPE_YUV_422_I,
|
||||
/* YUV Semi-planar */
|
||||
DPE_YCbCr_422_SP,
|
||||
DPE_YCrCb_422_SP,
|
||||
DPE_YCbCr_420_SP,
|
||||
DPE_YCrCb_420_SP,
|
||||
/* YUV Planar */
|
||||
DPE_YCbCr_422_P,
|
||||
DPE_YCrCb_422_P,
|
||||
DPE_YCbCr_420_P,
|
||||
DPE_YCrCb_420_P,
|
||||
/* YUV Package */
|
||||
DPE_YUYV_422_Pkg,
|
||||
DPE_UYVY_422_Pkg,
|
||||
DPE_YVYU_422_Pkg,
|
||||
DPE_VYUY_422_Pkg,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -293,9 +293,11 @@ static int kirin_drm_platform_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id kirin_drm_dt_ids[] = {
|
||||
#ifdef CONFIG_DRM_HISI_KIRIN620
|
||||
{ .compatible = "hisilicon,hi6220-ade",
|
||||
.data = &ade_driver_data,
|
||||
},
|
||||
#endif
|
||||
{ /* end node */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids);
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ struct kirin_drm_data {
|
|||
void (*cleanup_hw_ctx)(void *hw_ctx);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DRM_HISI_KIRIN620
|
||||
extern struct kirin_drm_data ade_driver_data;
|
||||
#endif
|
||||
|
||||
#endif /* __KIRIN_DRM_DRV_H__ */
|
||||
|
|
|
|||
424
drivers/gpu/drm/hisilicon/kirin/kirin_drm_dsi.c
Normal file
424
drivers/gpu/drm/hisilicon/kirin/kirin_drm_dsi.c
Normal file
|
|
@ -0,0 +1,424 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* DesignWare MIPI DSI Host Controller v1.02 driver
|
||||
*
|
||||
* Copyright (c) 2016 Linaro Limited.
|
||||
* Copyright (c) 2014-2016 Hisilicon Limited.
|
||||
*
|
||||
* Author:
|
||||
* <shizongxuan@huawei.com>
|
||||
* <zhangxiubin@huawei.com>
|
||||
* <lvda3@hisilicon.com>
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_encoder_slave.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_sysfs.h>
|
||||
|
||||
#include "kirin_drm_dsi.h"
|
||||
#include "dw_dsi_reg.h"
|
||||
|
||||
static struct kirin_dsi_ops *hisi_dsi_ops;
|
||||
|
||||
void dsi_set_output_client(struct drm_device *dev)
|
||||
{
|
||||
enum dsi_output_client client;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
struct dw_dsi *dsi;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
||||
/* find dsi encoder */
|
||||
drm_for_each_encoder(encoder, dev)
|
||||
if (encoder->encoder_type == DRM_MODE_ENCODER_DSI)
|
||||
break;
|
||||
dsi = encoder_to_dsi(encoder);
|
||||
|
||||
/* find HDMI connector */
|
||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter)
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
|
||||
break;
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
/*
|
||||
* set the proper dsi output client
|
||||
*/
|
||||
client = connector->status == connector_status_connected ? OUT_HDMI :
|
||||
OUT_PANEL;
|
||||
if (client != dsi->cur_client) {
|
||||
/*
|
||||
* set the switch ic to select the HDMI or MIPI_DSI
|
||||
*/
|
||||
if (hisi_dsi_ops->version == KIRIN960_DSI)
|
||||
gpiod_set_value_cansleep(dsi->gpio_mux, client);
|
||||
|
||||
dsi->cur_client = client;
|
||||
/* let the userspace know panel connector status has changed */
|
||||
drm_sysfs_hotplug_event(dev);
|
||||
DRM_INFO("client change to %s\n",
|
||||
client == OUT_HDMI ? "HDMI" : "panel");
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dsi_set_output_client);
|
||||
/************************for the panel attach to dsi*****************************/
|
||||
static int dsi_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct dw_dsi *dsi = connector_to_dsi(connector);
|
||||
|
||||
return drm_panel_get_modes(dsi->panel, connector);
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
dsi_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
enum drm_mode_status mode_status = MODE_OK;
|
||||
|
||||
return mode_status;
|
||||
}
|
||||
|
||||
static struct drm_encoder *
|
||||
dsi_connector_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct dw_dsi *dsi = connector_to_dsi(connector);
|
||||
|
||||
return &dsi->encoder;
|
||||
}
|
||||
|
||||
static struct drm_connector_helper_funcs dsi_connector_helper_funcs = {
|
||||
.get_modes = dsi_connector_get_modes,
|
||||
.mode_valid = dsi_connector_mode_valid,
|
||||
.best_encoder = dsi_connector_best_encoder,
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
dsi_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct dw_dsi *dsi = connector_to_dsi(connector);
|
||||
enum drm_connector_status status;
|
||||
|
||||
status = dsi->cur_client == OUT_PANEL ? connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void dsi_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_unregister(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static struct drm_connector_funcs dsi_atomic_connector_funcs = {
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.detect = dsi_connector_detect,
|
||||
.destroy = dsi_connector_destroy,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static int dsi_connector_init(struct drm_device *dev, struct dw_dsi *dsi)
|
||||
{
|
||||
struct drm_encoder *encoder = &dsi->encoder;
|
||||
struct drm_connector *connector = &dsi->connector;
|
||||
int ret;
|
||||
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
drm_connector_helper_add(connector, &dsi_connector_helper_funcs);
|
||||
|
||||
ret = drm_connector_init(dev, &dsi->connector,
|
||||
&dsi_atomic_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_connector_attach_encoder(connector, encoder);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
DRM_INFO("connector init\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/***************************for the encoder_helper_funcs****************************************/
|
||||
static const struct drm_encoder_funcs dw_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
/* do nothing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
dsi_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode)
|
||||
|
||||
{
|
||||
return hisi_dsi_ops->encoder_valid(encoder, mode);
|
||||
}
|
||||
|
||||
static void dsi_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
{
|
||||
struct dw_dsi *dsi = encoder_to_dsi(encoder);
|
||||
|
||||
drm_mode_copy(&dsi->cur_mode, adj_mode);
|
||||
}
|
||||
|
||||
static void dsi_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct dw_dsi *dsi = encoder_to_dsi(encoder);
|
||||
|
||||
if (dsi->enable)
|
||||
return;
|
||||
|
||||
hisi_dsi_ops->encoder_enable(encoder);
|
||||
|
||||
if (hisi_dsi_ops->version == KIRIN960_DSI) {
|
||||
/* turn on panel */
|
||||
if (dsi->panel && drm_panel_prepare(dsi->panel))
|
||||
DRM_ERROR("failed to prepare panel\n");
|
||||
|
||||
/*dw_dsi_set_mode(dsi, DSI_VIDEO_MODE);*/
|
||||
|
||||
/* turn on panel's back light */
|
||||
if (dsi->panel && drm_panel_enable(dsi->panel))
|
||||
DRM_ERROR("failed to enable panel\n");
|
||||
}
|
||||
|
||||
dsi->enable = true;
|
||||
}
|
||||
|
||||
static void dw_dsi_set_mode(struct dw_dsi *dsi, enum dsi_work_mode mode)
|
||||
{
|
||||
struct dsi_hw_ctx *ctx = dsi->ctx;
|
||||
void __iomem *base = ctx->base;
|
||||
|
||||
writel(RESET, base + PWR_UP);
|
||||
writel(mode, base + MODE_CFG);
|
||||
writel(POWERUP, base + PWR_UP);
|
||||
}
|
||||
|
||||
static void dsi_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct dw_dsi *dsi = encoder_to_dsi(encoder);
|
||||
struct dsi_hw_ctx *ctx = dsi->ctx;
|
||||
|
||||
if (!dsi->enable)
|
||||
return;
|
||||
|
||||
dw_dsi_set_mode(dsi, DSI_COMMAND_MODE);
|
||||
|
||||
if (hisi_dsi_ops->version == KIRIN960_DSI) {
|
||||
/* turn off panel's backlight */
|
||||
if (dsi->panel && drm_panel_disable(dsi->panel))
|
||||
DRM_ERROR("failed to disable panel\n");
|
||||
|
||||
/* turn off panel */
|
||||
if (dsi->panel && drm_panel_unprepare(dsi->panel))
|
||||
DRM_ERROR("failed to unprepare panel\n");
|
||||
|
||||
clk_disable_unprepare(ctx->dss_dphy0_ref_clk);
|
||||
clk_disable_unprepare(ctx->dss_dphy0_cfg_clk);
|
||||
clk_disable_unprepare(ctx->dss_pclk_dsi0_clk);
|
||||
}
|
||||
|
||||
dsi->enable = false;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs dw_encoder_helper_funcs = {
|
||||
.atomic_check = dsi_encoder_atomic_check,
|
||||
.mode_valid = dsi_encoder_mode_valid,
|
||||
.mode_set = dsi_encoder_mode_set,
|
||||
.enable = dsi_encoder_enable,
|
||||
.disable = dsi_encoder_disable
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
|
||||
{
|
||||
struct drm_encoder *encoder = &dsi->encoder;
|
||||
struct drm_bridge *bridge = dsi->bridge;
|
||||
int ret;
|
||||
|
||||
/* associate the bridge to dsi encoder */
|
||||
ret = drm_bridge_attach(encoder, bridge, NULL, 0);
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to attach external bridge\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_drm_encoder_init(struct device *dev, struct drm_device *drm_dev,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
int ret;
|
||||
u32 crtc_mask = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
|
||||
|
||||
if (!crtc_mask) {
|
||||
DRM_ERROR("failed to find crtc mask\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
encoder->possible_crtcs = crtc_mask;
|
||||
ret = drm_encoder_init(drm_dev, encoder, &dw_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DSI, NULL);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to init dsi encoder\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_encoder_helper_add(encoder, &dw_encoder_helper_funcs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct dsi_data *ddata = dev_get_drvdata(dev);
|
||||
struct dw_dsi *dsi = &ddata->dsi;
|
||||
struct drm_device *drm_dev = data;
|
||||
int ret;
|
||||
|
||||
DRM_INFO("+.\n");
|
||||
ret = dw_drm_encoder_init(dev, drm_dev, &dsi->encoder);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dsi->bridge) {
|
||||
ret = dsi_bridge_init(drm_dev, dsi);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (hisi_dsi_ops->version == KIRIN960_DSI) {
|
||||
if (dsi->panel) {
|
||||
ret = dsi_connector_init(drm_dev, dsi);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else if (hisi_dsi_ops->version == KIRIN620_DSI) {
|
||||
/*the panel for the kirin620 drm have not support*/
|
||||
}
|
||||
|
||||
DRM_INFO("-.\n");
|
||||
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_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dsi_data *data;
|
||||
struct dw_dsi *dsi;
|
||||
struct dsi_hw_ctx *ctx;
|
||||
int ret;
|
||||
|
||||
hisi_dsi_ops = (struct kirin_dsi_ops *)of_device_get_match_data(dev);
|
||||
|
||||
DRM_INFO("+.\n");
|
||||
data = devm_kzalloc(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;
|
||||
|
||||
if (hisi_dsi_ops == NULL)
|
||||
DRM_ERROR("hisi_dsi_ops is not bind\n");
|
||||
ret = hisi_dsi_ops->host_init(dev, dsi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hisi_dsi_ops->parse_dt(pdev, dsi);
|
||||
if (ret)
|
||||
goto err_host_unregister;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
ret = component_add(dev, &dsi_ops);
|
||||
if (ret)
|
||||
goto err_host_unregister;
|
||||
|
||||
DRM_INFO("-.\n");
|
||||
return 0;
|
||||
|
||||
err_host_unregister:
|
||||
mipi_dsi_host_unregister(&dsi->host);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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[] = {
|
||||
#ifdef CONFIG_DRM_HISI_KIRIN960
|
||||
{
|
||||
.compatible = "hisilicon,hi3660-dsi",
|
||||
.data = &kirin_dsi_960,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_HISI_KIRIN620
|
||||
{
|
||||
.compatible = "hisilicon,hi6220-dsi",
|
||||
.data = &kirin_dsi_620,
|
||||
},
|
||||
#endif
|
||||
{ /* end node */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dsi_of_match);
|
||||
|
||||
static struct platform_driver dsi_driver = {
|
||||
.probe = dsi_probe,
|
||||
.remove = dsi_remove,
|
||||
.driver = {
|
||||
.name = "dw-dsi",
|
||||
.of_match_table = dsi_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(dsi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("DesignWare MIPI DSI Host Controller v1.02 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
253
drivers/gpu/drm/hisilicon/kirin/kirin_drm_dsi.h
Normal file
253
drivers/gpu/drm/hisilicon/kirin/kirin_drm_dsi.h
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef __KIRIN_DRM_DSI_H__
|
||||
#define __KIRIN_DRM_DSI_H__
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <video/mipi_display.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <drm/drm_of.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 <drm/drm_panel.h>
|
||||
|
||||
#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
|
||||
#define PHY_REF_CLK_RATE 19200000
|
||||
#define PHY_REF_CLK_PERIOD_PS (1000000000 / (PHY_REF_CLK_RATE / 1000))
|
||||
|
||||
#define encoder_to_dsi(encoder) container_of(encoder, struct dw_dsi, encoder)
|
||||
#define host_to_dsi(host) container_of(host, struct dw_dsi, host)
|
||||
#define connector_to_dsi(connector) \
|
||||
container_of(connector, struct dw_dsi, connector)
|
||||
|
||||
enum dsi_output_client { OUT_HDMI = 0, OUT_PANEL, OUT_MAX };
|
||||
|
||||
struct dsi_phy_range {
|
||||
u32 min_range_kHz;
|
||||
u32 max_range_kHz;
|
||||
u32 pll_vco_750M;
|
||||
u32 hstx_ckg_sel;
|
||||
};
|
||||
|
||||
static const struct dsi_phy_range dphy_range_info[] = {
|
||||
{ 46875, 62500, 1, 7 },
|
||||
{ 62500, 93750, 0, 7 },
|
||||
{ 93750, 125000, 1, 6 },
|
||||
{ 125000, 187500, 0, 6 },
|
||||
{ 187500, 250000, 1, 5 },
|
||||
{ 250000, 375000, 0, 5 },
|
||||
{ 375000, 500000, 1, 4 },
|
||||
{ 500000, 750000, 0, 4 },
|
||||
{ 750000, 1000000, 1, 0 },
|
||||
{ 1000000, 1500000, 0, 0 }
|
||||
};
|
||||
|
||||
struct dsi_hw_ctx {
|
||||
void __iomem *base;
|
||||
char __iomem *peri_crg_base;
|
||||
|
||||
struct clk *pclk;
|
||||
struct clk *dss_dphy0_ref_clk;
|
||||
struct clk *dss_dphy1_ref_clk;
|
||||
struct clk *dss_dphy0_cfg_clk;
|
||||
struct clk *dss_dphy1_cfg_clk;
|
||||
struct clk *dss_pclk_dsi0_clk;
|
||||
struct clk *dss_pclk_dsi1_clk;
|
||||
};
|
||||
|
||||
struct mipi_panel_info {
|
||||
u8 dsi_version;
|
||||
u8 vc;
|
||||
u8 lane_nums;
|
||||
u8 lane_nums_select_support;
|
||||
u8 color_mode;
|
||||
u32 dsi_bit_clk; /* clock lane(p/n) */
|
||||
u32 burst_mode;
|
||||
u32 max_tx_esc_clk;
|
||||
u8 non_continue_en;
|
||||
|
||||
u32 dsi_bit_clk_val1;
|
||||
u32 dsi_bit_clk_val2;
|
||||
u32 dsi_bit_clk_val3;
|
||||
u32 dsi_bit_clk_val4;
|
||||
u32 dsi_bit_clk_val5;
|
||||
u32 dsi_bit_clk_upt;
|
||||
/*uint32_t dsi_pclk_rate;*/
|
||||
|
||||
u32 hs_wr_to_time;
|
||||
|
||||
/* dphy config parameter adjust*/
|
||||
u32 clk_post_adjust;
|
||||
u32 clk_pre_adjust;
|
||||
u32 clk_pre_delay_adjust;
|
||||
u32 clk_t_hs_exit_adjust;
|
||||
u32 clk_t_hs_trial_adjust;
|
||||
u32 clk_t_hs_prepare_adjust;
|
||||
int clk_t_lpx_adjust;
|
||||
u32 clk_t_hs_zero_adjust;
|
||||
u32 data_post_delay_adjust;
|
||||
int data_t_lpx_adjust;
|
||||
u32 data_t_hs_prepare_adjust;
|
||||
u32 data_t_hs_zero_adjust;
|
||||
u32 data_t_hs_trial_adjust;
|
||||
u32 rg_vrefsel_vcm_adjust;
|
||||
|
||||
/*only for Chicago<3660> use*/
|
||||
u32 rg_vrefsel_vcm_clk_adjust;
|
||||
u32 rg_vrefsel_vcm_data_adjust;
|
||||
};
|
||||
|
||||
struct mipi_phy_params {
|
||||
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 clk_division;
|
||||
/********for hikey620************/
|
||||
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;
|
||||
/*****************/
|
||||
|
||||
/****for hikey960*****/
|
||||
u64 lane_byte_clk;
|
||||
|
||||
u32 clk_lane_lp2hs_time;
|
||||
u32 clk_lane_hs2lp_time;
|
||||
u32 data_lane_lp2hs_time;
|
||||
u32 data_lane_hs2lp_time;
|
||||
u32 clk2data_delay;
|
||||
u32 data2clk_delay;
|
||||
|
||||
u32 clk_pre_delay;
|
||||
u32 clk_post_delay;
|
||||
u32 data_pre_delay;
|
||||
u32 data_post_delay;
|
||||
u32 phy_stop_wait_time;
|
||||
u32 rg_vrefsel_vcm;
|
||||
|
||||
u32 rg_pll_enswc;
|
||||
u32 rg_pll_chp;
|
||||
|
||||
u32 pll_register_override; /*0x1E[0]*/
|
||||
u32 pll_power_down; /*0x1E[1]*/
|
||||
u32 rg_band_sel; /*0x1E[2]*/
|
||||
u32 rg_phase_gen_en; /*0x1E[3]*/
|
||||
u32 reload_sel; /*0x1E[4]*/
|
||||
u32 rg_pll_cp_p; /*0x1E[7:5]*/
|
||||
u32 rg_pll_refsel; /*0x16[1:0]*/
|
||||
u32 rg_pll_cp; /*0x16[7:5]*/
|
||||
u32 load_command;
|
||||
/*********/
|
||||
};
|
||||
|
||||
struct ldi_panel_info {
|
||||
u32 h_back_porch;
|
||||
u32 h_front_porch;
|
||||
u32 h_pulse_width;
|
||||
|
||||
/*
|
||||
* note: vbp > 8 if used overlay compose,
|
||||
* also lcd vbp > 8 in lcd power on sequence
|
||||
*/
|
||||
u32 v_back_porch;
|
||||
u32 v_front_porch;
|
||||
u32 v_pulse_width;
|
||||
|
||||
u8 hsync_plr;
|
||||
u8 vsync_plr;
|
||||
u8 pixelclk_plr;
|
||||
u8 data_en_plr;
|
||||
|
||||
/* for cabc */
|
||||
u8 dpi0_overlap_size;
|
||||
u8 dpi1_overlap_size;
|
||||
};
|
||||
|
||||
struct dw_dsi_client {
|
||||
u32 lanes;
|
||||
u32 phy_clock; /* in kHz */
|
||||
enum mipi_dsi_pixel_format format;
|
||||
unsigned long mode_flags;
|
||||
};
|
||||
|
||||
struct dw_dsi {
|
||||
struct drm_encoder encoder;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_panel *panel;
|
||||
struct mipi_dsi_host host;
|
||||
struct drm_connector connector; /* connector for panel */
|
||||
struct drm_display_mode cur_mode;
|
||||
struct dsi_hw_ctx *ctx;
|
||||
struct mipi_phy_params phy;
|
||||
struct mipi_panel_info mipi;
|
||||
struct ldi_panel_info ldi;
|
||||
u32 lanes;
|
||||
enum mipi_dsi_pixel_format format;
|
||||
unsigned long mode_flags;
|
||||
struct gpio_desc *gpio_mux;
|
||||
struct dw_dsi_client client[OUT_MAX];
|
||||
enum dsi_output_client cur_client;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
struct dsi_data {
|
||||
struct dw_dsi dsi;
|
||||
struct dsi_hw_ctx ctx;
|
||||
};
|
||||
|
||||
enum kirin_dsi_version {
|
||||
KIRIN620_DSI = 0,
|
||||
KIRIN960_DSI
|
||||
};
|
||||
|
||||
/* display controller init/cleanup ops */
|
||||
struct kirin_dsi_ops {
|
||||
enum kirin_dsi_version version;
|
||||
int (*parse_dt)(struct platform_device *pdev, struct dw_dsi *dsi);
|
||||
int (*host_init)(struct device *dev, struct dw_dsi *dsi);
|
||||
void (*encoder_enable)(struct drm_encoder *encoder);
|
||||
enum drm_mode_status (*encoder_valid)(
|
||||
struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DRM_HISI_KIRIN960
|
||||
extern const struct kirin_dsi_ops kirin_dsi_960;
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_HISI_KIRIN620
|
||||
extern const struct kirin_dsi_ops kirin_dsi_620;
|
||||
#endif
|
||||
|
||||
#endif /* __KIRIN_DRM_DSI_H__ */
|
||||
Loading…
Reference in New Issue
Block a user