Loading drivers/gpu/drm/msm/dp/dp_aux.c +139 −312 Original line number Diff line number Diff line Loading @@ -20,14 +20,8 @@ #define DP_AUX_ENUM_STR(x) #x struct aux_buf { u8 *start; /* buffer start addr */ u8 *end; /* buffer end addr */ u8 *data; /* data pou32er */ u32 size; /* size of buffer */ u32 len; /* dara length */ u8 trans_num; /* transaction number */ enum aux_tx_mode tx_mode; enum { DP_AUX_DATA_INDEX_WRITE = BIT(31), }; struct dp_aux_private { Loading @@ -38,15 +32,12 @@ struct dp_aux_private { struct mutex mutex; struct completion comp; struct aux_cmd *cmds; struct aux_buf txp; struct aux_buf rxp; u32 aux_error_num; bool cmd_busy; bool native; bool read; u8 txbuf[256]; u8 rxbuf[256]; struct drm_dp_aux drm_aux; }; static char *dp_aux_get_error(u32 aux_error) Loading @@ -69,159 +60,104 @@ static char *dp_aux_get_error(u32 aux_error) } } static void dp_aux_buf_init(struct aux_buf *buf, u8 *data, u32 size) { buf->start = data; buf->size = size; buf->data = buf->start; buf->end = buf->start + buf->size; buf->len = 0; buf->trans_num = 0; buf->tx_mode = AUX_NATIVE; } static void dp_aux_buf_set(struct dp_aux_private *aux) { init_completion(&aux->comp); aux->cmd_busy = false; mutex_init(&aux->mutex); dp_aux_buf_init(&aux->txp, aux->txbuf, sizeof(aux->txbuf)); dp_aux_buf_init(&aux->rxp, aux->rxbuf, sizeof(aux->rxbuf)); } static void dp_aux_buf_reset(struct aux_buf *buf) { buf->data = buf->start; buf->len = 0; buf->trans_num = 0; buf->tx_mode = AUX_NATIVE; memset(buf->start, 0x0, 256); } static void dp_aux_buf_push(struct aux_buf *buf, u32 len) { buf->data += len; buf->len += len; } static u32 dp_aux_buf_trailing(struct aux_buf *buf) { return (u32)(buf->end - buf->data); } static u32 dp_aux_add_cmd(struct aux_buf *buf, struct aux_cmd *cmd) static u32 dp_aux_write(struct dp_aux_private *aux, struct drm_dp_aux_msg *msg) { u8 data; u8 *bp, *cp; u32 i, len; u32 data[4], reg, len; u8 *msgdata = msg->buffer; int const aux_cmd_fifo_len = 128; int i = 0; if (cmd->ex_mode == AUX_READ) if (aux->read) len = 4; else len = cmd->len + 4; if (dp_aux_buf_trailing(buf) < len) { pr_err("buf trailing error\n"); return 0; } len = msg->size + 4; /* * cmd fifo only has depth of 144 bytes * limit buf length to 128 bytes here */ if ((buf->len + len) > 128) { if (len > aux_cmd_fifo_len) { pr_err("buf len error\n"); return 0; } bp = buf->data; data = cmd->addr >> 16; data &= 0x0f; /* 4 addr bits */ if (cmd->ex_mode == AUX_READ) data |= BIT(4); *bp++ = data; *bp++ = cmd->addr >> 8; *bp++ = cmd->addr; *bp++ = cmd->len - 1; /* Pack cmd and write to HW */ data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */ if (aux->read) data[0] |= BIT(4); /* R/W */ if (cmd->ex_mode == AUX_WRITE) { cp = cmd->buf; data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */ data[2] = msg->address & 0xff; /* addr[7:0] */ data[3] = (msg->size - 1) & 0xff; /* len[7:0] */ for (i = 0; i < cmd->len; i++) *bp++ = *cp++; for (i = 0; i < len; i++) { reg = (i < 4) ? data[i] : msgdata[i - 4]; reg = ((reg) << 8) & 0x0000ff00; /* index = 0, write */ if (i == 0) reg |= DP_AUX_DATA_INDEX_WRITE; aux->catalog->data = reg; aux->catalog->write_data(aux->catalog); } dp_aux_buf_push(buf, len); buf->tx_mode = cmd->tx_mode; reg = 0; /* Transaction number == 1 */ if (!aux->native) /* i2c */ reg |= (BIT(8) | BIT(10) | BIT(11)); buf->trans_num++; reg |= BIT(9); aux->catalog->data = reg; aux->catalog->write_trans(aux->catalog); return cmd->len - 1; return len; } static u32 dp_aux_cmd_fifo_tx(struct dp_aux_private *aux) static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, struct drm_dp_aux_msg *msg) { u8 *dp; u32 data, len, cnt; struct aux_buf *tp = &aux->txp; u32 ret = 0, len = 0, timeout; int const aux_timeout_ms = HZ/4; reinit_completion(&aux->comp); len = tp->len; len = dp_aux_write(aux, msg); if (len == 0) { pr_err("invalid len\n"); return 0; pr_err("DP AUX write failed\n"); return -EINVAL; } cnt = 0; dp = tp->start; while (cnt < len) { data = *dp; data <<= 8; data &= 0x00ff00; if (cnt == 0) data |= BIT(31); aux->catalog->data = data; aux->catalog->write_data(aux->catalog); cnt++; dp++; timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms); if (!timeout) { pr_err("aux write timeout\n"); return -ETIMEDOUT; } data = (tp->trans_num - 1); if (tp->tx_mode == AUX_I2C) { data |= BIT(8); /* I2C */ data |= BIT(10); /* NO SEND ADDR */ data |= BIT(11); /* NO SEND STOP */ } pr_debug("aux status %s\n", dp_aux_get_error(aux->aux_error_num)); data |= BIT(9); /* GO */ aux->catalog->data = data; aux->catalog->write_trans(aux->catalog); if (aux->aux_error_num == DP_AUX_ERR_NONE) ret = len; else ret = -EINVAL; return tp->len; return ret; } static u32 dp_cmd_fifo_rx(struct dp_aux_private *aux, u32 len) static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux, struct drm_dp_aux_msg *msg) { u32 data; u8 *dp; u32 i; struct aux_buf *rp = &aux->rxp; u32 len = msg->size; data = 0; data |= BIT(31); /* INDEX_WRITE */ data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */ data |= BIT(0); /* read */ aux->catalog->data = data; aux->catalog->write_data(aux->catalog); dp = rp->data; dp = msg->buffer; /* discard first byte */ data = aux->catalog->read_data(aux->catalog); Loading @@ -230,9 +166,6 @@ static u32 dp_cmd_fifo_rx(struct dp_aux_private *aux, u32 len) data = aux->catalog->read_data(aux->catalog); *dp++ = (u8)((data >> 8) & 0xff); } rp->len = len; return len; } static void dp_aux_native_handler(struct dp_aux_private *aux) Loading Loading @@ -292,236 +225,133 @@ static void dp_aux_isr(struct dp_aux *dp_aux) if (!aux->cmd_busy) return; if (aux->cmds->tx_mode == AUX_NATIVE) if (aux->native) dp_aux_native_handler(aux); else dp_aux_i2c_handler(aux); } static int dp_aux_write(struct dp_aux_private *aux) /* * This function does the real job to process an AUX transaction. * It will call aux_reset() function to reset the AUX channel, * if the waiting is timeout. */ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg) { struct aux_cmd *cm; struct aux_buf *tp; u32 len, ret, timeout; ssize_t ret; int const aux_cmd_native_max = 16; int const aux_cmd_i2c_max = 128; struct dp_aux_private *aux = container_of(drm_aux, struct dp_aux_private, drm_aux); mutex_lock(&aux->mutex); tp = &aux->txp; dp_aux_buf_reset(tp); cm = aux->cmds; while (cm) { ret = dp_aux_add_cmd(tp, cm); if (ret <= 0) break; if (!cm->next) break; cm++; } reinit_completion(&aux->comp); aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); aux->cmd_busy = true; len = dp_aux_cmd_fifo_tx(aux); timeout = wait_for_completion_timeout(&aux->comp, HZ/4); if (!timeout) pr_err("aux write timeout\n"); pr_debug("aux status %s\n", dp_aux_get_error(aux->aux_error_num)); if (aux->aux_error_num == DP_AUX_ERR_NONE) ret = len; else ret = aux->aux_error_num; aux->cmd_busy = false; mutex_unlock(&aux->mutex); return ret; /* Ignore address only message */ if ((msg->size == 0) || (msg->buffer == NULL)) { msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; ret = msg->size; goto unlock_exit; } static int dp_aux_read(struct dp_aux_private *aux) { struct aux_cmd *cm; struct aux_buf *tp, *rp; u32 len, ret, timeout; mutex_lock(&aux->mutex); tp = &aux->txp; rp = &aux->rxp; dp_aux_buf_reset(tp); dp_aux_buf_reset(rp); cm = aux->cmds; len = 0; while (cm) { ret = dp_aux_add_cmd(tp, cm); len += cm->len; if (ret <= 0) break; if (!cm->next) break; cm++; /* msg sanity check */ if ((aux->native && (msg->size > aux_cmd_native_max)) || (msg->size > aux_cmd_i2c_max)) { pr_err("%s: invalid msg: size(%zu), request(%x)\n", __func__, msg->size, msg->request); ret = -EINVAL; goto unlock_exit; } reinit_completion(&aux->comp); aux->cmd_busy = true; dp_aux_cmd_fifo_tx(aux); ret = dp_aux_cmd_fifo_tx(aux, msg); if (ret < 0) { aux->catalog->reset(aux->catalog); /* reset aux */ goto unlock_exit; } timeout = wait_for_completion_timeout(&aux->comp, HZ/4); if (!timeout) pr_err("aux read timeout\n"); if (aux->aux_error_num == DP_AUX_ERR_NONE) { if (aux->read) dp_aux_cmd_fifo_rx(aux, msg); pr_debug("aux status %s\n", dp_aux_get_error(aux->aux_error_num)); msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; } else { /* Reply defer to retry */ msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER; } if (aux->aux_error_num == DP_AUX_ERR_NONE) ret = dp_cmd_fifo_rx(aux, len); else ret = aux->aux_error_num; /* Return requested size for success or retry */ ret = msg->size; aux->cmds->buf = rp->data; unlock_exit: aux->cmd_busy = false; mutex_unlock(&aux->mutex); return ret; } static int dp_aux_write_ex(struct dp_aux *dp_aux, u32 addr, u32 len, enum aux_tx_mode mode, u8 *buf) { struct aux_cmd cmd = {0}; struct dp_aux_private *aux; if (!dp_aux || !len) { pr_err("invalid input\n"); return -EINVAL; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); cmd.ex_mode = AUX_WRITE; cmd.tx_mode = mode; cmd.addr = addr; cmd.len = len; cmd.buf = buf; aux->cmds = &cmd; return dp_aux_write(aux); } static int dp_aux_read_ex(struct dp_aux *dp_aux, u32 addr, u32 len, enum aux_tx_mode mode, u8 **buf) { int rc = 0; struct aux_cmd cmd = {0}; struct dp_aux_private *aux; if (!dp_aux || !len) { pr_err("invalid input\n"); rc = -EINVAL; goto end; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); cmd.ex_mode = AUX_READ; cmd.tx_mode = mode; cmd.addr = addr; cmd.len = len; aux->cmds = &cmd; rc = dp_aux_read(aux); if (rc <= 0) { rc = -EINVAL; goto end; } *buf = cmd.buf; end: return rc; } static int dp_aux_process(struct dp_aux *dp_aux, struct aux_cmd *cmds) static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg) { struct dp_aux_private *aux; if (!dp_aux || !cmds) { if (!dp_aux) { pr_err("invalid input\n"); return -EINVAL; return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); aux->cmds = cmds; if (cmds->ex_mode == AUX_READ) return dp_aux_read(aux); else return dp_aux_write(aux); aux->catalog->reset(aux->catalog); aux->catalog->enable(aux->catalog, true); aux->catalog->setup(aux->catalog, aux_cfg); } static bool dp_aux_ready(struct dp_aux *dp_aux) static void dp_aux_deinit(struct dp_aux *dp_aux) { u8 data = 0; int count, ret; struct dp_aux_private *aux; if (!dp_aux) { pr_err("invalid input\n"); goto error; return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); for (count = 5; count; count--) { ret = dp_aux_write_ex(dp_aux, 0x50, 1, AUX_I2C, &data); if (ret >= 0) break; msleep(100); } if (count <= 0) { pr_err("aux chan NOT ready\n"); goto error; } return true; error: return false; aux->catalog->enable(aux->catalog, false); } static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg) static int dp_aux_register(struct dp_aux *dp_aux) { struct dp_aux_private *aux; int ret = 0; if (!dp_aux) { pr_err("invalid input\n"); return; ret = -EINVAL; goto exit; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); aux->catalog->reset(aux->catalog); aux->catalog->enable(aux->catalog, true); aux->catalog->setup(aux->catalog, aux_cfg); aux->drm_aux.name = "sde_dp_aux"; aux->drm_aux.dev = aux->dev; aux->drm_aux.transfer = dp_aux_transfer; ret = drm_dp_aux_register(&aux->drm_aux); if (ret) { pr_err("%s: failed to register drm aux: %d\n", __func__, ret); goto exit; } dp_aux->drm_aux = &aux->drm_aux; exit: return ret; } static void dp_aux_deinit(struct dp_aux *dp_aux) static void dp_aux_deregister(struct dp_aux *dp_aux) { struct dp_aux_private *aux; Loading @@ -531,8 +361,7 @@ static void dp_aux_deinit(struct dp_aux *dp_aux) } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); aux->catalog->enable(aux->catalog, false); drm_dp_aux_unregister(&aux->drm_aux); } struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog) Loading @@ -553,21 +382,19 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog) goto error; } aux->dev = dev; dp_aux_buf_set(aux); init_completion(&aux->comp); aux->cmd_busy = false; mutex_init(&aux->mutex); aux->dev = dev; aux->catalog = catalog; dp_aux = &aux->dp_aux; dp_aux->process = dp_aux_process; dp_aux->read = dp_aux_read_ex; dp_aux->write = dp_aux_write_ex; dp_aux->ready = dp_aux_ready; dp_aux->isr = dp_aux_isr; dp_aux->init = dp_aux_init; dp_aux->deinit = dp_aux_deinit; dp_aux->drm_aux_register = dp_aux_register; dp_aux->drm_aux_deregister = dp_aux_deregister; return dp_aux; error: Loading drivers/gpu/drm/msm/dp/dp_aux.h +4 −25 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #define _DP_AUX_H_ #include "dp_catalog.h" #include "drm_dp_helper.h" enum dp_aux_error { DP_AUX_ERR_NONE = 0, Loading @@ -26,32 +27,10 @@ enum dp_aux_error { DP_AUX_ERR_NACK_DEFER = -5, }; enum aux_tx_mode { AUX_NATIVE, AUX_I2C, }; enum aux_exe_mode { AUX_WRITE, AUX_READ, }; struct aux_cmd { enum aux_exe_mode ex_mode; enum aux_tx_mode tx_mode; u32 addr; u32 len; u8 *buf; bool next; }; struct dp_aux { int (*process)(struct dp_aux *aux, struct aux_cmd *cmd); int (*write)(struct dp_aux *aux, u32 addr, u32 len, enum aux_tx_mode mode, u8 *buf); int (*read)(struct dp_aux *aux, u32 addr, u32 len, enum aux_tx_mode mode, u8 **buf); bool (*ready)(struct dp_aux *aux); struct drm_dp_aux *drm_aux; int (*drm_aux_register)(struct dp_aux *aux); void (*drm_aux_deregister)(struct dp_aux *aux); void (*isr)(struct dp_aux *aux); void (*init)(struct dp_aux *aux, u32 *aux_cfg); void (*deinit)(struct dp_aux *aux); Loading drivers/gpu/drm/msm/dp/dp_catalog.c +0 −2 Original line number Diff line number Diff line Loading @@ -177,8 +177,6 @@ #define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004) #define EDID_START_ADDRESS 0x50 /* DP MMSS_CC registers */ #define MMSS_DP_LINK_CMD_RCGR (0x0138) #define MMSS_DP_LINK_CFG_RCGR (0x013C) Loading drivers/gpu/drm/msm/dp/dp_ctrl.c +56 −82 Original line number Diff line number Diff line Loading @@ -20,14 +20,9 @@ #include "dp_ctrl.h" #define DP_LINK_RATE_MULTIPLIER 27000000 #define DP_KHZ_TO_HZ 1000 #define DP_CRYPTO_CLK_RATE_KHZ 180000 /* sink power state */ #define SINK_POWER_ON 1 #define SINK_POWER_OFF 2 #define DP_CTRL_INTR_READY_FOR_VIDEO BIT(0) #define DP_CTRL_INTR_IDLE_PATTERN_SENT BIT(3) Loading Loading @@ -103,14 +98,6 @@ static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl) complete(&ctrl->video_comp); } static void dp_ctrl_set_sink_power_state(struct dp_ctrl_private *ctrl, u8 power_state) { const int len = 1; ctrl->aux->write(ctrl->aux, 0x600, len, AUX_NATIVE, &power_state); } static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state) { ctrl->catalog->state_ctrl(ctrl->catalog, state); Loading @@ -128,7 +115,7 @@ static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_OFF); drm_dp_link_power_down(ctrl->aux->drm_aux, &ctrl->panel->dp_link); reinit_completion(&ctrl->idle_comp); dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE); Loading @@ -143,12 +130,13 @@ static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) { u32 config = 0, tbd; u8 *dpcd = ctrl->panel->dpcd; config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */ config |= (0 << 11); /* RGB */ /* Scrambler reset enable */ if (ctrl->panel->dpcd.scrambler_reset) if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP) config |= (1 << 10); tbd = ctrl->link->get_test_bits_depth(ctrl->link, Loading @@ -158,7 +146,7 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) /* Num of Lanes */ config |= ((ctrl->link->lane_count - 1) << 4); if (ctrl->panel->dpcd.enhanced_frame) if (drm_dp_enhanced_frame_cap(dpcd)) config |= 0x40; config |= 0x04; /* progressive video */ Loading Loading @@ -327,7 +315,7 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl, even_distribution = 0; min_hblank = 0; lclk = link_rate * DP_LINK_RATE_MULTIPLIER; lclk = drm_dp_bw_code_to_link_rate(link_rate) * DP_KHZ_TO_HZ; pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n", pclk, lwidth, h_blank); Loading Loading @@ -763,7 +751,7 @@ static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl, buf[i] = voltage_level | pre_emphasis_level | max_level_reached; pr_debug("p|v=0x%x\n", voltage_level | pre_emphasis_level); return ctrl->aux->write(ctrl->aux, 0x103, 4, AUX_NATIVE, buf); return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4); } static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) Loading @@ -778,25 +766,6 @@ static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) dp_ctrl_update_sink_vx_px(ctrl, link->v_level, link->p_level); } static void dp_ctrl_cap_lane_rate_set(struct dp_ctrl_private *ctrl) { u8 buf[4]; struct dp_panel_dpcd *cap; cap = &ctrl->panel->dpcd; pr_debug("bw=%x lane=%d\n", ctrl->link->link_rate, ctrl->link->lane_count); buf[0] = ctrl->link->link_rate; buf[1] = ctrl->link->lane_count; if (cap->enhanced_frame) buf[1] |= 0x80; ctrl->aux->write(ctrl->aux, 0x100, 2, AUX_NATIVE, buf); } static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl, u8 pattern) { Loading @@ -805,33 +774,39 @@ static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl, pr_debug("pattern=%x\n", pattern); buf[0] = pattern; ctrl->aux->write(ctrl->aux, 0x102, 1, AUX_NATIVE, buf); drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf, 1); } static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) { int tries, old_v_level; int ret = 0; int usleep_time; int tries, old_v_level, ret = 0, len = 0; u8 link_status[DP_LINK_STATUS_SIZE]; int const maximum_retries = 5; dp_ctrl_state_ctrl(ctrl, 0); /* Make sure to clear the current pattern before starting a new one */ wmb(); ctrl->catalog->set_pattern(ctrl->catalog, 0x01); dp_ctrl_cap_lane_rate_set(ctrl); dp_ctrl_train_pattern_set(ctrl, 0x21); /* train_1 */ dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 | DP_RECOVERED_CLOCK_OUT_EN); /* train_1 */ dp_ctrl_update_vx_px(ctrl); tries = 0; old_v_level = ctrl->link->v_level; while (1) { usleep_time = ctrl->panel->dpcd.training_read_interval; usleep_range(usleep_time, usleep_time * 2); drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd); if (ctrl->link->clock_recovery(ctrl->link)) { len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux, link_status); if (len < DP_LINK_STATUS_SIZE) { pr_err("[%s]: DP link status read failed\n", __func__); ret = -1; break; } if (drm_dp_clock_recovery_ok(link_status, ctrl->link->lane_count)) { ret = 0; break; } Loading @@ -852,8 +827,7 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) old_v_level = ctrl->link->v_level; } ctrl->link->adjust_levels(ctrl->link); ctrl->link->adjust_levels(ctrl->link, link_status); dp_ctrl_update_vx_px(ctrl); } Loading @@ -869,15 +843,15 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl) switch (ctrl->link->link_rate) { case DP_LINK_RATE_810: ctrl->link->link_rate = DP_LINK_RATE_540; ctrl->link->link_rate = DP_LINK_BW_5_4; break; case DP_LINK_RATE_540: ctrl->link->link_rate = DP_LINK_RATE_270; case DP_LINK_BW_5_4: ctrl->link->link_rate = DP_LINK_BW_2_7; break; case DP_LINK_RATE_270: ctrl->link->link_rate = DP_LINK_RATE_162; case DP_LINK_BW_2_7: ctrl->link->link_rate = DP_LINK_BW_1_62; break; case DP_LINK_RATE_162: case DP_LINK_BW_1_62: default: ret = -EINVAL; break; Loading @@ -890,36 +864,38 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl) static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl) { int usleep_time; dp_ctrl_train_pattern_set(ctrl, 0); usleep_time = ctrl->panel->dpcd.training_read_interval; usleep_range(usleep_time, usleep_time * 2); drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); } static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) { int tries = 0; int ret = 0; int usleep_time; int tries = 0, ret = 0, len = 0; char pattern; int const maximum_retries = 5; u8 link_status[DP_LINK_STATUS_SIZE]; if (ctrl->panel->dpcd.flags & DPCD_TPS3) pattern = 0x03; if (drm_dp_tps3_supported(ctrl->panel->dpcd)) pattern = DP_TRAINING_PATTERN_3; else pattern = 0x02; pattern = DP_TRAINING_PATTERN_2; dp_ctrl_update_vx_px(ctrl); ctrl->catalog->set_pattern(ctrl->catalog, pattern); dp_ctrl_train_pattern_set(ctrl, pattern | 0x20); dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN); do { usleep_time = ctrl->panel->dpcd.training_read_interval; usleep_range(usleep_time, usleep_time * 2); drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux, link_status); if (len < DP_LINK_STATUS_SIZE) { pr_err("[%s]: DP link status read failed\n", __func__); ret = -1; break; } if (ctrl->link->channel_equalization(ctrl->link)) { if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count)) { ret = 0; break; } Loading @@ -930,8 +906,7 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) } tries++; ctrl->link->adjust_levels(ctrl->link); ctrl->link->adjust_levels(ctrl->link, link_status); dp_ctrl_update_vx_px(ctrl); } while (1); Loading @@ -941,12 +916,7 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl) { int ret = 0; ret = ctrl->aux->ready(ctrl->aux); if (!ret) { pr_err("aux chan NOT ready\n"); return ret; } struct drm_dp_link dp_link; ctrl->link->p_level = 0; ctrl->link->v_level = 0; Loading @@ -954,6 +924,11 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl) dp_ctrl_config_ctrl(ctrl); dp_ctrl_state_ctrl(ctrl, 0); dp_link.num_lanes = ctrl->link->lane_count; dp_link.rate = ctrl->link->link_rate; dp_link.capabilities = ctrl->panel->dp_link.capabilities; drm_dp_link_configure(ctrl->aux->drm_aux, &dp_link); ret = dp_ctrl_link_train_1(ctrl); if (ret < 0) { if (!dp_ctrl_link_rate_down_shift(ctrl)) { Loading Loading @@ -1007,7 +982,7 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train) ctrl->catalog->mainlink_ctrl(ctrl->catalog, true); dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_ON); drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->dp_link); if (ctrl->link->phy_pattern_requested(ctrl->link)) goto end; Loading Loading @@ -1065,8 +1040,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) ctrl->power->set_pixel_clk_parent(ctrl->power); dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk", (ctrl->link->link_rate * DP_LINK_RATE_MULTIPLIER) / DP_KHZ_TO_HZ); drm_dp_bw_code_to_link_rate(ctrl->link->link_rate)); dp_ctrl_set_clock_rate(ctrl, "ctrl_crypto_clk", DP_CRYPTO_CLK_RATE_KHZ); Loading Loading @@ -1208,7 +1182,7 @@ static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl) ctrl->catalog->hpd_config(ctrl->catalog, true); ctrl->link->link_rate = ctrl->panel->get_link_rate(ctrl->panel); ctrl->link->lane_count = ctrl->panel->dpcd.max_lane_count; ctrl->link->lane_count = ctrl->panel->dp_link.num_lanes; ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; pr_debug("link_rate=%d, lane_count=%d, pixel_rate=%d\n", Loading drivers/gpu/drm/msm/dp/dp_display.c +29 −28 Original line number Diff line number Diff line Loading @@ -195,6 +195,18 @@ static int dp_display_bind(struct device *dev, struct device *master, goto end; } rc = dp->aux->drm_aux_register(dp->aux); if (rc) { pr_err("DRM DP AUX register failed\n"); goto end; } rc = dp->panel->sde_edid_register(dp->panel); if (rc) { pr_err("DRM DP EDID register failed\n"); goto end; } rc = dp->power->power_client_init(dp->power, &priv->phandle); if (rc) { pr_err("Power client create failed\n"); Loading Loading @@ -227,6 +239,10 @@ static void dp_display_unbind(struct device *dev, struct device *master, (void)dp->power->power_client_deinit(dp->power); (void) dp->panel->sde_edid_deregister(dp->panel); (void) dp->aux->drm_aux_deregister(dp->aux); (void)dp_display_debugfs_deinit(dp); mutex_unlock(&dp->lock); Loading @@ -245,9 +261,8 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) if (rc) goto end; rc = dp->panel->read_edid(dp->panel); if (rc) goto end; sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc, (void **)&dp->panel->edid_ctrl); return 0; end: Loading @@ -256,6 +271,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) static int dp_display_process_hpd_low(struct dp_display_private *dp) { dp->dp_display.is_connected = false; return 0; } Loading Loading @@ -290,6 +306,7 @@ static int dp_display_usbpd_configure_cb(struct device *dev) if (dp->usbpd->hpd_high) dp_display_process_hpd_high(dp); dp->dp_display.is_connected = true; mutex_unlock(&dp->lock); end: Loading @@ -315,6 +332,7 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) } mutex_lock(&dp->lock); dp->dp_display.is_connected = false; disable_irq(dp->irq); mutex_unlock(&dp->lock); Loading Loading @@ -573,33 +591,17 @@ static int dp_display_validate_mode(struct dp_display *dp, return 0; } static int dp_display_get_modes(struct dp_display *dp, struct dp_display_mode *modes, u32 *count) static int dp_display_get_modes(struct dp_display *dp) { *count = 1; if (modes) { modes->timing.h_active = 1920; modes->timing.v_active = 1080; modes->timing.h_back_porch = 148; modes->timing.h_front_porch = 88; modes->timing.h_sync_width = 44; modes->timing.h_active_low = 0; modes->timing.v_back_porch = 36; modes->timing.v_front_porch = 4; modes->timing.v_sync_width = 5; modes->timing.v_active_low = 0; modes->timing.h_skew = 0; modes->timing.refresh_rate = 60; modes->timing.pixel_clk_khz = 148500; } int ret = 0; struct dp_display_private *dp_display; return 0; } dp_display = container_of(dp, struct dp_display_private, dp_display); static int dp_display_detect(struct dp_display *dp) { return 0; ret = _sde_edid_update_modes(dp->connector, dp_display->panel->edid_ctrl); return ret; } static int dp_display_probe(struct platform_device *pdev) Loading Loading @@ -637,7 +639,6 @@ static int dp_display_probe(struct platform_device *pdev) g_dp_display->set_mode = dp_display_set_mode; g_dp_display->validate_mode = dp_display_validate_mode; g_dp_display->get_modes = dp_display_get_modes; g_dp_display->detect = dp_display_detect; g_dp_display->prepare = dp_display_prepare; g_dp_display->unprepare = dp_display_unprepare; g_dp_display->request_irq = dp_request_irq; Loading Loading
drivers/gpu/drm/msm/dp/dp_aux.c +139 −312 Original line number Diff line number Diff line Loading @@ -20,14 +20,8 @@ #define DP_AUX_ENUM_STR(x) #x struct aux_buf { u8 *start; /* buffer start addr */ u8 *end; /* buffer end addr */ u8 *data; /* data pou32er */ u32 size; /* size of buffer */ u32 len; /* dara length */ u8 trans_num; /* transaction number */ enum aux_tx_mode tx_mode; enum { DP_AUX_DATA_INDEX_WRITE = BIT(31), }; struct dp_aux_private { Loading @@ -38,15 +32,12 @@ struct dp_aux_private { struct mutex mutex; struct completion comp; struct aux_cmd *cmds; struct aux_buf txp; struct aux_buf rxp; u32 aux_error_num; bool cmd_busy; bool native; bool read; u8 txbuf[256]; u8 rxbuf[256]; struct drm_dp_aux drm_aux; }; static char *dp_aux_get_error(u32 aux_error) Loading @@ -69,159 +60,104 @@ static char *dp_aux_get_error(u32 aux_error) } } static void dp_aux_buf_init(struct aux_buf *buf, u8 *data, u32 size) { buf->start = data; buf->size = size; buf->data = buf->start; buf->end = buf->start + buf->size; buf->len = 0; buf->trans_num = 0; buf->tx_mode = AUX_NATIVE; } static void dp_aux_buf_set(struct dp_aux_private *aux) { init_completion(&aux->comp); aux->cmd_busy = false; mutex_init(&aux->mutex); dp_aux_buf_init(&aux->txp, aux->txbuf, sizeof(aux->txbuf)); dp_aux_buf_init(&aux->rxp, aux->rxbuf, sizeof(aux->rxbuf)); } static void dp_aux_buf_reset(struct aux_buf *buf) { buf->data = buf->start; buf->len = 0; buf->trans_num = 0; buf->tx_mode = AUX_NATIVE; memset(buf->start, 0x0, 256); } static void dp_aux_buf_push(struct aux_buf *buf, u32 len) { buf->data += len; buf->len += len; } static u32 dp_aux_buf_trailing(struct aux_buf *buf) { return (u32)(buf->end - buf->data); } static u32 dp_aux_add_cmd(struct aux_buf *buf, struct aux_cmd *cmd) static u32 dp_aux_write(struct dp_aux_private *aux, struct drm_dp_aux_msg *msg) { u8 data; u8 *bp, *cp; u32 i, len; u32 data[4], reg, len; u8 *msgdata = msg->buffer; int const aux_cmd_fifo_len = 128; int i = 0; if (cmd->ex_mode == AUX_READ) if (aux->read) len = 4; else len = cmd->len + 4; if (dp_aux_buf_trailing(buf) < len) { pr_err("buf trailing error\n"); return 0; } len = msg->size + 4; /* * cmd fifo only has depth of 144 bytes * limit buf length to 128 bytes here */ if ((buf->len + len) > 128) { if (len > aux_cmd_fifo_len) { pr_err("buf len error\n"); return 0; } bp = buf->data; data = cmd->addr >> 16; data &= 0x0f; /* 4 addr bits */ if (cmd->ex_mode == AUX_READ) data |= BIT(4); *bp++ = data; *bp++ = cmd->addr >> 8; *bp++ = cmd->addr; *bp++ = cmd->len - 1; /* Pack cmd and write to HW */ data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */ if (aux->read) data[0] |= BIT(4); /* R/W */ if (cmd->ex_mode == AUX_WRITE) { cp = cmd->buf; data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */ data[2] = msg->address & 0xff; /* addr[7:0] */ data[3] = (msg->size - 1) & 0xff; /* len[7:0] */ for (i = 0; i < cmd->len; i++) *bp++ = *cp++; for (i = 0; i < len; i++) { reg = (i < 4) ? data[i] : msgdata[i - 4]; reg = ((reg) << 8) & 0x0000ff00; /* index = 0, write */ if (i == 0) reg |= DP_AUX_DATA_INDEX_WRITE; aux->catalog->data = reg; aux->catalog->write_data(aux->catalog); } dp_aux_buf_push(buf, len); buf->tx_mode = cmd->tx_mode; reg = 0; /* Transaction number == 1 */ if (!aux->native) /* i2c */ reg |= (BIT(8) | BIT(10) | BIT(11)); buf->trans_num++; reg |= BIT(9); aux->catalog->data = reg; aux->catalog->write_trans(aux->catalog); return cmd->len - 1; return len; } static u32 dp_aux_cmd_fifo_tx(struct dp_aux_private *aux) static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, struct drm_dp_aux_msg *msg) { u8 *dp; u32 data, len, cnt; struct aux_buf *tp = &aux->txp; u32 ret = 0, len = 0, timeout; int const aux_timeout_ms = HZ/4; reinit_completion(&aux->comp); len = tp->len; len = dp_aux_write(aux, msg); if (len == 0) { pr_err("invalid len\n"); return 0; pr_err("DP AUX write failed\n"); return -EINVAL; } cnt = 0; dp = tp->start; while (cnt < len) { data = *dp; data <<= 8; data &= 0x00ff00; if (cnt == 0) data |= BIT(31); aux->catalog->data = data; aux->catalog->write_data(aux->catalog); cnt++; dp++; timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms); if (!timeout) { pr_err("aux write timeout\n"); return -ETIMEDOUT; } data = (tp->trans_num - 1); if (tp->tx_mode == AUX_I2C) { data |= BIT(8); /* I2C */ data |= BIT(10); /* NO SEND ADDR */ data |= BIT(11); /* NO SEND STOP */ } pr_debug("aux status %s\n", dp_aux_get_error(aux->aux_error_num)); data |= BIT(9); /* GO */ aux->catalog->data = data; aux->catalog->write_trans(aux->catalog); if (aux->aux_error_num == DP_AUX_ERR_NONE) ret = len; else ret = -EINVAL; return tp->len; return ret; } static u32 dp_cmd_fifo_rx(struct dp_aux_private *aux, u32 len) static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux, struct drm_dp_aux_msg *msg) { u32 data; u8 *dp; u32 i; struct aux_buf *rp = &aux->rxp; u32 len = msg->size; data = 0; data |= BIT(31); /* INDEX_WRITE */ data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */ data |= BIT(0); /* read */ aux->catalog->data = data; aux->catalog->write_data(aux->catalog); dp = rp->data; dp = msg->buffer; /* discard first byte */ data = aux->catalog->read_data(aux->catalog); Loading @@ -230,9 +166,6 @@ static u32 dp_cmd_fifo_rx(struct dp_aux_private *aux, u32 len) data = aux->catalog->read_data(aux->catalog); *dp++ = (u8)((data >> 8) & 0xff); } rp->len = len; return len; } static void dp_aux_native_handler(struct dp_aux_private *aux) Loading Loading @@ -292,236 +225,133 @@ static void dp_aux_isr(struct dp_aux *dp_aux) if (!aux->cmd_busy) return; if (aux->cmds->tx_mode == AUX_NATIVE) if (aux->native) dp_aux_native_handler(aux); else dp_aux_i2c_handler(aux); } static int dp_aux_write(struct dp_aux_private *aux) /* * This function does the real job to process an AUX transaction. * It will call aux_reset() function to reset the AUX channel, * if the waiting is timeout. */ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg) { struct aux_cmd *cm; struct aux_buf *tp; u32 len, ret, timeout; ssize_t ret; int const aux_cmd_native_max = 16; int const aux_cmd_i2c_max = 128; struct dp_aux_private *aux = container_of(drm_aux, struct dp_aux_private, drm_aux); mutex_lock(&aux->mutex); tp = &aux->txp; dp_aux_buf_reset(tp); cm = aux->cmds; while (cm) { ret = dp_aux_add_cmd(tp, cm); if (ret <= 0) break; if (!cm->next) break; cm++; } reinit_completion(&aux->comp); aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); aux->cmd_busy = true; len = dp_aux_cmd_fifo_tx(aux); timeout = wait_for_completion_timeout(&aux->comp, HZ/4); if (!timeout) pr_err("aux write timeout\n"); pr_debug("aux status %s\n", dp_aux_get_error(aux->aux_error_num)); if (aux->aux_error_num == DP_AUX_ERR_NONE) ret = len; else ret = aux->aux_error_num; aux->cmd_busy = false; mutex_unlock(&aux->mutex); return ret; /* Ignore address only message */ if ((msg->size == 0) || (msg->buffer == NULL)) { msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; ret = msg->size; goto unlock_exit; } static int dp_aux_read(struct dp_aux_private *aux) { struct aux_cmd *cm; struct aux_buf *tp, *rp; u32 len, ret, timeout; mutex_lock(&aux->mutex); tp = &aux->txp; rp = &aux->rxp; dp_aux_buf_reset(tp); dp_aux_buf_reset(rp); cm = aux->cmds; len = 0; while (cm) { ret = dp_aux_add_cmd(tp, cm); len += cm->len; if (ret <= 0) break; if (!cm->next) break; cm++; /* msg sanity check */ if ((aux->native && (msg->size > aux_cmd_native_max)) || (msg->size > aux_cmd_i2c_max)) { pr_err("%s: invalid msg: size(%zu), request(%x)\n", __func__, msg->size, msg->request); ret = -EINVAL; goto unlock_exit; } reinit_completion(&aux->comp); aux->cmd_busy = true; dp_aux_cmd_fifo_tx(aux); ret = dp_aux_cmd_fifo_tx(aux, msg); if (ret < 0) { aux->catalog->reset(aux->catalog); /* reset aux */ goto unlock_exit; } timeout = wait_for_completion_timeout(&aux->comp, HZ/4); if (!timeout) pr_err("aux read timeout\n"); if (aux->aux_error_num == DP_AUX_ERR_NONE) { if (aux->read) dp_aux_cmd_fifo_rx(aux, msg); pr_debug("aux status %s\n", dp_aux_get_error(aux->aux_error_num)); msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; } else { /* Reply defer to retry */ msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER; } if (aux->aux_error_num == DP_AUX_ERR_NONE) ret = dp_cmd_fifo_rx(aux, len); else ret = aux->aux_error_num; /* Return requested size for success or retry */ ret = msg->size; aux->cmds->buf = rp->data; unlock_exit: aux->cmd_busy = false; mutex_unlock(&aux->mutex); return ret; } static int dp_aux_write_ex(struct dp_aux *dp_aux, u32 addr, u32 len, enum aux_tx_mode mode, u8 *buf) { struct aux_cmd cmd = {0}; struct dp_aux_private *aux; if (!dp_aux || !len) { pr_err("invalid input\n"); return -EINVAL; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); cmd.ex_mode = AUX_WRITE; cmd.tx_mode = mode; cmd.addr = addr; cmd.len = len; cmd.buf = buf; aux->cmds = &cmd; return dp_aux_write(aux); } static int dp_aux_read_ex(struct dp_aux *dp_aux, u32 addr, u32 len, enum aux_tx_mode mode, u8 **buf) { int rc = 0; struct aux_cmd cmd = {0}; struct dp_aux_private *aux; if (!dp_aux || !len) { pr_err("invalid input\n"); rc = -EINVAL; goto end; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); cmd.ex_mode = AUX_READ; cmd.tx_mode = mode; cmd.addr = addr; cmd.len = len; aux->cmds = &cmd; rc = dp_aux_read(aux); if (rc <= 0) { rc = -EINVAL; goto end; } *buf = cmd.buf; end: return rc; } static int dp_aux_process(struct dp_aux *dp_aux, struct aux_cmd *cmds) static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg) { struct dp_aux_private *aux; if (!dp_aux || !cmds) { if (!dp_aux) { pr_err("invalid input\n"); return -EINVAL; return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); aux->cmds = cmds; if (cmds->ex_mode == AUX_READ) return dp_aux_read(aux); else return dp_aux_write(aux); aux->catalog->reset(aux->catalog); aux->catalog->enable(aux->catalog, true); aux->catalog->setup(aux->catalog, aux_cfg); } static bool dp_aux_ready(struct dp_aux *dp_aux) static void dp_aux_deinit(struct dp_aux *dp_aux) { u8 data = 0; int count, ret; struct dp_aux_private *aux; if (!dp_aux) { pr_err("invalid input\n"); goto error; return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); for (count = 5; count; count--) { ret = dp_aux_write_ex(dp_aux, 0x50, 1, AUX_I2C, &data); if (ret >= 0) break; msleep(100); } if (count <= 0) { pr_err("aux chan NOT ready\n"); goto error; } return true; error: return false; aux->catalog->enable(aux->catalog, false); } static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg) static int dp_aux_register(struct dp_aux *dp_aux) { struct dp_aux_private *aux; int ret = 0; if (!dp_aux) { pr_err("invalid input\n"); return; ret = -EINVAL; goto exit; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); aux->catalog->reset(aux->catalog); aux->catalog->enable(aux->catalog, true); aux->catalog->setup(aux->catalog, aux_cfg); aux->drm_aux.name = "sde_dp_aux"; aux->drm_aux.dev = aux->dev; aux->drm_aux.transfer = dp_aux_transfer; ret = drm_dp_aux_register(&aux->drm_aux); if (ret) { pr_err("%s: failed to register drm aux: %d\n", __func__, ret); goto exit; } dp_aux->drm_aux = &aux->drm_aux; exit: return ret; } static void dp_aux_deinit(struct dp_aux *dp_aux) static void dp_aux_deregister(struct dp_aux *dp_aux) { struct dp_aux_private *aux; Loading @@ -531,8 +361,7 @@ static void dp_aux_deinit(struct dp_aux *dp_aux) } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); aux->catalog->enable(aux->catalog, false); drm_dp_aux_unregister(&aux->drm_aux); } struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog) Loading @@ -553,21 +382,19 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog) goto error; } aux->dev = dev; dp_aux_buf_set(aux); init_completion(&aux->comp); aux->cmd_busy = false; mutex_init(&aux->mutex); aux->dev = dev; aux->catalog = catalog; dp_aux = &aux->dp_aux; dp_aux->process = dp_aux_process; dp_aux->read = dp_aux_read_ex; dp_aux->write = dp_aux_write_ex; dp_aux->ready = dp_aux_ready; dp_aux->isr = dp_aux_isr; dp_aux->init = dp_aux_init; dp_aux->deinit = dp_aux_deinit; dp_aux->drm_aux_register = dp_aux_register; dp_aux->drm_aux_deregister = dp_aux_deregister; return dp_aux; error: Loading
drivers/gpu/drm/msm/dp/dp_aux.h +4 −25 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #define _DP_AUX_H_ #include "dp_catalog.h" #include "drm_dp_helper.h" enum dp_aux_error { DP_AUX_ERR_NONE = 0, Loading @@ -26,32 +27,10 @@ enum dp_aux_error { DP_AUX_ERR_NACK_DEFER = -5, }; enum aux_tx_mode { AUX_NATIVE, AUX_I2C, }; enum aux_exe_mode { AUX_WRITE, AUX_READ, }; struct aux_cmd { enum aux_exe_mode ex_mode; enum aux_tx_mode tx_mode; u32 addr; u32 len; u8 *buf; bool next; }; struct dp_aux { int (*process)(struct dp_aux *aux, struct aux_cmd *cmd); int (*write)(struct dp_aux *aux, u32 addr, u32 len, enum aux_tx_mode mode, u8 *buf); int (*read)(struct dp_aux *aux, u32 addr, u32 len, enum aux_tx_mode mode, u8 **buf); bool (*ready)(struct dp_aux *aux); struct drm_dp_aux *drm_aux; int (*drm_aux_register)(struct dp_aux *aux); void (*drm_aux_deregister)(struct dp_aux *aux); void (*isr)(struct dp_aux *aux); void (*init)(struct dp_aux *aux, u32 *aux_cfg); void (*deinit)(struct dp_aux *aux); Loading
drivers/gpu/drm/msm/dp/dp_catalog.c +0 −2 Original line number Diff line number Diff line Loading @@ -177,8 +177,6 @@ #define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004) #define EDID_START_ADDRESS 0x50 /* DP MMSS_CC registers */ #define MMSS_DP_LINK_CMD_RCGR (0x0138) #define MMSS_DP_LINK_CFG_RCGR (0x013C) Loading
drivers/gpu/drm/msm/dp/dp_ctrl.c +56 −82 Original line number Diff line number Diff line Loading @@ -20,14 +20,9 @@ #include "dp_ctrl.h" #define DP_LINK_RATE_MULTIPLIER 27000000 #define DP_KHZ_TO_HZ 1000 #define DP_CRYPTO_CLK_RATE_KHZ 180000 /* sink power state */ #define SINK_POWER_ON 1 #define SINK_POWER_OFF 2 #define DP_CTRL_INTR_READY_FOR_VIDEO BIT(0) #define DP_CTRL_INTR_IDLE_PATTERN_SENT BIT(3) Loading Loading @@ -103,14 +98,6 @@ static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl) complete(&ctrl->video_comp); } static void dp_ctrl_set_sink_power_state(struct dp_ctrl_private *ctrl, u8 power_state) { const int len = 1; ctrl->aux->write(ctrl->aux, 0x600, len, AUX_NATIVE, &power_state); } static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state) { ctrl->catalog->state_ctrl(ctrl->catalog, state); Loading @@ -128,7 +115,7 @@ static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_OFF); drm_dp_link_power_down(ctrl->aux->drm_aux, &ctrl->panel->dp_link); reinit_completion(&ctrl->idle_comp); dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE); Loading @@ -143,12 +130,13 @@ static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) { u32 config = 0, tbd; u8 *dpcd = ctrl->panel->dpcd; config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */ config |= (0 << 11); /* RGB */ /* Scrambler reset enable */ if (ctrl->panel->dpcd.scrambler_reset) if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP) config |= (1 << 10); tbd = ctrl->link->get_test_bits_depth(ctrl->link, Loading @@ -158,7 +146,7 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) /* Num of Lanes */ config |= ((ctrl->link->lane_count - 1) << 4); if (ctrl->panel->dpcd.enhanced_frame) if (drm_dp_enhanced_frame_cap(dpcd)) config |= 0x40; config |= 0x04; /* progressive video */ Loading Loading @@ -327,7 +315,7 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl, even_distribution = 0; min_hblank = 0; lclk = link_rate * DP_LINK_RATE_MULTIPLIER; lclk = drm_dp_bw_code_to_link_rate(link_rate) * DP_KHZ_TO_HZ; pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n", pclk, lwidth, h_blank); Loading Loading @@ -763,7 +751,7 @@ static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl, buf[i] = voltage_level | pre_emphasis_level | max_level_reached; pr_debug("p|v=0x%x\n", voltage_level | pre_emphasis_level); return ctrl->aux->write(ctrl->aux, 0x103, 4, AUX_NATIVE, buf); return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4); } static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) Loading @@ -778,25 +766,6 @@ static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) dp_ctrl_update_sink_vx_px(ctrl, link->v_level, link->p_level); } static void dp_ctrl_cap_lane_rate_set(struct dp_ctrl_private *ctrl) { u8 buf[4]; struct dp_panel_dpcd *cap; cap = &ctrl->panel->dpcd; pr_debug("bw=%x lane=%d\n", ctrl->link->link_rate, ctrl->link->lane_count); buf[0] = ctrl->link->link_rate; buf[1] = ctrl->link->lane_count; if (cap->enhanced_frame) buf[1] |= 0x80; ctrl->aux->write(ctrl->aux, 0x100, 2, AUX_NATIVE, buf); } static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl, u8 pattern) { Loading @@ -805,33 +774,39 @@ static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl, pr_debug("pattern=%x\n", pattern); buf[0] = pattern; ctrl->aux->write(ctrl->aux, 0x102, 1, AUX_NATIVE, buf); drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf, 1); } static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) { int tries, old_v_level; int ret = 0; int usleep_time; int tries, old_v_level, ret = 0, len = 0; u8 link_status[DP_LINK_STATUS_SIZE]; int const maximum_retries = 5; dp_ctrl_state_ctrl(ctrl, 0); /* Make sure to clear the current pattern before starting a new one */ wmb(); ctrl->catalog->set_pattern(ctrl->catalog, 0x01); dp_ctrl_cap_lane_rate_set(ctrl); dp_ctrl_train_pattern_set(ctrl, 0x21); /* train_1 */ dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 | DP_RECOVERED_CLOCK_OUT_EN); /* train_1 */ dp_ctrl_update_vx_px(ctrl); tries = 0; old_v_level = ctrl->link->v_level; while (1) { usleep_time = ctrl->panel->dpcd.training_read_interval; usleep_range(usleep_time, usleep_time * 2); drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd); if (ctrl->link->clock_recovery(ctrl->link)) { len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux, link_status); if (len < DP_LINK_STATUS_SIZE) { pr_err("[%s]: DP link status read failed\n", __func__); ret = -1; break; } if (drm_dp_clock_recovery_ok(link_status, ctrl->link->lane_count)) { ret = 0; break; } Loading @@ -852,8 +827,7 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) old_v_level = ctrl->link->v_level; } ctrl->link->adjust_levels(ctrl->link); ctrl->link->adjust_levels(ctrl->link, link_status); dp_ctrl_update_vx_px(ctrl); } Loading @@ -869,15 +843,15 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl) switch (ctrl->link->link_rate) { case DP_LINK_RATE_810: ctrl->link->link_rate = DP_LINK_RATE_540; ctrl->link->link_rate = DP_LINK_BW_5_4; break; case DP_LINK_RATE_540: ctrl->link->link_rate = DP_LINK_RATE_270; case DP_LINK_BW_5_4: ctrl->link->link_rate = DP_LINK_BW_2_7; break; case DP_LINK_RATE_270: ctrl->link->link_rate = DP_LINK_RATE_162; case DP_LINK_BW_2_7: ctrl->link->link_rate = DP_LINK_BW_1_62; break; case DP_LINK_RATE_162: case DP_LINK_BW_1_62: default: ret = -EINVAL; break; Loading @@ -890,36 +864,38 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl) static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl) { int usleep_time; dp_ctrl_train_pattern_set(ctrl, 0); usleep_time = ctrl->panel->dpcd.training_read_interval; usleep_range(usleep_time, usleep_time * 2); drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); } static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) { int tries = 0; int ret = 0; int usleep_time; int tries = 0, ret = 0, len = 0; char pattern; int const maximum_retries = 5; u8 link_status[DP_LINK_STATUS_SIZE]; if (ctrl->panel->dpcd.flags & DPCD_TPS3) pattern = 0x03; if (drm_dp_tps3_supported(ctrl->panel->dpcd)) pattern = DP_TRAINING_PATTERN_3; else pattern = 0x02; pattern = DP_TRAINING_PATTERN_2; dp_ctrl_update_vx_px(ctrl); ctrl->catalog->set_pattern(ctrl->catalog, pattern); dp_ctrl_train_pattern_set(ctrl, pattern | 0x20); dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN); do { usleep_time = ctrl->panel->dpcd.training_read_interval; usleep_range(usleep_time, usleep_time * 2); drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux, link_status); if (len < DP_LINK_STATUS_SIZE) { pr_err("[%s]: DP link status read failed\n", __func__); ret = -1; break; } if (ctrl->link->channel_equalization(ctrl->link)) { if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count)) { ret = 0; break; } Loading @@ -930,8 +906,7 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) } tries++; ctrl->link->adjust_levels(ctrl->link); ctrl->link->adjust_levels(ctrl->link, link_status); dp_ctrl_update_vx_px(ctrl); } while (1); Loading @@ -941,12 +916,7 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl) { int ret = 0; ret = ctrl->aux->ready(ctrl->aux); if (!ret) { pr_err("aux chan NOT ready\n"); return ret; } struct drm_dp_link dp_link; ctrl->link->p_level = 0; ctrl->link->v_level = 0; Loading @@ -954,6 +924,11 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl) dp_ctrl_config_ctrl(ctrl); dp_ctrl_state_ctrl(ctrl, 0); dp_link.num_lanes = ctrl->link->lane_count; dp_link.rate = ctrl->link->link_rate; dp_link.capabilities = ctrl->panel->dp_link.capabilities; drm_dp_link_configure(ctrl->aux->drm_aux, &dp_link); ret = dp_ctrl_link_train_1(ctrl); if (ret < 0) { if (!dp_ctrl_link_rate_down_shift(ctrl)) { Loading Loading @@ -1007,7 +982,7 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train) ctrl->catalog->mainlink_ctrl(ctrl->catalog, true); dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_ON); drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->dp_link); if (ctrl->link->phy_pattern_requested(ctrl->link)) goto end; Loading Loading @@ -1065,8 +1040,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) ctrl->power->set_pixel_clk_parent(ctrl->power); dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk", (ctrl->link->link_rate * DP_LINK_RATE_MULTIPLIER) / DP_KHZ_TO_HZ); drm_dp_bw_code_to_link_rate(ctrl->link->link_rate)); dp_ctrl_set_clock_rate(ctrl, "ctrl_crypto_clk", DP_CRYPTO_CLK_RATE_KHZ); Loading Loading @@ -1208,7 +1182,7 @@ static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl) ctrl->catalog->hpd_config(ctrl->catalog, true); ctrl->link->link_rate = ctrl->panel->get_link_rate(ctrl->panel); ctrl->link->lane_count = ctrl->panel->dpcd.max_lane_count; ctrl->link->lane_count = ctrl->panel->dp_link.num_lanes; ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; pr_debug("link_rate=%d, lane_count=%d, pixel_rate=%d\n", Loading
drivers/gpu/drm/msm/dp/dp_display.c +29 −28 Original line number Diff line number Diff line Loading @@ -195,6 +195,18 @@ static int dp_display_bind(struct device *dev, struct device *master, goto end; } rc = dp->aux->drm_aux_register(dp->aux); if (rc) { pr_err("DRM DP AUX register failed\n"); goto end; } rc = dp->panel->sde_edid_register(dp->panel); if (rc) { pr_err("DRM DP EDID register failed\n"); goto end; } rc = dp->power->power_client_init(dp->power, &priv->phandle); if (rc) { pr_err("Power client create failed\n"); Loading Loading @@ -227,6 +239,10 @@ static void dp_display_unbind(struct device *dev, struct device *master, (void)dp->power->power_client_deinit(dp->power); (void) dp->panel->sde_edid_deregister(dp->panel); (void) dp->aux->drm_aux_deregister(dp->aux); (void)dp_display_debugfs_deinit(dp); mutex_unlock(&dp->lock); Loading @@ -245,9 +261,8 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) if (rc) goto end; rc = dp->panel->read_edid(dp->panel); if (rc) goto end; sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc, (void **)&dp->panel->edid_ctrl); return 0; end: Loading @@ -256,6 +271,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) static int dp_display_process_hpd_low(struct dp_display_private *dp) { dp->dp_display.is_connected = false; return 0; } Loading Loading @@ -290,6 +306,7 @@ static int dp_display_usbpd_configure_cb(struct device *dev) if (dp->usbpd->hpd_high) dp_display_process_hpd_high(dp); dp->dp_display.is_connected = true; mutex_unlock(&dp->lock); end: Loading @@ -315,6 +332,7 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) } mutex_lock(&dp->lock); dp->dp_display.is_connected = false; disable_irq(dp->irq); mutex_unlock(&dp->lock); Loading Loading @@ -573,33 +591,17 @@ static int dp_display_validate_mode(struct dp_display *dp, return 0; } static int dp_display_get_modes(struct dp_display *dp, struct dp_display_mode *modes, u32 *count) static int dp_display_get_modes(struct dp_display *dp) { *count = 1; if (modes) { modes->timing.h_active = 1920; modes->timing.v_active = 1080; modes->timing.h_back_porch = 148; modes->timing.h_front_porch = 88; modes->timing.h_sync_width = 44; modes->timing.h_active_low = 0; modes->timing.v_back_porch = 36; modes->timing.v_front_porch = 4; modes->timing.v_sync_width = 5; modes->timing.v_active_low = 0; modes->timing.h_skew = 0; modes->timing.refresh_rate = 60; modes->timing.pixel_clk_khz = 148500; } int ret = 0; struct dp_display_private *dp_display; return 0; } dp_display = container_of(dp, struct dp_display_private, dp_display); static int dp_display_detect(struct dp_display *dp) { return 0; ret = _sde_edid_update_modes(dp->connector, dp_display->panel->edid_ctrl); return ret; } static int dp_display_probe(struct platform_device *pdev) Loading Loading @@ -637,7 +639,6 @@ static int dp_display_probe(struct platform_device *pdev) g_dp_display->set_mode = dp_display_set_mode; g_dp_display->validate_mode = dp_display_validate_mode; g_dp_display->get_modes = dp_display_get_modes; g_dp_display->detect = dp_display_detect; g_dp_display->prepare = dp_display_prepare; g_dp_display->unprepare = dp_display_unprepare; g_dp_display->request_irq = dp_request_irq; Loading