[PATCH 11/12] drm/rockchip: added implementation for a few FW commands.

From: Damian Kos
Date: Tue Jul 03 2018 - 06:04:16 EST


Added support for a register read, register write and register field write
commands.
Added support for adjust link training command.
Updated cdn_dp_get_event function, so it reads all SW event registers.
Added definitions mostly for Framer and Streamer.

Signed-off-by: Damian Kos <dkos@xxxxxxxxxxx>
---
drivers/gpu/drm/rockchip/cdn-dp-reg.c | 167 ++++++++++++++++++++++++++++++++-
drivers/gpu/drm/rockchip/cdn-dp-reg.h | 143 +++++++++++++++++++++++++++-
2 files changed, 305 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
index eb3042c..b061cfc 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
@@ -410,7 +410,10 @@ int cdn_dp_event_config(struct cdn_dp_device *dp)

u32 cdn_dp_get_event(struct cdn_dp_device *dp)
{
- return readl(dp->regs + SW_EVENTS0);
+ return readl(dp->regs + SW_EVENTS0)
+ | (readl(dp->regs + SW_EVENTS1) << 8)
+ | (readl(dp->regs + SW_EVENTS2) << 16)
+ | (readl(dp->regs + SW_EVENTS3) << 24);
}

int cdn_dp_get_hpd_status(struct cdn_dp_device *dp)
@@ -981,3 +984,165 @@ int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio)
DRM_DEV_ERROR(dp->dev, "audio config failed: %d\n", ret);
return ret;
}
+
+int cdn_dp_register_read(struct cdn_dp_device *dp, u32 addr, u32 *value)
+{
+ u8 msg[4], resp[8];
+ int ret;
+
+ if (addr == 0) {
+ ret = -EINVAL;
+ goto err_register_read;
+ }
+
+ msg[0] = (u8)(addr >> 24);
+ msg[1] = (u8)(addr >> 16);
+ msg[2] = (u8)(addr >> 8);
+ msg[3] = (u8)addr;
+
+ ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_GENERAL,
+ GENERAL_REGISTER_READ,
+ sizeof(msg), msg);
+ if (ret)
+ goto err_register_read;
+
+ ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_GENERAL,
+ GENERAL_REGISTER_READ,
+ sizeof(resp));
+ if (ret)
+ goto err_register_read;
+
+ ret = cdn_dp_mailbox_read_receive(dp, resp, sizeof(resp));
+ if (ret)
+ goto err_register_read;
+
+ /* Returned address value should be the same as requested */
+ if (memcmp(msg, resp, sizeof(msg))) {
+ ret = -EINVAL;
+ goto err_register_read;
+ }
+
+ *value = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7];
+
+err_register_read:
+ if (ret) {
+ DRM_DEV_ERROR(dp->dev, "Failed to read register.\n");
+ *value = 0;
+ }
+
+ return ret;
+}
+
+int cdn_dp_register_write(struct cdn_dp_device *dp, u32 addr, u32 value)
+{
+ u8 msg[8];
+ int ret;
+
+ if (addr == 0)
+ return -EINVAL;
+
+ msg[0] = (u8)(addr >> 24);
+ msg[1] = (u8)(addr >> 16);
+ msg[2] = (u8)(addr >> 8);
+ msg[3] = (u8)addr;
+ msg[4] = (u8)(value >> 24);
+ msg[5] = (u8)(value >> 16);
+ msg[6] = (u8)(value >> 8);
+ msg[7] = (u8)value;
+
+ ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_GENERAL,
+ GENERAL_REGISTER_WRITE,
+ sizeof(msg), msg);
+ if (ret)
+ DRM_DEV_ERROR(dp->dev, "Failed to write register.\n");
+
+ return ret;
+}
+
+int cdn_dp_register_write_field(struct cdn_dp_device *dp, u32 addr,
+ u8 index, u8 nbits, u32 value)
+{
+ u8 msg[10];
+ int ret;
+
+ if (addr == 0)
+ return -EINVAL;
+
+ msg[0] = (u8)(addr >> 24);
+ msg[1] = (u8)(addr >> 16);
+ msg[2] = (u8)(addr >> 8);
+ msg[3] = (u8)addr;
+ msg[4] = index;
+ msg[5] = nbits;
+ msg[6] = (u8)(value >> 24);
+ msg[7] = (u8)(value >> 16);
+ msg[8] = (u8)(value >> 8);
+ msg[9] = (u8)value;
+
+ ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_GENERAL,
+ GENERAL_REGISTER_WRITE_FIELD,
+ sizeof(msg), msg);
+ if (ret)
+ DRM_DEV_ERROR(dp->dev, "Failed to write register field.\n");
+
+ return ret;
+}
+/* rep should be a pointer already allocated with .regs of size 6 */
+int cdn_dp_adjust_lt(struct cdn_dp_device *dp, u8 nlanes,
+ u16 udelay, u8 *lanes_data,
+ u8 *dpcd)
+{
+ u8 payload[10];
+ u8 hdr[5]; /* For DPCD read response header */
+ u32 addr;
+ u8 const nregs = 6; /* Registers 0x202-0x207 */
+ int ret;
+
+ if (nlanes != 4 && nlanes != 2 && nlanes != 1) {
+ DRM_DEV_ERROR(dp->dev, "invalid number of lanes: %d\n", nlanes);
+ ret = -EINVAL;
+ goto err_adjust_lt;
+ }
+
+ payload[0] = nlanes;
+ payload[1] = (u8)(udelay >> 8);
+ payload[2] = (u8)udelay;
+
+ payload[3] = lanes_data[0];
+ if (nlanes > 1)
+ payload[4] = lanes_data[1];
+ if (nlanes > 2) {
+ payload[5] = lanes_data[2];
+ payload[6] = lanes_data[3];
+ }
+
+ ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX,
+ DPTX_ADJUST_LT,
+ sizeof(payload), payload);
+ if (ret)
+ goto err_adjust_lt;
+
+ /* Yes, read the DPCD read command response */
+ ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
+ DPTX_READ_DPCD,
+ sizeof(hdr) + nregs);
+ if (ret)
+ goto err_adjust_lt;
+
+ ret = cdn_dp_mailbox_read_receive(dp, hdr, sizeof(hdr));
+ if (ret)
+ goto err_adjust_lt;
+
+ addr = (hdr[2] << 24) | (hdr[3] << 8) | hdr[4];
+ if (addr != DP_LANE0_1_STATUS)
+ goto err_adjust_lt;
+
+ ret = cdn_dp_mailbox_read_receive(dp, dpcd, nregs);
+
+err_adjust_lt:
+ if (ret)
+ DRM_DEV_ERROR(dp->dev, "Failed to adjust Link Training.\n");
+
+ return ret;
+}
+
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
index c4bbb4a..b5472ad 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
@@ -156,6 +156,14 @@
#define DP_FRONT_BACK_PORCH 0x2278
#define DP_BYTE_COUNT 0x227c

