Loading drivers/gpu/drm/msm/dp/dp_aux.c +157 −26 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -29,22 +29,25 @@ struct dp_aux_private { struct dp_aux dp_aux; struct dp_catalog_aux *catalog; struct dp_aux_cfg *cfg; struct mutex mutex; struct completion comp; struct drm_dp_aux drm_aux; u32 aux_error_num; u32 retry_cnt; bool cmd_busy; bool native; bool read; bool no_send_addr; bool no_send_stop; u32 offset; u32 segment; u32 aux_error_num; u32 retry_cnt; atomic_t aborted; struct drm_dp_aux drm_aux; u8 *dpcd; u8 *edid; }; static char *dp_aux_get_error(u32 aux_error) Loading Loading @@ -320,6 +323,7 @@ static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, * * @aux: DP AUX private structure * @input_msg: input message from DRM upstream APIs * @send_seg: send the seg to sink * * return: void * Loading @@ -327,7 +331,7 @@ static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, * sinks that do not handle the i2c middle-of-transaction flag correctly. */ static void dp_aux_transfer_helper(struct dp_aux_private *aux, struct drm_dp_aux_msg *input_msg) struct drm_dp_aux_msg *input_msg, bool send_seg) { struct drm_dp_aux_msg helper_msg; u32 const message_size = 0x10; Loading @@ -346,7 +350,7 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, * duplicate AUX transactions related to this while reading the * first 16 bytes of each block. */ if (!(aux->offset % edid_block_length)) if (!(aux->offset % edid_block_length) || !send_seg) goto end; aux->read = false; Loading Loading @@ -388,26 +392,16 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, aux->segment = 0x0; /* reset segment at end of block */ } /* * 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) static int dp_aux_transfer_ready(struct dp_aux_private *aux, struct drm_dp_aux_msg *msg, bool send_seg) { ssize_t ret; int ret = 0; int const aux_cmd_native_max = 16; int const aux_cmd_i2c_max = 128; int const retry_count = 5; struct dp_aux_private *aux = container_of(drm_aux, struct dp_aux_private, drm_aux); mutex_lock(&aux->mutex); if (atomic_read(&aux->aborted)) { ret = -ETIMEDOUT; goto unlock_exit; goto error; } aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); Loading @@ -416,8 +410,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, 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; goto error; } /* msg sanity check */ Loading @@ -426,14 +419,14 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, pr_err("%s: invalid msg: size(%zu), request(%x)\n", __func__, msg->size, msg->request); ret = -EINVAL; goto unlock_exit; goto error; } dp_aux_update_offset_and_segment(aux, msg); dp_aux_transfer_helper(aux, msg); dp_aux_transfer_helper(aux, msg, send_seg); aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); aux->cmd_busy = true; if (aux->read) { aux->no_send_addr = true; Loading @@ -443,6 +436,98 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, aux->no_send_stop = true; } aux->cmd_busy = true; error: return ret; } static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg) { u8 buf[SZ_64]; u32 timeout; ssize_t ret; struct dp_aux_private *aux = container_of(drm_aux, struct dp_aux_private, drm_aux); ret = dp_aux_transfer_ready(aux, msg, false); if (ret) goto end; aux->aux_error_num = DP_AUX_ERR_NONE; if (aux->native) { if (aux->read && ((msg->address + msg->size) < SZ_1K)) { aux->dp_aux.reg = msg->address; reinit_completion(&aux->comp); timeout = wait_for_completion_timeout(&aux->comp, HZ); if (!timeout) pr_err("aux timeout for 0x%x\n", msg->address); aux->dp_aux.reg = 0xFFFF; memcpy(msg->buffer, aux->dpcd + msg->address, msg->size); aux->aux_error_num = DP_AUX_ERR_NONE; } else { memset(msg->buffer, 0, msg->size); } } else { if (aux->read && msg->address == 0x50) { memcpy(msg->buffer, aux->edid + aux->offset - 16, msg->size); } } if (aux->aux_error_num == DP_AUX_ERR_NONE) { snprintf(buf, SZ_64, "[drm-dp] dbg: %5s %5s %5xh(%2zu): ", aux->native ? "NATIVE" : "I2C", aux->read ? "READ" : "WRITE", msg->address, msg->size); print_hex_dump(KERN_DEBUG, buf, DUMP_PREFIX_NONE, 8, 1, msg->buffer, msg->size, false); 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; } ret = msg->size; end: return ret; } /* * 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) { u8 buf[SZ_64]; ssize_t ret; int const retry_count = 5; struct dp_aux_private *aux = container_of(drm_aux, struct dp_aux_private, drm_aux); mutex_lock(&aux->mutex); ret = dp_aux_transfer_ready(aux, msg, true); if (ret) goto unlock_exit; if (!aux->cmd_busy) { ret = msg->size; goto unlock_exit; } ret = dp_aux_cmd_fifo_tx(aux, msg); if ((ret < 0) && aux->native && !atomic_read(&aux->aborted)) { aux->retry_cnt++; Loading @@ -459,6 +544,14 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, if (aux->read) dp_aux_cmd_fifo_rx(aux, msg); snprintf(buf, SZ_64, "[drm-dp] %5s %5s %5xh(%2zu): ", aux->native ? "NATIVE" : "I2C", aux->read ? "READ" : "WRITE", msg->address, msg->size); print_hex_dump(KERN_DEBUG, buf, DUMP_PREFIX_NONE, 8, 1, msg->buffer, msg->size, false); msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; } else { Loading Loading @@ -558,6 +651,41 @@ static void dp_aux_deregister(struct dp_aux *dp_aux) drm_dp_aux_unregister(&aux->drm_aux); } static void dp_aux_dpcd_updated(struct dp_aux *dp_aux) { struct dp_aux_private *aux; if (!dp_aux) { pr_err("invalid input\n"); return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); complete(&aux->comp); } static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en, u8 *edid, u8 *dpcd) { struct dp_aux_private *aux; if (!dp_aux) { pr_err("invalid input\n"); return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); aux->edid = edid; aux->dpcd = dpcd; if (en) aux->drm_aux.transfer = dp_aux_transfer_debug; else aux->drm_aux.transfer = dp_aux_transfer; } struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, struct dp_aux_cfg *aux_cfg) { Loading Loading @@ -586,6 +714,7 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, aux->cfg = aux_cfg; dp_aux = &aux->dp_aux; aux->retry_cnt = 0; aux->dp_aux.reg = 0xFFFF; dp_aux->isr = dp_aux_isr; dp_aux->init = dp_aux_init; Loading @@ -594,6 +723,8 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, dp_aux->drm_aux_deregister = dp_aux_deregister; dp_aux->reconfig = dp_aux_reconfig; dp_aux->abort = dp_aux_abort_transaction; dp_aux->dpcd_updated = dp_aux_dpcd_updated; dp_aux->set_sim_mode = dp_aux_set_sim_mode; return dp_aux; error: Loading drivers/gpu/drm/msm/dp/dp_aux.h +19 −1 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -18,6 +18,19 @@ #include "dp_catalog.h" #include "drm_dp_helper.h" #define DP_STATE_NOTIFICATION_SENT BIT(0) #define DP_STATE_TRAIN_1_STARTED BIT(1) #define DP_STATE_TRAIN_1_SUCCEEDED BIT(2) #define DP_STATE_TRAIN_1_FAILED BIT(3) #define DP_STATE_TRAIN_2_STARTED BIT(4) #define DP_STATE_TRAIN_2_SUCCEEDED BIT(5) #define DP_STATE_TRAIN_2_FAILED BIT(6) #define DP_STATE_CTRL_POWERED_ON BIT(7) #define DP_STATE_CTRL_POWERED_OFF BIT(8) #define DP_STATE_LINK_MAINTENANCE_STARTED BIT(9) #define DP_STATE_LINK_MAINTENANCE_COMPLETED BIT(10) #define DP_STATE_LINK_MAINTENANCE_FAILED BIT(11) enum dp_aux_error { DP_AUX_ERR_NONE = 0, DP_AUX_ERR_ADDR = -1, Loading @@ -29,6 +42,9 @@ enum dp_aux_error { }; struct dp_aux { u32 reg; u32 state; struct drm_dp_aux *drm_aux; int (*drm_aux_register)(struct dp_aux *aux); void (*drm_aux_deregister)(struct dp_aux *aux); Loading @@ -37,6 +53,8 @@ struct dp_aux { void (*deinit)(struct dp_aux *aux); void (*reconfig)(struct dp_aux *aux); void (*abort)(struct dp_aux *aux); void (*dpcd_updated)(struct dp_aux *aux); void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd); }; struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, Loading drivers/gpu/drm/msm/dp/dp_ctrl.c +38 −7 Original line number Diff line number Diff line Loading @@ -820,6 +820,10 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) u8 link_status[DP_LINK_STATUS_SIZE]; int const maximum_retries = 5; ctrl->aux->state &= ~DP_STATE_TRAIN_1_FAILED; ctrl->aux->state &= ~DP_STATE_TRAIN_1_SUCCEEDED; ctrl->aux->state |= DP_STATE_TRAIN_1_STARTED; dp_ctrl_state_ctrl(ctrl, 0); /* Make sure to clear the current pattern before starting a new one */ wmb(); Loading @@ -829,13 +833,13 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) DP_LINK_SCRAMBLING_DISABLE); /* train_1 */ if (ret <= 0) { ret = -EINVAL; return ret; goto end; } ret = dp_ctrl_update_vx_px(ctrl); if (ret <= 0) { ret = -EINVAL; return ret; goto end; } tries = 0; Loading Loading @@ -879,6 +883,13 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) break; } } end: ctrl->aux->state &= ~DP_STATE_TRAIN_1_STARTED; if (ret) ctrl->aux->state |= DP_STATE_TRAIN_1_FAILED; else ctrl->aux->state |= DP_STATE_TRAIN_1_SUCCEEDED; return ret; } Loading Loading @@ -922,6 +933,10 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) int const maximum_retries = 5; u8 link_status[DP_LINK_STATUS_SIZE]; ctrl->aux->state &= ~DP_STATE_TRAIN_2_FAILED; ctrl->aux->state &= ~DP_STATE_TRAIN_2_SUCCEEDED; ctrl->aux->state |= DP_STATE_TRAIN_2_STARTED; dp_ctrl_state_ctrl(ctrl, 0); /* Make sure to clear the current pattern before starting a new one */ wmb(); Loading @@ -934,14 +949,14 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) ret = dp_ctrl_update_vx_px(ctrl); if (ret <= 0) { ret = -EINVAL; return ret; goto end; } ctrl->catalog->set_pattern(ctrl->catalog, pattern); ret = dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN); if (ret <= 0) { ret = -EINVAL; return ret; goto end; } do { Loading @@ -968,7 +983,13 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) break; } } while (!atomic_read(&ctrl->aborted)); end: ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED; if (ret) ctrl->aux->state |= DP_STATE_TRAIN_2_FAILED; else ctrl->aux->state |= DP_STATE_TRAIN_2_SUCCEEDED; return ret; } Loading Loading @@ -1109,8 +1130,7 @@ static int dp_ctrl_disable_mainlink_clocks(struct dp_ctrl_private *ctrl) return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false); } static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool multi_func) static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset) { struct dp_ctrl_private *ctrl; struct dp_catalog_ctrl *catalog; Loading @@ -1125,7 +1145,7 @@ static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, ctrl->orientation = flip; catalog = ctrl->catalog; if (!multi_func) { if (reset) { catalog->usb_reset(ctrl->catalog, flip); catalog->phy_reset(ctrl->catalog); } Loading Loading @@ -1192,6 +1212,10 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) return -EINVAL; } ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED; ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED; ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED; ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); Loading Loading @@ -1231,6 +1255,13 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) ret = dp_ctrl_setup_main_link(ctrl, true); } while (ret == -EAGAIN); ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED; if (ret) ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED; else ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED; return ret; } Loading drivers/gpu/drm/msm/dp/dp_ctrl.h +2 −2 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -23,7 +23,7 @@ #include "dp_catalog.h" struct dp_ctrl { int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool multi_func); int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset); void (*deinit)(struct dp_ctrl *dp_ctrl); int (*on)(struct dp_ctrl *dp_ctrl); void (*off)(struct dp_ctrl *dp_ctrl); Loading drivers/gpu/drm/msm/dp/dp_debug.c +238 −116 Original line number Diff line number Diff line Loading @@ -36,15 +36,52 @@ struct dp_debug_private { u8 *dpcd; u32 dpcd_size; int vdo; struct dp_usbpd *usbpd; struct dp_link *link; struct dp_panel *panel; struct dp_aux *aux; struct drm_connector **connector; struct device *dev; struct work_struct sim_work; struct dp_debug dp_debug; }; static int dp_debug_get_edid_buf(struct dp_debug_private *debug) { int rc = 0; if (!debug->edid) { debug->edid = devm_kzalloc(debug->dev, SZ_256, GFP_KERNEL); if (!debug->edid) { rc = -ENOMEM; goto end; } debug->edid_size = SZ_256; } end: return rc; } static int dp_debug_get_dpcd_buf(struct dp_debug_private *debug) { int rc = 0; if (!debug->dpcd) { debug->dpcd = devm_kzalloc(debug->dev, SZ_1K, GFP_KERNEL); if (!debug->dpcd) { rc = -ENOMEM; goto end; } debug->dpcd_size = SZ_1K; } end: return rc; } static ssize_t dp_debug_write_edid(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -75,7 +112,8 @@ static ssize_t dp_debug_write_edid(struct file *file, edid_size = size / char_to_nib; buf_t = buf; memset(debug->edid, 0, debug->edid_size); if (dp_debug_get_edid_buf(debug)) goto bail; if (edid_size != debug->edid_size) { pr_debug("clearing debug edid\n"); Loading @@ -100,13 +138,13 @@ static ssize_t dp_debug_write_edid(struct file *file, buf_t += char_to_nib; } print_hex_dump(KERN_DEBUG, "DEBUG EDID: ", DUMP_PREFIX_NONE, 16, 1, debug->edid, debug->edid_size, false); edid = debug->edid; bail: kfree(buf); if (!debug->dp_debug.sim_mode) debug->panel->set_edid(debug->panel, edid); return rc; } Loading @@ -119,8 +157,8 @@ static ssize_t dp_debug_write_dpcd(struct file *file, size_t dpcd_size = 0; size_t size = 0, dpcd_buf_index = 0; ssize_t rc = count; pr_debug("count=%zu\n", count); char offset_ch[5]; u32 offset; if (!debug) return -ENODEV; Loading @@ -128,7 +166,7 @@ static ssize_t dp_debug_write_dpcd(struct file *file, if (*ppos) goto bail; size = min_t(size_t, count, SZ_32); size = min_t(size_t, count, SZ_2K); buf = kzalloc(size, GFP_KERNEL); if (!buf) { Loading @@ -139,16 +177,30 @@ static ssize_t dp_debug_write_dpcd(struct file *file, if (copy_from_user(buf, user_buff, size)) goto bail; dpcd_size = size / char_to_nib; buf_t = buf; memcpy(offset_ch, buf, 4); offset_ch[4] = '\0'; memset(debug->dpcd, 0, debug->dpcd_size); if (kstrtoint(offset_ch, 16, &offset)) { pr_err("offset kstrtoint error\n"); goto bail; } if (dpcd_size != debug->dpcd_size) { pr_debug("clearing debug dpcd\n"); if (dp_debug_get_dpcd_buf(debug)) goto bail; if (offset == 0xFFFF) { pr_err("clearing dpcd\n"); memset(debug->dpcd, 0, debug->dpcd_size); goto bail; } size -= 4; dpcd_size = size / char_to_nib; buf_t = buf + 4; dpcd_buf_index = offset; while (dpcd_size--) { char t[3]; int d; Loading @@ -167,16 +219,39 @@ static ssize_t dp_debug_write_dpcd(struct file *file, buf_t += char_to_nib; } print_hex_dump(KERN_DEBUG, "DEBUG DPCD: ", DUMP_PREFIX_NONE, 8, 1, debug->dpcd, debug->dpcd_size, false); dpcd = debug->dpcd; bail: kfree(buf); if (debug->dp_debug.sim_mode) debug->aux->dpcd_updated(debug->aux); else debug->panel->set_dpcd(debug->panel, dpcd); return rc; } static ssize_t dp_debug_read_dpcd(struct file *file, char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[SZ_8]; u32 len = 0; if (!debug) return -ENODEV; if (*ppos) return 0; len += snprintf(buf, SZ_8, "0x%x\n", debug->aux->reg); if (copy_to_user(user_buff, buf, len)) return -EFAULT; *ppos += len; return len; } static ssize_t dp_debug_write_hpd(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -421,7 +496,6 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, struct dp_debug_private *debug = file->private_data; char *buf; u32 len = 0, rc = 0; u64 lclk = 0; u32 max_size = SZ_4K; if (!debug) Loading @@ -434,124 +508,60 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, if (!buf) return -ENOMEM; rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\tdp_panel\n\t\tmax_pclk_khz = %d\n", debug->panel->max_pclk_khz); rc = snprintf(buf + len, max_size, "\tstate=0x%x\n", debug->aux->state); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\tdrm_dp_link\n\t\trate = %u\n", rc = snprintf(buf + len, max_size, "\tlink_rate=%u\n", debug->panel->link_info.rate); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tnum_lanes = %u\n", rc = snprintf(buf + len, max_size, "\tnum_lanes=%u\n", debug->panel->link_info.num_lanes); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tcapabilities = %lu\n", debug->panel->link_info.capabilities); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\tdp_panel_info:\n\t\tactive = %dx%d\n", rc = snprintf(buf + len, max_size, "\tresolution=%dx%d@%dHz\n", debug->panel->pinfo.h_active, debug->panel->pinfo.v_active); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tback_porch = %dx%d\n", debug->panel->pinfo.h_back_porch, debug->panel->pinfo.v_back_porch); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tfront_porch = %dx%d\n", debug->panel->pinfo.h_front_porch, debug->panel->pinfo.v_front_porch); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tsync_width = %dx%d\n", debug->panel->pinfo.h_sync_width, debug->panel->pinfo.v_sync_width); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tactive_low = %dx%d\n", debug->panel->pinfo.h_active_low, debug->panel->pinfo.v_active_low); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\th_skew = %d\n", debug->panel->pinfo.h_skew); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\trefresh rate = %d\n", debug->panel->pinfo.v_active, debug->panel->pinfo.refresh_rate); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tpixel clock khz = %d\n", rc = snprintf(buf + len, max_size, "\tpclock=%dKHz\n", debug->panel->pinfo.pixel_clk_khz); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tbpp = %d\n", rc = snprintf(buf + len, max_size, "\tbpp=%d\n", debug->panel->pinfo.bpp); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; /* Link Information */ rc = snprintf(buf + len, max_size, "\tdp_link:\n\t\ttest_requested = %d\n", debug->link->sink_request); rc = snprintf(buf + len, max_size, "\ttest_req=%s\n", dp_link_get_test_name(debug->link->sink_request)); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tlane_count = %d\n", debug->link->link_params.lane_count); "\tlane_count=%d\n", debug->link->link_params.lane_count); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tbw_code = %d\n", debug->link->link_params.bw_code); "\tbw_code=%d\n", debug->link->link_params.bw_code); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; lclk = drm_dp_bw_code_to_link_rate( debug->link->link_params.bw_code) * 1000; rc = snprintf(buf + len, max_size, "\t\tlclk = %lld\n", lclk); "\tv_level=%d\n", debug->link->phy_params.v_level); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tv_level = %d\n", debug->link->phy_params.v_level); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tp_level = %d\n", debug->link->phy_params.p_level); "\tp_level=%d\n", debug->link->phy_params.p_level); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; Loading Loading @@ -816,6 +826,90 @@ static ssize_t dp_debug_read_hdr(struct file *file, return rc; } static ssize_t dp_debug_write_sim(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[SZ_8]; size_t len = 0; int sim; if (!debug) return -ENODEV; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_8 - 1); if (copy_from_user(buf, user_buff, len)) goto end; buf[len] = '\0'; if (kstrtoint(buf, 10, &sim) != 0) goto end; if (sim) { if (dp_debug_get_edid_buf(debug)) goto end; if (dp_debug_get_dpcd_buf(debug)) goto error; } else { if (debug->edid) { devm_kfree(debug->dev, debug->edid); debug->edid = NULL; } if (debug->dpcd) { devm_kfree(debug->dev, debug->dpcd); debug->dpcd = NULL; } } debug->dp_debug.sim_mode = !!sim; debug->aux->set_sim_mode(debug->aux, debug->dp_debug.sim_mode, debug->edid, debug->dpcd); end: return len; error: devm_kfree(debug->dev, debug->edid); return len; } static ssize_t dp_debug_write_attention(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[SZ_8]; size_t len = 0; int vdo; if (!debug) return -ENODEV; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_8 - 1); if (copy_from_user(buf, user_buff, len)) goto end; buf[len] = '\0'; if (kstrtoint(buf, 10, &vdo) != 0) goto end; debug->vdo = vdo; schedule_work(&debug->sim_work); end: return len; } static const struct file_operations dp_debug_fops = { .open = simple_open, .read = dp_debug_read_info, Loading @@ -840,6 +934,7 @@ static const struct file_operations edid_fops = { static const struct file_operations dpcd_fops = { .open = simple_open, .write = dp_debug_write_dpcd, .read = dp_debug_read_dpcd, }; static const struct file_operations connected_fops = { Loading @@ -865,6 +960,16 @@ static const struct file_operations hdr_fops = { .read = dp_debug_read_hdr, }; static const struct file_operations sim_fops = { .open = simple_open, .write = dp_debug_write_sim, }; static const struct file_operations attention_fops = { .open = simple_open, .write = dp_debug_write_attention, }; static int dp_debug_init(struct dp_debug *dp_debug) { int rc = 0; Loading Loading @@ -967,6 +1072,26 @@ static int dp_debug_init(struct dp_debug *dp_debug) goto error_remove_dir; } file = debugfs_create_file("sim", 0644, dir, debug, &sim_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs sim failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("attention", 0644, dir, debug, &attention_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs attention failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } return 0; error_remove_dir: Loading @@ -977,9 +1102,17 @@ static int dp_debug_init(struct dp_debug *dp_debug) return rc; } static void dp_debug_sim_work(struct work_struct *work) { struct dp_debug_private *debug = container_of(work, typeof(*debug), sim_work); debug->usbpd->simulate_attention(debug->usbpd, debug->vdo); } struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_usbpd *usbpd, struct dp_link *link, struct drm_connector **connector) struct dp_aux *aux, struct drm_connector **connector) { int rc = 0; struct dp_debug_private *debug; Loading @@ -997,28 +1130,13 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, goto error; } debug->edid = devm_kzalloc(dev, SZ_256, GFP_KERNEL); if (!debug->edid) { rc = -ENOMEM; kfree(debug); goto error; } debug->edid_size = SZ_256; debug->dpcd = devm_kzalloc(dev, SZ_16, GFP_KERNEL); if (!debug->dpcd) { rc = -ENOMEM; kfree(debug); goto error; } debug->dpcd_size = SZ_16; INIT_WORK(&debug->sim_work, dp_debug_sim_work); debug->dp_debug.debug_en = false; debug->usbpd = usbpd; debug->link = link; debug->panel = panel; debug->aux = aux; debug->dev = dev; debug->connector = connector; Loading Loading @@ -1063,7 +1181,11 @@ void dp_debug_put(struct dp_debug *dp_debug) dp_debug_deinit(dp_debug); if (debug->edid) devm_kfree(debug->dev, debug->edid); if (debug->dpcd) devm_kfree(debug->dev, debug->dpcd); devm_kfree(debug->dev, debug); } Loading
drivers/gpu/drm/msm/dp/dp_aux.c +157 −26 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -29,22 +29,25 @@ struct dp_aux_private { struct dp_aux dp_aux; struct dp_catalog_aux *catalog; struct dp_aux_cfg *cfg; struct mutex mutex; struct completion comp; struct drm_dp_aux drm_aux; u32 aux_error_num; u32 retry_cnt; bool cmd_busy; bool native; bool read; bool no_send_addr; bool no_send_stop; u32 offset; u32 segment; u32 aux_error_num; u32 retry_cnt; atomic_t aborted; struct drm_dp_aux drm_aux; u8 *dpcd; u8 *edid; }; static char *dp_aux_get_error(u32 aux_error) Loading Loading @@ -320,6 +323,7 @@ static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, * * @aux: DP AUX private structure * @input_msg: input message from DRM upstream APIs * @send_seg: send the seg to sink * * return: void * Loading @@ -327,7 +331,7 @@ static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, * sinks that do not handle the i2c middle-of-transaction flag correctly. */ static void dp_aux_transfer_helper(struct dp_aux_private *aux, struct drm_dp_aux_msg *input_msg) struct drm_dp_aux_msg *input_msg, bool send_seg) { struct drm_dp_aux_msg helper_msg; u32 const message_size = 0x10; Loading @@ -346,7 +350,7 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, * duplicate AUX transactions related to this while reading the * first 16 bytes of each block. */ if (!(aux->offset % edid_block_length)) if (!(aux->offset % edid_block_length) || !send_seg) goto end; aux->read = false; Loading Loading @@ -388,26 +392,16 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, aux->segment = 0x0; /* reset segment at end of block */ } /* * 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) static int dp_aux_transfer_ready(struct dp_aux_private *aux, struct drm_dp_aux_msg *msg, bool send_seg) { ssize_t ret; int ret = 0; int const aux_cmd_native_max = 16; int const aux_cmd_i2c_max = 128; int const retry_count = 5; struct dp_aux_private *aux = container_of(drm_aux, struct dp_aux_private, drm_aux); mutex_lock(&aux->mutex); if (atomic_read(&aux->aborted)) { ret = -ETIMEDOUT; goto unlock_exit; goto error; } aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); Loading @@ -416,8 +410,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, 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; goto error; } /* msg sanity check */ Loading @@ -426,14 +419,14 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, pr_err("%s: invalid msg: size(%zu), request(%x)\n", __func__, msg->size, msg->request); ret = -EINVAL; goto unlock_exit; goto error; } dp_aux_update_offset_and_segment(aux, msg); dp_aux_transfer_helper(aux, msg); dp_aux_transfer_helper(aux, msg, send_seg); aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); aux->cmd_busy = true; if (aux->read) { aux->no_send_addr = true; Loading @@ -443,6 +436,98 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, aux->no_send_stop = true; } aux->cmd_busy = true; error: return ret; } static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg) { u8 buf[SZ_64]; u32 timeout; ssize_t ret; struct dp_aux_private *aux = container_of(drm_aux, struct dp_aux_private, drm_aux); ret = dp_aux_transfer_ready(aux, msg, false); if (ret) goto end; aux->aux_error_num = DP_AUX_ERR_NONE; if (aux->native) { if (aux->read && ((msg->address + msg->size) < SZ_1K)) { aux->dp_aux.reg = msg->address; reinit_completion(&aux->comp); timeout = wait_for_completion_timeout(&aux->comp, HZ); if (!timeout) pr_err("aux timeout for 0x%x\n", msg->address); aux->dp_aux.reg = 0xFFFF; memcpy(msg->buffer, aux->dpcd + msg->address, msg->size); aux->aux_error_num = DP_AUX_ERR_NONE; } else { memset(msg->buffer, 0, msg->size); } } else { if (aux->read && msg->address == 0x50) { memcpy(msg->buffer, aux->edid + aux->offset - 16, msg->size); } } if (aux->aux_error_num == DP_AUX_ERR_NONE) { snprintf(buf, SZ_64, "[drm-dp] dbg: %5s %5s %5xh(%2zu): ", aux->native ? "NATIVE" : "I2C", aux->read ? "READ" : "WRITE", msg->address, msg->size); print_hex_dump(KERN_DEBUG, buf, DUMP_PREFIX_NONE, 8, 1, msg->buffer, msg->size, false); 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; } ret = msg->size; end: return ret; } /* * 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) { u8 buf[SZ_64]; ssize_t ret; int const retry_count = 5; struct dp_aux_private *aux = container_of(drm_aux, struct dp_aux_private, drm_aux); mutex_lock(&aux->mutex); ret = dp_aux_transfer_ready(aux, msg, true); if (ret) goto unlock_exit; if (!aux->cmd_busy) { ret = msg->size; goto unlock_exit; } ret = dp_aux_cmd_fifo_tx(aux, msg); if ((ret < 0) && aux->native && !atomic_read(&aux->aborted)) { aux->retry_cnt++; Loading @@ -459,6 +544,14 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, if (aux->read) dp_aux_cmd_fifo_rx(aux, msg); snprintf(buf, SZ_64, "[drm-dp] %5s %5s %5xh(%2zu): ", aux->native ? "NATIVE" : "I2C", aux->read ? "READ" : "WRITE", msg->address, msg->size); print_hex_dump(KERN_DEBUG, buf, DUMP_PREFIX_NONE, 8, 1, msg->buffer, msg->size, false); msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; } else { Loading Loading @@ -558,6 +651,41 @@ static void dp_aux_deregister(struct dp_aux *dp_aux) drm_dp_aux_unregister(&aux->drm_aux); } static void dp_aux_dpcd_updated(struct dp_aux *dp_aux) { struct dp_aux_private *aux; if (!dp_aux) { pr_err("invalid input\n"); return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); complete(&aux->comp); } static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en, u8 *edid, u8 *dpcd) { struct dp_aux_private *aux; if (!dp_aux) { pr_err("invalid input\n"); return; } aux = container_of(dp_aux, struct dp_aux_private, dp_aux); aux->edid = edid; aux->dpcd = dpcd; if (en) aux->drm_aux.transfer = dp_aux_transfer_debug; else aux->drm_aux.transfer = dp_aux_transfer; } struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, struct dp_aux_cfg *aux_cfg) { Loading Loading @@ -586,6 +714,7 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, aux->cfg = aux_cfg; dp_aux = &aux->dp_aux; aux->retry_cnt = 0; aux->dp_aux.reg = 0xFFFF; dp_aux->isr = dp_aux_isr; dp_aux->init = dp_aux_init; Loading @@ -594,6 +723,8 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, dp_aux->drm_aux_deregister = dp_aux_deregister; dp_aux->reconfig = dp_aux_reconfig; dp_aux->abort = dp_aux_abort_transaction; dp_aux->dpcd_updated = dp_aux_dpcd_updated; dp_aux->set_sim_mode = dp_aux_set_sim_mode; return dp_aux; error: Loading
drivers/gpu/drm/msm/dp/dp_aux.h +19 −1 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -18,6 +18,19 @@ #include "dp_catalog.h" #include "drm_dp_helper.h" #define DP_STATE_NOTIFICATION_SENT BIT(0) #define DP_STATE_TRAIN_1_STARTED BIT(1) #define DP_STATE_TRAIN_1_SUCCEEDED BIT(2) #define DP_STATE_TRAIN_1_FAILED BIT(3) #define DP_STATE_TRAIN_2_STARTED BIT(4) #define DP_STATE_TRAIN_2_SUCCEEDED BIT(5) #define DP_STATE_TRAIN_2_FAILED BIT(6) #define DP_STATE_CTRL_POWERED_ON BIT(7) #define DP_STATE_CTRL_POWERED_OFF BIT(8) #define DP_STATE_LINK_MAINTENANCE_STARTED BIT(9) #define DP_STATE_LINK_MAINTENANCE_COMPLETED BIT(10) #define DP_STATE_LINK_MAINTENANCE_FAILED BIT(11) enum dp_aux_error { DP_AUX_ERR_NONE = 0, DP_AUX_ERR_ADDR = -1, Loading @@ -29,6 +42,9 @@ enum dp_aux_error { }; struct dp_aux { u32 reg; u32 state; struct drm_dp_aux *drm_aux; int (*drm_aux_register)(struct dp_aux *aux); void (*drm_aux_deregister)(struct dp_aux *aux); Loading @@ -37,6 +53,8 @@ struct dp_aux { void (*deinit)(struct dp_aux *aux); void (*reconfig)(struct dp_aux *aux); void (*abort)(struct dp_aux *aux); void (*dpcd_updated)(struct dp_aux *aux); void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd); }; struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, Loading
drivers/gpu/drm/msm/dp/dp_ctrl.c +38 −7 Original line number Diff line number Diff line Loading @@ -820,6 +820,10 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) u8 link_status[DP_LINK_STATUS_SIZE]; int const maximum_retries = 5; ctrl->aux->state &= ~DP_STATE_TRAIN_1_FAILED; ctrl->aux->state &= ~DP_STATE_TRAIN_1_SUCCEEDED; ctrl->aux->state |= DP_STATE_TRAIN_1_STARTED; dp_ctrl_state_ctrl(ctrl, 0); /* Make sure to clear the current pattern before starting a new one */ wmb(); Loading @@ -829,13 +833,13 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) DP_LINK_SCRAMBLING_DISABLE); /* train_1 */ if (ret <= 0) { ret = -EINVAL; return ret; goto end; } ret = dp_ctrl_update_vx_px(ctrl); if (ret <= 0) { ret = -EINVAL; return ret; goto end; } tries = 0; Loading Loading @@ -879,6 +883,13 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) break; } } end: ctrl->aux->state &= ~DP_STATE_TRAIN_1_STARTED; if (ret) ctrl->aux->state |= DP_STATE_TRAIN_1_FAILED; else ctrl->aux->state |= DP_STATE_TRAIN_1_SUCCEEDED; return ret; } Loading Loading @@ -922,6 +933,10 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) int const maximum_retries = 5; u8 link_status[DP_LINK_STATUS_SIZE]; ctrl->aux->state &= ~DP_STATE_TRAIN_2_FAILED; ctrl->aux->state &= ~DP_STATE_TRAIN_2_SUCCEEDED; ctrl->aux->state |= DP_STATE_TRAIN_2_STARTED; dp_ctrl_state_ctrl(ctrl, 0); /* Make sure to clear the current pattern before starting a new one */ wmb(); Loading @@ -934,14 +949,14 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) ret = dp_ctrl_update_vx_px(ctrl); if (ret <= 0) { ret = -EINVAL; return ret; goto end; } ctrl->catalog->set_pattern(ctrl->catalog, pattern); ret = dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN); if (ret <= 0) { ret = -EINVAL; return ret; goto end; } do { Loading @@ -968,7 +983,13 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) break; } } while (!atomic_read(&ctrl->aborted)); end: ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED; if (ret) ctrl->aux->state |= DP_STATE_TRAIN_2_FAILED; else ctrl->aux->state |= DP_STATE_TRAIN_2_SUCCEEDED; return ret; } Loading Loading @@ -1109,8 +1130,7 @@ static int dp_ctrl_disable_mainlink_clocks(struct dp_ctrl_private *ctrl) return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false); } static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool multi_func) static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset) { struct dp_ctrl_private *ctrl; struct dp_catalog_ctrl *catalog; Loading @@ -1125,7 +1145,7 @@ static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, ctrl->orientation = flip; catalog = ctrl->catalog; if (!multi_func) { if (reset) { catalog->usb_reset(ctrl->catalog, flip); catalog->phy_reset(ctrl->catalog); } Loading Loading @@ -1192,6 +1212,10 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) return -EINVAL; } ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED; ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED; ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED; ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); Loading Loading @@ -1231,6 +1255,13 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) ret = dp_ctrl_setup_main_link(ctrl, true); } while (ret == -EAGAIN); ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED; if (ret) ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED; else ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED; return ret; } Loading
drivers/gpu/drm/msm/dp/dp_ctrl.h +2 −2 Original line number Diff line number Diff line /* * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -23,7 +23,7 @@ #include "dp_catalog.h" struct dp_ctrl { int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool multi_func); int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset); void (*deinit)(struct dp_ctrl *dp_ctrl); int (*on)(struct dp_ctrl *dp_ctrl); void (*off)(struct dp_ctrl *dp_ctrl); Loading
drivers/gpu/drm/msm/dp/dp_debug.c +238 −116 Original line number Diff line number Diff line Loading @@ -36,15 +36,52 @@ struct dp_debug_private { u8 *dpcd; u32 dpcd_size; int vdo; struct dp_usbpd *usbpd; struct dp_link *link; struct dp_panel *panel; struct dp_aux *aux; struct drm_connector **connector; struct device *dev; struct work_struct sim_work; struct dp_debug dp_debug; }; static int dp_debug_get_edid_buf(struct dp_debug_private *debug) { int rc = 0; if (!debug->edid) { debug->edid = devm_kzalloc(debug->dev, SZ_256, GFP_KERNEL); if (!debug->edid) { rc = -ENOMEM; goto end; } debug->edid_size = SZ_256; } end: return rc; } static int dp_debug_get_dpcd_buf(struct dp_debug_private *debug) { int rc = 0; if (!debug->dpcd) { debug->dpcd = devm_kzalloc(debug->dev, SZ_1K, GFP_KERNEL); if (!debug->dpcd) { rc = -ENOMEM; goto end; } debug->dpcd_size = SZ_1K; } end: return rc; } static ssize_t dp_debug_write_edid(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -75,7 +112,8 @@ static ssize_t dp_debug_write_edid(struct file *file, edid_size = size / char_to_nib; buf_t = buf; memset(debug->edid, 0, debug->edid_size); if (dp_debug_get_edid_buf(debug)) goto bail; if (edid_size != debug->edid_size) { pr_debug("clearing debug edid\n"); Loading @@ -100,13 +138,13 @@ static ssize_t dp_debug_write_edid(struct file *file, buf_t += char_to_nib; } print_hex_dump(KERN_DEBUG, "DEBUG EDID: ", DUMP_PREFIX_NONE, 16, 1, debug->edid, debug->edid_size, false); edid = debug->edid; bail: kfree(buf); if (!debug->dp_debug.sim_mode) debug->panel->set_edid(debug->panel, edid); return rc; } Loading @@ -119,8 +157,8 @@ static ssize_t dp_debug_write_dpcd(struct file *file, size_t dpcd_size = 0; size_t size = 0, dpcd_buf_index = 0; ssize_t rc = count; pr_debug("count=%zu\n", count); char offset_ch[5]; u32 offset; if (!debug) return -ENODEV; Loading @@ -128,7 +166,7 @@ static ssize_t dp_debug_write_dpcd(struct file *file, if (*ppos) goto bail; size = min_t(size_t, count, SZ_32); size = min_t(size_t, count, SZ_2K); buf = kzalloc(size, GFP_KERNEL); if (!buf) { Loading @@ -139,16 +177,30 @@ static ssize_t dp_debug_write_dpcd(struct file *file, if (copy_from_user(buf, user_buff, size)) goto bail; dpcd_size = size / char_to_nib; buf_t = buf; memcpy(offset_ch, buf, 4); offset_ch[4] = '\0'; memset(debug->dpcd, 0, debug->dpcd_size); if (kstrtoint(offset_ch, 16, &offset)) { pr_err("offset kstrtoint error\n"); goto bail; } if (dpcd_size != debug->dpcd_size) { pr_debug("clearing debug dpcd\n"); if (dp_debug_get_dpcd_buf(debug)) goto bail; if (offset == 0xFFFF) { pr_err("clearing dpcd\n"); memset(debug->dpcd, 0, debug->dpcd_size); goto bail; } size -= 4; dpcd_size = size / char_to_nib; buf_t = buf + 4; dpcd_buf_index = offset; while (dpcd_size--) { char t[3]; int d; Loading @@ -167,16 +219,39 @@ static ssize_t dp_debug_write_dpcd(struct file *file, buf_t += char_to_nib; } print_hex_dump(KERN_DEBUG, "DEBUG DPCD: ", DUMP_PREFIX_NONE, 8, 1, debug->dpcd, debug->dpcd_size, false); dpcd = debug->dpcd; bail: kfree(buf); if (debug->dp_debug.sim_mode) debug->aux->dpcd_updated(debug->aux); else debug->panel->set_dpcd(debug->panel, dpcd); return rc; } static ssize_t dp_debug_read_dpcd(struct file *file, char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[SZ_8]; u32 len = 0; if (!debug) return -ENODEV; if (*ppos) return 0; len += snprintf(buf, SZ_8, "0x%x\n", debug->aux->reg); if (copy_to_user(user_buff, buf, len)) return -EFAULT; *ppos += len; return len; } static ssize_t dp_debug_write_hpd(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { Loading Loading @@ -421,7 +496,6 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, struct dp_debug_private *debug = file->private_data; char *buf; u32 len = 0, rc = 0; u64 lclk = 0; u32 max_size = SZ_4K; if (!debug) Loading @@ -434,124 +508,60 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, if (!buf) return -ENOMEM; rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\tdp_panel\n\t\tmax_pclk_khz = %d\n", debug->panel->max_pclk_khz); rc = snprintf(buf + len, max_size, "\tstate=0x%x\n", debug->aux->state); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\tdrm_dp_link\n\t\trate = %u\n", rc = snprintf(buf + len, max_size, "\tlink_rate=%u\n", debug->panel->link_info.rate); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tnum_lanes = %u\n", rc = snprintf(buf + len, max_size, "\tnum_lanes=%u\n", debug->panel->link_info.num_lanes); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tcapabilities = %lu\n", debug->panel->link_info.capabilities); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\tdp_panel_info:\n\t\tactive = %dx%d\n", rc = snprintf(buf + len, max_size, "\tresolution=%dx%d@%dHz\n", debug->panel->pinfo.h_active, debug->panel->pinfo.v_active); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tback_porch = %dx%d\n", debug->panel->pinfo.h_back_porch, debug->panel->pinfo.v_back_porch); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tfront_porch = %dx%d\n", debug->panel->pinfo.h_front_porch, debug->panel->pinfo.v_front_porch); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tsync_width = %dx%d\n", debug->panel->pinfo.h_sync_width, debug->panel->pinfo.v_sync_width); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tactive_low = %dx%d\n", debug->panel->pinfo.h_active_low, debug->panel->pinfo.v_active_low); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\th_skew = %d\n", debug->panel->pinfo.h_skew); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\trefresh rate = %d\n", debug->panel->pinfo.v_active, debug->panel->pinfo.refresh_rate); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tpixel clock khz = %d\n", rc = snprintf(buf + len, max_size, "\tpclock=%dKHz\n", debug->panel->pinfo.pixel_clk_khz); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tbpp = %d\n", rc = snprintf(buf + len, max_size, "\tbpp=%d\n", debug->panel->pinfo.bpp); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; /* Link Information */ rc = snprintf(buf + len, max_size, "\tdp_link:\n\t\ttest_requested = %d\n", debug->link->sink_request); rc = snprintf(buf + len, max_size, "\ttest_req=%s\n", dp_link_get_test_name(debug->link->sink_request)); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tlane_count = %d\n", debug->link->link_params.lane_count); "\tlane_count=%d\n", debug->link->link_params.lane_count); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tbw_code = %d\n", debug->link->link_params.bw_code); "\tbw_code=%d\n", debug->link->link_params.bw_code); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; lclk = drm_dp_bw_code_to_link_rate( debug->link->link_params.bw_code) * 1000; rc = snprintf(buf + len, max_size, "\t\tlclk = %lld\n", lclk); "\tv_level=%d\n", debug->link->phy_params.v_level); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tv_level = %d\n", debug->link->phy_params.v_level); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; rc = snprintf(buf + len, max_size, "\t\tp_level = %d\n", debug->link->phy_params.p_level); "\tp_level=%d\n", debug->link->phy_params.p_level); if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) goto error; Loading Loading @@ -816,6 +826,90 @@ static ssize_t dp_debug_read_hdr(struct file *file, return rc; } static ssize_t dp_debug_write_sim(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[SZ_8]; size_t len = 0; int sim; if (!debug) return -ENODEV; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_8 - 1); if (copy_from_user(buf, user_buff, len)) goto end; buf[len] = '\0'; if (kstrtoint(buf, 10, &sim) != 0) goto end; if (sim) { if (dp_debug_get_edid_buf(debug)) goto end; if (dp_debug_get_dpcd_buf(debug)) goto error; } else { if (debug->edid) { devm_kfree(debug->dev, debug->edid); debug->edid = NULL; } if (debug->dpcd) { devm_kfree(debug->dev, debug->dpcd); debug->dpcd = NULL; } } debug->dp_debug.sim_mode = !!sim; debug->aux->set_sim_mode(debug->aux, debug->dp_debug.sim_mode, debug->edid, debug->dpcd); end: return len; error: devm_kfree(debug->dev, debug->edid); return len; } static ssize_t dp_debug_write_attention(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; char buf[SZ_8]; size_t len = 0; int vdo; if (!debug) return -ENODEV; if (*ppos) return 0; /* Leave room for termination char */ len = min_t(size_t, count, SZ_8 - 1); if (copy_from_user(buf, user_buff, len)) goto end; buf[len] = '\0'; if (kstrtoint(buf, 10, &vdo) != 0) goto end; debug->vdo = vdo; schedule_work(&debug->sim_work); end: return len; } static const struct file_operations dp_debug_fops = { .open = simple_open, .read = dp_debug_read_info, Loading @@ -840,6 +934,7 @@ static const struct file_operations edid_fops = { static const struct file_operations dpcd_fops = { .open = simple_open, .write = dp_debug_write_dpcd, .read = dp_debug_read_dpcd, }; static const struct file_operations connected_fops = { Loading @@ -865,6 +960,16 @@ static const struct file_operations hdr_fops = { .read = dp_debug_read_hdr, }; static const struct file_operations sim_fops = { .open = simple_open, .write = dp_debug_write_sim, }; static const struct file_operations attention_fops = { .open = simple_open, .write = dp_debug_write_attention, }; static int dp_debug_init(struct dp_debug *dp_debug) { int rc = 0; Loading Loading @@ -967,6 +1072,26 @@ static int dp_debug_init(struct dp_debug *dp_debug) goto error_remove_dir; } file = debugfs_create_file("sim", 0644, dir, debug, &sim_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs sim failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } file = debugfs_create_file("attention", 0644, dir, debug, &attention_fops); if (IS_ERR_OR_NULL(file)) { rc = PTR_ERR(file); pr_err("[%s] debugfs attention failed, rc=%d\n", DEBUG_NAME, rc); goto error_remove_dir; } return 0; error_remove_dir: Loading @@ -977,9 +1102,17 @@ static int dp_debug_init(struct dp_debug *dp_debug) return rc; } static void dp_debug_sim_work(struct work_struct *work) { struct dp_debug_private *debug = container_of(work, typeof(*debug), sim_work); debug->usbpd->simulate_attention(debug->usbpd, debug->vdo); } struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_usbpd *usbpd, struct dp_link *link, struct drm_connector **connector) struct dp_aux *aux, struct drm_connector **connector) { int rc = 0; struct dp_debug_private *debug; Loading @@ -997,28 +1130,13 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, goto error; } debug->edid = devm_kzalloc(dev, SZ_256, GFP_KERNEL); if (!debug->edid) { rc = -ENOMEM; kfree(debug); goto error; } debug->edid_size = SZ_256; debug->dpcd = devm_kzalloc(dev, SZ_16, GFP_KERNEL); if (!debug->dpcd) { rc = -ENOMEM; kfree(debug); goto error; } debug->dpcd_size = SZ_16; INIT_WORK(&debug->sim_work, dp_debug_sim_work); debug->dp_debug.debug_en = false; debug->usbpd = usbpd; debug->link = link; debug->panel = panel; debug->aux = aux; debug->dev = dev; debug->connector = connector; Loading Loading @@ -1063,7 +1181,11 @@ void dp_debug_put(struct dp_debug *dp_debug) dp_debug_deinit(dp_debug); if (debug->edid) devm_kfree(debug->dev, debug->edid); if (debug->dpcd) devm_kfree(debug->dev, debug->dpcd); devm_kfree(debug->dev, debug); }