Merge "qseecom: fix secure app loading failure by kernel mode qseecom client"
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index afbae5e..31e0b6b 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -302,6 +302,28 @@
- qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent
to panel in order to switch from command mode to video mode dynamically.
Refer to "qcom,mdss-dsi-on-command" section for adding commands.
+- qcom,esd-check-enabled: Boolean used to enable ESD recovery feature.
+- qcom,mdss-dsi-panel-status-command: A byte stream formed by multiple dcs packets based on
+ qcom dsi controller protocol, to read the panel status.
+ This value is used to kick in the ESD recovery.
+ byte 0: dcs data type
+ byte 1: set to indicate this is an individual packet
+ (no chain)
+ byte 2: virtual channel number
+ byte 3: expect ack from client (dcs read command)
+ byte 4: wait number of specified ms after dcs command
+ transmitted
+ byte 5, 6: 16 bits length in network byte order
+ byte 7 and beyond: number byte of payload
+- qcom,mdss-dsi-panel-status-command-mode:
+ String that specifies the ctrl state for reading the panel status.
+ "dsi_lp_mode" = DSI low power mode
+ "dsi_hs_mode" = DSI high speed mode
+- qcom,mdss-dsi-panel-status-check-mode:Specifies the panel status check method for ESD recovery.
+ "bta_check" = Uses BTA to check the panel status
+ "reg_read" = Reads panel status register to check the panel status
+- qcom,mdss-dsi-panel-status-value: Specifies the value of the panel status register when the panel is
+ in good state.
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -412,5 +434,10 @@
qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B
15 01 00 00 00 00 02 C2 08];
qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03];
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-value = <0x9c>;
};
};
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 8078abf..8c91db0 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -19,7 +19,7 @@
- qcom,max-current : maximum current that the LED can sustain in mA
- linux,name : name of the led that is used in led framework
-Optional properties for each child node, WLED, Flash, MPP and RGB:
+Optional properties for each child node, WLED, Flash, MPP, RGB and KPDBL:
- qcom,in-order-command-processing : specify if user space requests leds in order
WLED is primarily used as display backlight. Display subsystem uses
@@ -121,6 +121,7 @@
for vph_pwr.
- qcom,row-src-en: specify to enable row source
- qcom,always-on: specify if the module has to be always on
+- qcom,use-blink: Use blink sysfs entry for switching into lpg mode. For optimal use, set default mode to pwm. All required lpg parameters must be supplied.
Required properties for PWM mode only:
- qcom,pwm-channel: pwm channel the led will operate on
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index 8eb9b64..2cb528c 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -27,6 +27,10 @@
should be performed during boot up.
- qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value,
using a smaller count for this buffer will reduce the memory usage.
+=======
+- qcom,is-pronto-v3: boolean flag to determine the pronto hardware version
+in use. subsequently correct workqueue will be used by DXE engine to push frames
+in TX data path.
- qcom,wcnss-pm : <Core rail LDO#, PA rail LDO#, XO settling time,
RPM power collapse enabled, standalone power collapse enabled>
Power manager related parameter for LDO configuration.
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
index cbc38f2..996fcae 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -508,6 +508,7 @@
05 01 00 00 78 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-check-mode = "bta_check";
qcom,mdss-dsi-h-sync-pulse = <1>;
qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index bab1735..b5189d4 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -511,6 +511,7 @@
05 01 00 00 78 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-check-mode = "bta_check";
qcom,dynamic-mode-switch-enabled;
qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 14 00 02 C2 0B
15 01 00 00 00 00 02 C2 08];
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index 06abbd8..4be97d8 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -138,21 +138,31 @@
qcom,row-id = <0>;
qcom,row-src-en;
qcom,always-on;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,use-blink;
+ qcom,in-order-command-processing;
};
qcom,kpdbl2 {
label = "kpdbl";
- linux,name = "kpdbl-lut-2";
- qcom,mode = "lpg";
+ linux,name = "kpdbl-pwm-2";
+ qcom,mode = "pwm";
qcom,pwm-channel = <9>;
qcom,pwm-us = <1000>;
- qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
qcom,id = <7>;
qcom,max-current = <20>;
qcom,row-id = <1>;
qcom,row-src-en;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,use-blink;
+ qcom,in-order-command-processing;
+
};
qcom,kpdbl3 {
@@ -165,6 +175,13 @@
qcom,max-current = <20>;
qcom,row-id = <2>;
qcom,row-src-en;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,use-blink;
+ qcom,in-order-command-processing;
+
};
qcom,kpdbl4 {
@@ -177,6 +194,13 @@
qcom,max-current = <20>;
qcom,row-id = <3>;
qcom,row-src-en;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ qcom,use-blink;
+ qcom,in-order-command-processing;
+
};
};
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 99dbec8..495117f 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -214,7 +214,7 @@
interrupts = <0 44 0>;
vdd-supply = <&gdsc_venus>;
qcom,hfi = "venus";
- qcom,has-ocmem;
+ qcom,ocmem-size = <524288>; /* 512 * 1024*/
qcom,max-hw-load = <1216800>; /* 3840 x 2160 @ 30 + 1080p @ 30*/
};
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 1c44f9a..d70b9d4 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -101,8 +101,6 @@
SMD_PKT_STATUS = 1U << 0,
SMD_PKT_READ = 1U << 1,
SMD_PKT_WRITE = 1U << 2,
- SMD_PKT_READ_DUMP_BUFFER = 1U << 3,
- SMD_PKT_WRITE_DUMP_BUFFER = 1U << 4,
SMD_PKT_POLL = 1U << 5,
};
@@ -116,18 +114,6 @@
ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: "x); \
} while (0)
-#define SMD_PKT_LOG_BUF(buf, cnt) \
-do { \
- char log_buf[128]; \
- int i; \
- if (smd_pkt_ilctxt) { \
- i = cnt < 16 ? cnt : 16; \
- hex_dump_to_buffer(buf, i, 16, 1, log_buf, \
- sizeof(log_buf), false); \
- ipc_log_string(smd_pkt_ilctxt, "<SMD_PKT>: %s", log_buf); \
- } \
-} while (0)
-
#define D_STATUS(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_STATUS) \
@@ -149,24 +135,6 @@
SMD_PKT_LOG_STRING(x); \
} while (0)
-#define D_READ_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
- if (msm_smd_pkt_debug_mask & SMD_PKT_READ_DUMP_BUFFER) \
- print_hex_dump(KERN_INFO, prestr, \
- DUMP_PREFIX_NONE, 16, 1, \
- buf, cnt, 1); \
- SMD_PKT_LOG_BUF(buf, cnt); \
-} while (0)
-
-#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) \
-do { \
- if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE_DUMP_BUFFER) \
- print_hex_dump(KERN_INFO, prestr, \
- DUMP_PREFIX_NONE, 16, 1, \
- buf, cnt, 1); \
- SMD_PKT_LOG_BUF(buf, cnt); \
-} while (0)
-
#define D_POLL(x...) \
do { \
if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \
@@ -184,8 +152,6 @@
#define D_STATUS(x...) do {} while (0)
#define D_READ(x...) do {} while (0)
#define D_WRITE(x...) do {} while (0)
-#define D_READ_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
#define D_POLL(x...) do {} while (0)
#define E_SMD_PKT_SSR(x) do {} while (0)
#endif
@@ -432,7 +398,6 @@
return notify_reset(smd_pkt_devp);
}
} while (pkt_size != bytes_read);
- D_READ_DUMP_BUFFER("Read: ", (bytes_read > 16 ? 16 : bytes_read), buf);
mutex_unlock(&smd_pkt_devp->rx_lock);
mutex_lock(&smd_pkt_devp->ch_lock);
@@ -540,8 +505,6 @@
} while (bytes_written != count);
smd_write_end(smd_pkt_devp->ch);
mutex_unlock(&smd_pkt_devp->tx_lock);
- D_WRITE_DUMP_BUFFER("Write: ",
- (bytes_written > 16 ? 16 : bytes_written), buf);
D_WRITE("Finished %s on smd_pkt_dev id:%d %d bytes\n",
__func__, smd_pkt_devp->i, count);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index eda745f..0141a63 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -237,14 +237,6 @@
int pid;
};
-struct diag_nrt_wake_lock {
- int enabled;
- int ref_count;
- int copy_count;
- struct wake_lock read_lock;
- spinlock_t read_spinlock;
-};
-
struct real_time_vote_t {
uint16_t proc;
uint8_t real_time_vote;
@@ -291,8 +283,6 @@
struct diag_request *write_ptr_1;
struct diag_request *write_ptr_2;
- struct diag_nrt_wake_lock nrt_lock;
-
struct workqueue_struct *wq;
struct work_struct diag_read_smd_work;
@@ -469,6 +459,10 @@
int smux_connected;
struct diag_request *write_ptr_mdm;
#endif
+ /* Wakeup source related variables */
+ spinlock_t ws_lock;
+ int ws_ref_count;
+ int copy_count;
};
extern struct diag_bridge_dev *diag_bridge;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 263715d..81a6655 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -300,6 +300,7 @@
driver->logging_mode = USB_MODE;
diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN);
diagfwd_connect();
+ diag_ws_reset();
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
diag_clear_hsic_tbl();
diagfwd_cancel_hsic(REOPEN_HSIC);
@@ -636,10 +637,9 @@
}
entry->in_service = 0;
- mutex_unlock(&entry->write_buf_mutex);
-
exit_stat = 0;
exit:
+ mutex_unlock(&entry->write_buf_mutex);
*pret = ret;
return exit_stat;
@@ -1145,8 +1145,8 @@
int num_data = 0, data_type;
int remote_token;
int exit_stat;
- int clear_read_wakelock;
unsigned long flags;
+ int copy_data = 0;
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
@@ -1164,7 +1164,6 @@
mutex_lock(&driver->diagchar_mutex);
- clear_read_wakelock = 0;
if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver->
logging_mode == MEMORY_DEVICE_MODE)) {
remote_token = 0;
@@ -1225,10 +1224,8 @@
COPY_USER_SPACE_OR_EXIT(buf+ret,
*(data->buf_in_1),
data->write_ptr_1->length);
- if (!driver->real_time_mode) {
- process_lock_on_copy(&data->nrt_lock);
- clear_read_wakelock++;
- }
+ diag_ws_on_copy();
+ copy_data = 1;
spin_lock_irqsave(&data->in_busy_lock, flags);
data->in_busy_1 = 0;
spin_unlock_irqrestore(&data->in_busy_lock,
@@ -1243,10 +1240,8 @@
COPY_USER_SPACE_OR_EXIT(buf+ret,
*(data->buf_in_2),
data->write_ptr_2->length);
- if (!driver->real_time_mode) {
- process_lock_on_copy(&data->nrt_lock);
- clear_read_wakelock++;
- }
+ diag_ws_on_copy();
+ copy_data = 1;
spin_lock_irqsave(&data->in_busy_lock, flags);
data->in_busy_2 = 0;
spin_unlock_irqrestore(&data->in_busy_lock,
@@ -1434,12 +1429,18 @@
goto exit;
}
exit:
- if (clear_read_wakelock) {
- for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
- process_lock_on_copy_complete(
- &driver->smd_data[i].nrt_lock);
- }
mutex_unlock(&driver->diagchar_mutex);
+ if (copy_data) {
+ /*
+ * Flush any work that is currently pending on the data
+ * channels. This will ensure that the next read is not
+ * missed.
+ */
+ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++)
+ flush_workqueue(driver->smd_data[i].wq);
+ wake_up(&driver->smd_wait_q);
+ diag_ws_on_copy_complete();
+ }
return ret;
}
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index dd19d64..9c767c6 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -374,91 +374,62 @@
return buf_size;
}
-void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time)
+void diag_ws_on_notify()
{
- unsigned long read_lock_flags;
-
- spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
- if (real_time)
- lock->enabled = 0;
- else
- lock->enabled = 1;
- lock->ref_count = 0;
- lock->copy_count = 0;
- wake_unlock(&lock->read_lock);
- spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
-}
-
-void process_lock_on_notify(struct diag_nrt_wake_lock *lock)
-{
- unsigned long read_lock_flags;
-
- spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
/*
- * Do not work with ref_count here in case
- * of spurious interrupt
+ * Do not deal with reference count here as there can be
+ * spurious interrupts
*/
- if (lock->enabled && !wake_lock_active(&lock->read_lock))
- wake_lock(&lock->read_lock);
- spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+ pm_stay_awake(driver->diag_dev);
}
-void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len)
+void diag_ws_on_read(int pkt_len)
{
- unsigned long read_lock_flags;
+ unsigned long flags;
- spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
- if (lock->enabled) {
- if (pkt_len > 0) {
- /*
- * We have an data that is read that
- * needs to be processed, make sure the
- * processor does not go to sleep
- */
- lock->ref_count++;
- if (!wake_lock_active(&lock->read_lock))
- wake_lock(&lock->read_lock);
- } else {
- /*
- * There was no data associated with the
- * read from the smd, unlock the wake lock
- * if it is not needed.
- */
- if (lock->ref_count < 1) {
- if (wake_lock_active(&lock->read_lock))
- wake_unlock(&lock->read_lock);
- lock->ref_count = 0;
- lock->copy_count = 0;
- }
+ spin_lock_irqsave(&driver->ws_lock, flags);
+ if (pkt_len > 0) {
+ driver->ws_ref_count++;
+ } else {
+ if (driver->ws_ref_count < 1) {
+ pm_relax(driver->diag_dev);
+ driver->ws_ref_count = 0;
+ driver->copy_count = 0;
}
}
- spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+ spin_unlock_irqrestore(&driver->ws_lock, flags);
}
-void process_lock_on_copy(struct diag_nrt_wake_lock *lock)
+void diag_ws_on_copy()
{
- unsigned long read_lock_flags;
-
- spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
- if (lock->enabled)
- lock->copy_count++;
- spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+ unsigned long flags;
+ spin_lock_irqsave(&driver->ws_lock, flags);
+ driver->copy_count++;
+ spin_unlock_irqrestore(&driver->ws_lock, flags);
}
-void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock)
+void diag_ws_on_copy_complete()
{
- unsigned long read_lock_flags;
-
- spin_lock_irqsave(&lock->read_spinlock, read_lock_flags);
- if (lock->enabled) {
- lock->ref_count -= lock->copy_count;
- if (lock->ref_count < 1) {
- wake_unlock(&lock->read_lock);
- lock->ref_count = 0;
- }
- lock->copy_count = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&driver->ws_lock, flags);
+ driver->ws_ref_count -= driver->copy_count;
+ if (driver->ws_ref_count < 1) {
+ pm_relax(driver->diag_dev);
+ driver->ws_ref_count = 0;
}
- spin_unlock_irqrestore(&lock->read_spinlock, read_lock_flags);
+ driver->copy_count = 0;
+ spin_unlock_irqrestore(&driver->ws_lock, flags);
+}
+
+void diag_ws_reset()
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&driver->ws_lock, flags);
+ pm_relax(driver->diag_dev);
+ driver->ws_ref_count = 0;
+ driver->copy_count = 0;
+ spin_unlock_irqrestore(&driver->ws_lock, flags);
}
/* Process the data read from the smd data channel */
@@ -479,7 +450,7 @@
/* This print is for debugging */
pr_err("diag, In %s, received data on non-designated command channel: %d\n",
__func__, smd_info->peripheral);
- return 0;
+ goto err;
}
/* If the data is already hdlc encoded */
@@ -493,6 +464,7 @@
} else {
pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
__func__, smd_info->peripheral);
+ goto err;
}
if (write_ptr_modem) {
@@ -504,6 +476,7 @@
if (err) {
pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
__func__, err);
+ goto err;
}
spin_unlock_irqrestore(&smd_info->in_busy_lock, flags);
}
@@ -518,6 +491,7 @@
} else {
pr_err("diag: In %s, no match for in_busy_1, peripheral: %d\n",
__func__, smd_info->peripheral);
+ goto err;
}
if (write_ptr_modem) {
@@ -533,26 +507,64 @@
success = diag_add_hdlc_encoding(smd_info, buf,
total_recd, write_buf,
&write_length);
- spin_lock_irqsave(&smd_info->in_busy_lock,
- flags);
if (success) {
+ spin_lock_irqsave(
+ &smd_info->in_busy_lock, flags);
write_ptr_modem->length = write_length;
*in_busy_ptr = 1;
err = diag_device_write(write_buf,
smd_info->peripheral,
write_ptr_modem);
+ spin_unlock_irqrestore(
+ &smd_info->in_busy_lock, flags);
if (err) {
pr_err_ratelimited("diag: In %s, diag_device_write error: %d\n",
__func__, err);
+ goto err;
}
}
- spin_unlock_irqrestore(&smd_info->in_busy_lock,
- flags);
+ } else {
+ goto err;
}
}
}
return 0;
+err:
+ if (driver->logging_mode == MEMORY_DEVICE_MODE)
+ diag_ws_on_read(0);
+ return 0;
+}
+
+void diag_smd_queue_read(struct diag_smd_info *smd_info)
+{
+ if (!smd_info || !smd_info->ch)
+ return;
+
+ switch (smd_info->type) {
+ case SMD_DCI_TYPE:
+ case SMD_DCI_CMD_TYPE:
+ queue_work(driver->diag_dci_wq,
+ &(smd_info->diag_read_smd_work));
+ break;
+ case SMD_DATA_TYPE:
+ queue_work(smd_info->wq,
+ &(smd_info->diag_read_smd_work));
+ break;
+ case SMD_CNTL_TYPE:
+ case SMD_CMD_TYPE:
+ queue_work(driver->diag_wq,
+ &(smd_info->diag_read_smd_work));
+ break;
+ default:
+ pr_err("diag: In %s, invalid type: %d\n", __func__,
+ smd_info->type);
+ return;
+ }
+
+ if (driver->logging_mode == MEMORY_DEVICE_MODE &&
+ smd_info->type == SMD_DATA_TYPE)
+ diag_ws_on_notify();
}
static int diag_smd_resize_buf(struct diag_smd_info *smd_info, void **buf,
@@ -775,8 +787,9 @@
}
}
}
- if (!driver->real_time_mode && smd_info->type == SMD_DATA_TYPE)
- process_lock_on_read(&smd_info->nrt_lock, pkt_len);
+ if (smd_info->type == SMD_DATA_TYPE &&
+ driver->logging_mode == MEMORY_DEVICE_MODE)
+ diag_ws_on_read(pkt_len);
if (total_recd > 0) {
if (!buf) {
@@ -805,6 +818,10 @@
return;
fail_return:
+ if (smd_info->type == SMD_DATA_TYPE &&
+ driver->logging_mode == MEMORY_DEVICE_MODE)
+ diag_ws_on_read(0);
+
if (smd_info->type == SMD_DCI_TYPE ||
smd_info->type == SMD_DCI_CMD_TYPE)
diag_dci_try_deactivate_wakeup_source();
@@ -2197,24 +2214,15 @@
diag_dci_notify_client(smd_info->peripheral_mask,
DIAG_STATUS_OPEN);
}
- } else if (event == SMD_EVENT_DATA && !driver->real_time_mode &&
- smd_info->type == SMD_DATA_TYPE) {
- process_lock_on_notify(&smd_info->nrt_lock);
- }
-
- wake_up(&driver->smd_wait_q);
-
- if (smd_info->type == SMD_DCI_TYPE ||
- smd_info->type == SMD_DCI_CMD_TYPE) {
- if (event == SMD_EVENT_DATA)
+ wake_up(&driver->smd_wait_q);
+ diag_smd_queue_read(smd_info);
+ } else if (event == SMD_EVENT_DATA) {
+ wake_up(&driver->smd_wait_q);
+ diag_smd_queue_read(smd_info);
+ if (smd_info->type == SMD_DCI_TYPE ||
+ smd_info->type == SMD_DCI_CMD_TYPE) {
diag_dci_try_activate_wakeup_source();
- queue_work(driver->diag_dci_wq,
- &(smd_info->diag_read_smd_work));
- } else if (smd_info->type == SMD_DATA_TYPE) {
- queue_work(smd_info->wq,
- &(smd_info->diag_read_smd_work));
- } else {
- queue_work(driver->diag_wq, &(smd_info->diag_read_smd_work));
+ }
}
}
@@ -2343,10 +2351,8 @@
void diag_smd_destructor(struct diag_smd_info *smd_info)
{
- if (smd_info->type == SMD_DATA_TYPE) {
- wake_lock_destroy(&smd_info->nrt_lock.read_lock);
+ if (smd_info->type == SMD_DATA_TYPE)
destroy_workqueue(smd_info->wq);
- }
if (smd_info->ch)
smd_close(smd_info->ch);
@@ -2539,30 +2545,6 @@
goto err;
}
- smd_info->nrt_lock.enabled = 0;
- smd_info->nrt_lock.ref_count = 0;
- smd_info->nrt_lock.copy_count = 0;
- if (type == SMD_DATA_TYPE) {
- spin_lock_init(&smd_info->nrt_lock.read_spinlock);
-
- switch (peripheral) {
- case MODEM_DATA:
- wake_lock_init(&smd_info->nrt_lock.read_lock,
- WAKE_LOCK_SUSPEND, "diag_nrt_modem_read");
- break;
- case LPASS_DATA:
- wake_lock_init(&smd_info->nrt_lock.read_lock,
- WAKE_LOCK_SUSPEND, "diag_nrt_lpass_read");
- break;
- case WCNSS_DATA:
- wake_lock_init(&smd_info->nrt_lock.read_lock,
- WAKE_LOCK_SUSPEND, "diag_nrt_wcnss_read");
- break;
- default:
- break;
- }
- }
-
return 1;
err:
kfree(smd_info->buf_in_1);
@@ -2596,6 +2578,9 @@
driver->supports_apps_hdlc_encoding = 1;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
+ spin_lock_init(&driver->ws_lock);
+ driver->ws_ref_count = 0;
+ driver->copy_count = 0;
for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
driver->separate_cmdrsp[i] = 0;
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 7b2ded3..8ca8955 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -26,11 +26,6 @@
void diagfwd_exit(void);
void diag_process_hdlc(void *data, unsigned len);
void diag_smd_send_req(struct diag_smd_info *smd_info);
-void process_lock_enabling(struct diag_nrt_wake_lock *lock, int real_time);
-void process_lock_on_notify(struct diag_nrt_wake_lock *lock);
-void process_lock_on_read(struct diag_nrt_wake_lock *lock, int pkt_len);
-void process_lock_on_copy(struct diag_nrt_wake_lock *lock);
-void process_lock_on_copy_complete(struct diag_nrt_wake_lock *lock);
void diag_usb_legacy_notifier(void *, unsigned, struct diag_request *);
long diagchar_ioctl(struct file *, unsigned int, unsigned long);
int diag_device_write(void *, int, struct diag_request *);
@@ -56,6 +51,12 @@
int diag_apps_responds(void);
void diag_update_pkt_buffer(unsigned char *buf, int type);
int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf);
+void diag_ws_on_notify(void);
+void diag_ws_on_read(int pkt_len);
+void diag_ws_on_copy(void);
+void diag_ws_on_copy_complete(void);
+void diag_ws_reset(void);
+void diag_smd_queue_read(struct diag_smd_info *smd_info);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
int diagfwd_connect(void);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index a75f7f69..9d6dfbb 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -418,7 +418,6 @@
pr_err("diag: ch invalid, feature update on proc %d\n",
smd_info->peripheral);
}
- process_lock_enabling(&data->nrt_lock, real_time);
mutex_unlock(&driver->diag_cntl_mutex);
}
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index b8975aa..383ddd7 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -514,7 +514,8 @@
(unsigned long)(pengine);
pengine->bw_reaper_timer.expires = jiffies +
msecs_to_jiffies(QCRYPTO_HIGH_BANDWIDTH_TIMEOUT);
- add_timer(&(pengine->bw_reaper_timer));
+ mod_timer(&(pengine->bw_reaper_timer),
+ pengine->bw_reaper_timer.expires);
}
static void qcrypto_ce_bw_allocate_req(struct crypto_engine *pengine)
@@ -537,7 +538,7 @@
spin_unlock_irqrestore(&cp->lock, flags);
qcrypto_ce_set_bus(pengine, true);
-
+ qcrypto_bw_set_timeout(pengine);
spin_lock_irqsave(&cp->lock, flags);
pengine->bw_state = BUS_HAS_BANDWIDTH;
pengine->high_bw_req = false;
@@ -598,7 +599,8 @@
spin_unlock_irqrestore(&cp->lock, flags);
if (restart)
_start_qcrypto_process(cp, pengine);
- qcrypto_bw_set_timeout(pengine);
+ if (pengine->bw_state != BUS_NO_BANDWIDTH)
+ qcrypto_bw_set_timeout(pengine);
}
static int qcrypto_count_sg(struct scatterlist *sg, int nbytes)
@@ -1692,12 +1694,12 @@
rctx->orig_src = req->src;
rctx->orig_dst = req->dst;
- if ((MAX_ALIGN_SIZE*2 > ULONG_MAX - req->assoclen) ||
- ((MAX_ALIGN_SIZE*2 + req->assoclen) >
- ULONG_MAX - qreq.authsize) ||
- ((MAX_ALIGN_SIZE*2 + req->assoclen +
+ if ((MAX_ALIGN_SIZE*2 > UINT_MAX - qreq.assoclen) ||
+ ((MAX_ALIGN_SIZE*2 + qreq.assoclen) >
+ UINT_MAX - qreq.authsize) ||
+ ((MAX_ALIGN_SIZE*2 + qreq.assoclen +
qreq.authsize) >
- ULONG_MAX - req->cryptlen)) {
+ UINT_MAX - req->cryptlen)) {
pr_err("Integer overflow on aead req length.\n");
return -EINVAL;
}
@@ -4303,7 +4305,6 @@
pengine->active_seq = 0;
pengine->last_active_seq = 0;
pengine->check_flag = false;
- qcrypto_bw_set_timeout(pengine);
tasklet_init(&pengine->done_tasklet, req_done, (unsigned long)pengine);
crypto_init_queue(&pengine->req_queue, MSM_QCRYPTO_REQ_QUEUE_LENGTH);
@@ -4706,38 +4707,32 @@
struct crypto_engine *pengine;
struct crypto_priv *cp;
unsigned long flags;
- bool restart = false;
pengine = platform_get_drvdata(pdev);
if (!pengine)
return -EINVAL;
-
cp = pengine->pcp;
if (!cp->ce_support.clk_mgmt_sus_res)
return 0;
-
spin_lock_irqsave(&cp->lock, flags);
if (pengine->bw_state == BUS_SUSPENDED) {
- pengine->bw_state = BUS_BANDWIDTH_ALLOCATING;
spin_unlock_irqrestore(&cp->lock, flags);
-
if (qce_pm_table.resume)
qce_pm_table.resume(pengine->qce);
- qcrypto_ce_set_bus(pengine, true);
-
spin_lock_irqsave(&cp->lock, flags);
- pengine->bw_state = BUS_HAS_BANDWIDTH;
- pengine->high_bw_req = false;
- restart = true;
+ pengine->bw_state = BUS_NO_BANDWIDTH;
pengine->active_seq++;
- pengine->check_flag = true;
+ pengine->check_flag = false;
+ if (cp->req_queue.qlen || pengine->req_queue.qlen) {
+ if (pengine->high_bw_req == false) {
+ qcrypto_ce_bw_allocate_req(pengine);
+ pengine->high_bw_req = true;
+ }
+ }
}
spin_unlock_irqrestore(&cp->lock, flags);
- if (restart)
- _start_qcrypto_process(cp, pengine);
-
return 0;
}
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 8774df6..059e488 100755
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -221,6 +221,8 @@
#define KPDBL_MODULE_EN 0x80
#define KPDBL_MODULE_DIS 0x00
#define KPDBL_MODULE_EN_MASK 0x80
+#define NUM_KPDBL_LEDS 4
+#define KPDBL_MASTER_BIT_INDEX 0
/**
* enum qpnp_leds - QPNP supported led ids
@@ -432,6 +434,7 @@
* @always_on - always on row
* @lut_params - lut parameters to be used by pwm driver
* @duty_cycles - duty cycles for lut
+ * @pwm_mode - pwm mode in use
*/
struct kpdbl_config_data {
struct pwm_config_data *pwm_cfg;
@@ -441,6 +444,7 @@
bool always_on;
struct pwm_duty_cycles *duty_cycles;
struct lut_params lut_params;
+ u8 pwm_mode;
};
/**
@@ -490,8 +494,11 @@
int turn_off_delay_ms;
};
-static int num_kpbl_leds_on;
static DEFINE_MUTEX(flash_lock);
+static struct pwm_device *kpdbl_master;
+static u32 kpdbl_master_period_us;
+DECLARE_BITMAP(kpdbl_leds_in_use, NUM_KPDBL_LEDS);
+static bool is_kpdbl_master_turn_on;
static int
qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
@@ -1278,7 +1285,8 @@
if (!led->kpdbl_cfg->pwm_cfg->blinking)
led->kpdbl_cfg->pwm_cfg->mode =
led->kpdbl_cfg->pwm_cfg->default_mode;
- if (!num_kpbl_leds_on) {
+
+ if (bitmap_empty(kpdbl_leds_in_use, NUM_KPDBL_LEDS)) {
rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
KPDBL_MODULE_EN_MASK, KPDBL_MODULE_EN);
if (rc) {
@@ -1288,6 +1296,33 @@
}
}
+ /* On some platforms, GPLED1 channel should always be enabled
+ * for the other GPLEDs 2/3/4 to glow. Before enabling GPLED
+ * 2/3/4, first check if GPLED1 is already enabled. If GPLED1
+ * channel is not enabled, then enable the GPLED1 channel but
+ * with a 0 brightness
+ */
+ if (!led->kpdbl_cfg->always_on &&
+ !test_bit(KPDBL_MASTER_BIT_INDEX, kpdbl_leds_in_use) &&
+ kpdbl_master) {
+ rc = pwm_config_us(kpdbl_master, 0,
+ kpdbl_master_period_us);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "pwm config failed\n");
+ return rc;
+ }
+
+ rc = pwm_enable(kpdbl_master);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "pwm enable failed\n");
+ return rc;
+ }
+ set_bit(KPDBL_MASTER_BIT_INDEX,
+ kpdbl_leds_in_use);
+ }
+
if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
period_us = led->kpdbl_cfg->pwm_cfg->pwm_period_us;
if (period_us > INT_MAX / NSEC_PER_USEC) {
@@ -1317,39 +1352,77 @@
return rc;
}
- num_kpbl_leds_on++;
+ set_bit(led->kpdbl_cfg->row_id, kpdbl_leds_in_use);
+
+ /* is_kpdbl_master_turn_on will be set to true when GPLED1
+ * channel is enabled and has a valid brightness value
+ */
+ if (led->kpdbl_cfg->always_on)
+ is_kpdbl_master_turn_on = true;
} else {
led->kpdbl_cfg->pwm_cfg->mode =
led->kpdbl_cfg->pwm_cfg->default_mode;
+ /* Before disabling GPLED1, check if any other GPLED 2/3/4 is
+ * on. If any of the other GPLED 2/3/4 is on, then have the
+ * GPLED1 channel enabled with 0 brightness.
+ */
if (led->kpdbl_cfg->always_on) {
- rc = pwm_config_us(led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
- led->kpdbl_cfg->pwm_cfg->pwm_period_us);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev,
+ if (bitmap_weight(kpdbl_leds_in_use,
+ NUM_KPDBL_LEDS) > 1) {
+ rc = pwm_config_us(
+ led->kpdbl_cfg->pwm_cfg->pwm_dev, 0,
+ led->kpdbl_cfg->pwm_cfg->pwm_period_us);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
"pwm config failed\n");
- return rc;
- }
+ return rc;
+ }
- rc = pwm_enable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
- if (rc < 0) {
- dev_err(&led->spmi_dev->dev, "pwm enable failed\n");
- return rc;
+ rc = pwm_enable(led->kpdbl_cfg->pwm_cfg->
+ pwm_dev);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "pwm enable failed\n");
+ return rc;
+ }
+ } else {
+ if (kpdbl_master) {
+ pwm_disable(kpdbl_master);
+ clear_bit(KPDBL_MASTER_BIT_INDEX,
+ kpdbl_leds_in_use);
+ rc = qpnp_led_masked_write(
+ led, KPDBL_ENABLE(led->base),
+ KPDBL_MODULE_EN_MASK,
+ KPDBL_MODULE_DIS);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Failed to write led"
+ " enable reg\n");
+ return rc;
+ }
+ }
}
- } else
+ is_kpdbl_master_turn_on = false;
+ } else {
pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
-
- if (num_kpbl_leds_on > 0)
- num_kpbl_leds_on--;
-
- if (!num_kpbl_leds_on) {
- rc = qpnp_led_masked_write(led, KPDBL_ENABLE(led->base),
+ clear_bit(led->kpdbl_cfg->row_id, kpdbl_leds_in_use);
+ if (bitmap_weight(kpdbl_leds_in_use,
+ NUM_KPDBL_LEDS) == 1 && kpdbl_master &&
+ !is_kpdbl_master_turn_on) {
+ pwm_disable(kpdbl_master);
+ clear_bit(KPDBL_MASTER_BIT_INDEX,
+ kpdbl_leds_in_use);
+ rc = qpnp_led_masked_write(
+ led, KPDBL_ENABLE(led->base),
KPDBL_MODULE_EN_MASK, KPDBL_MODULE_DIS);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
"Failed to write led enable reg\n");
- return rc;
+ return rc;
+ }
+ is_kpdbl_master_turn_on = false;
}
}
}
@@ -1764,7 +1837,7 @@
struct spmi_device *spmi_dev,
const char *name)
{
- int rc, start_idx, idx_len;
+ int rc, start_idx, idx_len, lut_max_size;
if (pwm_cfg->pwm_channel != -1) {
pwm_cfg->pwm_dev =
@@ -1786,14 +1859,18 @@
idx_len =
pwm_cfg->duty_cycles->num_duty_pcts;
- if (idx_len >= PWM_LUT_MAX_SIZE &&
- start_idx) {
+ if (strnstr(name, "kpdbl", sizeof("kpdbl")))
+ lut_max_size = PWM_GPLED_LUT_MAX_SIZE;
+ else
+ lut_max_size = PWM_LUT_MAX_SIZE;
+
+ if (idx_len >= lut_max_size && start_idx) {
dev_err(&spmi_dev->dev,
"Wrong LUT size or index\n");
return -EINVAL;
}
- if ((start_idx + idx_len) >
- PWM_LUT_MAX_SIZE) {
+
+ if ((start_idx + idx_len) > lut_max_size) {
dev_err(&spmi_dev->dev,
"Exceed LUT limit\n");
return -EINVAL;
@@ -1843,6 +1920,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for pwm_us\n");
@@ -1895,6 +1975,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for pause lo\n");
@@ -1947,6 +2030,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for pause hi\n");
@@ -1999,6 +2085,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for start idx\n");
@@ -2052,6 +2141,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for ramp step\n");
@@ -2104,6 +2196,9 @@
case QPNP_ID_RGB_BLUE:
pwm_cfg = led->rgb_cfg->pwm_cfg;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for lut flags\n");
@@ -2160,6 +2255,10 @@
pwm_cfg = led->rgb_cfg->pwm_cfg;
max_duty_pcts = PWM_LUT_MAX_SIZE;
break;
+ case QPNP_ID_KPDBL:
+ pwm_cfg = led->kpdbl_cfg->pwm_cfg;
+ max_duty_pcts = PWM_GPLED_LUT_MAX_SIZE;
+ break;
default:
dev_err(&led->spmi_dev->dev,
"Invalid LED id type for duty pcts\n");
@@ -2229,12 +2328,17 @@
pwm_cfg->blinking = true;
if (led->id == QPNP_ID_LED_MPP)
led->mpp_cfg->pwm_mode = LPG_MODE;
+ else if (led->id == QPNP_ID_KPDBL)
+ led->kpdbl_cfg->pwm_mode = LPG_MODE;
pwm_cfg->mode = LPG_MODE;
} else {
pwm_cfg->blinking = false;
pwm_cfg->mode = pwm_cfg->default_mode;
if (led->id == QPNP_ID_LED_MPP)
led->mpp_cfg->pwm_mode = pwm_cfg->default_mode;
+ else if (led->id == QPNP_ID_KPDBL)
+ led->kpdbl_cfg->pwm_mode =
+ pwm_cfg->default_mode;
}
pwm_free(pwm_cfg->pwm_dev);
qpnp_pwm_init(pwm_cfg, led->spmi_dev, led->cdev.name);
@@ -2249,6 +2353,11 @@
if (rc < 0)
dev_err(&led->spmi_dev->dev,
"MPP set brightness failed (%d)\n", rc);
+ } else if (led->id == QPNP_ID_KPDBL) {
+ rc = qpnp_kpdbl_set(led);
+ if (rc < 0)
+ dev_err(&led->spmi_dev->dev,
+ "KPDBL set brightness failed (%d)\n", rc);
}
}
mutex_unlock(&led->lock);
@@ -2278,6 +2387,9 @@
case QPNP_ID_RGB_BLUE:
led_blink(led, led->rgb_cfg->pwm_cfg);
break;
+ case QPNP_ID_KPDBL:
+ led_blink(led, led->kpdbl_cfg->pwm_cfg);
+ break;
default:
dev_err(&led->spmi_dev->dev, "Invalid LED id type for blink\n");
return -EINVAL;
@@ -2511,6 +2623,11 @@
return rc;
}
+ if (led->kpdbl_cfg->always_on) {
+ kpdbl_master = led->kpdbl_cfg->pwm_cfg->pwm_dev;
+ kpdbl_master_period_us = led->kpdbl_cfg->pwm_cfg->pwm_period_us;
+ }
+
/* dump kpdbl registers */
qpnp_dump_regs(led, kpdbl_debug_regs, ARRAY_SIZE(kpdbl_debug_regs));
@@ -2927,9 +3044,10 @@
struct device_node *node)
{
struct property *prop;
- int rc, i;
+ int rc, i, lut_max_size;
u32 val;
u8 *temp_cfg;
+ const char *led_label;
rc = of_property_read_u32(node, "qcom,pwm-channel", &val);
if (!rc)
@@ -2973,9 +3091,22 @@
goto bad_lpg_params;
}
+ rc = of_property_read_string(node, "label", &led_label);
+
+ if (rc < 0) {
+ dev_err(&spmi_dev->dev,
+ "Failure reading label, rc = %d\n", rc);
+ return rc;
+ }
+
+ if (strcmp(led_label, "kpdbl") == 0)
+ lut_max_size = PWM_GPLED_LUT_MAX_SIZE;
+ else
+ lut_max_size = PWM_LUT_MAX_SIZE;
+
pwm_cfg->duty_cycles->duty_pcts =
devm_kzalloc(&spmi_dev->dev,
- sizeof(int) * PWM_LUT_MAX_SIZE,
+ sizeof(int) * lut_max_size,
GFP_KERNEL);
if (!pwm_cfg->duty_cycles->duty_pcts) {
dev_err(&spmi_dev->dev,
@@ -2986,7 +3117,7 @@
pwm_cfg->old_duty_pcts =
devm_kzalloc(&spmi_dev->dev,
- sizeof(int) * PWM_LUT_MAX_SIZE,
+ sizeof(int) * lut_max_size,
GFP_KERNEL);
if (!pwm_cfg->old_duty_pcts) {
dev_err(&spmi_dev->dev,
@@ -3383,7 +3514,8 @@
goto fail_id_check;
}
} else if (strncmp(led_label, "kpdbl", sizeof("kpdbl")) == 0) {
- num_kpbl_leds_on = 0;
+ bitmap_zero(kpdbl_leds_in_use, NUM_KPDBL_LEDS);
+ is_kpdbl_master_turn_on = false;
rc = qpnp_get_config_kpdbl(led, temp);
if (rc < 0) {
dev_err(&led->spmi_dev->dev,
@@ -3493,6 +3625,29 @@
if (rc)
goto fail_id_check;
}
+ } else if (led->id == QPNP_ID_KPDBL) {
+ if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &pwm_attr_group);
+ if (rc)
+ goto fail_id_check;
+ }
+ if (led->kpdbl_cfg->pwm_cfg->use_blink) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &blink_attr_group);
+ if (rc)
+ goto fail_id_check;
+
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &lpg_attr_group);
+ if (rc)
+ goto fail_id_check;
+ } else if (led->kpdbl_cfg->pwm_cfg->mode == LPG_MODE) {
+ rc = sysfs_create_group(&led->cdev.dev->kobj,
+ &lpg_attr_group);
+ if (rc)
+ goto fail_id_check;
+ }
}
/* configure default state */
@@ -3582,6 +3737,20 @@
sysfs_remove_group(&led_array[i].cdev.dev->\
kobj, &lpg_attr_group);
break;
+ case QPNP_ID_KPDBL:
+ if (led_array[i].kpdbl_cfg->pwm_cfg->mode == PWM_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->
+ kobj, &pwm_attr_group);
+ if (led_array[i].kpdbl_cfg->pwm_cfg->use_blink) {
+ sysfs_remove_group(&led_array[i].cdev.dev->
+ kobj, &blink_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->
+ kobj, &lpg_attr_group);
+ } else if (led_array[i].kpdbl_cfg->pwm_cfg->mode
+ == LPG_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->
+ kobj, &lpg_attr_group);
+ break;
default:
dev_err(&led_array[i].spmi_dev->dev,
"Invalid LED(%d)\n",
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
index ef8f37c..a8f0d18 100644
--- a/drivers/md/dm-req-crypt.c
+++ b/drivers/md/dm-req-crypt.c
@@ -833,13 +833,20 @@
start_sector_orig = tmpll;
- if (argv[5]) {
- if (!strcmp(argv[5], "fde_enabled"))
- is_fde_enabled = true;
- else
- is_fde_enabled = false;
+ /* Allow backward compatible */
+ if (argc >= 6) {
+ if (argv[5]) {
+ if (!strcmp(argv[5], "fde_enabled"))
+ is_fde_enabled = true;
+ else
+ is_fde_enabled = false;
+ } else {
+ DMERR(" %s Arg[5] invalid\n", __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ctr_exit;
+ }
} else {
- DMERR(" %s Arg[5] invalid, set FDE eanbled.\n", __func__);
+ DMERR(" %s Arg[5] missing, set FDE enabled.\n", __func__);
is_fde_enabled = true; /* backward compatible */
}
DMDEBUG("%s is_fde_enabled=%d\n", __func__, is_fde_enabled);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index b4196e9..106f5eb 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -298,10 +298,8 @@
return buff->map_info.phy_addr;
QUEUE_BUFF_ERROR2:
- ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle,
- cpp_dev->domain_num, 0);
-QUEUE_BUFF_ERROR1:
ion_free(cpp_dev->client, buff->map_info.ion_handle);
+QUEUE_BUFF_ERROR1:
buff->map_info.ion_handle = NULL;
kzfree(buff);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index b8c972d..34dcd1d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1005,7 +1005,7 @@
return rc;
}
-static int msm_venc_enable_hier_p(struct msm_vidc_inst *inst)
+static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, bool enable)
{
int num_enh_layers = 0;
u32 property_id = 0;
@@ -1020,9 +1020,10 @@
if (inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_VP8)
return 0;
- num_enh_layers = inst->capability.hier_p.max - 1;
- if (!num_enh_layers)
- return 0;
+ num_enh_layers = enable ? inst->capability.hier_p.max - 1 : 0;
+
+ dprintk(VIDC_DBG, "%s Hier-P in firmware\n",
+ num_enh_layers ? "Enable" : "Disable");
hdev = inst->core->device;
property_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS;
@@ -1048,10 +1049,6 @@
return -EINVAL;
}
- rc = msm_venc_enable_hier_p(inst);
- if (rc)
- return rc;
-
if (inst->capability.pixelprocess_capabilities &
HAL_VIDEO_ENCODER_SCALING_CAPABILITY)
rc = msm_comm_check_scaling_supported(inst);
@@ -2192,6 +2189,9 @@
case V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS:
property_id = HAL_CONFIG_VENC_HIER_P_NUM_FRAMES;
hier_p_layers = ctrl->val;
+ rc = msm_venc_toggle_hier_p(inst, hier_p_layers ? true : false);
+ if (rc)
+ break;
if (hier_p_layers > (inst->capability.hier_p.max - 1)) {
dprintk(VIDC_ERR,
"Error setting hier p num layers = %d max supported by f/w = %d\n",
@@ -2244,6 +2244,12 @@
for (i = 0; i < ctrl->count; i++) {
switch (control[i].id) {
case V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE:
+ if (control[i].value !=
+ V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE) {
+ rc = msm_venc_toggle_hier_p(inst, false);
+ if (rc)
+ break;
+ }
ltrmode.ltrmode = control[i].value;
ltrmode.trustmode = 1;
property_id = HAL_PARAM_VENC_LTRMODE;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index df21c26..ba17820 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1552,7 +1552,7 @@
dprintk(VIDC_WARN,
"Failed to scale DDR bus. Performance might be impacted\n");
}
- if (core->resources.has_ocmem) {
+ if (core->resources.ocmem_size) {
if (msm_comm_scale_bus(core, inst->session_type,
OCMEM_MEM))
dprintk(VIDC_WARN,
@@ -1560,52 +1560,6 @@
}
}
-static inline unsigned long get_ocmem_requirement(u32 height, u32 width)
-{
- int num_mbs = 0;
- num_mbs = GET_NUM_MBS(height, width);
- /*TODO: This should be changes once the numbers are
- * available from firmware*/
- return 512 * 1024;
-}
-
-static int msm_comm_unset_ocmem(struct msm_vidc_core *core)
-{
- int rc = 0;
- struct hfi_device *hdev;
-
- if (!core || !core->device) {
- dprintk(VIDC_ERR, "%s invalid parameters", __func__);
- return -EINVAL;
- }
- hdev = core->device;
-
- if (core->state == VIDC_CORE_INVALID) {
- dprintk(VIDC_ERR,
- "Core is in bad state. Cannot unset ocmem\n");
- return -EIO;
- }
-
- init_completion(
- &core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)]);
-
- rc = call_hfi_op(hdev, unset_ocmem, hdev->hfi_device_data);
- if (rc) {
- dprintk(VIDC_INFO, "Failed to unset OCMEM on driver\n");
- goto release_ocmem_failed;
- }
- rc = wait_for_completion_timeout(
- &core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)],
- msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
- if (!rc) {
- dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
- __func__, SYS_MSG_INDEX(RELEASE_RESOURCE_DONE));
- rc = -EIO;
- }
-release_ocmem_failed:
- return rc;
-}
-
static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
{
struct msm_vidc_core *core = inst->core;
@@ -1899,10 +1853,8 @@
struct msm_vidc_inst *inst)
{
int rc = 0;
- u32 ocmem_sz = 0;
struct hfi_device *hdev;
int num_mbs_per_sec = 0;
- int height, width;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1939,31 +1891,7 @@
inst, inst->state);
goto exit;
}
- if (inst->core->resources.has_ocmem) {
- height = max(inst->prop.height[CAPTURE_PORT],
- inst->prop.height[OUTPUT_PORT]);
- width = max(inst->prop.width[CAPTURE_PORT],
- inst->prop.width[OUTPUT_PORT]);
- ocmem_sz = get_ocmem_requirement(
- height, width);
- rc = msm_comm_scale_bus(inst->core, inst->session_type,
- OCMEM_MEM);
- if (!rc) {
- mutex_lock(&inst->core->lock);
- rc = call_hfi_op(hdev, alloc_ocmem,
- hdev->hfi_device_data,
- ocmem_sz);
- mutex_unlock(&inst->core->lock);
- if (rc) {
- dprintk(VIDC_WARN,
- "Failed to allocate OCMEM. Performance will be impacted\n");
- msm_comm_unvote_buses(inst->core, OCMEM_MEM);
- }
- } else {
- dprintk(VIDC_WARN,
- "Failed to vote for OCMEM BW. Performance will be impacted\n");
- }
- }
+
rc = call_hfi_op(hdev, session_load_res, (void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
@@ -3711,12 +3639,6 @@
if (list_empty(&core->instances) &&
core->state != VIDC_CORE_UNINIT) {
if (core->state > VIDC_CORE_INIT) {
- if (core->resources.has_ocmem) {
- if (core->state != VIDC_CORE_INVALID)
- msm_comm_unset_ocmem(core);
- call_hfi_op(hdev, free_ocmem,
- hdev->hfi_device_data);
- }
dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
rc = call_hfi_op(hdev, core_release,
hdev->hfi_device_data);
@@ -3732,7 +3654,7 @@
call_hfi_op(hdev, unload_fw, hdev->hfi_device_data);
dprintk(VIDC_DBG, "Firmware unloaded\n");
- if (core->resources.has_ocmem)
+ if (core->resources.ocmem_size)
msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
else
msm_comm_unvote_buses(core, DDR_MEM);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index ecfff85..10f3797 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -348,7 +348,7 @@
goto err_mem_alloc;
}
for (i = 0; i < num_bus_pdata; i++) {
- if (!res->has_ocmem &&
+ if (!res->ocmem_size &&
(!strcmp(bus_pdata_config_vector[i].name,
"qcom,enc-ocmem-ab-ib")
|| !strcmp(bus_pdata_config_vector[i].name,
@@ -567,9 +567,11 @@
kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
res->irq = kres ? kres->start : -1;
- res->has_ocmem = of_property_read_bool(pdev->dev.of_node,
- "qcom,has-ocmem");
-
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,ocmem-size", &res->ocmem_size);
+ if (rc) {
+ dprintk(VIDC_INFO, "Failed to read ocmem size: %d\n", rc);
+ }
rc = msm_vidc_load_freq_table(res);
if (rc) {
dprintk(VIDC_ERR, "Failed to load freq table: %d\n", rc);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index e75b410..87d4d42 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -74,7 +74,7 @@
struct msm_bus_scale_pdata *bus_pdata;
struct iommu_set iommu_group_set;
struct buffer_usage_set buffer_usage_set;
- bool has_ocmem;
+ uint32_t ocmem_size;
uint32_t max_load;
struct platform_device *pdev;
};
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
old mode 100755
new mode 100644
index 52bbe12..4bc534c
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1186,14 +1186,6 @@
return 0;
}
-static int q6_hfi_unset_ocmem(void *dev)
-{
- (void)dev;
-
- /* Q6 does not support ocmem */
- return -EINVAL;
-}
-
static int q6_hfi_iommu_get_domain_partition(void *dev, u32 flags,
u32 buffer_type, int *domain, int *partition)
{
@@ -1374,7 +1366,6 @@
hdev->session_flush = q6_hfi_session_flush;
hdev->session_set_property = q6_hfi_session_set_property;
hdev->session_get_property = q6_hfi_session_get_property;
- hdev->unset_ocmem = q6_hfi_unset_ocmem;
hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
hdev->load_fw = q6_hfi_load_fw;
hdev->unload_fw = q6_hfi_unload_fw;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
old mode 100755
new mode 100644
index fb27511..f5587fc
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -904,115 +904,59 @@
return rc;
}
-static int venus_hfi_set_ocmem(void *dev, struct ocmem_buf *ocmem, int locked)
-{
- struct vidc_resource_hdr rhdr;
- struct venus_hfi_device *device = dev;
- int rc = 0;
- if (!device || !ocmem) {
- dprintk(VIDC_ERR, "Invalid params, core:%p, ocmem: %p\n",
- device, ocmem);
- return -EINVAL;
- }
- rhdr.resource_id = VIDC_RESOURCE_OCMEM;
- rhdr.resource_handle = (u32) &device->resources.ocmem;
- rhdr.size = ocmem->len;
- rc = venus_hfi_core_set_resource(device, &rhdr, ocmem, locked);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
- goto ocmem_set_failed;
- }
- dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
- ocmem->addr, ocmem->len);
-ocmem_set_failed:
- return rc;
-}
+static DECLARE_COMPLETION(pc_prep_done);
+static DECLARE_COMPLETION(release_resources_done);
-static int venus_hfi_unset_ocmem(void *dev)
-{
- struct vidc_resource_hdr rhdr;
- struct venus_hfi_device *device = dev;
- int rc = 0;
-
- if (!device) {
- dprintk(VIDC_ERR, "%s Invalid params, device:%p\n",
- __func__, device);
- rc = -EINVAL;
- goto ocmem_unset_failed;
- }
- if (!device->resources.ocmem.buf) {
- dprintk(VIDC_INFO, "%s Trying to free OCMEM which is not set",
- __func__);
- rc = -EINVAL;
- goto ocmem_unset_failed;
- }
- rhdr.resource_id = VIDC_RESOURCE_OCMEM;
- rhdr.resource_handle = (u32) &device->resources.ocmem;
- rc = venus_hfi_core_release_resource(device, &rhdr);
- if (rc)
- dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n");
-ocmem_unset_failed:
- return rc;
-}
-
-static int __alloc_ocmem(void *dev, unsigned long size, int locked)
+static int __alloc_ocmem(struct venus_hfi_device *device)
{
int rc = 0;
struct ocmem_buf *ocmem_buffer;
- struct venus_hfi_device *device = dev;
+ unsigned long size;
- if (!device || !size) {
- dprintk(VIDC_ERR, "%s Invalid param, core: %p, size: %lu\n",
- __func__, device, size);
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
return -EINVAL;
}
+
+ size = device->res->ocmem_size;
+ if (!size)
+ return rc;
+
ocmem_buffer = device->resources.ocmem.buf;
- if (!ocmem_buffer ||
- ocmem_buffer->len < size) {
+ if (!ocmem_buffer || ocmem_buffer->len < size) {
ocmem_buffer = ocmem_allocate(OCMEM_VIDEO, size);
if (IS_ERR_OR_NULL(ocmem_buffer)) {
dprintk(VIDC_ERR,
- "ocmem_allocate_nb failed: %d\n",
- (u32) ocmem_buffer);
+ "ocmem_allocate failed: %lu\n",
+ (unsigned long)ocmem_buffer);
rc = -ENOMEM;
+ device->resources.ocmem.buf = NULL;
goto ocmem_alloc_failed;
}
device->resources.ocmem.buf = ocmem_buffer;
- rc = venus_hfi_set_ocmem(device, ocmem_buffer, locked);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
- goto ocmem_set_failed;
- }
- device->ocmem_size = size;
- } else
+ } else {
dprintk(VIDC_DBG,
"OCMEM is enough. reqd: %lu, available: %lu\n",
size, ocmem_buffer->len);
-
- return rc;
-ocmem_set_failed:
- ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
- device->resources.ocmem.buf = NULL;
+ }
ocmem_alloc_failed:
return rc;
}
-static int venus_hfi_alloc_ocmem(void *dev, unsigned long size)
+static int __free_ocmem(struct venus_hfi_device *device)
{
- return __alloc_ocmem(dev, size, true);
-}
-
-static int venus_hfi_free_ocmem(void *dev)
-{
- struct venus_hfi_device *device = dev;
int rc = 0;
- if (!device) {
- dprintk(VIDC_ERR, "%s invalid device handle %p",
- __func__, device);
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
return -EINVAL;
}
+ if (!device->res->ocmem_size)
+ return rc;
+
if (device->resources.ocmem.buf) {
rc = ocmem_free(OCMEM_VIDEO, device->resources.ocmem.buf);
if (rc)
@@ -1022,6 +966,147 @@
return rc;
}
+static int __set_ocmem(struct venus_hfi_device *device, bool locked)
+{
+ struct vidc_resource_hdr rhdr;
+ int rc = 0;
+ struct on_chip_mem *ocmem;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ ocmem = &device->resources.ocmem;
+ if (!ocmem->buf) {
+ dprintk(VIDC_ERR, "Invalid params, ocmem_buffer: 0x%p\n",
+ ocmem->buf);
+ return -EINVAL;
+ }
+
+ rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+ /*
+ * This handle is just used as a cookie and not(cannot be)
+ * accessed by fw
+ */
+ rhdr.resource_handle = (u32)(unsigned long)ocmem;
+ rhdr.size = ocmem->buf->len;
+ rc = venus_hfi_core_set_resource(device, &rhdr, ocmem->buf, locked);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to set OCMEM on driver\n");
+ goto ocmem_set_failed;
+ }
+ dprintk(VIDC_DBG, "OCMEM set, addr = %lx, size: %ld\n",
+ ocmem->buf->addr, ocmem->buf->len);
+ocmem_set_failed:
+ return rc;
+}
+
+static int __unset_ocmem(struct venus_hfi_device *device)
+{
+ struct vidc_resource_hdr rhdr;
+ int rc = 0;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
+ rc = -EINVAL;
+ goto ocmem_unset_failed;
+ }
+
+ if (!device->resources.ocmem.buf) {
+ dprintk(VIDC_INFO,
+ "%s Trying to unset OCMEM which is not allocated\n",
+ __func__);
+ rc = -EINVAL;
+ goto ocmem_unset_failed;
+ }
+ rhdr.resource_id = VIDC_RESOURCE_OCMEM;
+ /*
+ * This handle is just used as a cookie and not(cannot be)
+ * accessed by fw
+ */
+ rhdr.resource_handle = (u32)(unsigned long)&device->resources.ocmem;
+ rc = venus_hfi_core_release_resource(device, &rhdr);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to unset OCMEM on driver\n");
+ocmem_unset_failed:
+ return rc;
+}
+
+static int __alloc_set_ocmem(struct venus_hfi_device *device, bool locked)
+{
+ int rc = 0;
+
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ if (!device->res->ocmem_size)
+ return rc;
+
+ rc = __alloc_ocmem(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to allocate ocmem: %d\n", rc);
+ goto ocmem_alloc_failed;
+ }
+ rc = __set_ocmem(device, locked);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
+ goto ocmem_set_failed;
+ }
+ return rc;
+ocmem_set_failed:
+ __free_ocmem(device);
+ocmem_alloc_failed:
+ return rc;
+}
+
+static int __unset_free_ocmem(struct venus_hfi_device *device)
+{
+ int rc = 0;
+ if (!device || !device->res) {
+ dprintk(VIDC_ERR, "%s Invalid param, device: 0x%p\n",
+ __func__, device);
+ return -EINVAL;
+ }
+
+ if (!device->res->ocmem_size)
+ return rc;
+
+ init_completion(&release_resources_done);
+ rc = __unset_ocmem(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to unset OCMEM during PC %d\n", rc);
+ goto ocmem_unset_failed;
+ }
+ rc = wait_for_completion_timeout(&release_resources_done,
+ msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+ if (!rc) {
+ dprintk(VIDC_ERR,
+ "Wait interrupted or timeout for RELEASE_RESOURCES: %d\n",
+ rc);
+ rc = -EIO;
+ goto release_resources_failed;
+ }
+
+ rc = __free_ocmem(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to free OCMEM during PC\n");
+ goto ocmem_free_failed;
+ }
+ return rc;
+
+ocmem_free_failed:
+ __set_ocmem(device, true);
+release_resources_failed:
+ocmem_unset_failed:
+ return rc;
+}
+
static inline int venus_hfi_tzbsp_set_video_state(enum tzbsp_video_state state)
{
struct tzbsp_video_set_state_req cmd = {0};
@@ -1135,9 +1220,6 @@
--device->clk_cnt;
}
-static DECLARE_COMPLETION(pc_prep_done);
-static DECLARE_COMPLETION(release_resources_done);
-
static int venus_hfi_halt_axi(struct venus_hfi_device *device)
{
u32 reg;
@@ -1201,7 +1283,7 @@
dprintk(VIDC_ERR, "Failed to disable GDSC, %d", rc);
return rc;
}
- if (device->res->has_ocmem)
+ if (device->res->ocmem_size)
venus_hfi_unvote_buses(device, DDR_MEM|OCMEM_MEM);
else
venus_hfi_unvote_buses(device, DDR_MEM);
@@ -1221,7 +1303,7 @@
return -EINVAL;
}
- if (device->res->has_ocmem)
+ if (device->res->ocmem_size)
rc = venus_hfi_scale_buses(device, DDR_MEM|OCMEM_MEM);
else
rc = venus_hfi_scale_buses(device, DDR_MEM);
@@ -1292,7 +1374,7 @@
* of alloc_ocmem
*/
WARN_ON(!mutex_is_locked(&device->write_lock));
- rc = __alloc_ocmem(device, device->ocmem_size, false);
+ rc = __alloc_set_ocmem(device, false);
if (rc) {
dprintk(VIDC_ERR, "Failed to allocate OCMEM");
goto err_alloc_ocmem;
@@ -1311,7 +1393,7 @@
err_enable_clk:
regulator_disable(device->gdsc);
err_enable_gdsc:
- if (device->res->has_ocmem)
+ if (device->res->ocmem_size)
venus_hfi_unvote_buses(device, DDR_MEM|OCMEM_MEM);
else
venus_hfi_unvote_buses(device, DDR_MEM);
@@ -1934,13 +2016,26 @@
dprintk(VIDC_ERR, "invalid device");
return -ENODEV;
}
-
if (dev->hal_client) {
mutex_lock(&dev->clk_pwr_lock);
rc = venus_hfi_clk_gating_off(device);
if (rc) {
dprintk(VIDC_ERR,
- "%s : Clock enable failed\n", __func__);
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&dev->clk_pwr_lock);
+ return -EIO;
+ }
+ mutex_unlock(&dev->clk_pwr_lock);
+ rc = __unset_free_ocmem(dev);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to unset and free OCMEM in core release, rc : %d\n",
+ rc);
+ mutex_lock(&dev->clk_pwr_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
mutex_unlock(&dev->clk_pwr_lock);
return -EIO;
}
@@ -1951,6 +2046,7 @@
dev->intr_status = 0;
mutex_unlock(&dev->clk_pwr_lock);
}
+
VENUS_SET_STATE(dev, VENUS_STATE_DEINIT);
dprintk(VIDC_INFO, "HAL exited\n");
@@ -2743,45 +2839,6 @@
return rc;
}
-static int venus_hfi_unset_free_ocmem(struct venus_hfi_device *device)
-{
- int rc = 0;
-
- if (!device) {
- dprintk(VIDC_ERR, "Invalid param: %p\n", device);
- return -EINVAL;
- }
-
- init_completion(&release_resources_done);
- rc = venus_hfi_unset_ocmem(device);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to unset OCMEM during PC %d\n", rc);
- goto ocmem_unset_failed;
- }
- rc = wait_for_completion_timeout(&release_resources_done,
- msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
- if (!rc) {
- dprintk(VIDC_ERR,
- "Wait interrupted or timeout for RELEASE_RESOURCES: %d\n",
- rc);
- rc = -EIO;
- goto release_resources_failed;
- }
-
- rc = venus_hfi_free_ocmem(device);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to free OCMEM during PC\n");
- goto ocmem_free_failed;
- }
- return rc;
-
-ocmem_free_failed:
- venus_hfi_alloc_ocmem(device, device->ocmem_size);
-release_resources_failed:
-ocmem_unset_failed:
- return rc;
-}
-
static int venus_hfi_prepare_pc(struct venus_hfi_device *device)
{
int rc = 0;
@@ -2819,18 +2876,20 @@
}
mutex_unlock(&device->clk_pwr_lock);
- rc = venus_hfi_unset_free_ocmem(device);
+ rc = __unset_free_ocmem(device);
if (rc) {
dprintk(VIDC_ERR,
- "Failed to unset and free OCMEM for PC %d\n",
- rc);
+ "Failed to unset and free OCMEM for PC, rc : %d\n", rc);
return;
}
rc = venus_hfi_prepare_pc(device);
if (rc) {
- dprintk(VIDC_ERR, "Failed to prepare for PC %d\n", rc);
- venus_hfi_alloc_ocmem(device, device->ocmem_size);
+ dprintk(VIDC_ERR, "Failed to prepare for PC, rc : %d\n", rc);
+ rc = __alloc_set_ocmem(device, true);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to re-allocate OCMEM. Performance will be impacted\n");
return;
}
@@ -2926,6 +2985,14 @@
dprintk(VIDC_DBG,
"Received HFI_MSG_SYS_RELEASE_RESOURCE\n");
complete(&release_resources_done);
+ } else if (rc == HFI_MSG_SYS_INIT_DONE) {
+ int ret = 0;
+ dprintk(VIDC_DBG,
+ "Received HFI_MSG_SYS_INIT_DONE\n");
+ ret = __alloc_set_ocmem(device, true);
+ if (ret)
+ dprintk(VIDC_WARN,
+ "Failed to allocate OCMEM. Performance will be impacted\n");
}
}
while (!venus_hfi_iface_dbgq_read(device, packet)) {
@@ -3058,7 +3125,7 @@
strlcpy(clock[VCODEC_AXI_CLK].name, "bus_clk",
sizeof(clock[VCODEC_AXI_CLK].name));
- if (res->has_ocmem) {
+ if (res->ocmem_size) {
strlcpy(clock[VCODEC_OCMEM_CLK].name, "mem_clk",
sizeof(clock[VCODEC_OCMEM_CLK].name));
}
@@ -3081,7 +3148,7 @@
}
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !res->ocmem_size)
continue;
cl = &device->resources.clock[i];
if (!cl->clk) {
@@ -3097,7 +3164,7 @@
if (i < VCODEC_MAX_CLKS) {
for (--i; i >= VCODEC_CLK; i--) {
- if (i == VCODEC_OCMEM_CLK && !res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !res->ocmem_size)
continue;
cl = &device->resources.clock[i];
clk_put(cl->clk);
@@ -3116,7 +3183,7 @@
}
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !device->res->ocmem_size)
continue;
clk_put(device->resources.clock[i].clk);
}
@@ -3135,7 +3202,7 @@
WARN_ON(!mutex_is_locked(&device->clk_pwr_lock));
if (device->clk_state == ENABLED_PREPARED) {
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !device->res->ocmem_size)
continue;
cl = &device->resources.clock[i];
usleep(100);
@@ -3154,7 +3221,7 @@
}
}
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !device->res->ocmem_size)
continue;
cl = &device->resources.clock[i];
clk_unprepare(cl->clk);
@@ -3181,7 +3248,7 @@
return 0;
}
for (i = VCODEC_CLK; i < VCODEC_MAX_CLKS; i++) {
- if (i == VCODEC_OCMEM_CLK && !device->res->has_ocmem)
+ if (i == VCODEC_OCMEM_CLK && !device->res->ocmem_size)
continue;
cl = &device->resources.clock[i];
rc = clk_prepare_enable(cl->clk);
@@ -3329,7 +3396,7 @@
goto err_init_bus;
}
- if (device->res->has_ocmem) {
+ if (device->res->ocmem_size) {
bus_info->ocmem_handle[MSM_VIDC_ENCODER] =
msm_bus_scale_register_client(
&device->res->bus_pdata[BUS_IDX_ENC_OCMEM]);
@@ -3355,59 +3422,6 @@
return -EINVAL;
}
-static int venus_hfi_ocmem_notify_handler(struct notifier_block *this,
- unsigned long event, void *data)
-{
- struct ocmem_buf *buff = data;
- struct venus_hfi_device *device;
- struct venus_resources *resources;
- struct on_chip_mem *ocmem;
- int rc = NOTIFY_DONE;
- if (event == OCMEM_ALLOC_GROW) {
- ocmem = container_of(this, struct on_chip_mem, vidc_ocmem_nb);
- if (!ocmem) {
- dprintk(VIDC_ERR, "Wrong handler passed\n");
- rc = NOTIFY_BAD;
- goto err_ocmem_notify;
- }
- resources = container_of(ocmem,
- struct venus_resources, ocmem);
- device = container_of(resources,
- struct venus_hfi_device, resources);
- if (venus_hfi_set_ocmem(device, buff, 1)) {
- dprintk(VIDC_ERR, "Failed to set ocmem: %d\n", rc);
- goto err_ocmem_notify;
- }
- rc = NOTIFY_OK;
- }
-
-err_ocmem_notify:
- return rc;
-}
-
-static void venus_hfi_ocmem_init(struct venus_hfi_device *device)
-{
- struct on_chip_mem *ocmem;
-
- ocmem = &device->resources.ocmem;
- ocmem->vidc_ocmem_nb.notifier_call = venus_hfi_ocmem_notify_handler;
- ocmem->handle =
- ocmem_notifier_register(OCMEM_VIDEO, &ocmem->vidc_ocmem_nb);
- if (IS_ERR_OR_NULL(ocmem->handle)) {
- dprintk(VIDC_WARN,
- "Failed to register OCMEM notifier. Performance might be impacted\n");
- ocmem->handle = NULL;
- }
-}
-
-static void venus_hfi_deinit_ocmem(struct venus_hfi_device *device)
-{
- if (device->resources.ocmem.handle)
- ocmem_notifier_unregister(device->resources.ocmem.handle,
- &device->resources.ocmem.vidc_ocmem_nb);
-}
-
-
static int venus_hfi_init_resources(struct venus_hfi_device *device,
struct msm_vidc_platform_resources *res)
{
@@ -3445,9 +3459,6 @@
goto err_register_iommu_domain;
}
- if (res->has_ocmem)
- venus_hfi_ocmem_init(device);
-
return rc;
err_register_iommu_domain:
@@ -3461,8 +3472,6 @@
static void venus_hfi_deinit_resources(struct venus_hfi_device *device)
{
- if (device->res->has_ocmem)
- venus_hfi_deinit_ocmem(device);
venus_hfi_deregister_iommu_domains(device);
venus_hfi_deinit_bus(device);
venus_hfi_deinit_clocks(device);
@@ -3660,10 +3669,6 @@
return -EINVAL;
}
- rc = venus_hfi_free_ocmem(device);
- if (rc)
- dprintk(VIDC_WARN, "%s - failed to free ocmem\n", __func__);
-
rc = venus_hfi_core_release(device);
if (rc) {
dprintk(VIDC_ERR, "%s - failed to release venus core rc = %d\n",
@@ -3929,9 +3934,6 @@
hdev->scale_clocks = venus_hfi_scale_clocks;
hdev->scale_bus = venus_hfi_scale_bus;
hdev->unvote_bus = venus_hfi_unvote_bus;
- hdev->unset_ocmem = venus_hfi_unset_ocmem;
- hdev->alloc_ocmem = venus_hfi_alloc_ocmem;
- hdev->free_ocmem = venus_hfi_free_ocmem;
hdev->iommu_get_domain_partition = venus_hfi_iommu_get_domain_partition;
hdev->load_fw = venus_hfi_load_fw;
hdev->unload_fw = venus_hfi_unload_fw;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index 9169355..05d7b6a 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -196,7 +196,6 @@
u32 device_id;
u32 clk_load;
u32 bus_load[MSM_VIDC_MAX_DEVICES];
- unsigned long ocmem_size;
enum clock_state clk_state;
bool power_enabled;
enum vidc_clocks clk_gating_level;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
old mode 100755
new mode 100644
index 8484bb2..6cc4dee
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1156,9 +1156,6 @@
enum session_type type, enum mem_type mtype);
int (*unvote_bus)(void *dev, enum session_type type,
enum mem_type mtype);
- int (*unset_ocmem)(void *dev);
- int (*alloc_ocmem)(void *dev, unsigned long size);
- int (*free_ocmem)(void *dev);
int (*iommu_get_domain_partition)(void *dev, u32 flags, u32 buffer_type,
int *domain_num, int *partition_num);
int (*load_fw)(void *dev);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index fb66cbb..3a93469 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -616,6 +616,25 @@
return ret;
}
+static int qseecom_perf_enable(struct qseecom_dev_handle *data)
+{
+ int ret = 0;
+ ret = qsee_vote_for_clock(data, CLK_DFAB);
+ if (ret) {
+ pr_err("Failed to vote for DFAB clock with err %d\n", ret);
+ goto perf_enable_exit;
+ }
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ pr_err("Failed to vote for SFPB clock with err %d\n", ret);
+ goto perf_enable_exit;
+ }
+
+perf_enable_exit:
+ return ret;
+}
+
static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
void __user *argp)
{
@@ -631,10 +650,29 @@
pr_err("Invalid bandwidth mode (%d)\n", req_mode);
return ret;
}
- mutex_lock(&qsee_bw_mutex);
- ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
- mutex_unlock(&qsee_bw_mutex);
+ /*
+ * Register bus bandwidth needs if bus scaling feature is enabled;
+ * otherwise, qseecom enable/disable clocks for the client directly.
+ */
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
+ mutex_unlock(&qsee_bw_mutex);
+ } else {
+ pr_debug("Bus scaling feature is NOT enabled\n");
+ pr_debug("request bandwidth mode %d for the client\n",
+ req_mode);
+ if (req_mode != INACTIVE) {
+ ret = qseecom_perf_enable(data);
+ if (ret)
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ } else {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
+ }
return ret;
}
@@ -1294,15 +1332,9 @@
return ret;
}
} else {
- ret = qsee_vote_for_clock(data, CLK_DFAB);
+ ret = qseecom_perf_enable(data);
if (ret) {
- pr_err("Failed to vote for DFAB clock%d\n", ret);
- return ret;
- }
- ret = qsee_vote_for_clock(data, CLK_SFPB);
- if (ret) {
- qsee_disable_clock_vote(data, CLK_DFAB);
- pr_err("Failed to vote for SFPB clock%d\n", ret);
+ pr_err("Failed to vote for clocks with err %d\n", ret);
goto exit;
}
}
@@ -2287,6 +2319,7 @@
int ret = 0;
struct qseecom_send_cmd_req req = {0, 0, 0, 0};
struct qseecom_dev_handle *data;
+ bool perf_enabled = false;
if (handle == NULL) {
pr_err("Handle is not initialized\n");
@@ -2310,11 +2343,35 @@
return ret;
}
}
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd
+ * to tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ atomic_dec(&data->ioctl_count);
+ mutex_unlock(&app_access_lock);
+ return -EINVAL;
+ }
+ perf_enabled = true;
+ }
+
ret = __qseecom_send_cmd(data, &req);
if (qseecom.support_bus_scaling)
__qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
+
atomic_dec(&data->ioctl_count);
mutex_unlock(&app_access_lock);
@@ -2343,16 +2400,10 @@
if (ret)
pr_err("Failed to scale bus (med) %d\n", ret);
} else {
- ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
+ ret = qseecom_perf_enable(handle->dev);
if (ret)
- pr_err("Failed to vote for DFAB clock%d\n",
- ret);
- ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
- if (ret) {
- pr_err("Failed to vote for SFPB clock%d\n",
- ret);
- qsee_disable_clock_vote(handle->dev, CLK_DFAB);
- }
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
}
} else {
if (!qseecom.support_bus_scaling) {
@@ -3419,6 +3470,7 @@
int ret = 0;
struct qseecom_dev_handle *data = file->private_data;
void __user *argp = (void __user *) arg;
+ bool perf_enabled = false;
if (!data) {
pr_err("Invalid/uninitialized device handle\n");
@@ -3492,11 +3544,33 @@
break;
}
}
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd
+ * to tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ perf_enabled = true;
+ }
atomic_inc(&data->ioctl_count);
ret = qseecom_send_cmd(data, argp);
if (qseecom.support_bus_scaling)
__qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -3530,11 +3604,33 @@
break;
}
}
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd
+ * to tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ perf_enabled = true;
+ }
atomic_inc(&data->ioctl_count);
ret = qseecom_send_modfd_cmd(data, argp);
if (qseecom.support_bus_scaling)
__qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -3664,12 +3760,9 @@
__qseecom_register_bus_bandwidth_needs(data, HIGH);
mutex_unlock(&qsee_bw_mutex);
} else {
- ret = qsee_vote_for_clock(data, CLK_DFAB);
+ ret = qseecom_perf_enable(data);
if (ret)
- pr_err("Fail to vote for DFAB clock%d\n", ret);
- ret = qsee_vote_for_clock(data, CLK_SFPB);
- if (ret)
- pr_err("Fail to vote for SFPB clock%d\n", ret);
+ pr_err("Fail to vote for clocks %d\n", ret);
}
atomic_dec(&data->ioctl_count);
break;
diff --git a/drivers/net/ethernet/msm/msm_rmnet.c b/drivers/net/ethernet/msm/msm_rmnet.c
index 06f8cd4..7a0e1b5 100644
--- a/drivers/net/ethernet/msm/msm_rmnet.c
+++ b/drivers/net/ethernet/msm/msm_rmnet.c
@@ -3,7 +3,7 @@
* Virtual Ethernet Interface for MSM7K Networking
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012, 2014, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -141,7 +141,8 @@
struct device_attribute *attr,
char *buf)
{
- return sprintf(buf, "%lu\n", (unsigned long) timeout_suspend_us);
+ return snprintf(buf, PAGE_SIZE, "%lu\n",
+ (unsigned long) timeout_suspend_us);
}
static DEVICE_ATTR(timeout_suspend, 0664, timeout_suspend_show, timeout_suspend_store);
@@ -196,7 +197,7 @@
char *buf)
{
struct rmnet_private *p = netdev_priv(to_net_dev(d));
- return sprintf(buf, "%lu\n", p->wakeups_xmit);
+ return snprintf(buf, PAGE_SIZE, "%lu\n", p->wakeups_xmit);
}
DEVICE_ATTR(wakeups_xmit, 0444, wakeups_xmit_show, NULL);
@@ -205,7 +206,7 @@
char *buf)
{
struct rmnet_private *p = netdev_priv(to_net_dev(d));
- return sprintf(buf, "%lu\n", p->wakeups_rcv);
+ return snprintf(buf, PAGE_SIZE, "%lu\n", p->wakeups_rcv);
}
DEVICE_ATTR(wakeups_rcv, 0444, wakeups_rcv_show, NULL);
@@ -229,7 +230,7 @@
{
struct rmnet_private *p = netdev_priv(to_net_dev(d));
p = netdev_priv(to_net_dev(d));
- return sprintf(buf, "%lu\n", timeout_us);
+ return snprintf(buf, PAGE_SIZE, "%lu\n", timeout_us);
}
DEVICE_ATTR(timeout, 0664, timeout_show, timeout_store);
diff --git a/drivers/net/ethernet/msm/msm_rmnet_sdio.c b/drivers/net/ethernet/msm/msm_rmnet_sdio.c
index 754cb83..695d6c69 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_sdio.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_sdio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2012, 2014, 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
@@ -109,7 +109,8 @@
struct device_attribute *attr,
char *buf)
{
- return sprintf(buf, "%lu\n", (unsigned long) timeout_suspend_us);
+ return snprintf(buf, PAGE_SIZE, "%lu\n",
+ (unsigned long) timeout_suspend_us);
}
static DEVICE_ATTR(timeout_suspend, 0664, timeout_suspend_show,
@@ -168,7 +169,7 @@
char *buf)
{
struct rmnet_private *p = netdev_priv(to_net_dev(d));
- return sprintf(buf, "%lu\n", p->wakeups_xmit);
+ return snprintf(buf, PAGE_SIZE, "%lu\n", p->wakeups_xmit);
}
DEVICE_ATTR(wakeups_xmit, 0444, wakeups_xmit_show, NULL);
@@ -177,7 +178,7 @@
char *buf)
{
struct rmnet_private *p = netdev_priv(to_net_dev(d));
- return sprintf(buf, "%lu\n", p->wakeups_rcv);
+ return snprintf(buf, PAGE_SIZE, "%lu\n", p->wakeups_rcv);
}
DEVICE_ATTR(wakeups_rcv, 0444, wakeups_rcv_show, NULL);
@@ -201,7 +202,7 @@
{
struct rmnet_private *p = netdev_priv(to_net_dev(d));
p = netdev_priv(to_net_dev(d));
- return sprintf(buf, "%lu\n", timeout_us);
+ return snprintf(buf, PAGE_SIZE, "%lu\n", timeout_us);
}
DEVICE_ATTR(timeout, 0664, timeout_show, timeout_store);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index db34307..ed6fa29 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -35,6 +35,7 @@
#include <linux/rwsem.h>
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/qpnp/qpnp-adc.h>
+#include <linux/pm_qos.h>
#include <mach/board.h>
#include <mach/msm_smd.h>
@@ -51,6 +52,10 @@
#define VERSION "1.01"
#define WCNSS_PIL_DEVICE "wcnss"
+#define WCNSS_DISABLE_PC_LATENCY 100
+#define WCNSS_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE
+#define WCNSS_PM_QOS_TIMEOUT 15000
+
/* module params */
#define WCNSS_CONFIG_UNSPECIFIED (-1)
#define UINT32_MAX (0xFFFFFFFFU)
@@ -210,6 +215,7 @@
#define WCNSS_BUILD_VER_REQ (WCNSS_CTRL_MSG_START + 9)
#define WCNSS_BUILD_VER_RSP (WCNSS_CTRL_MSG_START + 10)
#define WCNSS_PM_CONFIG_REQ (WCNSS_CTRL_MSG_START + 11)
+#define WCNSS_CBC_COMPLETE_IND (WCNSS_CTRL_MSG_START + 12)
/* max 20mhz channel count */
#define WCNSS_MAX_CH_NUM 45
@@ -402,6 +408,7 @@
void __iomem *alarms_tactl;
void __iomem *fiq_reg;
int nv_downloaded;
+ int is_cbc_done;
unsigned char *fw_cal_data;
unsigned char *user_cal_data;
int fw_cal_rcvd;
@@ -426,6 +433,9 @@
u16 unsafe_ch_list[WCNSS_MAX_CH_NUM];
void *wcnss_notif_hdle;
u8 is_shutdown;
+ struct pm_qos_request wcnss_pm_qos_request;
+ int pc_disabled;
+ struct delayed_work wcnss_pm_qos_del_req;
} *penv = NULL;
static ssize_t wcnss_wlan_macaddr_store(struct device *dev,
@@ -970,6 +980,46 @@
device_remove_file(dev, &dev_attr_wcnss_mac_addr);
}
}
+
+static void wcnss_pm_qos_add_request(void)
+{
+ pr_info("%s: add request", __func__);
+ pm_qos_add_request(&penv->wcnss_pm_qos_request, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+}
+
+static void wcnss_pm_qos_remove_request(void)
+{
+ pr_info("%s: remove request", __func__);
+ pm_qos_remove_request(&penv->wcnss_pm_qos_request);
+}
+
+void wcnss_pm_qos_update_request(int val)
+{
+ pr_info("%s: update request %d", __func__, val);
+ pm_qos_update_request(&penv->wcnss_pm_qos_request, val);
+}
+
+void wcnss_disable_pc_remove_req(void)
+{
+ if (penv->pc_disabled) {
+ wcnss_pm_qos_update_request(WCNSS_ENABLE_PC_LATENCY);
+ wcnss_pm_qos_remove_request();
+ wcnss_allow_suspend();
+ penv->pc_disabled = 0;
+ }
+}
+
+void wcnss_disable_pc_add_req(void)
+{
+ if (!penv->pc_disabled) {
+ wcnss_pm_qos_add_request();
+ wcnss_prevent_suspend();
+ wcnss_pm_qos_update_request(WCNSS_DISABLE_PC_LATENCY);
+ penv->pc_disabled = 1;
+ }
+}
+
static void wcnss_smd_notify_event(void *data, unsigned int event)
{
int len = 0;
@@ -993,6 +1043,8 @@
WCNSS_CTRL_CHANNEL);
schedule_work(&penv->wcnssctrl_version_work);
schedule_work(&penv->wcnss_pm_config_work);
+ __cancel_delayed_work(&penv->wcnss_pm_qos_del_req);
+ schedule_delayed_work(&penv->wcnss_pm_qos_del_req, 0);
break;
@@ -1000,6 +1052,7 @@
pr_debug("wcnss: closing WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
penv->nv_downloaded = 0;
+ penv->is_cbc_done = 0;
break;
default:
@@ -1191,6 +1244,14 @@
}
EXPORT_SYMBOL(wcnss_get_wlan_config);
+int wcnss_is_hw_pronto_ver3(void)
+{
+ if (penv && penv->pdev)
+ return penv->wlan_config.is_pronto_v3;
+ return 0;
+}
+EXPORT_SYMBOL(wcnss_is_hw_pronto_ver3);
+
int wcnss_device_ready(void)
{
if (penv && penv->pdev && penv->nv_downloaded &&
@@ -1200,6 +1261,15 @@
}
EXPORT_SYMBOL(wcnss_device_ready);
+int wcnss_cbc_complete(void)
+{
+ if (penv && penv->pdev && penv->is_cbc_done &&
+ !wcnss_device_is_shutdown())
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL(wcnss_cbc_complete);
+
int wcnss_device_is_shutdown(void)
{
if (penv && penv->is_shutdown)
@@ -1835,6 +1905,10 @@
pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
fw_status);
break;
+ case WCNSS_CBC_COMPLETE_IND:
+ penv->is_cbc_done = 1;
+ pr_info("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n");
+ break;
case WCNSS_CALDATA_UPLD_REQ:
extract_cal_data(len);
@@ -2028,6 +2102,11 @@
return;
}
+static void wcnss_pm_qos_enable_pc(struct work_struct *worker)
+{
+ wcnss_disable_pc_remove_req();
+ return;
+}
static void wcnss_caldata_dnld(const void *cal_data,
unsigned int cal_data_size, bool msg_to_follow)
@@ -2261,10 +2340,14 @@
unsigned long wcnss_phys_addr;
int size = 0;
struct resource *res;
+ int is_pronto_v3;
int pil_retry = 0;
int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
"qcom,has-pronto-hw");
+ is_pronto_v3 = of_property_read_bool(pdev->dev.of_node,
+ "qcom,is-pronto-v3");
+
if (of_property_read_u32(pdev->dev.of_node,
"qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) {
penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT;
@@ -2287,6 +2370,7 @@
}
penv->wcnss_hw_type = (has_pronto_hw) ? WCNSS_PRONTO_HW : WCNSS_RIVA_HW;
penv->wlan_config.use_48mhz_xo = has_48mhz_xo;
+ penv->wlan_config.is_pronto_v3 = is_pronto_v3;
if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) {
has_autodetect_xo = of_property_read_bool(pdev->dev.of_node,
@@ -2342,8 +2426,11 @@
INIT_WORK(&penv->wcnssctrl_version_work, wcnss_send_version_req);
INIT_WORK(&penv->wcnss_pm_config_work, wcnss_send_pm_config);
INIT_WORK(&penv->wcnssctrl_nvbin_dnld_work, wcnss_nvbin_dnld_main);
+ INIT_DELAYED_WORK(&penv->wcnss_pm_qos_del_req, wcnss_pm_qos_enable_pc);
wake_lock_init(&penv->wcnss_wake_lock, WAKE_LOCK_SUSPEND, "wcnss");
+ /* Add pm_qos request to disable power collapse for DDR */
+ wcnss_disable_pc_add_req();
if (wcnss_hardware_type() == WCNSS_PRONTO_HW) {
size = 0x3000;
@@ -2467,6 +2554,7 @@
if (IS_ERR(penv->pil)) {
dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
ret = PTR_ERR(penv->pil);
+ wcnss_disable_pc_add_req();
wcnss_pronto_log_debug_regs();
}
} while (pil_retry++ < WCNSS_MAX_PIL_RETRY && IS_ERR(penv->pil));
@@ -2479,6 +2567,8 @@
penv->pil = NULL;
goto fail_pil;
}
+ /* Remove pm_qos request */
+ wcnss_disable_pc_remove_req();
return 0;
@@ -2531,6 +2621,7 @@
else
wcnss_gpios_config(penv->gpios_5wire, false);
fail_gpio_res:
+ wcnss_disable_pc_remove_req();
penv = NULL;
return ret;
}
@@ -2657,14 +2748,18 @@
static int wcnss_notif_cb(struct notifier_block *this, unsigned long code,
void *ss_handle)
{
- pr_debug("%s: wcnss notification event: %lu\n", __func__, code);
+ pr_info("%s: wcnss notification event: %lu\n", __func__, code);
- if (SUBSYS_POWERUP_FAILURE == code)
- wcnss_pronto_log_debug_regs();
- else if (SUBSYS_BEFORE_SHUTDOWN == code)
- penv->is_shutdown = 1;
- else if (SUBSYS_AFTER_POWERUP == code)
- penv->is_shutdown = 0;
+ if (code == SUBSYS_BEFORE_SHUTDOWN) {
+ penv->is_shutdown = 1;
+ wcnss_disable_pc_add_req();
+ schedule_delayed_work(&penv->wcnss_pm_qos_del_req,
+ msecs_to_jiffies(WCNSS_PM_QOS_TIMEOUT));
+ } else if (code == SUBSYS_POWERUP_FAILURE) {
+ wcnss_pronto_log_debug_regs();
+ wcnss_disable_pc_remove_req();
+ } else if (SUBSYS_AFTER_POWERUP == code)
+ penv->is_shutdown = 0;
return NOTIFY_DONE;
}
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 0f15a37..537dc1d 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -3095,8 +3095,10 @@
min_cycle = chip->fcc_learning_samples[0].chargecycles;
for (i = 1; i < chip->min_fcc_learning_samples; i++) {
if (min_cycle >
- chip->fcc_learning_samples[i].chargecycles)
+ chip->fcc_learning_samples[i].chargecycles) {
pos = i;
+ break;
+ }
}
} else {
/* find an empty location */
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index ae13322..4eb1033 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -20,7 +20,7 @@
dsi-v2-objs = dsi_v2.o dsi_host_v2.o dsi_io_v2.o
obj-$(CONFIG_FB_MSM_MDSS_MDP3) += dsi-v2.o
-mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o mdss_dsi_cmd.o
+mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o mdss_dsi_cmd.o mdss_dsi_status.o
mdss-dsi-objs += mdss_dsi_panel.o
mdss-dsi-objs += msm_mdss_io_8974.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 454fd15..592f70e 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -1263,7 +1263,83 @@
return 0;
}
-int msm_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int msm_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_req cmdreq;
+
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = ctrl->status_cmds.cmds;
+ cmdreq.cmds_cnt = ctrl->status_cmds.cmd_cnt;
+ cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL | CMD_REQ_RX;
+ cmdreq.rlen = 1;
+ cmdreq.cb = NULL;
+ cmdreq.rbuf = ctrl->status_buf.data;
+
+ return mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
+
+/**
+ * msm_dsi_reg_status_check() - Check dsi panel status through reg read
+ * @ctrl_pdata: pointer to the dsi controller structure
+ *
+ * This function can be used to check the panel status through reading the
+ * status register from the panel.
+ *
+ * Return: positive value if the panel is in good state, negative value or
+ * zero otherwise.
+ */
+int msm_dsi_reg_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int ret = 0;
+
+ if (ctrl_pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return 0;
+ }
+
+ pr_debug("%s: Checking Register status\n", __func__);
+
+ msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 1);
+
+ if (ctrl_pdata->status_cmds.link_state == DSI_HS_MODE)
+ dsi_set_tx_power_mode(0);
+
+ ret = msm_dsi_read_status(ctrl_pdata);
+
+ if (ctrl_pdata->status_cmds.link_state == DSI_HS_MODE)
+ dsi_set_tx_power_mode(1);
+
+ if (ret == 0) {
+ if (ctrl_pdata->status_buf.data[0] !=
+ ctrl_pdata->status_value) {
+ pr_err("%s: Read back value from panel is incorrect\n",
+ __func__);
+ ret = -EINVAL;
+ } else {
+ ret = 1;
+ }
+ } else {
+ pr_err("%s: Read status register returned error\n", __func__);
+ }
+
+ msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 0);
+ pr_debug("%s: Read register done with ret: %d\n", __func__, ret);
+
+ return ret;
+}
+
+/**
+ * msm_dsi_bta_status_check() - Check dsi panel status through bta check
+ * @ctrl_pdata: pointer to the dsi controller structure
+ *
+ * This function can be used to check status of the panel using bta check
+ * for the panel.
+ *
+ * Return: positive value if the panel is in good state, negative value or
+ * zero otherwise.
+ */
+static int msm_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
int ret = 0;
@@ -1478,9 +1554,19 @@
complete(&ctrl->mdp_comp);
dsi_buf_alloc(&ctrl->tx_buf, SZ_4K);
dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
+ dsi_buf_alloc(&ctrl->status_buf, SZ_4K);
ctrl->cmdlist_commit = msm_dsi_cmdlist_commit;
ctrl->panel_mode = ctrl->panel_data.panel_info.mipi.mode;
- ctrl->check_status = msm_dsi_bta_status_check;
+
+ if (ctrl->status_mode == ESD_REG)
+ ctrl->check_status = msm_dsi_reg_status_check;
+ else if (ctrl->status_mode == ESD_BTA)
+ ctrl->check_status = msm_dsi_bta_status_check;
+
+ if (ctrl->status_mode == ESD_MAX) {
+ pr_err("%s: Using default BTA for ESD check\n", __func__);
+ ctrl->check_status = msm_dsi_bta_status_check;
+ }
}
static int __devinit msm_dsi_probe(struct platform_device *pdev)
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 50e4a01..ee8994a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -1599,8 +1599,16 @@
}
ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
- ctrl_pdata->check_status = mdss_dsi_bta_status_check;
+ if (ctrl_pdata->status_mode == ESD_REG)
+ ctrl_pdata->check_status = mdss_dsi_reg_status_check;
+ else if (ctrl_pdata->status_mode == ESD_BTA)
+ ctrl_pdata->check_status = mdss_dsi_bta_status_check;
+
+ if (ctrl_pdata->status_mode == ESD_MAX) {
+ pr_err("%s: Using default BTA for ESD check\n", __func__);
+ ctrl_pdata->check_status = mdss_dsi_bta_status_check;
+ }
if (ctrl_pdata->bklt_ctrl == BL_PWM)
mdss_dsi_panel_pwm_cfg(ctrl_pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 609b7ce..aeb79a9e 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -85,6 +85,12 @@
UNKNOWN_CTRL,
};
+enum dsi_panel_status_mode {
+ ESD_BTA,
+ ESD_REG,
+ ESD_MAX,
+};
+
enum dsi_ctrl_op_mode {
DSI_LP_MODE,
DSI_HS_MODE,
@@ -286,6 +292,8 @@
struct dsi_panel_cmds on_cmds;
struct dsi_panel_cmds off_cmds;
+ struct dsi_panel_cmds status_cmds;
+ u32 status_value;
struct dsi_panel_cmds video2cmd;
struct dsi_panel_cmds cmd2video;
@@ -305,6 +313,8 @@
struct dsi_buf tx_buf;
struct dsi_buf rx_buf;
+ struct dsi_buf status_buf;
+ int status_mode;
};
struct dsi_status_data {
@@ -363,6 +373,7 @@
int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
+int mdss_dsi_reg_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type);
int mdss_dsi_panel_init(struct device_node *node,
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index d8a713e..0e48ee1 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -99,6 +99,7 @@
mutex_init(&ctrl->cmd_mutex);
mdss_dsi_buf_alloc(&ctrl->tx_buf, SZ_4K);
mdss_dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
+ mdss_dsi_buf_alloc(&ctrl->status_buf, SZ_4K);
ctrl->cmdlist_commit = mdss_dsi_cmdlist_commit;
@@ -612,6 +613,82 @@
pr_debug("%s: BTA done, status = %d\n", __func__, status);
}
+static int mdss_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_req cmdreq;
+
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = ctrl->status_cmds.cmds;
+ cmdreq.cmds_cnt = ctrl->status_cmds.cmd_cnt;
+ cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL | CMD_REQ_RX;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+ cmdreq.rbuf = ctrl->status_buf.data;
+
+ return mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
+
+/**
+ * mdss_dsi_reg_status_check() - Check dsi panel status through reg read
+ * @ctrl_pdata: pointer to the dsi controller structure
+ *
+ * This function can be used to check the panel status through reading the
+ * status register from the panel.
+ *
+ * Return: positive value if the panel is in good state, negative value or
+ * zero otherwise.
+ */
+int mdss_dsi_reg_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int ret = 0;
+
+ if (ctrl_pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return 0;
+ }
+
+ pr_debug("%s: Checking Register status\n", __func__);
+
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
+
+ if (ctrl_pdata->status_cmds.link_state == DSI_HS_MODE)
+ mdss_dsi_set_tx_power_mode(0, &ctrl_pdata->panel_data);
+
+ ret = mdss_dsi_read_status(ctrl_pdata);
+
+ if (ctrl_pdata->status_cmds.link_state == DSI_HS_MODE)
+ mdss_dsi_set_tx_power_mode(1, &ctrl_pdata->panel_data);
+
+ if (ret == 0) {
+ if (ctrl_pdata->status_buf.data[0] !=
+ ctrl_pdata->status_value) {
+ pr_err("%s: Read back value from panel is incorrect\n",
+ __func__);
+ ret = -EINVAL;
+ } else {
+ ret = 1;
+ }
+ } else {
+ pr_err("%s: Read status register returned error\n", __func__);
+ }
+
+ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0);
+ pr_debug("%s: Read register done with ret: %d\n", __func__, ret);
+
+ return ret;
+}
+
+/**
+ * mdss_dsi_bta_status_check() - Check dsi panel status through bta check
+ * @ctrl_pdata: pointer to the dsi controller structure
+ *
+ * This function can be used to check status of the panel using bta check
+ * for the panel.
+ *
+ * Return: positive value if the panel is in good state, negative value or
+ * zero otherwise.
+ */
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
int ret = 0;
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 4fa995f..6e2a7f5 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -41,6 +41,7 @@
{
int ret;
u32 duty;
+ u32 period_ns;
if (ctrl->pwm_bl == NULL) {
pr_err("%s: no PWM\n", __func__);
@@ -69,10 +70,23 @@
ctrl->pwm_enabled = 0;
}
- ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period);
- if (ret) {
- pr_err("%s: pwm_config_us() failed err=%d.\n", __func__, ret);
- return;
+ if (ctrl->pwm_period >= USEC_PER_SEC) {
+ ret = pwm_config_us(ctrl->pwm_bl, duty, ctrl->pwm_period);
+ if (ret) {
+ pr_err("%s: pwm_config_us() failed err=%d.\n",
+ __func__, ret);
+ return;
+ }
+ } else {
+ period_ns = ctrl->pwm_period * NSEC_PER_USEC;
+ ret = pwm_config(ctrl->pwm_bl,
+ level * period_ns / ctrl->bklt_max,
+ period_ns);
+ if (ret) {
+ pr_err("%s: pwm_config() failed err=%d.\n",
+ __func__, ret);
+ return;
+ }
}
ret = pwm_enable(ctrl->pwm_bl);
@@ -822,6 +836,8 @@
"qcom,ulps-enabled");
pr_info("%s: ulps feature %s", __func__,
(pinfo->ulps_feature_enabled ? "enabled" : "disabled"));
+ pinfo->esd_check_enabled = of_property_read_bool(np,
+ "qcom,esd-check-enabled");
pinfo->mipi.dynamic_switch_enabled = of_property_read_bool(np,
"qcom,dynamic-mode-switch-enabled");
@@ -1130,6 +1146,23 @@
mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds,
"qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state");
+ mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->status_cmds,
+ "qcom,mdss-dsi-panel-status-command",
+ "qcom,mdss-dsi-panel-status-command-state");
+ rc = of_property_read_u32(np, "qcom,mdss-dsi-panel-status-value", &tmp);
+ ctrl_pdata->status_value = (!rc ? tmp : 0);
+
+
+ ctrl_pdata->status_mode = ESD_MAX;
+ rc = of_property_read_string(np,
+ "qcom,mdss-dsi-panel-status-check-mode", &data);
+ if (!rc) {
+ if (!strcmp(data, "bta_check"))
+ ctrl_pdata->status_mode = ESD_BTA;
+ else if (!strcmp(data, "reg_read"))
+ ctrl_pdata->status_mode = ESD_REG;
+ }
+
rc = mdss_dsi_parse_panel_features(np, ctrl_pdata);
if (rc) {
pr_err("%s: failed to parse panel features\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_dsi_status.c b/drivers/video/msm/mdss/mdss_dsi_status.c
index c68155a..02540bb 100644
--- a/drivers/video/msm/mdss/mdss_dsi_status.c
+++ b/drivers/video/msm/mdss/mdss_dsi_status.c
@@ -32,7 +32,7 @@
#define STATUS_CHECK_INTERVAL_MS 5000
#define STATUS_CHECK_INTERVAL_MIN_MS 200
-#define DSI_STATUS_CHECK_DISABLE 1
+#define DSI_STATUS_CHECK_DISABLE 0
static uint32_t interval = STATUS_CHECK_INTERVAL_MS;
static uint32_t dsi_status_disable = DSI_STATUS_CHECK_DISABLE;
@@ -81,6 +81,7 @@
struct dsi_status_data *pdata = container_of(self,
struct dsi_status_data, fb_notifier);
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdss_panel_info *pinfo;
pdata->mfd = evdata->info->par;
ctrl_pdata = container_of(dev_get_platdata(&pdata->mfd->pdev->dev),
@@ -89,6 +90,14 @@
pr_err("%s: DSI ctrl not available\n", __func__);
return NOTIFY_BAD;
}
+
+ pinfo = &ctrl_pdata->panel_data.panel_info;
+
+ if (!(pinfo->esd_check_enabled)) {
+ pr_debug("ESD check is not enaled in panel dtsi\n");
+ return NOTIFY_DONE;
+ }
+
if (dsi_status_disable) {
pr_debug("%s: DSI status disabled\n", __func__);
return NOTIFY_DONE;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 95d403b..bf91a29 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -884,6 +884,8 @@
struct mdss_panel_data *pdata;
int (*update_ad_input)(struct msm_fb_data_type *mfd);
u32 temp = bkl_lvl;
+ int ret = -EINVAL;
+ bool is_bl_changed = (bkl_lvl != mfd->bl_level);
if (((!mfd->panel_power_on && mfd->dcm_state != DCM_ENTER)
|| !mfd->bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
@@ -896,6 +898,12 @@
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
+ if (mfd->mdp.ad_attenuate_bl) {
+ ret = (*mfd->mdp.ad_attenuate_bl)(bkl_lvl, &temp, mfd);
+ if (ret)
+ pr_err("Failed to attenuate BL\n");
+ }
+
mfd->bl_level_prev_scaled = mfd->bl_level_scaled;
if (!IS_CALIB_MODE_BL(mfd))
mdss_fb_scale_bl(mfd, &temp);
@@ -911,31 +919,42 @@
mfd->bl_level = bkl_lvl;
return;
}
+ pr_debug("backlight sent to panel :%d\n", temp);
pdata->set_backlight(pdata, temp);
mfd->bl_level = bkl_lvl;
mfd->bl_level_scaled = temp;
- if (mfd->mdp.update_ad_input) {
+ if (mfd->mdp.update_ad_input && is_bl_changed) {
update_ad_input = mfd->mdp.update_ad_input;
mutex_unlock(&mfd->bl_lock);
/* Will trigger ad_setup which will grab bl_lock */
update_ad_input(mfd);
- mdss_fb_bl_update_notify(mfd);
mutex_lock(&mfd->bl_lock);
}
+ mdss_fb_bl_update_notify(mfd);
}
}
void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
{
struct mdss_panel_data *pdata;
+ int ret = 0;
+ u32 temp;
mutex_lock(&mfd->bl_lock);
if (mfd->unset_bl_level && !mfd->bl_updated) {
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
mfd->bl_level = mfd->unset_bl_level;
- pdata->set_backlight(pdata, mfd->bl_level);
+ temp = mfd->bl_level;
+ if (mfd->mdp.ad_attenuate_bl) {
+ ret = (*mfd->mdp.ad_attenuate_bl)(temp,
+ &temp, mfd);
+ if (ret)
+ pr_err("Failed to attenuate BL\n");
+ }
+
+ pdata->set_backlight(pdata, temp);
mfd->bl_level_scaled = mfd->unset_bl_level;
mfd->bl_updated = 1;
}
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index fc53c55..1ab0fb7 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -123,6 +123,8 @@
int (*do_histogram)(struct msm_fb_data_type *mfd,
struct mdp_histogram *hist);
int (*update_ad_input)(struct msm_fb_data_type *mfd);
+ int (*ad_attenuate_bl)(u32 bl, u32 *bl_out,
+ struct msm_fb_data_type *mfd);
int (*panel_register_done)(struct mdss_panel_data *pdata);
u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
int (*splash_init_fnc)(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 8a0c9b1..f7d02b2 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1536,7 +1536,11 @@
switch (pdata->panel_info.bpp) {
case 18:
- ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB666;
+ if (ctl->intf_type == MDSS_INTF_DSI)
+ ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB666 |
+ MDSS_MDP_PANEL_FORMAT_PACK_ALIGN_MSB;
+ else
+ ctl->dst_format = MDSS_MDP_PANEL_FORMAT_RGB666;
dither.flags = MDP_PP_OPS_ENABLE | MDP_PP_OPS_WRITE;
dither.g_y_depth = 2;
dither.r_cr_depth = 2;
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index ea41159..0b67a6d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -379,6 +379,7 @@
#define MDSS_MDP_MAX_AD_AL 65535
#define MDSS_MDP_MAX_AD_STR 255
+#define MDSS_MDP_AD_BL_SCALE 4095
#define MDSS_MDP_REG_AD_BYPASS 0x000
#define MDSS_MDP_REG_AD_CTRL_0 0x004
@@ -519,7 +520,9 @@
#define MDSS_MDP_REG_INTF_FRAME_COUNT 0x0AC
#define MDSS_MDP_REG_INTF_LINE_COUNT 0x0B0
#define MDSS_MDP_PANEL_FORMAT_RGB888 0x213F
-#define MDSS_MDP_PANEL_FORMAT_RGB666 0x21AA
+#define MDSS_MDP_PANEL_FORMAT_RGB666 0x212A
+
+#define MDSS_MDP_PANEL_FORMAT_PACK_ALIGN_MSB BIT(7)
enum mdss_mdp_pingpong_index {
MDSS_MDP_PINGPONG0,
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index f51eb83..f286de5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -40,6 +40,9 @@
#define CHECK_BOUNDS(offset, size, max_size) \
(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
+#define IS_RIGHT_MIXER_OV(flags, dst_x, left_lm_w) \
+ ((flags & MDSS_MDP_RIGHT_MIXER) || (dst_x >= left_lm_w))
+
#define PP_CLK_CFG_OFF 0
#define PP_CLK_CFG_ON 1
@@ -58,6 +61,12 @@
static void __overlay_kickoff_requeue(struct msm_fb_data_type *mfd);
static void __vsync_retire_signal(struct msm_fb_data_type *mfd, int val);
+static inline u32 left_lm_w_from_mfd(struct msm_fb_data_type *mfd)
+{
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+ return ctl->mixer_left->width;
+}
+
static int mdss_mdp_overlay_sd_ctrl(struct msm_fb_data_type *mfd,
unsigned int enable)
{
@@ -96,17 +105,71 @@
return 0;
}
+/*
+ * This function is modified from mainline version. Source-split
+ * change is too large to port over onto certain code bases.
+ * Source-split patch added a new way to determine if layer
+ * is intended for right panel, by using x offset >= left LM
+ * This function corrects the x offset.
+ * Additionally, patches that fix other issues assumes that checks
+ * and corrections in this function are in place.
+ */
+static int mdss_mdp_ov_xres_check(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req)
+{
+ u32 xres = 0;
+ u32 left_lm_w = left_lm_w_from_mfd(mfd);
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+
+ if (IS_RIGHT_MIXER_OV(req->flags, req->dst_rect.x, left_lm_w)) {
+ if (req->dst_rect.x >= left_lm_w) {
+ /*
+ * this is a step towards removing a reliance on
+ * MDSS_MDP_RIGHT_MIXER flags. With the new src split
+ * code, some clients of non-src-split chipsets have
+ * stopped sending MDSS_MDP_RIGHT_MIXER flag and
+ * modified their xres relative to full panel
+ * dimensions. In such cases, we need to deduct left
+ * layer mixer width before we programm this HW.
+ */
+ req->dst_rect.x -= left_lm_w;
+ req->flags |= MDSS_MDP_RIGHT_MIXER;
+ }
+
+ if (ctl->mixer_right) {
+ xres += ctl->mixer_right->width;
+ } else {
+ pr_err("ov cannot be placed on right mixer\n");
+ return -EPERM;
+ }
+ } else {
+ if (ctl->mixer_left) {
+ xres = ctl->mixer_left->width;
+ } else {
+ pr_err("ov cannot be placed on left mixer\n");
+ return -EPERM;
+ }
+ }
+
+ if (CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres)) {
+ pr_err("dst_xres is invalid. dst_x:%d, dst_w:%d, xres:%d\n",
+ req->dst_rect.x, req->dst_rect.w, xres);
+ return -EOVERFLOW;
+ }
+
+ return 0;
+}
+
int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
struct mdss_mdp_format_params *fmt)
{
- u32 xres, yres;
+ u32 yres;
u32 min_src_size, min_dst_size;
int content_secure;
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
- xres = mfd->fbi->var.xres;
yres = mfd->fbi->var.yres;
content_secure = (req->flags & MDP_SECURE_OVERLAY_SESSION);
@@ -167,8 +230,7 @@
if (!(req->flags & MDSS_MDP_ROT_ONLY)) {
u32 src_w, src_h, dst_w, dst_h;
- if ((CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
- CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres))) {
+ if (CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres)) {
pr_err("invalid destination rect=%d,%d,%d,%d\n",
req->dst_rect.x, req->dst_rect.y,
req->dst_rect.w, req->dst_rect.h);
@@ -354,6 +416,7 @@
hor_req_pixels, hor_fetch_pixels,
vert_req_pixels, vert_fetch_pixels,
pipe->img_width, pipe->img_height);
+ pipe->scale.enable_pxl_ext = 0;
return -EINVAL;
}
}
@@ -435,6 +498,7 @@
struct mdp_histogram_start_req hist;
int ret;
u32 bwc_enabled;
+ u32 left_lm_w = left_lm_w_from_mfd(mfd);
if (mdp5_data->ctl == NULL)
return -ENODEV;
@@ -450,7 +514,7 @@
return -EOVERFLOW;
}
- if (req->flags & MDSS_MDP_RIGHT_MIXER)
+ if (IS_RIGHT_MIXER_OV(req->flags, req->dst_rect.x, left_lm_w))
mixer_mux = MDSS_MDP_MIXER_MUX_RIGHT;
else
mixer_mux = MDSS_MDP_MIXER_MUX_LEFT;
@@ -468,6 +532,10 @@
return -EINVAL;
}
+ ret = mdss_mdp_ov_xres_check(mfd, req);
+ if (ret)
+ return ret;
+
ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
if (ret)
return ret;
@@ -605,7 +673,8 @@
pipe->overfetch_disable = OVERFETCH_DISABLE_BOTTOM;
if (!(pipe->flags & MDSS_MDP_DUAL_PIPE) ||
- (pipe->flags & MDSS_MDP_RIGHT_MIXER))
+ IS_RIGHT_MIXER_OV(req->flags,
+ req->dst_rect.x, left_lm_w))
pipe->overfetch_disable |= OVERFETCH_DISABLE_RIGHT;
pr_debug("overfetch flags=%x\n", pipe->overfetch_disable);
} else {
@@ -1616,7 +1685,7 @@
pr_warn("right fb pipe not needed\n");
return -EINVAL;
}
-
+ req.flags = req.flags | MDSS_MDP_RIGHT_MIXER;
req.src_rect.x = mixer->width;
req.src_rect.w = fbi->var.xres - mixer->width;
} else {
@@ -2202,6 +2271,11 @@
u32 copyback = 0;
u32 copy_from_kernel = 0;
+ if (mfd->panel_info->partial_update_enabled) {
+ pr_err("Partical update feature is enabled.");
+ return -EPERM;
+ }
+
ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
if (ret)
return ret;
@@ -2315,6 +2389,11 @@
u32 pp_bus_handle;
static int req = -1;
+ if (mfd->panel_info->partial_update_enabled) {
+ pr_err("Partical update feature is enabled.");
+ return -EPERM;
+ }
+
switch (cmd) {
case MSMFB_HISTOGRAM_START:
if (!mfd->panel_power_on)
@@ -2472,6 +2551,7 @@
int ret = 0, left_cnt = 0, right_cnt = 0;
int i;
u32 new_reqs = 0;
+ u32 left_lm_w = left_lm_w_from_mfd(mfd);
ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
if (ret)
@@ -2499,7 +2579,7 @@
if (pipe->play_cnt == 0)
new_reqs |= pipe->ndx;
- if (pipe->flags & MDSS_MDP_RIGHT_MIXER) {
+ if (IS_RIGHT_MIXER_OV(req->flags, req->dst_rect.x, left_lm_w)) {
if (right_cnt >= MDSS_MDP_MAX_STAGE) {
pr_err("too many pipes on right mixer\n");
ret = -EINVAL;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index ad8e8a6..225862d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -399,13 +399,27 @@
struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
-static u32 pp_ad_attenuate_bl(u32 bl, struct mdss_ad_info *ad);
+static int pp_ad_attenuate_bl(u32 bl, u32 *bl_out,
+ struct msm_fb_data_type *mfd);
static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
static inline bool pp_sts_is_enabled(u32 sts, int side);
static inline void pp_sts_set_split_bits(u32 *sts, u32 bits);
static u32 last_sts, last_state;
+inline int linear_map(int in, int *out, int in_max, int out_max)
+{
+ if (in < 0 || !out || in_max <= 0 || out_max <= 0)
+ return -EINVAL;
+ *out = ((in * out_max) / in_max);
+ pr_debug("in = %d, out = %d, in_max = %d, out_max = %d\n",
+ in, *out, in_max, out_max);
+ if ((in > 0) && (*out == 0))
+ *out = 1;
+ return 0;
+
+}
+
int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
struct mdp_csc_cfg *data)
{
@@ -814,19 +828,18 @@
* TODO: Allow pipe to be programmed whenever new CSC is
* applied (i.e. dirty bit)
*/
- if (pipe->play_cnt == 0)
- mdss_mdp_csc_setup_data(MDSS_MDP_BLOCK_SSPP,
- pipe->num, 1, &pipe->pp_cfg.csc_cfg);
+ mdss_mdp_csc_setup_data(MDSS_MDP_BLOCK_SSPP, pipe->num,
+ 1, &pipe->pp_cfg.csc_cfg);
} else {
- if (pipe->src_fmt->is_yuv)
+ if (pipe->src_fmt->is_yuv) {
opmode |= (0 << 19) | /* DST_DATA=RGB */
(1 << 18) | /* SRC_DATA=YCBCR */
(1 << 17); /* CSC_1_EN */
- /*
- * TODO: Needs to be part of dirty bit logic: if there is a
- * previously configured pipe need to re-configure CSC matrix
- */
- if (pipe->play_cnt == 0) {
+ /*
+ * TODO: Needs to be part of dirty bit logic: if there
+ * is a previously configured pipe need to re-configure
+ * CSC matrix
+ */
mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
MDSS_MDP_CSC_YUV2RGB);
}
@@ -1749,9 +1762,13 @@
if (ad->state & PP_AD_STATE_BL_LIN) {
bl = ad->bl_lin[bl >> ad->bl_bright_shift];
bl = bl << ad->bl_bright_shift;
- bl = pp_ad_attenuate_bl(bl, ad);
+ ret = pp_ad_attenuate_bl(bl, &bl, ad->mfd);
+ if (ret)
+ pr_err("Failed to attenuate BL\n");
}
- ad->bl_data = bl;
+ linear_map(bl, &ad->bl_data,
+ ad->bl_mfd->panel_info->bl_max,
+ MDSS_MDP_AD_BL_SCALE);
pp_ad_input_write(&mdata->ad_off[dspp_num], ad);
}
if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
@@ -3905,6 +3922,11 @@
return -ENODEV;
}
+ if (ad_mfd->panel_info->type == DTV_PANEL) {
+ pr_debug("AD not supported on external display\n");
+ return ret;
+ }
+
mixer_num = mdss_mdp_get_ctl_mixers(ad_mfd->index, mixer_id);
if (!mixer_num) {
pr_debug("no mixers connected, %d", mixer_num);
@@ -4049,11 +4071,7 @@
} else if (init_cfg->ops & MDP_PP_AD_CFG) {
memcpy(&ad->cfg, &init_cfg->params.cfg,
sizeof(struct mdss_ad_cfg));
- /*
- * TODO: specify panel independent range of input from cfg,
- * scale input backlight_scale to panel bl_max's range
- */
- ad->cfg.backlight_scale = bl_mfd->panel_info->bl_max;
+ ad->cfg.backlight_scale = MDSS_MDP_AD_BL_SCALE;
ad->sts |= PP_AD_STS_DIRTY_CFG;
}
@@ -4176,7 +4194,7 @@
if (!ret) {
if (wait) {
mutex_lock(&ad->lock);
- init_completion(&ad->comp);
+ INIT_COMPLETION(ad->comp);
mutex_unlock(&ad->lock);
}
if (wait) {
@@ -4315,10 +4333,7 @@
frame_end = 0xFFFF;
procs_start = 0x0;
procs_end = 0xFFFF;
- if (split_mode)
- tile_ctrl = 0x0;
- else
- tile_ctrl = 0x1;
+ tile_ctrl = 0x0;
}
@@ -4471,9 +4486,13 @@
if (ad->state & PP_AD_STATE_BL_LIN) {
bl = ad->bl_lin[bl >> ad->bl_bright_shift];
bl = bl << ad->bl_bright_shift;
- bl = pp_ad_attenuate_bl(bl, ad);
+ ret = pp_ad_attenuate_bl(bl, &bl, ad->mfd);
+ if (ret)
+ pr_err("Failed to attenuate BL\n");
}
- ad->bl_data = bl;
+ linear_map(bl, &ad->bl_data,
+ ad->bl_mfd->panel_info->bl_max,
+ MDSS_MDP_AD_BL_SCALE);
}
mutex_unlock(&bl_mfd->bl_lock);
ad->reg_sts |= PP_AD_STS_DIRTY_DATA;
@@ -4523,6 +4542,7 @@
if (bl_mfd != mfd)
bl_mfd->ext_ad_ctrl = mfd->index;
bl_mfd->mdp.update_ad_input = pp_update_ad_input;
+ bl_mfd->mdp.ad_attenuate_bl = pp_ad_attenuate_bl;
bl_mfd->ext_bl_ctrl = ad->cfg.bl_ctrl_mode;
mutex_unlock(&bl_mfd->bl_lock);
@@ -4552,6 +4572,7 @@
memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
mutex_lock(&bl_mfd->bl_lock);
bl_mfd->mdp.update_ad_input = NULL;
+ bl_mfd->mdp.ad_attenuate_bl = NULL;
bl_mfd->ext_bl_ctrl = 0;
bl_mfd->ext_ad_ctrl = -1;
mutex_unlock(&bl_mfd->bl_lock);
@@ -4692,28 +4713,60 @@
addr + ((PP_AD_LUT_LEN - 1) * 2));
}
-static u32 pp_ad_attenuate_bl(u32 bl, struct mdss_ad_info *ad)
+static int pp_ad_attenuate_bl(u32 bl, u32 *bl_out,
+ struct msm_fb_data_type *mfd)
{
u32 shift = 0, ratio_temp = 0;
- u32 n, lut_interval, bl_att, out;
+ u32 n, lut_interval, bl_att;
+ int ret = -1;
+ struct mdss_ad_info *ad;
- ratio_temp = ad->cfg.backlight_max / (AD_BL_ATT_LUT_LEN - 1);
+ if (bl < 0) {
+ pr_err("Invalid backlight input\n");
+ return ret;
+ }
+
+ ret = mdss_mdp_get_ad(mfd, &ad);
+ if (ret || !ad || !ad->bl_mfd || !ad->bl_mfd->panel_info ||
+ !ad->bl_mfd->panel_info->bl_max || !ad->bl_att_lut) {
+ pr_err("Failed to get the ad.\n");
+ return ret;
+ }
+ pr_debug("bl_in = %d\n", bl);
+ /* map panel backlight range to AD backlight range */
+ linear_map(bl, &bl, ad->bl_mfd->panel_info->bl_max,
+ MDSS_MDP_AD_BL_SCALE);
+
+ pr_debug("Before attenuation = %d\n", bl);
+ ratio_temp = MDSS_MDP_AD_BL_SCALE / (AD_BL_ATT_LUT_LEN - 1);
while (ratio_temp > 0) {
ratio_temp = ratio_temp >> 1;
shift++;
}
n = bl >> shift;
- lut_interval = (ad->cfg.backlight_max + 1) / (AD_BL_ATT_LUT_LEN - 1);
+ if (n >= (AD_BL_ATT_LUT_LEN - 1)) {
+ pr_err("Invalid index for BL attenuation: %d.\n", n);
+ return ret;
+ }
+ lut_interval = (MDSS_MDP_AD_BL_SCALE + 1) / (AD_BL_ATT_LUT_LEN - 1);
bl_att = ad->bl_att_lut[n] + (bl - lut_interval * n) *
(ad->bl_att_lut[n + 1] - ad->bl_att_lut[n]) /
lut_interval;
+ pr_debug("n = %d, bl_att = %d\n", n, bl_att);
if (ad->init.alpha_base)
- out = (ad->init.alpha * bl_att +
+ *bl_out = (ad->init.alpha * bl_att +
(ad->init.alpha_base - ad->init.alpha) * bl) /
ad->init.alpha_base;
else
- out = bl;
- return out;
+ *bl_out = bl;
+
+ pr_debug("After attenuation = %d\n", *bl_out);
+ /* map AD backlight range back to panel backlight range */
+ linear_map(*bl_out, bl_out, MDSS_MDP_AD_BL_SCALE,
+ ad->bl_mfd->panel_info->bl_max);
+
+ pr_debug("bl_out = %d\n", *bl_out);
+ return 0;
}
int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets)
@@ -4751,6 +4804,7 @@
mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
mdata->ad_cfgs[i].last_bl = 0;
mutex_init(&mdata->ad_cfgs[i].lock);
+ init_completion(&mdata->ad_cfgs[i].comp);
mdata->ad_cfgs[i].handle.vsync_handler = pp_ad_vsync_handler;
mdata->ad_cfgs[i].handle.cmd_post_flush = true;
INIT_WORK(&mdata->ad_cfgs[i].calc_work, pp_ad_calc_worker);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 084cba4..8713db4 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -328,6 +328,7 @@
u32 mode_gpio_state;
bool dynamic_fps;
bool ulps_feature_enabled;
+ bool esd_check_enabled;
char dfps_update;
int new_fps;
int panel_max_fps;
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index c5d5366..9f50f89 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -398,19 +398,22 @@
client = mhl_ctrl->i2c_handle;
- if (on) {
+ mutex_lock(&mhl_ctrl->sii_config_lock);
+ if (on && !mhl_ctrl->irq_req_done) {
rc = mhl_vreg_config(mhl_ctrl, 1);
if (rc) {
pr_err("%s: vreg init failed [%d]\n",
__func__, rc);
- return -ENODEV;
+ rc = -ENODEV;
+ goto vreg_config_error;
}
rc = mhl_gpio_config(mhl_ctrl, 1);
if (rc) {
pr_err("%s: gpio init failed [%d]\n",
__func__, rc);
- return -ENODEV;
+ rc = -ENODEV;
+ goto vreg_config_error;
}
rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
@@ -419,17 +422,22 @@
if (rc) {
pr_err("%s: request_threaded_irq failed, status: %d\n",
__func__, rc);
- return -ENODEV;
+ rc = -ENODEV;
+ goto vreg_config_error;
} else {
mhl_ctrl->irq_req_done = true;
+ /* wait for i2c interrupt line to be activated */
+ msleep(100);
}
- } else {
+ } else if (!on && mhl_ctrl->irq_req_done) {
free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
mhl_gpio_config(mhl_ctrl, 0);
mhl_vreg_config(mhl_ctrl, 0);
mhl_ctrl->irq_req_done = false;
}
+vreg_config_error:
+ mutex_unlock(&mhl_ctrl->sii_config_lock);
return rc;
}
@@ -471,15 +479,10 @@
flush_work(&mhl_ctrl->mhl_intr_work);
- if (!mhl_ctrl->irq_req_done) {
- rc = mhl_sii_config(mhl_ctrl, true);
- if (rc) {
- pr_err("%s: Failed to config vreg/gpio\n", __func__);
- return rc;
- }
-
- /* wait for i2c interrupt line to be activated */
- msleep(100);
+ rc = mhl_sii_config(mhl_ctrl, true);
+ if (rc) {
+ pr_err("%s: Failed to config vreg/gpio\n", __func__);
+ return rc;
}
if (!mhl_ctrl->disc_enabled) {
@@ -1532,22 +1535,29 @@
pr_debug("%s\n", __func__);
if (!enable) {
- regulator_disable(reg_8941_vdda);
- regulator_put(reg_8941_vdda);
- reg_8941_vdda = NULL;
+ if (reg_8941_vdda) {
+ regulator_disable(reg_8941_vdda);
+ regulator_put(reg_8941_vdda);
+ reg_8941_vdda = NULL;
+ }
- regulator_disable(reg_8941_smps3a);
- regulator_put(reg_8941_smps3a);
- reg_8941_smps3a = NULL;
+ if (reg_8941_smps3a) {
+ regulator_disable(reg_8941_smps3a);
+ regulator_put(reg_8941_smps3a);
+ reg_8941_smps3a = NULL;
+ }
- regulator_disable(reg_8941_l02);
- regulator_put(reg_8941_l02);
- reg_8941_l02 = NULL;
+ if (reg_8941_l02) {
+ regulator_disable(reg_8941_l02);
+ regulator_put(reg_8941_l02);
+ reg_8941_l02 = NULL;
+ }
- regulator_disable(reg_8941_l24);
- regulator_put(reg_8941_l24);
- reg_8941_l24 = NULL;
-
+ if (reg_8941_l24) {
+ regulator_disable(reg_8941_l24);
+ regulator_put(reg_8941_l24);
+ reg_8941_l24 = NULL;
+ }
return 0;
}
@@ -1858,6 +1868,7 @@
init_completion(&mhl_ctrl->rgnd_done);
+ mutex_init(&mhl_ctrl->sii_config_lock);
mhl_ctrl->mhl_psy.name = "ext-vbus";
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index 42ee81e..69cf36d 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -164,6 +164,11 @@
int wr_burst_pending;
struct completion req_write_done;
spinlock_t lock;
+ /*
+ * Lock between mhl_sii_config and
+ * mhl_sii_device_discovery functions
+ */
+ struct mutex sii_config_lock;
bool tx_powered_off;
uint8_t dwnstream_hpd;
bool mhl_det_discon;
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index 9368d8f..8b45fcc 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -51,7 +51,15 @@
#define IPA_IOCTL_GET_NAT_OFFSET 28
#define IPA_IOCTL_RM_ADD_DEPENDENCY 29
#define IPA_IOCTL_RM_DEL_DEPENDENCY 30
-#define IPA_IOCTL_MAX 31
+#define IPA_IOCTL_GENERATE_FLT_EQ 31
+#define IPA_IOCTL_QUERY_INTF_EXT_PROPS 32
+#define IPA_IOCTL_QUERY_EP_MAPPING 33
+#define IPA_IOCTL_QUERY_RT_TBL_INDEX 34
+#define IPA_IOCTL_WRITE_QMAPID 35
+#define IPA_IOCTL_MDFY_FLT_RULE 36
+#define IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_ADD 37
+#define IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_DEL 38
+#define IPA_IOCTL_MAX 39
/**
* max size of the header to be inserted
@@ -179,7 +187,38 @@
WLAN_AP_DISCONNECT,
WLAN_STA_CONNECT,
WLAN_STA_DISCONNECT,
- IPA_EVENT_MAX
+ IPA_WLAN_EVENT_MAX
+};
+
+/**
+ * enum ipa_wan_event - Events for wan client
+ *
+ * wan default route add/del
+ */
+enum ipa_wan_event {
+ WAN_UPSTREAM_ROUTE_ADD = IPA_WLAN_EVENT_MAX,
+ WAN_UPSTREAM_ROUTE_DEL,
+ IPA_WAN_EVENT_MAX
+};
+
+enum ipa_ecm_event {
+ ECM_CONNECT = IPA_WAN_EVENT_MAX,
+ ECM_DISCONNECT,
+ IPA_EVENT_MAX_NUM
+};
+
+#define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM)
+
+/**
+ * struct ipa_wan_msg - To hold information about wan client
+ * @name: name of the wan interface
+ *
+ * CnE need to pass the name of default wan iface when connected/disconnected.
+ */
+struct ipa_wan_msg {
+ char upstream_ifname[IPA_RESOURCE_NAME_MAX];
+ char tethered_ifname[IPA_RESOURCE_NAME_MAX];
+ enum ipa_ip_type ip;
};
/**
@@ -824,6 +863,14 @@
IPA_IOCTL_RM_DEL_DEPENDENCY, \
struct ipa_ioc_rm_dependency *)
+#define IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_ADD _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_ADD, \
+ struct ipa_wan_msg *)
+
+#define IPA_IOC_NOTIFY_WAN_UPSTREAM_ROUTE_DEL _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_NOTIFY_WAN_UPSTREAM_ROUTE_DEL, \
+ struct ipa_wan_msg *)
+
/*
* unique magic number of the Tethering bridge ioctls
*/
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index e6c46d1..56ba8ab 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -28,6 +28,8 @@
struct wcnss_wlan_config {
int use_48mhz_xo;
+ int is_pronto_v3;
+ void __iomem *msm_wcnss_base;
};
enum {
@@ -40,6 +42,7 @@
#define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
#define HAVE_WCNSS_RESET_INTR 1
#define HAVE_WCNSS_CAL_DOWNLOAD 1
+#define HAVE_CBC_DONE 1
#define HAVE_WCNSS_RX_BUFF_COUNT 1
#define WLAN_MAC_ADDR_SIZE (6)
@@ -77,7 +80,9 @@
void wcnss_resume_notify(void);
void wcnss_riva_log_debug_regs(void);
void wcnss_pronto_log_debug_regs(void);
+int wcnss_is_hw_pronto_ver3(void);
int wcnss_device_ready(void);
+int wcnss_cbc_complete(void);
int wcnss_device_is_shutdown(void);
void wcnss_riva_dump_pmic_regs(void);
int wcnss_xo_auto_detect_enabled(void);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index a8a94c1..066c364 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -289,7 +289,7 @@
/*
* A queue for waiters to do rmdir() cgroup. A tasks will sleep when
- * cgroup->count == 0 && list_empty(&cgroup->children) && subsys has some
+ * list_empty(&cgroup->children) && subsys has some
* reference to css->refcnt. In general, this refcnt is expected to goes down
* to zero, soon.
*
@@ -3912,6 +3912,10 @@
struct cgroup_subsys *ss;
unsigned long flags;
bool failed = false;
+
+ if (atomic_read(&cgrp->count) != 0)
+ return false;
+
local_irq_save(flags);
for_each_subsys(cgrp->root, ss) {
struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d4c0534..7eefa94 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -657,6 +657,8 @@
int migratetype = 0;
int batch_free = 0;
int to_free = count;
+ int free = 0;
+ int cma_free = 0;
int mt = 0;
spin_lock(&zone->lock);
@@ -687,17 +689,23 @@
do {
page = list_entry(list->prev, struct page, lru);
mt = get_pageblock_migratetype(page);
+ if (likely(mt != MIGRATE_ISOLATE))
+ mt = page_private(page);
+
/* must delete as __free_one_page list manipulates */
list_del(&page->lru);
/* MIGRATE_MOVABLE list may include MIGRATE_RESERVEs */
- __free_one_page(page, zone, 0, page_private(page));
- trace_mm_page_pcpu_drain(page, 0, page_private(page));
- if (is_migrate_cma(mt))
- __mod_zone_page_state(zone,
- NR_FREE_CMA_PAGES, 1);
+ __free_one_page(page, zone, 0, mt);
+ trace_mm_page_pcpu_drain(page, 0, mt);
+ if (likely(mt != MIGRATE_ISOLATE)) {
+ free++;
+ if (is_migrate_cma(mt))
+ cma_free++;
+ }
} while (--to_free && --batch_free && !list_empty(list));
}
- __mod_zone_page_state(zone, NR_FREE_PAGES, count);
+ __mod_zone_page_state(zone, NR_FREE_PAGES, free);
+ __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, cma_free);
spin_unlock(&zone->lock);
}
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index e17925f..75a1a14 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -6777,7 +6777,9 @@
/* Clean up starts */
/* Turn off PA ramp generator */
snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
- if (!mbhc->hph_pa_dac_state)
+ if (!mbhc->hph_pa_dac_state &&
+ (!(test_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state) ||
+ test_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state))))
wcd9xxx_enable_static_pa(mbhc, false);
wcd9xxx_restore_registers(codec, &taiko->reg_save_restore);
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 1553d1c..e973d10 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -3966,6 +3966,7 @@
{"CS-VOICE_UL1", NULL, "VOC_EXT_EC MUX"},
{"VOIP_UL", NULL, "VOC_EXT_EC MUX"},
{"VoLTE_UL", NULL, "VOC_EXT_EC MUX"},
+ {"VOICE2_UL", NULL, "VOC_EXT_EC MUX"},
{"AUDIO_REF_EC_UL1 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"},
{"AUDIO_REF_EC_UL1 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"},