+/* dptx framer global config fields */
+#define DP_FRAMER_NUM_LANES(x) (x - 1)
+#define DP_FRAMER_EN BIT(3)
+#define DP_FRAMER_RATE_GOVERNOR_EN BIT(4)
+#define DP_FRAMER_NO_VIDEO_MODE BIT(5)
+#define DP_FRAMER_DISABLE_PHY_RST BIT(6)
+#define DP_FRAMER_WR_FAILING_EDGE_VSYNC BIT(7)
+
/* dptx stream addr */
#define MSA_HORIZONTAL_0 0x2280
#define MSA_HORIZONTAL_1 0x2284
@@ -323,10 +331,13 @@
#define MB_MODULE_ID_GENERAL 0x0a

/* general opcode */
-#define GENERAL_MAIN_CONTROL 0x01
-#define GENERAL_TEST_ECHO 0x02
-#define GENERAL_BUS_SETTINGS 0x03
-#define GENERAL_TEST_ACCESS 0x04
+#define GENERAL_MAIN_CONTROL 0x01
+#define GENERAL_TEST_ECHO 0x02
+#define GENERAL_BUS_SETTINGS 0x03
+#define GENERAL_TEST_ACCESS 0x04
+#define GENERAL_REGISTER_WRITE 0x05
+#define GENERAL_REGISTER_WRITE_FIELD 0x06
+#define GENERAL_REGISTER_READ 0x07

#define DPTX_SET_POWER_MNG 0x00
#define DPTX_SET_HOST_CAPABILITIES 0x01
@@ -346,6 +357,7 @@
#define DPTX_SET_LINK_BREAK_POINT 0x0f
#define DPTX_FORCE_LANES 0x10
#define DPTX_HPD_STATE 0x11
+#define DPTX_ADJUST_LT 0x12

#define FW_STANDBY 0
#define FW_ACTIVE 1
@@ -424,6 +436,122 @@
/* Reference cycles when using lane clock as reference */
#define LANE_REF_CYC 0x8000

