diff options
| author | Manoj Rao <manojraj@codeaurora.org> | 2013-01-21 16:44:08 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:14:19 -0700 |
| commit | dba93255c8f682bb25200b8a97a487d3628d9114 (patch) | |
| tree | 5acddc4955c71f6a3d3b0500722d3bf52c4b1c69 | |
| parent | fa1b60d13d37d28f16d65ae7aa8fb2f13dc2a251 (diff) | |
msm: 8974: MHL Scratchpad interface implementation
MHL Scratchpad provides an interface for
the MHL peer devices to communicate with each other
Each device shall provide a sixteen
byte writeable memory space to its peer.
This change implements the scratchpad read and write
interfaces for MHL Tx chipset.
Change-Id: Ifaaa2e799424514ec68c8e4c7434f95a68261fe1
Signed-off-by: Manoj Rao <manojraj@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mhl_msc.c | 179 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mhl_msc.h | 6 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mhl_sii8334.c | 18 |
3 files changed, 179 insertions, 24 deletions
diff --git a/drivers/video/fbdev/msm/mhl_msc.c b/drivers/video/fbdev/msm/mhl_msc.c index 94f6d2b8de9f..3d3fff973752 100644 --- a/drivers/video/fbdev/msm/mhl_msc.c +++ b/drivers/video/fbdev/msm/mhl_msc.c @@ -67,12 +67,37 @@ void mhl_register_msc(struct mhl_tx_ctrl *ctrl) mhl_ctrl = ctrl; } +static int mhl_flag_scrpd_burst_req(struct mhl_tx_ctrl *mhl_ctrl, + struct msc_command_struct *req) +{ + int postpone_send = 0; + + if ((req->command == MHL_SET_INT) && + (req->offset == MHL_RCHANGE_INT)) { + if (mhl_ctrl->scrpd_busy) { + /* reduce priority */ + if (req->payload.data[0] == MHL_INT_REQ_WRT) + postpone_send = 1; + } else { + if (req->payload.data[0] == MHL_INT_REQ_WRT) { + mhl_ctrl->scrpd_busy = true; + mhl_ctrl->wr_burst_pending = true; + } else if (req->payload.data[0] == MHL_INT_GRT_WRT) { + mhl_ctrl->scrpd_busy = true; + } + } + } + return postpone_send; +} + + + void mhl_msc_send_work(struct work_struct *work) { struct mhl_tx_ctrl *mhl_ctrl = container_of(work, struct mhl_tx_ctrl, mhl_msc_send_work); struct msc_cmd_envelope *cmd_env; - int ret; + int ret, postpone_send; /* * Remove item from the queue * and schedule it @@ -85,21 +110,39 @@ void mhl_msc_send_work(struct work_struct *work) list_del(&cmd_env->msc_queue_envelope); mutex_unlock(&msc_send_workqueue_mutex); - ret = mhl_send_msc_command(mhl_ctrl, &cmd_env->msc_cmd_msg); - if (ret == -EAGAIN) { - int retry = 2; - while (retry--) { - ret = mhl_send_msc_command( - mhl_ctrl, - &cmd_env->msc_cmd_msg); - if (ret != -EAGAIN) - break; + postpone_send = mhl_flag_scrpd_burst_req( + mhl_ctrl, + &cmd_env->msc_cmd_msg); + if (postpone_send) { + if (cmd_env->msc_cmd_msg.retry-- > 0) { + mutex_lock(&msc_send_workqueue_mutex); + list_add_tail( + &cmd_env->msc_queue_envelope, + &mhl_ctrl->list_cmd); + mutex_unlock(&msc_send_workqueue_mutex); + } else { + pr_err("%s: max scrpd retry out\n", + __func__); + } + } else { + ret = mhl_send_msc_command(mhl_ctrl, + &cmd_env->msc_cmd_msg); + if (ret == -EAGAIN) { + int retry = 2; + while (retry--) { + ret = mhl_send_msc_command( + mhl_ctrl, + &cmd_env->msc_cmd_msg); + if (ret != -EAGAIN) + break; + } } + if (ret == -EAGAIN) + pr_err("%s: send_msc_command retry out!\n", + __func__); + vfree(cmd_env); } - if (ret == -EAGAIN) - pr_err("%s: send_msc_command retry out!\n", __func__); - vfree(cmd_env); mutex_lock(&msc_send_workqueue_mutex); } mutex_unlock(&msc_send_workqueue_mutex); @@ -179,20 +222,26 @@ int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl, case DEVCAP_OFFSET_INT_STAT_SIZE: break; } - + break; + case MHL_WRITE_BURST: + mhl_msc_send_set_int( + mhl_ctrl, + MHL_RCHANGE_INT, + MHL_INT_DSCR_CHG, + MSC_PRIORITY_SEND); break; } return 0; } int mhl_msc_send_set_int(struct mhl_tx_ctrl *mhl_ctrl, - u8 offset, u8 mask) + u8 offset, u8 mask, u8 prior) { struct msc_command_struct req; req.command = MHL_SET_INT; req.offset = offset; req.payload.data[0] = mask; - return mhl_queue_msc_command(mhl_ctrl, &req, MSC_NORMAL_SEND); + return mhl_queue_msc_command(mhl_ctrl, &req, prior); } int mhl_msc_send_write_stat(struct mhl_tx_ctrl *mhl_ctrl, @@ -205,6 +254,27 @@ int mhl_msc_send_write_stat(struct mhl_tx_ctrl *mhl_ctrl, return mhl_queue_msc_command(mhl_ctrl, &req, MSC_NORMAL_SEND); } +static int mhl_msc_write_burst(struct mhl_tx_ctrl *mhl_ctrl, + u8 offset, u8 *data, u8 length) +{ + struct msc_command_struct req; + if (!mhl_ctrl) + return -EFAULT; + + if (!mhl_ctrl->wr_burst_pending) + return -EFAULT; + + req.command = MHL_WRITE_BURST; + req.offset = offset; + req.length = length; + req.payload.burst_data = data; + mhl_queue_msc_command(mhl_ctrl, &req, MSC_PRIORITY_SEND); + mhl_ctrl->wr_burst_pending = false; + return 0; +} + + + int mhl_msc_send_msc_msg(struct mhl_tx_ctrl *mhl_ctrl, u8 sub_cmd, u8 cmd_data) { @@ -384,6 +454,7 @@ int mhl_msc_recv_msc_msg(struct mhl_tx_ctrl *mhl_ctrl, int mhl_msc_recv_set_int(struct mhl_tx_ctrl *mhl_ctrl, u8 offset, u8 set_int) { + int prior; if (offset >= 2) return -EFAULT; @@ -394,18 +465,36 @@ int mhl_msc_recv_set_int(struct mhl_tx_ctrl *mhl_ctrl, mhl_ctrl->devcap_state = 0; mhl_msc_read_devcap_all(mhl_ctrl); } - if (set_int & MHL_INT_DSCR_CHG) + if (set_int & MHL_INT_DSCR_CHG) { + /* peer's scratchpad reg changed */ pr_debug("%s: dscr chg\n", __func__); + mhl_read_scratchpad(mhl_ctrl); + mhl_ctrl->scrpd_busy = false; + } if (set_int & MHL_INT_REQ_WRT) { - /* SET_INT: GRT_WRT */ + /* SET_INT: REQ_WRT */ + if (mhl_ctrl->scrpd_busy) { + prior = MSC_NORMAL_SEND; + } else { + prior = MSC_PRIORITY_SEND; + mhl_ctrl->scrpd_busy = true; + } mhl_msc_send_set_int( mhl_ctrl, MHL_RCHANGE_INT, - MHL_INT_GRT_WRT); + MHL_INT_GRT_WRT, + prior); } - if (set_int & MHL_INT_GRT_WRT) + if (set_int & MHL_INT_GRT_WRT) { + /* SET_INT: GRT_WRT */ pr_debug("%s: recvd req to permit/grant write", __func__); + mhl_msc_write_burst( + mhl_ctrl, + MHL_SCRATCHPAD_OFFSET, + mhl_ctrl->scrpd.data, + mhl_ctrl->scrpd.length); + } break; case 1: if (set_int & MHL_INT_EDID_CHG) { @@ -487,3 +576,53 @@ int mhl_msc_recv_write_stat(struct mhl_tx_ctrl *mhl_ctrl, mhl_ctrl->path_en_state = value; return 0; } + +static int mhl_request_write_burst(struct mhl_tx_ctrl *mhl_ctrl, + u8 start_reg, + u8 length, u8 *data) +{ + int rc = 0; + + if (!(mhl_ctrl->devcap[DEVCAP_OFFSET_FEATURE_FLAG] & + MHL_FEATURE_SP_SUPPORT)) { + pr_debug("MHL: SCRATCHPAD_NOT_SUPPORTED\n"); + rc = -EFAULT; + } else { + if (mhl_ctrl->scrpd_busy) { + pr_debug("MHL: scratchpad_busy\n"); + rc = -EBUSY; + } else { + int i, reg; + for (i = 0, reg = start_reg; (i < length) && + (reg < MHL_SCRATCHPAD_SIZE); i++, reg++) + mhl_ctrl->scrpd.data[reg] = data[i]; + mhl_ctrl->scrpd.length = length; + mhl_ctrl->scrpd.offset = start_reg; + mhl_msc_send_set_int( + mhl_ctrl, + MHL_RCHANGE_INT, + MHL_INT_REQ_WRT, + MSC_PRIORITY_SEND); + } + } + return rc; +} + +/* write scratchpad entry */ +int mhl_write_scratchpad(struct mhl_tx_ctrl *mhl_ctrl, + u8 offset, u8 length, u8 *data) +{ + int rc; + + if ((length < ADOPTER_ID_SIZE) || + (length > MAX_SCRATCHPAD_TRANSFER_SIZE) || + (offset > (MAX_SCRATCHPAD_TRANSFER_SIZE - ADOPTER_ID_SIZE)) || + ((offset + length) > MAX_SCRATCHPAD_TRANSFER_SIZE)) { + pr_debug("MHL: write_burst (0x%02x)\n", -EINVAL); + return -EINVAL; + } + + rc = mhl_request_write_burst(mhl_ctrl, offset, length, data); + + return rc; +} diff --git a/drivers/video/fbdev/msm/mhl_msc.h b/drivers/video/fbdev/msm/mhl_msc.h index 9a7b3d6649c1..8a1fd3943b2e 100644 --- a/drivers/video/fbdev/msm/mhl_msc.h +++ b/drivers/video/fbdev/msm/mhl_msc.h @@ -29,14 +29,15 @@ int mhl_msc_command_done(struct mhl_tx_ctrl *mhl_ctrl, struct msc_command_struct *req); int mhl_msc_send_set_int(struct mhl_tx_ctrl *mhl_ctrl, - u8 offset, u8 mask); + u8 offset, u8 mask, u8 priority); int mhl_msc_send_write_stat(struct mhl_tx_ctrl *mhl_ctrl, u8 offset, u8 value); int mhl_msc_send_msc_msg(struct mhl_tx_ctrl *mhl_ctrl, u8 sub_cmd, u8 cmd_data); -int mhl_msc_recv_set_int(struct mhl_tx_ctrl *mhl_ctrl, u8 offset, u8 set_int); +int mhl_msc_recv_set_int(struct mhl_tx_ctrl *mhl_ctrl, + u8 offset, u8 set_int); int mhl_msc_recv_write_stat(struct mhl_tx_ctrl *mhl_ctrl, u8 offset, u8 value); @@ -48,6 +49,7 @@ void mhl_msc_send_work(struct work_struct *work); /* Tx should implement these APIs */ int mhl_send_msc_command(struct mhl_tx_ctrl *mhl_ctrl, struct msc_command_struct *req); +void mhl_read_scratchpad(struct mhl_tx_ctrl *mhl_ctrl); void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state); void mhl_tmds_ctrl(struct mhl_tx_ctrl *ctrl, uint8_t on); /******************************************************************/ diff --git a/drivers/video/fbdev/msm/mhl_sii8334.c b/drivers/video/fbdev/msm/mhl_sii8334.c index 53c4783a1ea4..4d6af156fe7c 100644 --- a/drivers/video/fbdev/msm/mhl_sii8334.c +++ b/drivers/video/fbdev/msm/mhl_sii8334.c @@ -802,7 +802,8 @@ static void mhl_msm_connection(struct mhl_tx_ctrl *mhl_ctrl) mhl_msc_send_set_int(mhl_ctrl, MHL_RCHANGE_INT, - MHL_INT_DCAP_CHG); + MHL_INT_DCAP_CHG, + MSC_PRIORITY_SEND); } @@ -1101,7 +1102,8 @@ int mhl_send_msc_command(struct mhl_tx_ctrl *mhl_ctrl, } burst_data = req->payload.burst_data; for (i = 0; i < req->length; i++, burst_data++) - MHL_SII_CBUS_WR(0xC0 + i, *burst_data); + MHL_SII_REG_NAME_WR(REG_CBUS_SCRATCHPAD_0 + i, + *burst_data); break; default: pr_err("%s: unknown command! (%02x)\n", @@ -1138,6 +1140,18 @@ cbus_send_fail: return -EFAULT; } +/* read scratchpad */ +void mhl_read_scratchpad(struct mhl_tx_ctrl *mhl_ctrl) +{ + struct i2c_client *client = mhl_ctrl->i2c_handle; + int i; + + for (i = 0; i < MHL_SCRATCHPAD_SIZE; i++) { + mhl_ctrl->scrpd.data[i] = MHL_SII_REG_NAME_RD( + REG_CBUS_SCRATCHPAD_0 + i); + } +} + static void mhl_cbus_isr(struct mhl_tx_ctrl *mhl_ctrl) { uint8_t regval; |
