summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/adsprpc.c17
-rw-r--r--drivers/char/diag/diagchar.h1
-rw-r--r--drivers/char/diag/diagchar_core.c69
-rw-r--r--drivers/char/diag/diagfwd_mhi.c32
-rw-r--r--drivers/crypto/msm/ice.c2
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c43
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h3
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c5
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c56
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h13
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h6
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.c26
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.h4
-rw-r--r--drivers/hwtracing/coresight/coresight-remote-etm.c3
-rw-r--r--drivers/md/dm-android-verity.c2
-rw-r--r--drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c35
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c48
-rw-r--r--drivers/media/platform/msm/vidc/msm_venc.c2
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc.c6
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c57
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.h6
-rw-r--r--drivers/mmc/host/sdhci-msm.c4
-rw-r--r--drivers/mmc/host/sdhci.c2
-rw-r--r--drivers/mmc/host/sdhci.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c107
-rw-r--r--drivers/net/wireless/cnss2/main.c3
-rw-r--r--drivers/net/wireless/cnss2/pci.c8
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dp.c6
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c4
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c2
-rw-r--r--drivers/power/supply/qcom/smb-lib.c53
-rw-r--r--drivers/power/supply/qcom/smb-lib.h1
-rw-r--r--drivers/power/supply/qcom/step-chg-jeita.c272
-rw-r--r--drivers/power/supply/qcom/step-chg-jeita.h17
-rw-r--r--drivers/thermal/msm_thermal.c2
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c52
-rw-r--r--drivers/usb/gadget/function/f_accessory.c31
-rw-r--r--drivers/usb/gadget/function/f_qdss.c140
-rw-r--r--drivers/usb/gadget/function/f_qdss.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c15
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c34
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp_v3.c11
43 files changed, 982 insertions, 227 deletions
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index a84172106e0f..8017961783f7 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -291,6 +291,7 @@ struct fastrpc_file {
int cid;
int ssrcount;
int pd;
+ int file_close;
struct fastrpc_apps *apps;
struct fastrpc_perf perf;
struct dentry *debugfs_file;
@@ -319,6 +320,7 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = {
.channel = SMD_APPS_DSPS,
.link.link_info.edge = "dsps",
.link.link_info.transport = "smem",
+ .vmid = VMID_SSC_Q6,
},
{
.name = "cdsprpc-smd",
@@ -699,7 +701,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned attr,
if (vmid) {
int srcVM[1] = {VMID_HLOS};
int destVM[2] = {VMID_HLOS, vmid};
- int destVMperm[2] = {PERM_READ | PERM_WRITE,
+ int destVMperm[2] = {PERM_READ | PERM_WRITE | PERM_EXEC,
PERM_READ | PERM_WRITE | PERM_EXEC};
VERIFY(err, !hyp_assign_phys(map->phys,
@@ -771,7 +773,7 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, ssize_t size,
if (vmid) {
int srcVM[1] = {VMID_HLOS};
int destVM[2] = {VMID_HLOS, vmid};
- int destVMperm[2] = {PERM_READ | PERM_WRITE,
+ int destVMperm[2] = {PERM_READ | PERM_WRITE | PERM_EXEC,
PERM_READ | PERM_WRITE | PERM_EXEC};
VERIFY(err, !hyp_assign_phys(buf->phys, buf_page_size(size),
@@ -2195,6 +2197,9 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
return 0;
}
(void)fastrpc_release_current_dsp_process(fl);
+ spin_lock(&fl->hlock);
+ fl->file_close = 1;
+ spin_unlock(&fl->hlock);
fastrpc_context_list_dtor(fl);
fastrpc_buf_list_free(fl);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
@@ -2583,6 +2588,14 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num,
p.inv.fds = 0;
p.inv.attrs = 0;
+ spin_lock(&fl->hlock);
+ if (fl->file_close == 1) {
+ err = EBADF;
+ pr_warn("ADSPRPC: fastrpc_device_release is happening, So not sending any new requests to DSP");
+ spin_unlock(&fl->hlock);
+ goto bail;
+ }
+ spin_unlock(&fl->hlock);
switch (ioctl_num) {
case FASTRPC_IOCTL_INVOKE:
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index cc56d68217b3..d81a39e2c637 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -642,6 +642,7 @@ struct diagchar_dev {
#endif
int time_sync_enabled;
uint8_t uses_time_api;
+ struct platform_device *pdev;
};
extern struct diagchar_dev *driver;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index afaedc99a4e7..eaed3b101095 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -22,6 +22,8 @@
#include <linux/sched.h>
#include <linux/ratelimit.h>
#include <linux/timer.h>
+#include <linux/platform_device.h>
+#include <linux/msm_mhi.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <linux/usb/usbdiag.h>
#endif
@@ -701,6 +703,11 @@ static void diag_cmd_invalidate_polling(int change_flag)
driver->polling_reg_flag = 0;
list_for_each_safe(start, temp, &driver->cmd_reg_list) {
item = list_entry(start, struct diag_cmd_reg_t, link);
+ if (&item->entry == NULL) {
+ pr_err("diag: In %s, unable to search command\n",
+ __func__);
+ return;
+ }
polling = diag_cmd_chk_polling(&item->entry);
if (polling == DIAG_CMD_POLLING) {
driver->polling_reg_flag = 1;
@@ -842,6 +849,12 @@ void diag_cmd_remove_reg_by_pid(int pid)
mutex_lock(&driver->cmd_reg_mutex);
list_for_each_safe(start, temp, &driver->cmd_reg_list) {
item = list_entry(start, struct diag_cmd_reg_t, link);
+ if (&item->entry == NULL) {
+ pr_err("diag: In %s, unable to search command\n",
+ __func__);
+ mutex_unlock(&driver->cmd_reg_mutex);
+ return;
+ }
if (item->pid == pid) {
list_del(&item->link);
kfree(item);
@@ -860,6 +873,12 @@ void diag_cmd_remove_reg_by_proc(int proc)
mutex_lock(&driver->cmd_reg_mutex);
list_for_each_safe(start, temp, &driver->cmd_reg_list) {
item = list_entry(start, struct diag_cmd_reg_t, link);
+ if (&item->entry == NULL) {
+ pr_err("diag: In %s, unable to search command\n",
+ __func__);
+ mutex_unlock(&driver->cmd_reg_mutex);
+ return;
+ }
if (item->proc == proc) {
list_del(&item->link);
kfree(item);
@@ -1836,14 +1855,18 @@ static int diag_ioctl_lsm_deinit(void)
{
int i;
+ mutex_lock(&driver->diagchar_mutex);
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
break;
- if (i == driver->num_clients)
+ if (i == driver->num_clients) {
+ mutex_unlock(&driver->diagchar_mutex);
return -EINVAL;
+ }
driver->data_ready[i] |= DEINIT_TYPE;
+ mutex_unlock(&driver->diagchar_mutex);
wake_up_interruptible(&driver->wait_q);
return 1;
@@ -3585,6 +3608,41 @@ static int diagchar_cleanup(void)
return 0;
}
+static int diag_mhi_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ if (!mhi_is_device_ready(&pdev->dev, "qcom,mhi"))
+ return -EPROBE_DEFER;
+ driver->pdev = pdev;
+ ret = diag_remote_init();
+ if (ret) {
+ diag_remote_exit();
+ return ret;
+ }
+ ret = diagfwd_bridge_init();
+ if (ret) {
+ diagfwd_bridge_exit();
+ return ret;
+ }
+ pr_debug("diag: mhi device is ready\n");
+ return 0;
+}
+
+static const struct of_device_id diag_mhi_table[] = {
+ {.compatible = "qcom,diag-mhi"},
+ {},
+};
+
+static struct platform_driver diag_mhi_driver = {
+ .probe = diag_mhi_probe,
+ .driver = {
+ .name = "DIAG MHI Platform",
+ .owner = THIS_MODULE,
+ .of_match_table = diag_mhi_table,
+ },
+};
+
static int __init diagchar_init(void)
{
dev_t dev;
@@ -3674,9 +3732,6 @@ static int __init diagchar_init(void)
ret = diag_masks_init();
if (ret)
goto fail;
- ret = diag_remote_init();
- if (ret)
- goto fail;
ret = diag_mux_init();
if (ret)
goto fail;
@@ -3713,9 +3768,7 @@ static int __init diagchar_init(void)
goto fail;
pr_debug("diagchar initialized now");
- ret = diagfwd_bridge_init();
- if (ret)
- diagfwd_bridge_exit();
+ platform_driver_register(&diag_mhi_driver);
return 0;
fail:
@@ -3729,9 +3782,7 @@ fail:
diagfwd_cntl_exit();
diag_dci_exit();
diag_masks_exit();
- diag_remote_exit();
return -1;
-
}
static void diagchar_exit(void)
diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c
index 03133a5a89aa..edfba6bb09c9 100644
--- a/drivers/char/diag/diagfwd_mhi.c
+++ b/drivers/char/diag/diagfwd_mhi.c
@@ -197,7 +197,7 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info)
struct diag_mhi_buf_tbl_t *item = NULL;
struct diag_mhi_ch_t *ch = NULL;
- if (!mhi_info || !mhi_info->enabled)
+ if (!mhi_info)
return;
/* Clear all the pending reads */
@@ -678,7 +678,25 @@ static int diag_mhi_register_ch(int id, struct diag_mhi_ch_t *ch)
atomic_set(&(ch->opened), 0);
ctxt = SET_CH_CTXT(id, ch->type);
ch->client_info.mhi_client_cb = mhi_notifier;
- return mhi_register_channel(&ch->hdl, NULL);
+ ch->client_info.chan = ch->chan;
+ ch->client_info.dev = &driver->pdev->dev;
+ ch->client_info.node_name = "qcom,mhi";
+ ch->client_info.user_data = (void *)(uintptr_t)ctxt;
+ return mhi_register_channel(&ch->hdl, &ch->client_info);
+}
+
+static void diag_mhi_dev_exit(int dev)
+{
+ struct diag_mhi_info *mhi_info = NULL;
+
+ mhi_info = &diag_mhi[dev];
+ if (!mhi_info)
+ return;
+ if (mhi_info->mhi_wq)
+ destroy_workqueue(mhi_info->mhi_wq);
+ mhi_close(mhi_info->id);
+ if (mhi_info->mempool_init)
+ diagmem_exit(driver, mhi_info->mempool);
}
int diag_mhi_init()
@@ -726,22 +744,16 @@ int diag_mhi_init()
return 0;
fail:
- diag_mhi_exit();
+ diag_mhi_dev_exit(i);
return -ENOMEM;
}
void diag_mhi_exit()
{
int i;
- struct diag_mhi_info *mhi_info = NULL;
for (i = 0; i < NUM_MHI_DEV; i++) {
- mhi_info = &diag_mhi[i];
- if (mhi_info->mhi_wq)
- destroy_workqueue(mhi_info->mhi_wq);
- mhi_close(mhi_info->id);
- if (mhi_info->mempool_init)
- diagmem_exit(driver, mhi_info->mempool);
+ diag_mhi_dev_exit(i);
}
}
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index 7dd8d3d3f6ad..49165daa807f 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -1432,7 +1432,7 @@ static int qcom_ice_config_start(struct platform_device *pdev,
int ret = 0;
bool is_pfe = false;
- if (!pdev || !req || !setting) {
+ if (!pdev || !req) {
pr_err("%s: Invalid params passed\n", __func__);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 1b295949122b..e8b3e85603e4 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -1961,6 +1961,30 @@ enable_packet_control:
hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control);
}
+static void sde_hdmi_clear_hdr_infoframe(struct sde_hdmi *display)
+{
+ struct hdmi *hdmi;
+ struct drm_connector *connector;
+ u32 packet_control = 0;
+
+ if (!display) {
+ SDE_ERROR("invalid input\n");
+ return;
+ }
+
+ hdmi = display->ctrl.ctrl;
+ connector = display->ctrl.ctrl->connector;
+
+ if (!hdmi || !connector) {
+ SDE_ERROR("invalid input\n");
+ return;
+ }
+
+ packet_control = hdmi_read(hdmi, HDMI_GEN_PKT_CTRL);
+ packet_control &= ~HDMI_GEN_PKT_CTRL_CLR_MASK;
+ hdmi_write(hdmi, HDMI_GEN_PKT_CTRL, packet_control);
+}
+
int sde_hdmi_set_property(struct drm_connector *connector,
struct drm_connector_state *state,
int property_index,
@@ -2305,15 +2329,28 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector,
void *display,
struct msm_display_kickoff_params *params)
{
+ struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
+ struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl;
+ u8 hdr_op;
if (!connector || !display || !params) {
pr_err("Invalid params\n");
return -EINVAL;
}
- if (connector->hdr_supported)
- sde_hdmi_panel_set_hdr_infoframe(display,
- params->hdr_metadata);
+ hdr_ctrl = params->hdr_ctrl;
+
+ hdr_op = sde_hdmi_hdr_get_ops(hdmi_display->curr_hdr_state,
+ hdr_ctrl->hdr_state);
+
+ if (hdr_op == HDR_SEND_INFO) {
+ if (connector->hdr_supported)
+ sde_hdmi_panel_set_hdr_infoframe(display,
+ &hdr_ctrl->hdr_meta);
+ } else if (hdr_op == HDR_CLEAR_INFO)
+ sde_hdmi_clear_hdr_infoframe(display);
+
+ hdmi_display->curr_hdr_state = hdr_ctrl->hdr_state;
return 0;
}
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index 743d34d05e57..bafb2b949a6b 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -147,6 +147,7 @@ struct sde_hdmi {
u32 hdcp22_present;
u8 hdcp_status;
u32 enc_lvl;
+ u8 curr_hdr_state;
bool auth_state;
bool sink_hdcp22_support;
bool src_hdcp22_support;
@@ -198,6 +199,8 @@ enum hdmi_tx_scdc_access_type {
#define HDMI_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2
#define HDMI_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
+#define HDMI_GEN_PKT_CTRL_CLR_MASK 0x7
+
/* Maximum pixel clock rates for hdmi tx */
#define HDMI_DEFAULT_MAX_PCLK_RATE 148500
#define HDMI_TX_3_MAX_PCLK_RATE 297000
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
index a4c3c2e7ce46..62dd3aaf7078 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
@@ -518,12 +518,17 @@ static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge)
{
struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
struct hdmi *hdmi = sde_hdmi_bridge->hdmi;
+ struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
+ struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
/* need to update hdcp info here to ensure right HDCP support*/
sde_hdmi_update_hdcp_info(hdmi->connector);
/* start HDCP authentication */
sde_hdmi_start_hdcp(hdmi->connector);
+
+ /* reset HDR state */
+ display->curr_hdr_state = HDR_DISABLE;
}
static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c
index ba47b7702efd..a291a1112aeb 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.c
@@ -68,6 +68,15 @@ static void sde_hdmi_hdcp2p2_ddc_clear_status(struct sde_hdmi *display)
hdmi_write(hdmi, HDMI_HDCP2P2_DDC_STATUS, reg_val);
}
+static const char *sde_hdmi_hdr_sname(enum sde_hdmi_hdr_state hdr_state)
+{
+ switch (hdr_state) {
+ case HDR_DISABLE: return "HDR_DISABLE";
+ case HDR_ENABLE: return "HDR_ENABLE";
+ default: return "HDR_INVALID_STATE";
+ }
+}
+
/**
* sde_hdmi_dump_regs - utility to dump HDMI regs
* @hdmi_display: Pointer to private display handle
@@ -898,3 +907,50 @@ int sde_hdmi_sink_dc_support(struct drm_connector *connector,
return dc_format;
}
+
+u8 sde_hdmi_hdr_get_ops(u8 curr_state,
+ u8 new_state)
+{
+
+ /** There could be 3 valid state transitions:
+ * 1. HDR_DISABLE -> HDR_ENABLE
+ *
+ * In this transition, we shall start sending
+ * HDR metadata with metadata from the HDR clip
+ *
+ * 2. HDR_ENABLE -> HDR_ENABLE
+ *
+ * In this transition, we will keep sending
+ * HDR metadata but with EOTF and metadata as 0
+ *
+ * 3. HDR_ENABLE -> HDR_DISABLE
+ *
+ * In this transition, we will stop sending
+ * metadata to the sink and clear PKT_CTRL register
+ * bits.
+ */
+
+ if ((curr_state == HDR_DISABLE)
+ && (new_state == HDR_ENABLE)) {
+ HDMI_UTIL_DEBUG("State changed %s ---> %s\n",
+ sde_hdmi_hdr_sname(curr_state),
+ sde_hdmi_hdr_sname(new_state));
+ return HDR_SEND_INFO;
+ } else if ((curr_state == HDR_ENABLE)
+ && (new_state == HDR_ENABLE)) {
+ HDMI_UTIL_DEBUG("State changed %s ---> %s\n",
+ sde_hdmi_hdr_sname(curr_state),
+ sde_hdmi_hdr_sname(new_state));
+ return HDR_SEND_INFO;
+ } else if ((curr_state == HDR_ENABLE)
+ && (new_state == HDR_DISABLE)) {
+ HDMI_UTIL_DEBUG("State changed %s ---> %s\n",
+ sde_hdmi_hdr_sname(curr_state),
+ sde_hdmi_hdr_sname(new_state));
+ return HDR_CLEAR_INFO;
+ }
+
+ HDMI_UTIL_DEBUG("Unsupported OR no state change\n");
+ return HDR_UNSUPPORTED_OP;
+}
+
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h
index 10effed54a14..1d89ae222a7b 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_util.h
@@ -125,6 +125,17 @@ enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask {
RXSTATUS_REAUTH_REQ = BIT(14),
};
+enum sde_hdmi_hdr_state {
+ HDR_DISABLE,
+ HDR_ENABLE
+};
+
+enum sde_hdmi_hdr_op {
+ HDR_UNSUPPORTED_OP,
+ HDR_SEND_INFO,
+ HDR_CLEAR_INFO
+};
+
struct sde_hdmi_tx_hdcp2p2_ddc_data {
enum sde_hdmi_tx_hdcp2p2_rxstatus_intr_mask intr_mask;
u32 timeout_ms;
@@ -170,4 +181,6 @@ bool sde_hdmi_validate_pixclk(struct drm_connector *connector,
unsigned long pclk);
int sde_hdmi_sink_dc_support(struct drm_connector *connector,
struct drm_display_mode *mode);
+u8 sde_hdmi_hdr_get_ops(u8 curr_state,
+ u8 new_state);
#endif /* _SDE_HDMI_UTIL_H_ */
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index ac15f399df7d..08868fce1cb0 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -144,7 +144,7 @@ enum msm_mdp_conn_property {
/* blob properties, always put these first */
CONNECTOR_PROP_SDE_INFO,
CONNECTOR_PROP_HDR_INFO,
- CONNECTOR_PROP_HDR_METADATA,
+ CONNECTOR_PROP_HDR_CONTROL,
/* # of blob properties */
CONNECTOR_PROP_BLOBCOUNT,
@@ -237,10 +237,10 @@ struct msm_display_info {
/**
* struct - msm_display_kickoff_params - info for display features at kickoff
- * @hdr_metadata: HDR metadata info passed from userspace
+ * @hdr_ctrl: HDR control info passed from userspace
*/
struct msm_display_kickoff_params {
- struct drm_msm_ext_panel_hdr_metadata *hdr_metadata;
+ struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 76e6e4ef6e7d..875513d2840f 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -83,7 +83,7 @@ int sde_connector_pre_kickoff(struct drm_connector *connector)
if (!c_conn->ops.pre_kickoff)
return 0;
- params.hdr_metadata = &c_state->hdr_meta;
+ params.hdr_ctrl = &c_state->hdr_ctrl;
rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
@@ -247,6 +247,7 @@ static int _sde_connector_set_hdr_info(
void *usr_ptr)
{
struct drm_connector *connector;
+ struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl;
struct drm_msm_ext_panel_hdr_metadata *hdr_meta;
int i;
@@ -262,21 +263,26 @@ static int _sde_connector_set_hdr_info(
return -ENOTSUPP;
}
- memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
+ memset(&c_state->hdr_ctrl, 0, sizeof(c_state->hdr_ctrl));
if (!usr_ptr) {
- SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n");
+ SDE_DEBUG_CONN(c_conn, "hdr control cleared\n");
return 0;
}
- if (copy_from_user(&c_state->hdr_meta,
+ if (copy_from_user(&c_state->hdr_ctrl,
(void __user *)usr_ptr,
- sizeof(*hdr_meta))) {
- SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n");
+ sizeof(*hdr_ctrl))) {
+ SDE_ERROR_CONN(c_conn, "failed to copy hdr control\n");
return -EFAULT;
}
- hdr_meta = &c_state->hdr_meta;
+ hdr_ctrl = &c_state->hdr_ctrl;
+
+ SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n",
+ hdr_ctrl->hdr_state);
+
+ hdr_meta = &hdr_ctrl->hdr_meta;
SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n",
hdr_meta->hdr_supported);
@@ -362,7 +368,7 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
SDE_ERROR("invalid topology_control: 0x%llX\n", val);
}
- if (idx == CONNECTOR_PROP_HDR_METADATA) {
+ if (idx == CONNECTOR_PROP_HDR_CONTROL) {
rc = _sde_connector_set_hdr_info(c_conn, c_state, (void *)val);
if (rc)
SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc);
@@ -718,8 +724,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
}
msm_property_install_volatile_range(&c_conn->property_info,
- "hdr_metadata", 0x0, 0, ~0, 0,
- CONNECTOR_PROP_HDR_METADATA);
+ "hdr_control", 0x0, 0, ~0, 0,
+ CONNECTOR_PROP_HDR_CONTROL);
msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 19e2b8a3e41c..8257f29bd4b8 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -221,14 +221,14 @@ struct sde_connector {
* @out_fb: Pointer to output frame buffer, if applicable
* @aspace: Address space for accessing frame buffer objects, if applicable
* @property_values: Local cache of current connector property values
- * @hdr_meta: HDR metadata info passed from userspace
+ * @hdr_ctrl: HDR control info passed from userspace
*/
struct sde_connector_state {
struct drm_connector_state base;
struct drm_framebuffer *out_fb;
struct msm_gem_address_space *aspace;
uint64_t property_values[CONNECTOR_PROP_COUNT];
- struct drm_msm_ext_panel_hdr_metadata hdr_meta;
+ struct drm_msm_ext_panel_hdr_ctrl hdr_ctrl;
};
/**
diff --git a/drivers/hwtracing/coresight/coresight-remote-etm.c b/drivers/hwtracing/coresight/coresight-remote-etm.c
index 30b13282f6c0..cc0b25b130d7 100644
--- a/drivers/hwtracing/coresight/coresight-remote-etm.c
+++ b/drivers/hwtracing/coresight/coresight-remote-etm.c
@@ -186,12 +186,9 @@ static void remote_etm_rcv_msg(struct work_struct *work)
struct remote_etm_drvdata *drvdata = container_of(work,
struct remote_etm_drvdata,
work_rcv_msg);
- mutex_lock(&drvdata->mutex);
if (qmi_recv_msg(drvdata->handle) < 0)
dev_err(drvdata->dev, "%s: Error receiving QMI message\n",
__func__);
-
- mutex_unlock(&drvdata->mutex);
}
static void remote_etm_notify(struct qmi_handle *handle,
diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c
index 4f6086970131..43d566fd38ae 100644
--- a/drivers/md/dm-android-verity.c
+++ b/drivers/md/dm-android-verity.c
@@ -645,6 +645,8 @@ static int add_as_linear_device(struct dm_target *ti, char *dev)
android_verity_target.iterate_devices = dm_linear_iterate_devices,
android_verity_target.io_hints = NULL;
+ set_disk_ro(dm_disk(dm_table_get_md(ti->table)), 0);
+
err = dm_linear_ctr(ti, DM_LINEAR_ARGS, linear_table_args);
if (!err) {
diff --git a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c
index 1adb380f335f..40806d5a164f 100644
--- a/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/ais/sensor/actuator/msm_actuator.c
@@ -1722,6 +1722,10 @@ static long msm_actuator_subdev_do_ioctl(
parg = &actuator_data;
break;
}
+ break;
+ case VIDIOC_MSM_ACTUATOR_CFG:
+ pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
+ return -EINVAL;
}
rc = msm_actuator_subdev_ioctl(sd, cmd, parg);
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
index e40869d41a5d..821833d53905 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -903,26 +903,45 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds,
void msm_jpeg_io_dump(void *base, int size)
{
- char line_str[128], *p_str;
+ char line_str[128];
void __iomem *addr = (void __iomem *)base;
int i;
u32 *p = (u32 *) addr;
+ size_t offset = 0;
+ size_t used = 0;
+ size_t min_range = 0;
+ size_t sizeof_line_str = sizeof(line_str);
u32 data;
JPEG_DBG_HIGH("%s:%d] %pK %d", __func__, __LINE__, addr, size);
line_str[0] = '\0';
- p_str = line_str;
for (i = 0; i < size/4; i++) {
if (i % 4 == 0) {
- snprintf(p_str, 12, "%08lx: ", (unsigned long)p);
- p_str += 10;
+ used = snprintf(line_str + offset,
+ sizeof_line_str - offset, "%pK ", p);
+ if ((used < min_range) ||
+ (offset + used >= sizeof_line_str)) {
+ JPEG_PR_ERR("%s\n", line_str);
+ offset = 0;
+ line_str[0] = '\0';
+ } else {
+ offset += used;
+ }
}
data = msm_camera_io_r(p++);
- snprintf(p_str, 12, "%08x ", data);
- p_str += 9;
+ used = snprintf(line_str + offset,
+ sizeof_line_str - offset, "%08x ", data);
+ if ((used < min_range) ||
+ (offset + used >= sizeof_line_str)) {
+ JPEG_PR_ERR("%s\n", line_str);
+ offset = 0;
+ line_str[0] = '\0';
+ } else {
+ offset += used;
+ }
if ((i + 1) % 4 == 0) {
JPEG_DBG_HIGH("%s\n", line_str);
line_str[0] = '\0';
- p_str = line_str;
+ offset = 0;
}
}
if (line_str[0] != '\0')
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 28a4006b480c..0f6389370643 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1491,6 +1491,7 @@ static int msm_vdec_queue_setup(struct vb2_queue *q,
rc = -EINVAL;
break;
}
+ msm_dcvs_try_enable(inst);
/* Pretend as if FW itself is asking for
* additional buffers.
@@ -1570,9 +1571,10 @@ exit:
return rc;
}
-static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst)
+static int set_max_internal_buffers_size(struct msm_vidc_inst *inst)
{
int rc = 0;
+ struct msm_vidc_list *buf_list = &inst->scratchbufs;
struct {
enum hal_buffer type;
struct hal_buffer_requirements *req;
@@ -1580,13 +1582,17 @@ static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst)
} internal_buffers[] = {
{ HAL_BUFFER_INTERNAL_SCRATCH, NULL, 0},
{ HAL_BUFFER_INTERNAL_SCRATCH_1, NULL, 0},
- { HAL_BUFFER_INTERNAL_SCRATCH_2, NULL, 0},
- { HAL_BUFFER_INTERNAL_PERSIST, NULL, 0},
- { HAL_BUFFER_INTERNAL_PERSIST_1, NULL, 0},
};
struct hal_frame_size frame_sz;
int i;
+ mutex_lock(&buf_list->lock);
+ if (!list_empty(&buf_list->list)) {
+ dprintk(VIDC_DBG, "Scratch list already has allocated buf\n");
+ mutex_unlock(&buf_list->lock);
+ return 0;
+ }
+ mutex_unlock(&buf_list->lock);
frame_sz.buffer_type = HAL_BUFFER_INPUT;
frame_sz.width = inst->capability.width.max;
@@ -1612,6 +1618,15 @@ static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst)
get_buff_req_buffer(inst, internal_buffers[i].type);
internal_buffers[i].size = internal_buffers[i].req ?
internal_buffers[i].req->buffer_size : 0;
+
+ rc = allocate_and_set_internal_bufs(inst,
+ internal_buffers[i].req,
+ &inst->scratchbufs, false);
+ if (rc)
+ goto alloc_fail;
+ dprintk(VIDC_DBG,
+ "Allocated scratch type : %d size to : %zd\n",
+ internal_buffers[i].type, internal_buffers[i].size);
}
frame_sz.buffer_type = HAL_BUFFER_INPUT;
@@ -1624,25 +1639,18 @@ static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst)
dprintk(VIDC_ERR,
"%s Failed to get back old buf req, %d\n",
__func__, rc);
- return rc;
+ goto alloc_fail;
}
-
dprintk(VIDC_DBG,
"Old buffer reqs, buffer type = %d width = %d, height = %d\n",
frame_sz.buffer_type, frame_sz.width,
frame_sz.height);
- for (i = 0; i < ARRAY_SIZE(internal_buffers); i++) {
- if (internal_buffers[i].req) {
- internal_buffers[i].req->buffer_size =
- internal_buffers[i].size;
- dprintk(VIDC_DBG,
- "Changing buffer type : %d size to : %zd\n",
- internal_buffers[i].type,
- internal_buffers[i].size);
- }
- }
return 0;
+
+alloc_fail:
+ msm_comm_release_scratch_buffers(inst, false);
+ return rc;
}
static inline int start_streaming(struct msm_vidc_inst *inst)
@@ -1653,6 +1661,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
struct hal_buffer_size_minimum b;
unsigned int buffer_size;
struct msm_vidc_format *fmt = NULL;
+ bool max_internal_buf = false;
fmt = &inst->fmts[CAPTURE_PORT];
buffer_size = fmt->get_frame_size(0,
@@ -1676,8 +1685,9 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "H/w scaling is not in valid range\n");
return -EINVAL;
}
- if ((inst->flags & VIDC_SECURE) && !inst->in_reconfig &&
- !slave_side_cp) {
+ max_internal_buf = (inst->flags & VIDC_SECURE) && !slave_side_cp
+ && (inst->session_type == MSM_VIDC_DECODER);
+ if (max_internal_buf) {
rc = set_max_internal_buffers_size(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -1686,7 +1696,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
goto fail_start;
}
}
- rc = msm_comm_set_scratch_buffers(inst);
+ rc = msm_comm_set_scratch_buffers(inst, max_internal_buf);
if (rc) {
dprintk(VIDC_ERR,
"Failed to set scratch buffers: %d\n", rc);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c5816511e056..e4698e0cdcd8 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1868,7 +1868,7 @@ static inline int start_streaming(struct msm_vidc_inst *inst)
"Failed to get Buffer Requirements : %d\n", rc);
goto fail_start;
}
- rc = msm_comm_set_scratch_buffers(inst);
+ rc = msm_comm_set_scratch_buffers(inst, false);
if (rc) {
dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc);
goto fail_start;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 2b3070974df8..de4705c3d2eb 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -826,7 +826,8 @@ int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
if (inst->session_type == MSM_VIDC_ENCODER &&
!i)
- size = b->m.planes[i].bytesused;
+ size = b->m.planes[i].bytesused +
+ b->m.planes[i].data_offset;
else
size = -1;
@@ -1060,7 +1061,8 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
if (binfo->handle[i] &&
(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
if (inst->session_type == MSM_VIDC_DECODER && !i)
- size = b->m.planes[i].bytesused;
+ size = b->m.planes[i].bytesused +
+ b->m.planes[i].data_offset;
else
size = -1;
rc = msm_comm_smem_cache_operations(inst,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index f85fe6fd3867..1d910f4b235c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -3342,9 +3342,9 @@ static bool reuse_internal_buffers(struct msm_vidc_inst *inst,
return reused;
}
-static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst,
+int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst,
struct hal_buffer_requirements *internal_bufreq,
- struct msm_vidc_list *buf_list)
+ struct msm_vidc_list *buf_list, bool set_on_fw)
{
struct msm_smem *handle;
struct internal_buf *binfo;
@@ -3381,11 +3381,13 @@ static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst,
binfo->handle = handle;
binfo->buffer_type = internal_bufreq->buffer_type;
- rc = set_internal_buf_on_fw(inst, internal_bufreq->buffer_type,
- handle, false);
- if (rc)
- goto fail_set_buffers;
-
+ if (set_on_fw) {
+ rc = set_internal_buf_on_fw(inst,
+ internal_bufreq->buffer_type,
+ handle, false);
+ if (rc)
+ goto fail_set_buffers;
+ }
mutex_lock(&buf_list->lock);
list_add_tail(&binfo->list, &buf_list->list);
mutex_unlock(&buf_list->lock);
@@ -3426,7 +3428,7 @@ static int set_internal_buffers(struct msm_vidc_inst *inst,
return 0;
return allocate_and_set_internal_bufs(inst, internal_buf,
- buf_list);
+ buf_list, true);
}
int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
@@ -3587,39 +3589,6 @@ int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd)
"Failed to flush buffers: %d\n", rc);
}
break;
- case V4L2_DEC_QCOM_CMD_RECONFIG_HINT:
- {
- u32 *ptr = NULL;
- struct hal_buffer_requirements *output_buf;
-
- rc = msm_comm_try_get_bufreqs(inst);
- if (rc) {
- dprintk(VIDC_ERR,
- "Getting buffer requirements failed: %d\n",
- rc);
- break;
- }
-
- output_buf = get_buff_req_buffer(inst,
- msm_comm_get_hal_output_buffer(inst));
- if (output_buf) {
- if (dec) {
- ptr = (u32 *)dec->raw.data;
- ptr[0] = output_buf->buffer_size;
- ptr[1] = output_buf->buffer_count_actual;
- dprintk(VIDC_DBG,
- "Reconfig hint, size is %u, count is %u\n",
- ptr[0], ptr[1]);
- } else {
- dprintk(VIDC_ERR, "Null decoder\n");
- }
- } else {
- dprintk(VIDC_DBG,
- "This output buffer not required, buffer_type: %x\n",
- HAL_BUFFER_OUTPUT);
- }
- break;
- }
default:
dprintk(VIDC_ERR, "Unknown Command %d\n", which_cmd);
rc = -ENOTSUPP;
@@ -4453,15 +4422,15 @@ error:
return rc;
}
-int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
-{
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst,
+ bool max_int_buffer) {
int rc = 0;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
}
- if (msm_comm_release_scratch_buffers(inst, true))
+ if (!max_int_buffer && msm_comm_release_scratch_buffers(inst, true))
dprintk(VIDC_WARN, "Failed to release scratch buffers\n");
rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 7d28859c040c..5658df95db26 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -41,9 +41,13 @@ int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
enum hal_property ptype, void *pdata);
int msm_comm_try_get_prop(struct msm_vidc_inst *inst,
enum hal_property ptype, union hal_get_property *hprop);
-int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst,
+ bool max_int_buffer);
int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_output_buffers(struct msm_vidc_inst *inst);
+int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst,
+ struct hal_buffer_requirements *internal_bufreq,
+ struct msm_vidc_list *buf_list, bool set_on_fw);
int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb);
void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 8dc93900b16d..907763ddf234 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -4179,8 +4179,10 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
/* keep track of the value in SDHCI_CAPABILITIES */
msm_host->caps_0 = caps;
- if ((major == 1) && (minor >= 0x6b))
+ if ((major == 1) && (minor >= 0x6b)) {
msm_host->ice_hci_support = true;
+ host->cdr_support = true;
+ }
}
#ifdef CONFIG_MMC_CQ_HCI
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index a5ff9f73dfbc..0033fea0a800 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3633,7 +3633,7 @@ static void sdhci_cmdq_set_transfer_params(struct mmc_host *mmc)
ctrl |= SDHCI_CTRL_ADMA32;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
- if (host->ops->toggle_cdr)
+ if (host->ops->toggle_cdr && !host->cdr_support)
host->ops->toggle_cdr(host, false);
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 93129b26dc5e..300be7fd0f24 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -564,6 +564,7 @@ struct sdhci_host {
bool runtime_suspended; /* Host is runtime suspended */
bool bus_on; /* Bus power prevents runtime suspend */
bool preset_enabled; /* Preset is enabled */
+ bool cdr_support;
struct mmc_request *mrq; /* Current request */
struct mmc_command *cmd; /* Current command */
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index e430bab869a8..cce931e51d7e 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -667,6 +667,36 @@ ath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw,
*def = &conf->def;
}
+static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
+{
+ int ret;
+ unsigned long time_left;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ ret = ath10k_wmi_peer_delete(ar, vdev_id, addr);
+ if (ret)
+ return ret;
+
+ ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr);
+ if (ret)
+ return ret;
+
+ if (QCA_REV_WCN3990(ar)) {
+ time_left = wait_for_completion_timeout(&ar->peer_delete_done,
+ 50 * HZ);
+
+ if (time_left == 0) {
+ ath10k_warn(ar, "Timeout in receiving peer delete response\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ ar->num_peers--;
+
+ return 0;
+}
+
static int ath10k_peer_create(struct ath10k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -711,7 +741,7 @@ static int ath10k_peer_create(struct ath10k *ar,
spin_unlock_bh(&ar->data_lock);
ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n",
addr, vdev_id);
- ath10k_wmi_peer_delete(ar, vdev_id, addr);
+ ath10k_peer_delete(ar, vdev_id, addr);
return -ENOENT;
}
@@ -779,36 +809,6 @@ static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
}
-static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
-{
- int ret;
- unsigned long time_left;
-
- lockdep_assert_held(&ar->conf_mutex);
-
- ret = ath10k_wmi_peer_delete(ar, vdev_id, addr);
- if (ret)
- return ret;
-
- ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr);
- if (ret)
- return ret;
-
- if (QCA_REV_WCN3990(ar)) {
- time_left = wait_for_completion_timeout(&ar->peer_delete_done,
- 50 * HZ);
-
- if (time_left == 0) {
- ath10k_warn(ar, "Timeout in receiving peer delete response\n");
- return -ETIMEDOUT;
- }
- }
-
- ar->num_peers--;
-
- return 0;
-}
-
static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
{
struct ath10k_peer *peer, *tmp;
@@ -5094,7 +5094,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
err_peer_delete:
if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
arvif->vdev_type == WMI_VDEV_TYPE_IBSS)
- ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr);
+ ath10k_peer_delete(ar, arvif->vdev_id, vif->addr);
err_vdev_delete:
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
@@ -5150,8 +5150,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
- ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id,
- vif->addr);
+ ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
+ vif->addr);
if (ret)
ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n",
arvif->vdev_id, ret);
@@ -7168,12 +7168,25 @@ ath10k_mac_update_vif_chan(struct ath10k *ar,
if (WARN_ON(!arvif->is_up))
continue;
+ if (QCA_REV_WCN3990(ar)) {
+ /* In the case of wcn3990 WLAN module we send
+ * vdev restart only, no need to send vdev down.
+ */
- ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
- if (ret) {
- ath10k_warn(ar, "failed to down vdev %d: %d\n",
- arvif->vdev_id, ret);
- continue;
+ ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
+ if (ret) {
+ ath10k_warn(ar,
+ "failed to restart vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
+ } else {
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ if (ret) {
+ ath10k_warn(ar, "failed to down vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
}
}
@@ -7204,11 +7217,17 @@ ath10k_mac_update_vif_chan(struct ath10k *ar,
ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
ret);
- ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
- if (ret) {
- ath10k_warn(ar, "failed to restart vdev %d: %d\n",
- arvif->vdev_id, ret);
- continue;
+ if (!QCA_REV_WCN3990(ar)) {
+ /* In case of other than wcn3990 WLAN module we
+ * send vdev down and vdev restart to the firmware.
+ */
+
+ ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def);
+ if (ret) {
+ ath10k_warn(ar, "failed to restart vdev %d: %d\n",
+ arvif->vdev_id, ret);
+ continue;
+ }
}
ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index 432960afe09a..e114d0c51a07 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -1100,7 +1100,8 @@ static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv)
return -ENODEV;
}
- if (plat_priv->ramdump_info_v2.dump_data_valid) {
+ if (plat_priv->ramdump_info_v2.dump_data_valid ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
cnss_pci_clear_dump_info(pci_priv);
}
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index a17b72ce03ba..236654285db7 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -1392,8 +1392,12 @@ void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv)
cnss_pci_set_mhi_state_bit(pci_priv, CNSS_MHI_RESUME);
cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_OFF);
- if (!plat_priv->ramdump_info_v2.dump_data_valid)
- cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
+
+ if (plat_priv->ramdump_info_v2.dump_data_valid ||
+ test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state))
+ return;
+
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
}
static int cnss_pci_probe(struct pci_dev *pci_dev,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 5fe425ea7655..034b7fc45d8d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -2093,6 +2093,8 @@ static void ipa3_cleanup_wlan_rx_common_cache(void)
struct ipa3_rx_pkt_wrapper *rx_pkt;
struct ipa3_rx_pkt_wrapper *tmp;
+ spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock);
+
list_for_each_entry_safe(rx_pkt, tmp,
&ipa3_ctx->wc_memb.wlan_comm_desc_list, link) {
list_del(&rx_pkt->link);
@@ -2113,6 +2115,8 @@ static void ipa3_cleanup_wlan_rx_common_cache(void)
IPAERR("wlan comm buff total cnt: %d\n",
ipa3_ctx->wc_memb.wlan_comm_total_cnt);
+ spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock);
+
}
static void ipa3_alloc_wlan_rx_common_cache(u32 size)
@@ -2150,11 +2154,13 @@ static void ipa3_alloc_wlan_rx_common_cache(u32 size)
goto fail_dma_mapping;
}
+ spin_lock_bh(&ipa3_ctx->wc_memb.wlan_spinlock);
list_add_tail(&rx_pkt->link,
&ipa3_ctx->wc_memb.wlan_comm_desc_list);
rx_len_cached = ++ipa3_ctx->wc_memb.wlan_comm_total_cnt;
ipa3_ctx->wc_memb.wlan_comm_free_cnt++;
+ spin_unlock_bh(&ipa3_ctx->wc_memb.wlan_spinlock);
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index f8529faf159d..7c3b5838242e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -359,7 +359,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx,
entry->hdr = hdr_entry;
if (add_ref_hdr)
hdr_entry->ref_cnt++;
- entry->cookie = IPA_HDR_COOKIE;
+ entry->cookie = IPA_PROC_HDR_COOKIE;
needed_len = ipahal_get_proc_ctx_needed_len(proc_ctx->type);
@@ -610,7 +610,7 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl,
struct ipa3_hdr_proc_ctx_tbl *htbl = &ipa3_ctx->hdr_proc_ctx_tbl;
entry = ipa3_id_find(proc_ctx_hdl);
- if (!entry || (entry->cookie != IPA_HDR_COOKIE)) {
+ if (!entry || (entry->cookie != IPA_PROC_HDR_COOKIE)) {
IPAERR_RL("bad parm\n");
return -EINVAL;
}
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 7b7f991ecba9..240531948710 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -1946,6 +1946,7 @@ static int smb2_determine_initial_status(struct smb2 *chip)
smblib_handle_icl_change(0, &irq_data);
smblib_handle_step_chg_state_change(0, &irq_data);
smblib_handle_step_chg_soc_update_request(0, &irq_data);
+ smblib_handle_batt_temp_changed(0, &irq_data);
return 0;
}
@@ -2001,6 +2002,7 @@ static struct smb_irq_info smb2_irqs[] = {
[BATT_TEMP_IRQ] = {
.name = "bat-temp",
.handler = smblib_handle_batt_temp_changed,
+ .wake = true,
},
[BATT_OCP_IRQ] = {
.name = "bat-ocp",
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 64d71727f7e6..6be8b1714cdb 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -2883,6 +2883,51 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
return rc;
}
+static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
+{
+ u8 stat_1, stat_2;
+ int rc;
+
+ rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat_1);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat_2);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if ((chg->jeita_status && !(stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
+ ((stat_1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
+ /*
+ * We are moving from JEITA soft -> Normal and charging
+ * is terminated
+ */
+ rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't disable charging rc=%d\n",
+ rc);
+ return rc;
+ }
+ rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
+ CHARGING_ENABLE_CMD_BIT);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't enable charging rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ chg->jeita_status = stat_2 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
+
+ return 0;
+}
+
/***********************
* USB MAIN PSY GETTERS *
*************************/
@@ -3144,6 +3189,14 @@ irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
+ int rc;
+
+ rc = smblib_recover_from_soft_jeita(chg);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
+ rc);
+ return IRQ_HANDLED;
+ }
rerun_election(chg->fcc_votable);
power_supply_changed(chg->batt_psy);
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 18714827b8d2..d088167d4405 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -329,6 +329,7 @@ struct smb_charger {
bool pr_swap_in_progress;
int typec_mode;
int usb_icl_change_irq_enabled;
+ u32 jeita_status;
/* workaround flag */
u32 wa_flags;
diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c
new file mode 100644
index 000000000000..a2c08be960be
--- /dev/null
+++ b/drivers/power/supply/qcom/step-chg-jeita.c
@@ -0,0 +1,272 @@
+/* Copyright (c) 2017 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#define pr_fmt(fmt) "QCOM-STEPCHG: %s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/pmic-voter.h>
+#include "step-chg-jeita.h"
+
+#define MAX_STEP_CHG_ENTRIES 8
+#define STEP_CHG_VOTER "STEP_CHG_VOTER"
+#define STATUS_CHANGE_VOTER "STATUS_CHANGE_VOTER"
+
+#define is_between(left, right, value) \
+ (((left) >= (right) && (left) >= (value) \
+ && (value) >= (right)) \
+ || ((left) <= (right) && (left) <= (value) \
+ && (value) <= (right)))
+
+struct step_chg_data {
+ u32 vbatt_soc_low;
+ u32 vbatt_soc_high;
+ u32 fcc_ua;
+};
+
+struct step_chg_cfg {
+ u32 psy_prop;
+ char *prop_name;
+ struct step_chg_data cfg[MAX_STEP_CHG_ENTRIES];
+};
+
+struct step_chg_info {
+ ktime_t last_update_time;
+ bool step_chg_enable;
+
+ struct votable *fcc_votable;
+ struct wakeup_source *step_chg_ws;
+ struct power_supply *batt_psy;
+ struct delayed_work status_change_work;
+ struct notifier_block nb;
+};
+
+static struct step_chg_info *the_chip;
+
+/*
+ * Step Charging Configuration
+ * Update the table based on the battery profile
+ * Supports VBATT and SOC based source
+ */
+static struct step_chg_cfg step_chg_config = {
+ .psy_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ .prop_name = "VBATT",
+ .cfg = {
+ /* VBAT_LOW VBAT_HIGH FCC */
+ {3600000, 4000000, 3000000},
+ {4000000, 4200000, 2800000},
+ {4200000, 4400000, 2000000},
+ },
+/*
+ * SOC STEP-CHG configuration example.
+ *
+ * .psy_prop = POWER_SUPPLY_PROP_CAPACITY,
+ * .prop_name = "SOC",
+ * .cfg = {
+ * //SOC_LOW SOC_HIGH FCC
+ * {20, 70, 3000000},
+ * {70, 90, 2750000},
+ * {90, 100, 2500000},
+ * },
+ */
+};
+
+static bool is_batt_available(struct step_chg_info *chip)
+{
+ if (!chip->batt_psy)
+ chip->batt_psy = power_supply_get_by_name("battery");
+
+ if (!chip->batt_psy)
+ return false;
+
+ return true;
+}
+
+static int get_fcc(int threshold)
+{
+ int i;
+
+ for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
+ if (is_between(step_chg_config.cfg[i].vbatt_soc_low,
+ step_chg_config.cfg[i].vbatt_soc_high, threshold))
+ return step_chg_config.cfg[i].fcc_ua;
+
+ return -ENODATA;
+}
+
+static int handle_step_chg_config(struct step_chg_info *chip)
+{
+ union power_supply_propval pval = {0, };
+ int rc = 0, fcc_ua = 0;
+
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, &pval);
+ if (rc < 0)
+ chip->step_chg_enable = 0;
+ else
+ chip->step_chg_enable = pval.intval;
+
+ if (!chip->step_chg_enable) {
+ if (chip->fcc_votable)
+ vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
+ return 0;
+ }
+
+ rc = power_supply_get_property(chip->batt_psy,
+ step_chg_config.psy_prop, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't read %s property rc=%d\n",
+ step_chg_config.prop_name, rc);
+ return rc;
+ }
+
+ chip->fcc_votable = find_votable("FCC");
+ if (!chip->fcc_votable)
+ return -EINVAL;
+
+ fcc_ua = get_fcc(pval.intval);
+ if (fcc_ua < 0) {
+ /* remove the vote if no step-based fcc is found */
+ vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
+ return 0;
+ }
+
+ vote(chip->fcc_votable, STEP_CHG_VOTER, true, fcc_ua);
+
+ pr_debug("%s = %d Step-FCC = %duA\n",
+ step_chg_config.prop_name, pval.intval, fcc_ua);
+
+ return 0;
+}
+
+#define STEP_CHG_HYSTERISIS_DELAY_US 5000000 /* 5 secs */
+static void status_change_work(struct work_struct *work)
+{
+ struct step_chg_info *chip = container_of(work,
+ struct step_chg_info, status_change_work.work);
+ int rc = 0;
+ u64 elapsed_us;
+
+ elapsed_us = ktime_us_delta(ktime_get(), chip->last_update_time);
+ if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
+ goto release_ws;
+
+ if (!is_batt_available(chip))
+ goto release_ws;
+
+ rc = handle_step_chg_config(chip);
+ if (rc < 0)
+ goto release_ws;
+
+ chip->last_update_time = ktime_get();
+
+release_ws:
+ __pm_relax(chip->step_chg_ws);
+}
+
+static int step_chg_notifier_call(struct notifier_block *nb,
+ unsigned long ev, void *v)
+{
+ struct power_supply *psy = v;
+ struct step_chg_info *chip = container_of(nb, struct step_chg_info, nb);
+
+ if (ev != PSY_EVENT_PROP_CHANGED)
+ return NOTIFY_OK;
+
+ if ((strcmp(psy->desc->name, "battery") == 0)) {
+ __pm_stay_awake(chip->step_chg_ws);
+ schedule_delayed_work(&chip->status_change_work, 0);
+ }
+
+ return NOTIFY_OK;
+}
+
+static int step_chg_register_notifier(struct step_chg_info *chip)
+{
+ int rc;
+
+ chip->nb.notifier_call = step_chg_notifier_call;
+ rc = power_supply_reg_notifier(&chip->nb);
+ if (rc < 0) {
+ pr_err("Couldn't register psy notifier rc = %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+int qcom_step_chg_init(bool step_chg_enable)
+{
+ int rc;
+ struct step_chg_info *chip;
+
+ if (the_chip) {
+ pr_err("Already initialized\n");
+ return -EINVAL;
+ }
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->step_chg_ws = wakeup_source_register("qcom-step-chg");
+ if (!chip->step_chg_ws) {
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ chip->step_chg_enable = step_chg_enable;
+
+ if (step_chg_enable && (!step_chg_config.psy_prop ||
+ !step_chg_config.prop_name)) {
+ /* fail if step-chg configuration is invalid */
+ pr_err("Step-chg configuration not defined - fail\n");
+ return -ENODATA;
+ }
+
+ INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
+
+ rc = step_chg_register_notifier(chip);
+ if (rc < 0) {
+ pr_err("Couldn't register psy notifier rc = %d\n", rc);
+ goto release_wakeup_source;
+ }
+
+ the_chip = chip;
+
+ if (step_chg_enable)
+ pr_info("Step charging enabled. Using %s source\n",
+ step_chg_config.prop_name);
+
+ return 0;
+
+release_wakeup_source:
+ wakeup_source_unregister(chip->step_chg_ws);
+cleanup:
+ kfree(chip);
+ return rc;
+}
+
+void qcom_step_chg_deinit(void)
+{
+ struct step_chg_info *chip = the_chip;
+
+ if (!chip)
+ return;
+
+ cancel_delayed_work_sync(&chip->status_change_work);
+ power_supply_unreg_notifier(&chip->nb);
+ wakeup_source_unregister(chip->step_chg_ws);
+ the_chip = NULL;
+ kfree(chip);
+}
diff --git a/drivers/power/supply/qcom/step-chg-jeita.h b/drivers/power/supply/qcom/step-chg-jeita.h
new file mode 100644
index 000000000000..928eeb7a670b
--- /dev/null
+++ b/drivers/power/supply/qcom/step-chg-jeita.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2017 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __STEP_CHG_H__
+#define __STEP_CHG_H__
+int qcom_step_chg_init(bool);
+void qcom_step_chg_deinit(void);
+#endif /* __STEP_CHG_H__ */
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index b1f4c3f27111..4b586f62cdc7 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -2858,7 +2858,7 @@ static void msm_thermal_bite(int zone_id, int temp)
tsens_id, temp);
}
/* If it is a secure device ignore triggering the thermal bite. */
- if (scm_is_secure_device())
+ if (!scm_is_secure_device())
return;
if (!is_scm_armv8()) {
scm_call_atomic1(SCM_SVC_BOOT, THERM_SECURE_BITE_CMD, 0);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 8e8c1a349e6a..c3077ac11709 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -72,6 +72,8 @@ MODULE_PARM_DESC(cpu_to_affin, "affin usb irq to this cpu");
/* XHCI registers */
#define USB3_HCSPARAMS1 (0x4)
+#define USB3_HCCPARAMS2 (0x1c)
+#define HCC_CTC(p) ((p) & (1 << 3))
#define USB3_PORTSC (0x420)
/**
@@ -213,6 +215,7 @@ struct dwc3_msm {
struct notifier_block dwc3_cpu_notifier;
struct notifier_block usbdev_nb;
bool hc_died;
+ bool xhci_ss_compliance_enable;
struct extcon_dev *extcon_vbus;
struct extcon_dev *extcon_id;
@@ -2835,6 +2838,34 @@ static ssize_t speed_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RW(speed);
static void msm_dwc3_perf_vote_work(struct work_struct *w);
+static ssize_t xhci_link_compliance_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
+ if (mdwc->xhci_ss_compliance_enable)
+ return snprintf(buf, PAGE_SIZE, "y\n");
+ else
+ return snprintf(buf, PAGE_SIZE, "n\n");
+}
+
+static ssize_t xhci_link_compliance_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+ bool value;
+ int ret;
+
+ ret = strtobool(buf, &value);
+ if (!ret) {
+ mdwc->xhci_ss_compliance_enable = value;
+ return count;
+ }
+
+ return ret;
+}
+
+static DEVICE_ATTR_RW(xhci_link_compliance);
static int dwc3_msm_probe(struct platform_device *pdev)
{
@@ -3179,6 +3210,7 @@ static int dwc3_msm_probe(struct platform_device *pdev)
device_create_file(&pdev->dev, &dev_attr_mode);
device_create_file(&pdev->dev, &dev_attr_speed);
+ device_create_file(&pdev->dev, &dev_attr_xhci_link_compliance);
host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST;
if (host_mode ||
@@ -3210,6 +3242,7 @@ static int dwc3_msm_remove(struct platform_device *pdev)
int ret_pm;
device_remove_file(&pdev->dev, &dev_attr_mode);
+ device_remove_file(&pdev->dev, &dev_attr_xhci_link_compliance);
if (cpu_to_affin)
unregister_cpu_notifier(&mdwc->dwc3_cpu_notifier);
@@ -3474,6 +3507,25 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
}
/*
+ * If the Compliance Transition Capability(CTC) flag of
+ * HCCPARAMS2 register is set and xhci_link_compliance sysfs
+ * param has been enabled by the user for the SuperSpeed host
+ * controller, then write 10 (Link in Compliance Mode State)
+ * onto the Port Link State(PLS) field of the PORTSC register
+ * for 3.0 host controller which is at an offset of USB3_PORTSC
+ * + 0x10 from the DWC3 base address. Also, disable the runtime
+ * PM of 3.0 root hub (root hub of shared_hcd of xhci device)
+ */
+ if (HCC_CTC(dwc3_msm_read_reg(mdwc->base, USB3_HCCPARAMS2))
+ && mdwc->xhci_ss_compliance_enable
+ && dwc->maximum_speed == USB_SPEED_SUPER) {
+ dwc3_msm_write_reg(mdwc->base, USB3_PORTSC + 0x10,
+ 0x10340);
+ pm_runtime_disable(&hcd_to_xhci(platform_get_drvdata(
+ dwc->xhci))->shared_hcd->self.root_hub->dev);
+ }
+
+ /*
* In some cases it is observed that USB PHY is not going into
* suspend with host mode suspend functionality. Hence disable
* XHCI's runtime PM here if disable_host_mode_pm is set.
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index 1ef3442cf618..7950f25136a5 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -346,6 +346,7 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req)
struct acc_dev *dev = ep->driver_data;
char *string_dest = NULL;
int length = req->actual;
+ unsigned long flags;
if (req->status != 0) {
pr_err("acc_complete_set_string, err %d\n", req->status);
@@ -371,22 +372,26 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req)
case ACCESSORY_STRING_SERIAL:
string_dest = dev->serial;
break;
+ default:
+ pr_err("unknown accessory string index %d\n",
+ dev->string_index);
+ return;
}
- if (string_dest) {
- unsigned long flags;
- if (length >= ACC_STRING_SIZE)
- length = ACC_STRING_SIZE - 1;
-
- spin_lock_irqsave(&dev->lock, flags);
- memcpy(string_dest, req->buf, length);
- /* ensure zero termination */
- string_dest[length] = 0;
- spin_unlock_irqrestore(&dev->lock, flags);
- } else {
- pr_err("unknown accessory string index %d\n",
- dev->string_index);
+ if (!length) {
+ pr_debug("zero length for accessory string index %d\n",
+ dev->string_index);
+ return;
}
+
+ if (length >= ACC_STRING_SIZE)
+ length = ACC_STRING_SIZE - 1;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ memcpy(string_dest, req->buf, length);
+ /* ensure zero termination */
+ string_dest[length] = 0;
+ spin_unlock_irqrestore(&dev->lock, flags);
}
static void acc_complete_set_hid_report_desc(struct usb_ep *ep,
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
index 777acb489875..8536f10a2e35 100644
--- a/drivers/usb/gadget/function/f_qdss.c
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -183,15 +183,28 @@ static struct usb_qdss_opts *to_fi_usb_qdss_opts(struct usb_function_instance *f
}
/*----------------------------------------------------------------------*/
-static void qdss_ctrl_write_complete(struct usb_ep *ep,
+static void qdss_write_complete(struct usb_ep *ep,
struct usb_request *req)
{
struct f_qdss *qdss = ep->driver_data;
struct qdss_request *d_req = req->context;
+ struct usb_ep *in;
+ struct list_head *list_pool;
+ enum qdss_state state;
unsigned long flags;
pr_debug("qdss_ctrl_write_complete\n");
+ if (qdss->debug_inface_enabled) {
+ in = qdss->port.ctrl_in;
+ list_pool = &qdss->ctrl_write_pool;
+ state = USB_QDSS_CTRL_WRITE_DONE;
+ } else {
+ in = qdss->port.data;
+ list_pool = &qdss->data_write_pool;
+ state = USB_QDSS_DATA_WRITE_DONE;
+ }
+
if (!req->status) {
/* send zlp */
if ((req->length >= ep->maxpacket) &&
@@ -199,13 +212,13 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep,
req->length = 0;
d_req->actual = req->actual;
d_req->status = req->status;
- if (!usb_ep_queue(qdss->port.ctrl_in, req, GFP_ATOMIC))
+ if (!usb_ep_queue(in, req, GFP_ATOMIC))
return;
}
}
spin_lock_irqsave(&qdss->lock, flags);
- list_add_tail(&req->list, &qdss->ctrl_write_pool);
+ list_add_tail(&req->list, list_pool);
if (req->length != 0) {
d_req->actual = req->actual;
d_req->status = req->status;
@@ -213,8 +226,7 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep,
spin_unlock_irqrestore(&qdss->lock, flags);
if (qdss->ch.notify)
- qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_WRITE_DONE, d_req,
- NULL);
+ qdss->ch.notify(qdss->ch.priv, state, d_req, NULL);
}
static void qdss_ctrl_read_complete(struct usb_ep *ep,
@@ -252,6 +264,12 @@ void usb_qdss_free_req(struct usb_qdss_ch *ch)
return;
}
+ list_for_each_safe(act, tmp, &qdss->data_write_pool) {
+ req = list_entry(act, struct usb_request, list);
+ list_del(&req->list);
+ usb_ep_free_request(qdss->port.data, req);
+ }
+
list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) {
req = list_entry(act, struct usb_request, list);
list_del(&req->list);
@@ -271,23 +289,41 @@ int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf,
{
struct f_qdss *qdss = ch->priv_usb;
struct usb_request *req;
+ struct usb_ep *in;
+ struct list_head *list_pool;
int i;
pr_debug("usb_qdss_alloc_req\n");
- if (no_write_buf <= 0 || no_read_buf <= 0 || !qdss) {
+ if (!qdss) {
+ pr_err("usb_qdss_alloc_req: channel %s closed\n", ch->name);
+ return -ENODEV;
+ }
+
+ if ((qdss->debug_inface_enabled &&
+ (no_write_buf <= 0 || no_read_buf <= 0)) ||
+ (!qdss->debug_inface_enabled &&
+ (no_write_buf <= 0 || no_read_buf))) {
pr_err("usb_qdss_alloc_req: missing params\n");
return -ENODEV;
}
+ if (qdss->debug_inface_enabled) {
+ in = qdss->port.ctrl_in;
+ list_pool = &qdss->ctrl_write_pool;
+ } else {
+ in = qdss->port.data;
+ list_pool = &qdss->data_write_pool;
+ }
+
for (i = 0; i < no_write_buf; i++) {
- req = usb_ep_alloc_request(qdss->port.ctrl_in, GFP_ATOMIC);
+ req = usb_ep_alloc_request(in, GFP_ATOMIC);
if (!req) {
pr_err("usb_qdss_alloc_req: ctrl_in allocation err\n");
goto fail;
}
- req->complete = qdss_ctrl_write_complete;
- list_add_tail(&req->list, &qdss->ctrl_write_pool);
+ req->complete = qdss_write_complete;
+ list_add_tail(&req->list, list_pool);
}
for (i = 0; i < no_read_buf; i++) {
@@ -479,21 +515,20 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
qdss = container_of(work, struct f_qdss, disconnect_w);
pr_debug("usb_qdss_disconnect_work\n");
- /*
- * Uninitialized init data i.e. ep specific operation.
- * Notify qdss to cancel all active transfers.
- */
- if (qdss->ch.app_conn) {
+
+ /* Notify qdss to cancel all active transfers */
+ if (qdss->ch.notify)
+ qdss->ch.notify(qdss->ch.priv,
+ USB_QDSS_DISCONNECT,
+ NULL,
+ NULL);
+
+ /* Uninitialized init data i.e. ep specific operation */
+ if (qdss->ch.app_conn && !strcmp(qdss->ch.name, USB_QDSS_CH_MSM)) {
status = uninit_data(qdss->port.data);
if (status)
pr_err("%s: uninit_data error\n", __func__);
- if (qdss->ch.notify)
- qdss->ch.notify(qdss->ch.priv,
- USB_QDSS_DISCONNECT,
- NULL,
- NULL);
-
status = set_qdss_data_connection(qdss, 0);
if (status)
pr_err("qdss_disconnect error");
@@ -550,15 +585,16 @@ static void usb_qdss_connect_work(struct work_struct *work)
}
pr_debug("usb_qdss_connect_work\n");
+
+ if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM))
+ goto notify;
+
status = set_qdss_data_connection(qdss, 1);
if (status) {
pr_err("set_qdss_data_connection error(%d)", status);
return;
}
- if (qdss->ch.notify)
- qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT,
- NULL, &qdss->ch);
spin_lock_irqsave(&qdss->lock, flags);
req = qdss->endless_req;
spin_unlock_irqrestore(&qdss->lock, flags);
@@ -566,8 +602,15 @@ static void usb_qdss_connect_work(struct work_struct *work)
return;
status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC);
- if (status)
+ if (status) {
pr_err("%s: usb_ep_queue error (%d)\n", __func__, status);
+ return;
+ }
+
+notify:
+ if (qdss->ch.notify)
+ qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT,
+ NULL, &qdss->ch);
}
static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
@@ -706,6 +749,7 @@ static struct f_qdss *alloc_usb_qdss(char *channel_name)
spin_lock_init(&qdss->lock);
INIT_LIST_HEAD(&qdss->ctrl_read_pool);
INIT_LIST_HEAD(&qdss->ctrl_write_pool);
+ INIT_LIST_HEAD(&qdss->data_write_pool);
INIT_WORK(&qdss->connect_w, usb_qdss_connect_work);
INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work);
@@ -801,6 +845,50 @@ int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
}
EXPORT_SYMBOL(usb_qdss_ctrl_write);
+int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
+{
+ struct f_qdss *qdss = ch->priv_usb;
+ unsigned long flags;
+ struct usb_request *req = NULL;
+
+ pr_debug("usb_qdss_ctrl_write\n");
+
+ if (!qdss)
+ return -ENODEV;
+
+ spin_lock_irqsave(&qdss->lock, flags);
+
+ if (qdss->usb_connected == 0) {
+ spin_unlock_irqrestore(&qdss->lock, flags);
+ return -EIO;
+ }
+
+ if (list_empty(&qdss->data_write_pool)) {
+ pr_err("error: usb_qdss_data_write list is empty\n");
+ spin_unlock_irqrestore(&qdss->lock, flags);
+ return -EAGAIN;
+ }
+
+ req = list_first_entry(&qdss->data_write_pool, struct usb_request,
+ list);
+ list_del(&req->list);
+ spin_unlock_irqrestore(&qdss->lock, flags);
+
+ req->buf = d_req->buf;
+ req->length = d_req->length;
+ req->context = d_req;
+ if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) {
+ spin_lock_irqsave(&qdss->lock, flags);
+ list_add_tail(&req->list, &qdss->data_write_pool);
+ spin_unlock_irqrestore(&qdss->lock, flags);
+ pr_err("qdss usb_ep_queue failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_qdss_write);
+
struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv,
void (*notify)(void *, unsigned, struct qdss_request *,
struct usb_qdss_ch *))
@@ -859,7 +947,9 @@ void usb_qdss_close(struct usb_qdss_ch *ch)
pr_debug("usb_qdss_close\n");
spin_lock_irqsave(&qdss_lock, flags);
- if (!qdss || !qdss->usb_connected) {
+ ch->priv_usb = NULL;
+ if (!qdss || !qdss->usb_connected ||
+ !strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) {
ch->app_conn = 0;
spin_unlock_irqrestore(&qdss_lock, flags);
return;
diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h
index cad0f4cc06f9..fb7c01c0f939 100644
--- a/drivers/usb/gadget/function/f_qdss.h
+++ b/drivers/usb/gadget/function/f_qdss.h
@@ -53,6 +53,10 @@ struct f_qdss {
struct usb_qdss_ch ch;
struct list_head ctrl_read_pool;
struct list_head ctrl_write_pool;
+
+ /* for mdm channel SW path */
+ struct list_head data_write_pool;
+
struct work_struct connect_w;
struct work_struct disconnect_w;
spinlock_t lock;
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 2f169074261a..89ec73c21630 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -3982,12 +3982,6 @@ static int mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp)
{
int ret = 0;
- /* In case of HPD_IRQ events without DP link being turned on such as
- * adb shell stop, skip handling hpd_irq event.
- */
- if (!dp->dp_initialized)
- goto exit;
-
pr_debug("start\n");
dp->hpd_irq_on = true;
@@ -4103,6 +4097,15 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv)
if (dp_drv->alt_mode.dp_status.hpd_irq) {
pr_debug("Attention: hpd_irq high\n");
+ /* In case of HPD_IRQ events without DP link being
+ * turned on such as adb shell stop, skip handling
+ * hpd_irq event.
+ */
+ if (!dp_drv->dp_initialized) {
+ pr_err("DP not initialized yet\n");
+ return;
+ }
+
if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->cp_irq) {
if (!dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data))
return;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
index 71cab148e1c3..aabf7c507376 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, 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
@@ -358,7 +358,8 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
int ret = 0, i = 0;
char __iomem *hist_addr;
u32 sz = 0, temp = 0, *data = NULL;
- struct mdp_hist_lut_data_v1_7 *lut_data = NULL;
+ struct mdp_hist_lut_data_v1_7 lut_data_v1_7;
+ struct mdp_hist_lut_data_v1_7 *lut_data = &lut_data_v1_7;
struct mdp_hist_lut_data *lut_cfg_data = NULL;
if (!base_addr || !cfg_data) {
@@ -378,7 +379,11 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
lut_cfg_data->version, lut_cfg_data->cfg_payload);
return -EINVAL;
}
- lut_data = lut_cfg_data->cfg_payload;
+ if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload,
+ sizeof(*lut_data))) {
+ pr_err("copy from user failed for lut_data\n");
+ return -EFAULT;
+ }
if (lut_data->len != ENHIST_LUT_ENTRIES) {
pr_err("invalid hist_lut len %d", lut_data->len);
return -EINVAL;
@@ -1786,7 +1791,8 @@ static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data,
{
int ret = 0, i = 0;
struct mdp_igc_lut_data *lut_cfg_data = NULL;
- struct mdp_igc_lut_data_v1_7 *lut_data = NULL;
+ struct mdp_igc_lut_data_v1_7 lut_data_v1_7;
+ struct mdp_igc_lut_data_v1_7 *lut_data = &lut_data_v1_7;
char __iomem *c1 = NULL, *c2 = NULL;
u32 *c0c1_data = NULL, *c2_data = NULL;
u32 data = 0, sz = 0;
@@ -1810,7 +1816,11 @@ static int pp_igc_get_config(char __iomem *base_addr, void *cfg_data,
ret = -EINVAL;
goto exit;
}
- lut_data = lut_cfg_data->cfg_payload;
+ if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload,
+ sizeof(*lut_data))) {
+ pr_err("copy from user failed for lut_data\n");
+ return -EFAULT;
+ }
if (lut_data->len != IGC_LUT_ENTRIES) {
pr_err("invalid lut len %d\n", lut_data->len);
ret = -EINVAL;
@@ -1954,20 +1964,24 @@ static int pp_pgc_get_config(char __iomem *base_addr, void *cfg_data,
u32 *c0_data = NULL, *c1_data = NULL, *c2_data = NULL;
u32 val = 0, i = 0, sz = 0;
struct mdp_pgc_lut_data *pgc_data = NULL;
- struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = NULL;
+ struct mdp_pgc_lut_data_v1_7 pgc_lut_data_v17;
+ struct mdp_pgc_lut_data_v1_7 *pgc_data_v17 = &pgc_lut_data_v17;
if (!base_addr || !cfg_data) {
pr_err("invalid params base_addr %pK cfg_data %pK block_type %d\n",
base_addr, cfg_data, block_type);
return -EINVAL;
}
pgc_data = (struct mdp_pgc_lut_data *) cfg_data;
- pgc_data_v17 = (struct mdp_pgc_lut_data_v1_7 *)
- pgc_data->cfg_payload;
- if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data_v17) {
+ if (pgc_data->version != mdp_pgc_v1_7 || !pgc_data->cfg_payload) {
pr_err("invalid pgc version %d payload %pK\n",
- pgc_data->version, pgc_data_v17);
+ pgc_data->version, pgc_data->cfg_payload);
return -EINVAL;
}
+ if (copy_from_user(pgc_data_v17, (void __user *) pgc_data->cfg_payload,
+ sizeof(*pgc_data_v17))) {
+ pr_err("copy from user failed for pgc lut data\n");
+ return -EFAULT;
+ }
if (!(pgc_data->flags & MDP_PP_OPS_READ)) {
pr_info("read ops is not set %d", pgc_data->flags);
return -EINVAL;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c
index 25cb94f89dd5..b377f0921508 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp_v3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 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
@@ -298,7 +298,8 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
int ret = 0, i = 0;
char __iomem *hist_lut_addr;
u32 sz = 0, temp = 0, *data = NULL;
- struct mdp_hist_lut_data_v1_7 *lut_data = NULL;
+ struct mdp_hist_lut_data_v1_7 lut_data_v1_7;
+ struct mdp_hist_lut_data_v1_7 *lut_data = &lut_data_v1_7;
struct mdp_hist_lut_data *lut_cfg_data = NULL;
if (!base_addr || !cfg_data) {
@@ -323,7 +324,11 @@ static int pp_hist_lut_get_config(char __iomem *base_addr, void *cfg_data,
lut_cfg_data->version, lut_cfg_data->cfg_payload);
return -EINVAL;
}
- lut_data = lut_cfg_data->cfg_payload;
+ if (copy_from_user(lut_data, (void __user *) lut_cfg_data->cfg_payload,
+ sizeof(*lut_data))) {
+ pr_err("copy from user failed for lut_data\n");
+ return -EFAULT;
+ }
if (lut_data->len != ENHIST_LUT_ENTRIES) {
pr_err("invalid hist_lut len %d", lut_data->len);
return -EINVAL;