
Add DSI CTL MISR support for ctl 2.2 version. Reuse the same debugfs nodes to setup/collect misr. Change-Id: I3d8dfab093659ce53817d9511999c0c03cc33f62 Signed-off-by: Veera Sundaram Sankaran <quic_veeras@quicinc.com>
351 行
9.1 KiB
C
351 行
9.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
|
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
#include <linux/iopoll.h>
|
|
#include "dsi_ctrl_hw.h"
|
|
#include "dsi_ctrl_reg.h"
|
|
#include "dsi_hw.h"
|
|
#include "dsi_ctrl.h"
|
|
#include "dsi_catalog.h"
|
|
|
|
#define DISP_CC_MISC_CMD_REG_OFF 0x00
|
|
|
|
/* register to configure DMA scheduling */
|
|
#define DSI_DMA_SCHEDULE_CTRL 0x100
|
|
#define DSI_DMA_SCHEDULE_CTRL2 0x0104
|
|
|
|
/* offset addresses of MDP INTF base register, to be mapped for debug feature */
|
|
#define MDP_INTF_TEAR_OFFSET 0x280
|
|
#define MDP_INTF_TEAR_LINE_COUNT_OFFSET 0x30
|
|
#define MDP_INTF_LINE_COUNT_OFFSET 0xB0
|
|
|
|
#define DSI_MDP_MISR_CTRL 0x364
|
|
#define DSI_MDP_MISR_SIGNATURE 0x368
|
|
|
|
void dsi_ctrl_hw_22_setup_lane_map(struct dsi_ctrl_hw *ctrl,
|
|
struct dsi_lane_map *lane_map)
|
|
{
|
|
u32 reg_value = lane_map->lane_map_v2[DSI_LOGICAL_LANE_0] |
|
|
(lane_map->lane_map_v2[DSI_LOGICAL_LANE_1] << 4) |
|
|
(lane_map->lane_map_v2[DSI_LOGICAL_LANE_2] << 8) |
|
|
(lane_map->lane_map_v2[DSI_LOGICAL_LANE_3] << 12);
|
|
|
|
DSI_W32(ctrl, DSI_LANE_SWAP_CTRL, reg_value);
|
|
|
|
DSI_CTRL_HW_DBG(ctrl, "[DSI_%d] Lane swap setup complete\n",
|
|
ctrl->index);
|
|
}
|
|
|
|
int dsi_ctrl_hw_22_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl,
|
|
u32 lanes)
|
|
{
|
|
int rc = 0, val = 0;
|
|
u32 fifo_empty_mask = 0;
|
|
u32 const sleep_us = 10;
|
|
u32 const timeout_us = 100;
|
|
|
|
if (lanes & DSI_DATA_LANE_0)
|
|
fifo_empty_mask |= (BIT(12) | BIT(16));
|
|
|
|
if (lanes & DSI_DATA_LANE_1)
|
|
fifo_empty_mask |= BIT(20);
|
|
|
|
if (lanes & DSI_DATA_LANE_2)
|
|
fifo_empty_mask |= BIT(24);
|
|
|
|
if (lanes & DSI_DATA_LANE_3)
|
|
fifo_empty_mask |= BIT(28);
|
|
|
|
DSI_CTRL_HW_DBG(ctrl, "%s: polling for fifo empty, mask=0x%08x\n",
|
|
__func__, fifo_empty_mask);
|
|
rc = DSI_READ_POLL_TIMEOUT(ctrl, DSI_FIFO_STATUS, val,
|
|
(val & fifo_empty_mask), sleep_us, timeout_us);
|
|
if (rc) {
|
|
DSI_CTRL_HW_ERR(ctrl,
|
|
"%s: fifo not empty, FIFO_STATUS=0x%08x\n",
|
|
__func__, val);
|
|
goto error;
|
|
}
|
|
error:
|
|
return rc;
|
|
}
|
|
|
|
ssize_t dsi_ctrl_hw_22_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
|
|
char *buf,
|
|
u32 size)
|
|
{
|
|
return size;
|
|
}
|
|
|
|
/**
|
|
* dsi_ctrl_hw_22_phy_reset_config() - to configure clamp control during ulps
|
|
* @ctrl: Pointer to the controller host hardware.
|
|
* @enable: boolean to specify enable/disable.
|
|
*/
|
|
void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl,
|
|
bool enable)
|
|
{
|
|
u32 reg = 0;
|
|
|
|
reg = DSI_DISP_CC_R32(ctrl, DISP_CC_MISC_CMD_REG_OFF);
|
|
|
|
/* Mask/unmask disable PHY reset bit */
|
|
if (enable)
|
|
reg &= ~BIT(ctrl->index);
|
|
else
|
|
reg |= BIT(ctrl->index);
|
|
DSI_DISP_CC_W32(ctrl, DISP_CC_MISC_CMD_REG_OFF, reg);
|
|
}
|
|
|
|
/**
|
|
* dsi_ctrl_hw_22_schedule_dma_cmd() - to schedule DMA command transfer
|
|
* @ctrl: Pointer to the controller host hardware.
|
|
* @line_no: Line number at which command needs to be sent.
|
|
*/
|
|
void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_no)
|
|
{
|
|
u32 reg = 0;
|
|
|
|
reg = DSI_R32(ctrl, DSI_DMA_SCHEDULE_CTRL);
|
|
reg |= BIT(28);
|
|
reg |= (line_no & 0xffff);
|
|
|
|
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, reg);
|
|
ctrl->reset_trig_ctrl = true;
|
|
}
|
|
|
|
/*
|
|
* dsi_ctrl_hw_kickoff_non_embedded_mode()-Kickoff cmd in non-embedded mode
|
|
* @ctrl: - Pointer to the controller host hardware.
|
|
* @dsi_ctrl_cmd_dma_info: - command buffer information.
|
|
* @flags: - DSI CTRL Flags.
|
|
*/
|
|
void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl,
|
|
struct dsi_ctrl_cmd_dma_info *cmd,
|
|
u32 flags)
|
|
{
|
|
u32 reg = 0;
|
|
|
|
reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL);
|
|
|
|
reg &= ~BIT(31);/* disable broadcast */
|
|
reg &= ~BIT(30);
|
|
|
|
if (cmd->use_lpm)
|
|
reg |= BIT(26);
|
|
else
|
|
reg &= ~BIT(26);
|
|
|
|
/* Select non EMBEDDED_MODE, pick the packet header from register */
|
|
reg &= ~BIT(28);
|
|
reg |= BIT(24);/* long packet */
|
|
reg |= BIT(29);/* wc_sel = 1 */
|
|
reg |= (((cmd->datatype) & 0x03f) << 16);/* data type */
|
|
DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg);
|
|
|
|
/* Enable WRITE_WATERMARK_DISABLE and READ_WATERMARK_DISABLE bits */
|
|
reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL);
|
|
reg |= BIT(20);
|
|
reg |= BIT(16);
|
|
reg |= 0x33;/* Set READ and WRITE watermark levels to maximum */
|
|
DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg);
|
|
|
|
DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset);
|
|
DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, ((cmd->length) & 0xFFFFFF));
|
|
|
|
/* wait for writes to complete before kick off */
|
|
wmb();
|
|
|
|
if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER))
|
|
DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1);
|
|
}
|
|
|
|
/*
|
|
* dsi_ctrl_hw_22_config_clk_gating() - enable/disable clk gating on DSI PHY
|
|
* @ctrl: Pointer to the controller host hardware.
|
|
* @enable: bool to notify enable/disable.
|
|
* @clk_selection: clock to enable/disable clock gating.
|
|
*
|
|
*/
|
|
void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable,
|
|
enum dsi_clk_gate_type clk_selection)
|
|
{
|
|
u32 reg = 0;
|
|
u32 enable_select = 0;
|
|
|
|
reg = DSI_DISP_CC_R32(ctrl, DISP_CC_MISC_CMD_REG_OFF);
|
|
|
|
if (clk_selection & PIXEL_CLK)
|
|
enable_select |= ctrl->index ? BIT(6) : BIT(5);
|
|
|
|
if (clk_selection & BYTE_CLK)
|
|
enable_select |= ctrl->index ? BIT(8) : BIT(7);
|
|
|
|
if (clk_selection & DSI_PHY)
|
|
enable_select |= ctrl->index ? BIT(10) : BIT(9);
|
|
|
|
if (enable)
|
|
reg |= enable_select;
|
|
else
|
|
reg &= ~enable_select;
|
|
|
|
DSI_DISP_CC_W32(ctrl, DISP_CC_MISC_CMD_REG_OFF, reg);
|
|
}
|
|
|
|
/**
|
|
* dsi_ctrl_hw_22_configure_cmddma_window() - configure DMA window for CMD TX
|
|
* @ctrl: Pointer to the controller host hardware.
|
|
* @cmd: Pointer to the DSI DMA command info.
|
|
* @line_no: Line number at which the CMD needs to be triggered.
|
|
* @window: Width of the DMA CMD window.
|
|
*/
|
|
void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl,
|
|
struct dsi_ctrl_cmd_dma_info *cmd,
|
|
u32 line_no, u32 window)
|
|
{
|
|
u32 reg = 0;
|
|
|
|
if (cmd->en_broadcast) {
|
|
reg = DSI_R32(ctrl, DSI_TRIG_CTRL);
|
|
if (cmd->is_master) {
|
|
reg &= ~0xF;
|
|
reg |= 0xc;
|
|
} else {
|
|
reg &= ~0xF;
|
|
reg |= BIT(16);
|
|
}
|
|
|
|
DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
|
|
|
|
if (cmd->is_master) {
|
|
reg = 0;
|
|
reg |= line_no;
|
|
reg |= window << 16;
|
|
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, reg);
|
|
}
|
|
} else {
|
|
reg = DSI_R32(ctrl, DSI_TRIG_CTRL);
|
|
reg &= ~0xF;
|
|
reg |= 0xc;
|
|
DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
|
|
|
|
reg = 0;
|
|
reg |= line_no;
|
|
reg |= window << 16;
|
|
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, reg);
|
|
}
|
|
ctrl->reset_trig_ctrl = true;
|
|
}
|
|
|
|
/**
|
|
* dsi_ctrl_hw_22_reset_trigger_controls() - reset dsi trigger configurations
|
|
* @ctrl: Pointer to the controller host hardware.
|
|
* @cfg: DSI host configuration that is common to both video and
|
|
* command modes.
|
|
*/
|
|
void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl,
|
|
struct dsi_host_common_cfg *cfg)
|
|
{
|
|
u32 reg = 0;
|
|
const u8 trigger_map[DSI_TRIGGER_MAX] = {
|
|
0x0, 0x2, 0x1, 0x4, 0x5, 0x6 };
|
|
|
|
reg |= (cfg->te_mode == DSI_TE_ON_EXT_PIN) ? BIT(31) : 0;
|
|
reg |= (trigger_map[cfg->dma_cmd_trigger] & 0x7);
|
|
reg |= (trigger_map[cfg->mdp_cmd_trigger] & 0x7) << 4;
|
|
DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
|
|
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, 0x0);
|
|
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, 0x0);
|
|
ctrl->reset_trig_ctrl = false;
|
|
}
|
|
|
|
/**
|
|
* dsi_ctrl_hw_22_log_line_count() - reads the MDP interface line count
|
|
* registers.
|
|
* @ctrl: Pointer to the controller host hardware.
|
|
* @cmd_mode: Boolean to indicate command mode operation.
|
|
*
|
|
* Return: INTF register value.
|
|
*/
|
|
u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode)
|
|
{
|
|
|
|
u32 reg = 0;
|
|
|
|
if (IS_ERR_OR_NULL(ctrl->mdp_intf_base))
|
|
return reg;
|
|
|
|
if (cmd_mode)
|
|
reg = DSI_MDP_INTF_R32(ctrl, MDP_INTF_TEAR_OFFSET
|
|
+ MDP_INTF_TEAR_LINE_COUNT_OFFSET);
|
|
else
|
|
reg = DSI_MDP_INTF_R32(ctrl, MDP_INTF_LINE_COUNT_OFFSET);
|
|
return reg;
|
|
}
|
|
|
|
void dsi_ctrl_hw_22_configure_splitlink(struct dsi_ctrl_hw *ctrl,
|
|
struct dsi_host_common_cfg *common_cfg, u32 flags)
|
|
{
|
|
u32 reg = 0;
|
|
|
|
reg = DSI_R32(ctrl, DSI_SPLIT_LINK);
|
|
|
|
/* DMA_LINK_SEL */
|
|
reg &= ~(0x7 << 12);
|
|
|
|
/* Send command to both sublinks unless specified */
|
|
if (flags & DSI_CTRL_CMD_SUBLINK0)
|
|
reg |= BIT(12);
|
|
else if (flags & DSI_CTRL_CMD_SUBLINK1)
|
|
reg |= BIT(13);
|
|
else
|
|
reg |= (BIT(12) | BIT(13));
|
|
|
|
/**
|
|
* Avoid dma trigger on sublink1 for read commands. This can be
|
|
* enabled in future if panel supports sending read command on sublink1.
|
|
*/
|
|
if (flags & DSI_CTRL_CMD_READ) {
|
|
reg = reg & ~BIT(13);
|
|
}
|
|
|
|
DSI_W32(ctrl, DSI_SPLIT_LINK, reg);
|
|
|
|
/* Make sure the split link config is updated */
|
|
wmb();
|
|
}
|
|
|
|
void dsi_ctrl_hw_22_setup_misr(struct dsi_ctrl_hw *ctrl, enum dsi_op_mode panel_mode,
|
|
bool enable, u32 frame_count)
|
|
{
|
|
u32 config = 0;
|
|
|
|
DSI_W32(ctrl, DSI_MDP_MISR_CTRL, config);
|
|
wmb(); /* clear misr data */
|
|
|
|
if (enable) {
|
|
config = (frame_count & 0xffff);
|
|
config |= BIT(8) | BIT(24) | BIT(31); /* enable, panel data-only, free run mode */
|
|
}
|
|
|
|
DSI_CTRL_HW_DBG(ctrl, "MISR enable:%d, frame_count:%d, config:0x%x\n",
|
|
enable, frame_count, config);
|
|
DSI_W32(ctrl, DSI_MDP_MISR_CTRL, config);
|
|
wmb(); /* make sure MISR is configured */
|
|
}
|
|
|
|
u32 dsi_ctrl_hw_22_collect_misr(struct dsi_ctrl_hw *ctrl, enum dsi_op_mode panel_mode)
|
|
{
|
|
u32 enabled;
|
|
u32 misr = 0;
|
|
|
|
enabled = DSI_R32(ctrl, DSI_MDP_MISR_CTRL) & BIT(8);
|
|
if (enabled)
|
|
misr = DSI_R32(ctrl, DSI_MDP_MISR_SIGNATURE);
|
|
|
|
DSI_CTRL_HW_DBG(ctrl, "MISR enabled:%d value:0x%x\n", enabled, misr);
|
|
return misr;
|
|
}
|