// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Unisoc Inc.
*/
#include <linux/component.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <video/mipi_display.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
#include "sprd_drm.h"
#include "sprd_dpu.h"
#include "sprd_dsi.h"
#define SOFT_RESET 0x04
#define MASK_PROTOCOL_INT 0x0C
#define MASK_INTERNAL_INT 0x14
#define DSI_MODE_CFG 0x18
#define VIRTUAL_CHANNEL_ID 0x1C
#define GEN_RX_VCID GENMASK(1, 0)
#define VIDEO_PKT_VCID GENMASK(3, 2)
#define DPI_VIDEO_FORMAT 0x20
#define DPI_VIDEO_MODE_FORMAT GENMASK(5, 0)
#define LOOSELY18_EN BIT(6)
#define VIDEO_PKT_CONFIG 0x24
#define VIDEO_PKT_SIZE GENMASK(15, 0)
#define VIDEO_LINE_CHUNK_NUM GENMASK(31, 16)
#define VIDEO_LINE_HBLK_TIME 0x28
#define VIDEO_LINE_HBP_TIME GENMASK(15, 0)
#define VIDEO_LINE_HSA_TIME GENMASK(31, 16)
#define VIDEO_LINE_TIME 0x2C
#define VIDEO_VBLK_LINES 0x30
#define VFP_LINES GENMASK(9, 0)
#define VBP_LINES GENMASK(19, 10)
#define VSA_LINES GENMASK(29, 20)
#define VIDEO_VACTIVE_LINES 0x34
#define VID_MODE_CFG 0x38
#define VID_MODE_TYPE GENMASK(1, 0)
#define LP_VSA_EN BIT(8)
#define LP_VBP_EN BIT(9)
#define LP_VFP_EN BIT(10)
#define LP_VACT_EN BIT(11)
#define LP_HBP_EN BIT(12)
#define LP_HFP_EN BIT(13)
#define FRAME_BTA_ACK_EN BIT(14)
#define TIMEOUT_CNT_CLK_CONFIG 0x40
#define HTX_TO_CONFIG 0x44
#define LRX_H_TO_CONFIG 0x48
#define TX_ESC_CLK_CONFIG 0x5C
#define CMD_MODE_CFG 0x68
#define TEAR_FX_EN BIT(0)
#define GEN_HDR 0x6C
#define GEN_DT GENMASK(5, 0)
#define GEN_VC GENMASK(7, 6)
#define GEN_PLD_DATA 0x70
#define PHY_CLK_LANE_LP_CTRL 0x74
#define PHY_CLKLANE_TX_REQ_HS BIT(0)
#define AUTO_CLKLANE_CTRL_EN BIT(1)
#define PHY_INTERFACE_CTRL 0x78
#define RF_PHY_SHUTDOWN BIT(0)
#define RF_PHY_RESET_N BIT(1)
#define RF_PHY_CLK_EN BIT(2)
#define CMD_MODE_STATUS 0x98
#define GEN_CMD_RDATA_FIFO_EMPTY BIT(1)
#define GEN_CMD_WDATA_FIFO_EMPTY BIT(3)
#define GEN_CMD_CMD_FIFO_EMPTY BIT(5)
#define GEN_CMD_RDCMD_DONE BIT(7)
#define PHY_STATUS 0x9C
#define PHY_LOCK BIT(1)
#define PHY_MIN_STOP_TIME 0xA0
#define PHY_LANE_NUM_CONFIG 0xA4
#define PHY_CLKLANE_TIME_CONFIG 0xA8
#define PHY_CLKLANE_LP_TO_HS_TIME GENMASK(15, 0)
#define PHY_CLKLANE_HS_TO_LP_TIME GENMASK(31, 16)
#define PHY_DATALANE_TIME_CONFIG 0xAC
#define PHY_DATALANE_LP_TO_HS_TIME GENMASK(15, 0)
#define PHY_DATALANE_HS_TO_LP_TIME GENMASK(31, 16)
#define MAX_READ_TIME 0xB0
#define RX_PKT_CHECK_CONFIG 0xB4
#define RX_PKT_ECC_EN BIT(0)
#define RX_PKT_CRC_EN BIT(1)
#define TA_EN 0xB8
#define EOTP_EN 0xBC
#define TX_EOTP_EN BIT(0)
#define RX_EOTP_EN BIT(1)
#define VIDEO_NULLPKT_SIZE 0xC0
#define DCS_WM_PKT_SIZE 0xC4
#define VIDEO_SIG_DELAY_CONFIG 0xD0
#define VIDEO_SIG_DELAY GENMASK(23, 0)
#define PHY_TST_CTRL0 0xF0
#define PHY_TESTCLR BIT(0)
#define PHY_TESTCLK BIT(1)
#define PHY_TST_CTRL1 0xF4
#define PHY_TESTDIN GENMASK(7, 0)
#define PHY_TESTDOUT GENMASK(15, 8)
#define PHY_TESTEN BIT(16)
#define host_to_dsi(host) \
container_of(host, struct sprd_dsi, host)
static inline u32
dsi_reg_rd(struct dsi_context *ctx, u32 offset, u32 mask,
u32 shift)
{
return (readl(ctx->base + offset) & mask) >> shift;
}
static inline void
dsi_reg_wr(struct dsi_context *ctx, u32 offset, u32 mask,
u32 shift, u32 val)
{
u32 ret;
ret = readl(ctx->base + offset);
ret &= ~mask;
ret |= (val << shift) & mask;
writel(ret, ctx->base + offset);
}
static inline void
dsi_reg_up(struct dsi_context *ctx, u32 offset, u32 mask,
u32 val)
{
u32 ret = readl(ctx->base + offset);
writel((ret & ~mask) | (val & mask), ctx->base + offset);
}
static int regmap_tst_io_write(void *context, u32 reg, u32 val)
{
struct sprd_dsi *dsi = context;
struct dsi_context *ctx = &dsi->ctx;
if (val > 0xff || reg > 0xff)
return -EINVAL;
drm_dbg(dsi->drm, "reg = 0x%02x, val = 0x%02x\n", reg, val);
dsi_reg_up(ctx, PHY_TST_CTRL1, PHY_TESTEN, PHY_TESTEN);
dsi_reg_wr(ctx, PHY_TST_CTRL1, PHY_TESTDIN, 0, reg);
dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, PHY_TESTCLK);
dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, 0);
dsi_reg_up(ctx, PHY_TST_CTRL1, PHY_TESTEN, 0);
dsi_reg_wr(ctx, PHY_TST_CTRL1, PHY_TESTDIN, 0, val);
dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, PHY_TESTCLK);
dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, 0);
return 0;
}
static int regmap_tst_io_read(void *context, u32 reg, u32 *val)
{
struct sprd_dsi *dsi = context;
struct dsi_context *ctx = &dsi->ctx;
int ret;
if (reg > 0xff)
return -EINVAL;
dsi_reg_up(ctx, PHY_TST_CTRL1, PHY_TESTEN, PHY_TESTEN);
dsi_reg_wr(ctx, PHY_TST_CTRL1, PHY_TESTDIN, 0, reg);
dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, PHY_TESTCLK);
dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, 0);
dsi_reg_up(ctx, PHY_TST_CTRL1, PHY_TESTEN, 0);
udelay(1);
ret = dsi_reg_rd(ctx, PHY_TST_CTRL1, PHY_TESTDOUT, 8);
if (ret < 0)
return ret;
*val = ret;
drm_dbg(dsi->drm, "reg = 0x%02x, val = 0x%02x\n", reg, *val);
return 0;
}
static struct regmap_bus regmap_tst_io = {
.reg_write = regmap_tst_io_write,
.reg_read = regmap_tst_io_read,
};
static const struct regmap_config byte_config = {
.reg_bits = 8,
.val_bits = 8,
};
static int dphy_wait_pll_locked(struct dsi_context *ctx)
{
struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
int i;
for (