123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 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_hw,
- struct dsi_lane_map *lane_map)
- {
- struct dsi_ctrl *ctrl = container_of(ctrl_hw, struct dsi_ctrl, hw);
- u32 reg_value;
- /* Lane swap is performed through PHY for controller version 2.2/PHY versions 3.0 and above */
- if (ctrl->version >= DSI_CTRL_VERSION_2_2) {
- DSI_CTRL_HW_DBG(ctrl_hw, "DSI controller version is >=2.2, lane swap is performed through PHY");
- return;
- }
- 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_hw, DSI_LOGICAL_LANE_SWAP_CTRL, reg_value);
- DSI_CTRL_HW_DBG(ctrl_hw, "[DSI_%d] Lane swap setup complete\n",
- ctrl_hw->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;
- const u8 trigger_map[DSI_TRIGGER_MAX] = {
- 0x0, 0x2, 0x1, 0x4, 0x5, 0x6 };
- reg = DSI_R32(ctrl, DSI_TRIG_CTRL);
- reg &= ~BIT(16); /* Reset DMA_TRG_MUX */
- reg &= ~(0xF); /* Reset DMA_TRIGGER_SEL */
- reg |= (trigger_map[cfg->dma_cmd_trigger] & 0xF);
- 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;
- }
|