+#define CDN_DPTX_FRAMER 0x02200
+#define CDN_DP_FRAMER_GLOBAL_CONFIG (CDN_DPTX_FRAMER + 0x00)
+#define CDN_DP_NUM_LANES(x) (x - 1)
+#define CDN_DP_FRAMER_EN BIT(3)
+#define CDN_DP_RATE_GOVERNOR_EN BIT(4)
+#define CDN_DP_NO_VIDEO_MODE BIT(5)
+#define CDN_DP_DISABLE_PHY_RST BIT(6)
+#define CDN_DP_WR_FAILING_EDGE_VSYNC BIT(7)
+
+#define CDN_DP_SW_RESET (CDN_DPTX_FRAMER + 0x04)
+#define CDN_DP_FRAMER_TU (CDN_DPTX_FRAMER + 0x08)
+#define CDN_DP_FRAMER_TU_SIZE(x) (((x) & GENMASK(6, 0)) << 8)
+#define CDN_DP_FRAMER_TU_VS(x) ((x) & GENMASK(5, 0))
+#define CDN_DP_FRAMER_TU_CNT_RST_EN BIT(15)
+
+#define CDN_DPTX_STREAM 0x03000
+#define CDN_DP_MSA_HORIZONTAL_0 (CDN_DPTX_STREAM + 0x00)
+#define CDN_DP_MSAH0_H_TOTAL(x) (x)
+#define CDN_DP_MSAH0_HSYNC_START(x) ((x) << 16)
+
+#define CDN_DP_MSA_HORIZONTAL_1 (CDN_DPTX_STREAM + 0x04)
+#define CDN_DP_MSAH1_HSYNC_WIDTH(x) (x)
+#define CDN_DP_MSAH1_HSYNC_POL_LOW BIT(15)
+#define CDN_DP_MSAH1_HDISP_WIDTH(x) ((x) << 16)
+
+#define CDN_DP_MSA_VERTICAL_0 (CDN_DPTX_STREAM + 0x08)
+#define CDN_DP_MSAV0_V_TOTAL(x) (x)
+#define CDN_DP_MSAV0_VSYNC_START(x) ((x) << 16)
+
+#define CDN_DP_MSA_VERTICAL_1 (CDN_DPTX_STREAM + 0x0c)
+#define CDN_DP_MSAV1_VSYNC_WIDTH(x) (x)
+#define CDN_DP_MSAV1_VSYNC_POL_LOW BIT(15)
+#define CDN_DP_MSAV1_VDISP_WIDTH(x) ((x) << 16)
+
+#define CDN_DP_MSA_MISC (CDN_DPTX_STREAM + 0x10)
+#define CDN_DP_STREAM_CONFIG (CDN_DPTX_STREAM + 0x14)
+#define CDN_DP_RATE_GOVERNOR_STATUS (CDN_DPTX_STREAM + 0x2c)
+#define CDN_DP_RG_TU_VS_DIFF(x) ((x) << 8)
+
+#define CDN_DP_HORIZONTAL (CDN_DPTX_STREAM + 0x30)
+#define CDN_DP_H_HSYNC_WIDTH(x) (x)
+#define CDN_DP_H_H_TOTAL(x) ((x) << 16)
+
+#define CDN_DP_VERTICAL_0 (CDN_DPTX_STREAM + 0x34)
+#define CDN_DP_V0_VHEIGHT(x) (x)
+#define CDN_DP_V0_VSTART(x) ((x) << 16)
+
+#define CDN_DP_VERTICAL_1 (CDN_DPTX_STREAM + 0x38)
+#define CDN_DP_V1_VTOTAL(x) (x)
+#define CDN_DP_V1_VTOTAL_EVEN BIT(16)
+
+#define CDN_DP_FRAMER_PXL_REPR (CDN_DPTX_STREAM + 0x4c)
+#define CDN_DP_FRAMER_6_BPC BIT(0)
+#define CDN_DP_FRAMER_8_BPC BIT(1)
+#define CDN_DP_FRAMER_10_BPC BIT(2)
+#define CDN_DP_FRAMER_12_BPC BIT(3)
+#define CDN_DP_FRAMER_16_BPC BIT(4)
+#define CDN_DP_FRAMER_PXL_FORMAT 0x8
+#define CDN_DP_FRAMER_RGB BIT(0)
+#define CDN_DP_FRAMER_YCBCR444 BIT(1)
+#define CDN_DP_FRAMER_YCBCR422 BIT(2)
+#define CDN_DP_FRAMER_YCBCR420 BIT(3)
+#define CDN_DP_FRAMER_Y_ONLY BIT(4)
+
+#define CDN_DP_FRAMER_SP (CDN_DPTX_STREAM + 0x10)
+#define CDN_DP_FRAMER_VSYNC_POL_LOW BIT(0)
+#define CDN_DP_FRAMER_HSYNC_POL_LOW BIT(1)
+#define CDN_DP_FRAMER_INTERLACE BIT(2)
+
+#define CDN_DP_LINE_THRESH (CDN_DPTX_STREAM + 0x64)
+#define CDN_DP_VB_ID (CDN_DPTX_STREAM + 0x68)
+#define CDN_DP_VB_ID_INTERLACED BIT(2)
+
+#define CDN_DP_FRONT_BACK_PORCH (CDN_DPTX_STREAM + 0x78)
+#define CDN_DP_BACK_PORCH(x) (x)
+#define CDN_DP_FRONT_PORCH(x) ((x) << 16)
+
+#define CDN_DP_BYTE_COUNT (CDN_DPTX_STREAM + 0x7c)
+
+#define CDN_DPTX_GLOBAL 0x02300
+#define CDN_DP_LANE_EN (CDN_DPTX_GLOBAL + 0x00)
+#define CDN_DP_LANE_EN_LANES(x) GENMASK(x - 1, 0)
+#define CDN_DP_ENHNCD (CDN_DPTX_GLOBAL + 0x04)
+
+#define CDN_SOURCE_VIDEO_INTERFACE 0x00b00
+#define CDN_BND_HSYNC2VSYNC (CDN_SOURCE_VIDEO_INTERFACE + 0x00)
+#define CDN_IP_DTCT_WIN GENMASK(11, 0)
+#define CDN_IP_DET_INTERLACE_FORMAT BIT(12)
+#define CDN_IP_BYPASS_V_INTERFACE BIT(13)
+
+#define CDN_HSYNC2VSYNC_POL_CTRL (CDN_SOURCE_VIDEO_INTERFACE + 0x10)
+#define CDN_H2V_HSYNC_POL_ACTIVE_LOW BIT(1)
+#define CDN_H2V_VSYNC_POL_ACTIVE_LOW BIT(2)
+
+#define CDN_DPTX_PHY_CONFIG 0x02000
+#define CDN_PHY_TRAINING_EN BIT(0)
+#define CDN_PHY_TRAINING_TYPE(x) (((x) & GENMASK(3, 0)) << 1)
+#define CDN_PHY_SCRAMBLER_BYPASS BIT(5)
+#define CDN_PHY_ENCODER_BYPASS BIT(6)
+#define CDN_PHY_SKEW_BYPASS BIT(7)
+#define CDN_PHY_TRAINING_AUTO BIT(8)
+#define CDN_PHY_LANE0_SKEW(x) (((x) & GENMASK(2, 0)) << 9)
+#define CDN_PHY_LANE1_SKEW(x) (((x) & GENMASK(2, 0)) << 12)
+#define CDN_PHY_LANE2_SKEW(x) (((x) & GENMASK(2, 0)) << 15)
+#define CDN_PHY_LANE3_SKEW(x) (((x) & GENMASK(2, 0)) << 18)
+#define CDN_PHY_COMMON_CONFIG (CDN_PHY_LANE1_SKEW(1) | CDN_PHY_LANE2_SKEW(2) | CDN_PHY_LANE3_SKEW(3))
+#define CDN_PHY_10BIT_EN BIT(21)
+
+#define CDN_PRE_EMPHASIS(x) ((x) & GENMASK(1, 0))
+#define CDN_FORCE_PRE_EMPHASIS BIT(2)
+
+#define CDN_VOLT_SWING(x) ((x) & GENMASK(1, 0))
+#define CDN_FORCE_VOLT_SWING BIT(2)
+
+#define CDN_DP_TRAINING_PATTERN_4 0x7
+
enum voltage_swing_level {
VOLTAGE_LEVEL_0,
VOLTAGE_LEVEL_1,
@@ -479,4 +607,11 @@ int cdn_dp_get_edid_block(void *dp, u8 *edid,
int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio);
int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable);
int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio);
+int cdn_dp_register_read(struct cdn_dp_device *dp, u32 addr, u32 *value);
+int cdn_dp_register_write(struct cdn_dp_device *dp, u32 addr, u32 value);
+int cdn_dp_register_write_field(struct cdn_dp_device *dp, u32 addr,
+ u8 index, u8 nbits, u32 value);
+int cdn_dp_adjust_lt(struct cdn_dp_device *dp, u8 nlanes,
+ u16 udelay, u8 *lanes_data,
+ u8 *dpcd);
#endif /* _CDN_DP_REG_H */
--
1.7.1