Merge "msm: display: only release kickoff when no cleanup pipe"
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 749c594..1aca300 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -52,13 +52,15 @@
RGB Led is a tri-colored led, Red, Blue & Green.
Required properties for RGB led:
-- qcom,mode: mode the led should operate in, options "pwm" and "lpg"
-- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,mode: mode the led should operate in, options "pwm" and "lpg". "manual" mode is not supported for RGB led.
Required properties for PWM mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
- qcom,pwm-us: time the pwm device will modulate at (us)
Required properties for LPG mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
- qcom,duty-pcts: array of values for duty cycle to go through
- qcom,start-idx: starting point duty-pcts array
@@ -93,6 +95,7 @@
Required properties for LPG mode only:
- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
- qcom,duty-pcts: array of values for duty cycle to go through
- qcom,start-idx: starting point duty-pcts array
@@ -106,9 +109,7 @@
and the required rows are enabled by specifying values in the properties.
Required properties for keypad backlight:
-- qcom,mode: mode the led should operate in, options "pwm" and "lpg"
-- qcom,pwm-channel: pwm channel the led will operate on
-- qcom,pwm-us: time the pwm device will modulate at (us)
+- qcom,mode: mode the led should operate in, options "pwm" and "lpg". "manual" mode is not supported for keypad backlight.
- qcom,row-id: specify the id of the row. Supported values are 0 to 3.
Optional properties for keypad backlight:
@@ -118,9 +119,12 @@
- qcom,always-on: specify if the module has to be always on
Required properties for PWM mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
- qcom,pwm-us: time the pwm device will modulate at (us)
Required properties for LPG mode only:
+- qcom,pwm-channel: pwm channel the led will operate on
+- qcom,pwm-us: time the pwm device will modulate at (us)
- qcom,duty-pcts: array of values for duty cycle to go through
- qcom,start-idx: starting point duty-pcts array
@@ -201,6 +205,7 @@
linux,name = "led:rgb_green";
qcom,mode = "lpg";
qcom,pwm-channel = <5>;
+ qcom,pwm-us = <1000>;
qcom,duty-ms = <20>;
qcom,start-idx = <1>;
qcom,idx-len = <10>;
diff --git a/Documentation/devicetree/bindings/sound/voice-svc.txt b/Documentation/devicetree/bindings/sound/voice-svc.txt
index deca7f5..bb8649f 100644
--- a/Documentation/devicetree/bindings/sound/voice-svc.txt
+++ b/Documentation/devicetree/bindings/sound/voice-svc.txt
@@ -1,4 +1,6 @@
* Voice Service binding
+Provides an interface to access voice services
+exposed by DSP over APR interface.
Required properties:
- compatible : "qcom,msm-voice-svc"
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 63a37f5..4eb26a2 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1738,6 +1738,10 @@
compatible = "qti,msm-pcm-loopback";
};
+ qcom,msm-voice-svc {
+ compatible = "qcom,msm-voice-svc";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index c81720e..a5240cc 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -329,24 +329,40 @@
* before the CPU is brought up.
*/
case CPU_DEAD:
- case CPU_UP_CANCELED:
if (is_clk) {
clk_disable_unprepare(cpu_clk[cpu]);
clk_disable_unprepare(l2_clk);
update_l2_bw(NULL);
}
break;
+ case CPU_UP_CANCELED:
+ if (is_clk) {
+ clk_unprepare(cpu_clk[cpu]);
+ clk_unprepare(l2_clk);
+ update_l2_bw(NULL);
+ }
+ break;
case CPU_UP_PREPARE:
if (is_clk) {
- rc = clk_prepare_enable(l2_clk);
+ rc = clk_prepare(l2_clk);
if (rc < 0)
return NOTIFY_BAD;
- rc = clk_prepare_enable(cpu_clk[cpu]);
+ rc = clk_prepare(cpu_clk[cpu]);
if (rc < 0)
return NOTIFY_BAD;
update_l2_bw(&cpu);
}
break;
+ case CPU_STARTING:
+ if (is_clk) {
+ rc = clk_enable(l2_clk);
+ if (rc < 0)
+ return NOTIFY_BAD;
+ rc = clk_enable(cpu_clk[cpu]);
+ if (rc < 0)
+ return NOTIFY_BAD;
+ }
+ break;
default:
break;
}
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 935bb9a..7ad6401 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -280,7 +280,8 @@
static void *__alloc_from_contiguous(struct device *dev, size_t size,
pgprot_t prot, struct page **ret_page,
- bool no_kernel_mapping, const void *caller);
+ const void *caller,
+ struct dma_attrs *attrs);
struct dma_pool {
size_t size;
@@ -321,7 +322,7 @@
if (IS_ENABLED(CONFIG_CMA))
ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page,
- false, atomic_pool_init);
+ atomic_pool_init, NULL);
else
ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot,
&page, NULL);
@@ -508,19 +509,22 @@
#define NO_KERNEL_MAPPING_DUMMY 0x2222
static void *__alloc_from_contiguous(struct device *dev, size_t size,
pgprot_t prot, struct page **ret_page,
- bool no_kernel_mapping,
- const void *caller)
+ const void *caller,
+ struct dma_attrs *attrs)
{
unsigned long order = get_order(size);
size_t count = size >> PAGE_SHIFT;
struct page *page;
void *ptr;
+ bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING,
+ attrs);
page = dma_alloc_from_contiguous(dev, count, order);
if (!page)
return NULL;
- __dma_clear_buffer(page, size);
+ if (!dma_get_attr(DMA_ATTR_SKIP_ZEROING, attrs))
+ __dma_clear_buffer(page, size);
if (!PageHighMem(page)) {
__dma_remap(page, size, prot, no_kernel_mapping);
@@ -601,7 +605,7 @@
static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
gfp_t gfp, pgprot_t prot, const void *caller,
- bool no_kernel_mapping)
+ struct dma_attrs *attrs)
{
u64 mask = get_coherent_dma_mask(dev);
struct page *page;
@@ -642,7 +646,7 @@
addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
else
addr = __alloc_from_contiguous(dev, size, prot, &page,
- no_kernel_mapping, caller);
+ caller, attrs);
if (addr)
*handle = pfn_to_dma(dev, page_to_pfn(page));
@@ -659,14 +663,12 @@
{
pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
void *memory;
- bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING,
- attrs);
if (dma_alloc_from_coherent(dev, size, handle, &memory))
return memory;
return __dma_alloc(dev, size, handle, gfp, prot,
- __builtin_return_address(0), no_kernel_mapping);
+ __builtin_return_address(0), attrs);
}
/*
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 3d52735..947e229 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1519,8 +1519,25 @@
const struct mem_type *type)
{
pte_t *pte, *start_pte;
+ pmd_t *base_pmd;
- start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+ base_pmd = pmd_offset(
+ pud_offset(pgd_offset(&init_mm, addr), addr), addr);
+
+ if (pmd_none(*base_pmd) || pmd_bad(*base_pmd)) {
+ start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+#ifndef CONFIG_ARM_LPAE
+ /*
+ * Following is needed when new pte is allocated for pmd[1]
+ * cases, which may happen when base (start) address falls
+ * under pmd[1].
+ */
+ if (addr & SECTION_SIZE)
+ start_pte += pte_index(addr);
+#endif
+ } else {
+ start_pte = pte_offset_kernel(base_pmd, addr);
+ }
pte = start_pte;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index ba13ec1..93e932a 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1508,8 +1508,7 @@
return err;
}
if (pkt_type == CALLBACK_DATA_TYPE) {
- if (payload_size > driver->itemsize ||
- payload_size <= MIN_SIZ_ALLOW) {
+ if (payload_size > driver->itemsize) {
pr_err("diag: Dropping packet, invalid packet size. Current payload size %d\n",
payload_size);
driver->dropped_count++;
@@ -1541,6 +1540,11 @@
return ret;
}
/* The packet is for the remote processor */
+ if (payload_size <= MIN_SIZ_ALLOW) {
+ pr_err("diag: Integer underflow in %s, payload size: %d",
+ __func__, payload_size);
+ return -EBADMSG;
+ }
token_offset = 4;
payload_size -= 4;
buf += 4;
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 0c7c9e0..936541f 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -640,7 +640,6 @@
char *hdr;
char *bufp;
uint32_t read_data;
- int i;
memwidth = BMVAL(tmc_readl(drvdata, CORESIGHT_DEVID), 8, 10);
if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
@@ -654,16 +653,22 @@
bufp = drvdata->buf;
while (1) {
- for (i = 0; i < memwords; i++) {
- read_data = tmc_readl_no_log(drvdata, TMC_RRD);
- if (read_data == 0xFFFFFFFF)
- goto out;
- memcpy(bufp, &read_data, BYTES_PER_WORD);
- bufp += BYTES_PER_WORD;
+ read_data = tmc_readl_no_log(drvdata, TMC_RRD);
+ if (read_data == 0xFFFFFFFF)
+ goto out;
+ if ((bufp - drvdata->buf) >= drvdata->size) {
+ dev_err(drvdata->dev, "ETF-ETB end marker missing\n");
+ goto out;
}
+ memcpy(bufp, &read_data, BYTES_PER_WORD);
+ bufp += BYTES_PER_WORD;
}
out:
+ if ((bufp - drvdata->buf) % (memwords * BYTES_PER_WORD))
+ dev_dbg(drvdata->dev, "ETF-ETB data is not %lx bytes aligned\n",
+ (unsigned long) memwords * BYTES_PER_WORD);
+
if (drvdata->aborting) {
hdr = drvdata->buf - PAGE_SIZE;
*(uint32_t *)(hdr + TMC_ETFETB_DUMP_MAGIC_OFF) =
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index da68d05..048dc56 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -136,6 +136,7 @@
}
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+ dma_set_attr(DMA_ATTR_SKIP_ZEROING, &attrs);
cpu_addr = dma_alloc_attrs(sheap->dev, len, &handle, GFP_KERNEL,
&attrs);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 0c22694..915f5e7 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -81,8 +81,6 @@
To compile this driver as a module, choose M here: the
module will be called hbtp_input.
-endif
-
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
@@ -724,3 +722,5 @@
To compile this driver as a module, choose M here: the
module will be called CM36283.
+
+endif
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 0659b77..0413472 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -1755,7 +1755,7 @@
return -EINVAL;
}
rc = pwm_lut_config(pwm_cfg->pwm_dev,
- PM_PWM_PERIOD_MIN, /* ignored by hardware */
+ pwm_cfg->pwm_period_us,
pwm_cfg->duty_cycles->duty_pcts,
pwm_cfg->lut_params);
if (rc < 0) {
@@ -2862,7 +2862,7 @@
else
return rc;
- if (pwm_cfg->mode == PWM_MODE) {
+ if (pwm_cfg->mode != MANUAL_MODE) {
rc = of_property_read_u32(node, "qcom,pwm-us", &val);
if (!rc)
pwm_cfg->pwm_period_us = val;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 4700469..805ff0a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -147,13 +147,13 @@
uint32_t (*get_wm_mask) (uint32_t irq_status0, uint32_t irq_status1);
uint32_t (*get_comp_mask) (uint32_t irq_status0, uint32_t irq_status1);
uint32_t (*get_pingpong_status) (struct vfe_device *vfe_dev);
- long (*halt) (struct vfe_device *vfe_dev);
+ long (*halt) (struct vfe_device *vfe_dev, uint32_t blocking);
};
struct msm_vfe_core_ops {
void (*reg_update) (struct vfe_device *vfe_dev);
long (*reset_hw) (struct vfe_device *vfe_dev,
- enum msm_isp_reset_type reset_type);
+ enum msm_isp_reset_type reset_type, uint32_t blocking);
int (*init_hw) (struct vfe_device *vfe_dev);
void (*init_hw_reg) (struct vfe_device *vfe_dev);
void (*release_hw) (struct vfe_device *vfe_dev);
@@ -167,6 +167,12 @@
int (*get_platform_data) (struct vfe_device *vfe_dev);
void (*get_error_mask) (uint32_t *error_mask0, uint32_t *error_mask1);
void (*process_error_status) (struct vfe_device *vfe_dev);
+ void (*get_overflow_mask) (uint32_t *overflow_mask);
+ void (*get_irq_mask) (struct vfe_device *vfe_dev,
+ uint32_t *irq0_mask, uint32_t *irq1_mask);
+ void (*restore_irq_mask) (struct vfe_device *vfe_dev);
+ void (*get_halt_restart_mask) (uint32_t *irq0_mask,
+ uint32_t *irq1_mask);
};
struct msm_vfe_stats_ops {
int (*get_stats_idx) (enum msm_isp_stats_type stats_type);
@@ -298,6 +304,15 @@
uint32_t runtime_num_burst_capture;
uint8_t runtime_framedrop_update;
uint32_t runtime_output_format;
+ enum msm_vfe_frame_skip_pattern frame_skip_pattern;
+
+};
+
+enum msm_vfe_overflow_state {
+ NO_OVERFLOW,
+ OVERFLOW_DETECTED,
+ HALT_REQUESTED,
+ RESTART_REQUESTED,
};
struct msm_vfe_axi_composite_info {
@@ -314,6 +329,7 @@
uint32_t width;
long pixel_clock;
uint32_t input_format;/*V4L2 pix format with bayer pattern*/
+ uint32_t last_updt_frm_id;
};
enum msm_wm_ub_cfg_type {
@@ -393,6 +409,9 @@
#define MSM_VFE_TASKLETQ_SIZE 200
struct msm_vfe_error_info {
+ atomic_t overflow_state;
+ uint32_t overflow_recover_irq_mask0;
+ uint32_t overflow_recover_irq_mask1;
uint32_t error_mask0;
uint32_t error_mask1;
uint32_t violation_status;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index cf76131..ba1e58c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -393,19 +393,25 @@
};
static long msm_vfe32_reset_hardware(struct vfe_device *vfe_dev ,
- enum msm_isp_reset_type reset_type)
+ enum msm_isp_reset_type reset_type, uint32_t blocking)
{
uint32_t rst_val;
+ long rc = 0;
if (reset_type >= ISP_RST_MAX) {
pr_err("%s: Error Invalid parameter\n", __func__);
reset_type = ISP_RST_HARD;
}
rst_val = msm_vfe32_reset_values[reset_type];
init_completion(&vfe_dev->reset_complete);
- msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0x4);
- return wait_for_completion_timeout(
- &vfe_dev->reset_complete, msecs_to_jiffies(50));
+ if (blocking) {
+ msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0x4);
+ rc = wait_for_completion_timeout(
+ &vfe_dev->reset_complete, msecs_to_jiffies(50));
+ } else {
+ msm_camera_io_w_mb(0x3EF, vfe_dev->vfe_base + 0x4);
+ }
+ return rc;
}
static void msm_vfe32_axi_reload_wm(
@@ -659,6 +665,7 @@
val &= 0xFFFFFF3F;
val = val | bus_en << 7 | vfe_en << 6;
msm_camera_io_w(val, vfe_dev->vfe_base + 0x1E4);
+ msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x1E0);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1E0);
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1;
} else if (update_state == DISABLE_CAMIF) {
@@ -891,12 +898,15 @@
VFE32_PING_PONG_BASE(wm_idx, pingpong_status));
}
-static long msm_vfe32_axi_halt(struct vfe_device *vfe_dev)
+static long msm_vfe32_axi_halt(struct vfe_device *vfe_dev,
+ uint32_t blocking)
{
uint32_t halt_mask;
- uint32_t axi_busy_flag = true;
-
+ uint32_t axi_busy_flag = false;
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x1D8);
+ if (blocking) {
+ axi_busy_flag = true;
+ }
while (axi_busy_flag) {
if (msm_camera_io_r(
vfe_dev->vfe_base + 0x1DC) & 0x1)
@@ -1067,6 +1077,33 @@
return (irq_status0 >> 13) & 0x7F;
}
+static void msm_vfe32_get_overflow_mask(uint32_t *overflow_mask)
+{
+ *overflow_mask = 0x002FFF7E;
+}
+
+static void msm_vfe32_get_irq_mask(struct vfe_device *vfe_dev,
+ uint32_t *irq0_mask, uint32_t *irq1_mask)
+{
+ *irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
+ *irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x20);
+}
+
+static void msm_vfe32_restore_irq_mask(struct vfe_device *vfe_dev)
+{
+ msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0,
+ vfe_dev->vfe_base + 0x1C);
+ msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1,
+ vfe_dev->vfe_base + 0x20);
+}
+
+static void msm_vfe32_get_halt_restart_mask(uint32_t *irq0_mask,
+ uint32_t *irq1_mask)
+{
+ *irq0_mask = 0x0;
+ *irq1_mask = 0x01800000;
+}
+
static uint32_t msm_vfe32_stats_get_comp_mask(uint32_t irq_status0,
uint32_t irq_status1)
{
@@ -1220,6 +1257,11 @@
.release_hw = msm_vfe32_release_hardware,
.get_platform_data = msm_vfe32_get_platform_data,
.get_error_mask = msm_vfe32_get_error_mask,
+ .get_overflow_mask = msm_vfe32_get_overflow_mask,
+ .get_irq_mask = msm_vfe32_get_irq_mask,
+ .restore_irq_mask = msm_vfe32_restore_irq_mask,
+ .get_halt_restart_mask =
+ msm_vfe32_get_halt_restart_mask,
.process_error_status = msm_vfe32_process_error_status,
},
.stats_ops = {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 04136d0..81e9c74 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -620,18 +620,24 @@
static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev ,
- enum msm_isp_reset_type reset_type)
+ enum msm_isp_reset_type reset_type, uint32_t blocking)
{
uint32_t rst_val;
+ long rc = 0;
if (reset_type >= ISP_RST_MAX) {
pr_err("%s: Error Invalid parameter\n", __func__);
reset_type = ISP_RST_HARD;
}
rst_val = msm_vfe40_reset_values[reset_type];
init_completion(&vfe_dev->reset_complete);
- msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC);
- return wait_for_completion_timeout(
- &vfe_dev->reset_complete, msecs_to_jiffies(50));
+ if (blocking) {
+ msm_camera_io_w_mb(rst_val, vfe_dev->vfe_base + 0xC);
+ rc = wait_for_completion_timeout(
+ &vfe_dev->reset_complete, msecs_to_jiffies(50));
+ } else {
+ msm_camera_io_w_mb(0x1EF, vfe_dev->vfe_base + 0xC);
+ }
+ return rc;
}
static void msm_vfe40_axi_reload_wm(
@@ -924,6 +930,7 @@
val &= 0xFFFFFF3F;
val = val | bus_en << 7 | vfe_en << 6;
msm_camera_io_w(val, vfe_dev->vfe_base + 0x2F8);
+ msm_camera_io_w_mb(0x4, vfe_dev->vfe_base + 0x2F4);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2F4);
vfe_dev->axi_data.src_info[VFE_PIX_0].active = 1;
} else if (update_state == DISABLE_CAMIF) {
@@ -1165,16 +1172,24 @@
VFE40_PING_PONG_BASE(wm_idx, pingpong_status));
}
-static long msm_vfe40_axi_halt(struct vfe_device *vfe_dev)
+static long msm_vfe40_axi_halt(struct vfe_device *vfe_dev,
+ uint32_t blocking)
{
- uint32_t halt_mask;
- halt_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
- halt_mask |= (1 << 8);
- msm_camera_io_w_mb(halt_mask, vfe_dev->vfe_base + 0x2C);
+ long rc = 0;
+ /* Keep only restart mask and halt mask*/
+ msm_camera_io_w(BIT(31), vfe_dev->vfe_base + 0x28);
+ msm_camera_io_w(BIT(8), vfe_dev->vfe_base + 0x2C);
+ /* Clear IRQ Status*/
+ msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
+ msm_camera_io_w(0xFEFFFFFF, vfe_dev->vfe_base + 0x34);
init_completion(&vfe_dev->halt_complete);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0);
- return wait_for_completion_interruptible_timeout(
- &vfe_dev->halt_complete, msecs_to_jiffies(500));
+ if (blocking) {
+ atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
+ rc = wait_for_completion_interruptible_timeout(
+ &vfe_dev->halt_complete, msecs_to_jiffies(500));
+ }
+ return rc;
}
static uint32_t msm_vfe40_get_wm_mask(
@@ -1183,6 +1198,33 @@
return (irq_status0 >> 8) & 0x7F;
}
+static void msm_vfe40_get_overflow_mask(uint32_t *overflow_mask)
+{
+ *overflow_mask = 0x00FFFE7E;
+}
+
+static void msm_vfe40_get_irq_mask(struct vfe_device *vfe_dev,
+ uint32_t *irq0_mask, uint32_t *irq1_mask)
+{
+ *irq0_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
+ *irq1_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
+}
+
+static void msm_vfe40_restore_irq_mask(struct vfe_device *vfe_dev)
+{
+ msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask0,
+ vfe_dev->vfe_base + 0x28);
+ msm_camera_io_w(vfe_dev->error_info.overflow_recover_irq_mask1,
+ vfe_dev->vfe_base + 0x2C);
+}
+
+static void msm_vfe40_get_halt_restart_mask(uint32_t *irq0_mask,
+ uint32_t *irq1_mask)
+{
+ *irq0_mask = BIT(31);
+ *irq1_mask = BIT(8);
+}
+
static uint32_t msm_vfe40_get_comp_mask(
uint32_t irq_status0, uint32_t irq_status1)
{
@@ -1519,6 +1561,11 @@
.release_hw = msm_vfe40_release_hardware,
.get_platform_data = msm_vfe40_get_platform_data,
.get_error_mask = msm_vfe40_get_error_mask,
+ .get_overflow_mask = msm_vfe40_get_overflow_mask,
+ .get_irq_mask = msm_vfe40_get_irq_mask,
+ .restore_irq_mask = msm_vfe40_restore_irq_mask,
+ .get_halt_restart_mask =
+ msm_vfe40_get_halt_restart_mask,
.process_error_status = msm_vfe40_process_error_status,
},
.stats_ops = {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 508bcec..4c3a3d5 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -20,6 +20,9 @@
#define HANDLE_TO_IDX(handle) (handle & 0xFF)
+#define MSM_ISP_MIN_AB 450000000
+#define MSM_ISP_MIN_IB 900000000
+
int msm_isp_axi_create_stream(
struct msm_vfe_axi_shared_data *axi_data,
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
@@ -475,7 +478,8 @@
framedrop_period = msm_isp_get_framedrop_period(
stream_cfg_cmd->frame_skip_pattern);
-
+ stream_info->frame_skip_pattern =
+ stream_cfg_cmd->frame_skip_pattern;
if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
stream_info->framedrop_pattern = 0x0;
else
@@ -1069,6 +1073,8 @@
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
uint32_t total_pix_bandwidth = 0, total_rdi_bandwidth = 0;
uint32_t num_pix_streams = 0;
+ uint32_t num_rdi_streams = 0;
+ uint32_t total_streams = 0;
uint64_t total_bandwidth = 0;
for (i = 0; i < MAX_NUM_STREAM; i++) {
@@ -1080,6 +1086,7 @@
num_pix_streams++;
} else {
total_rdi_bandwidth += stream_info->bandwidth;
+ num_rdi_streams++;
}
}
}
@@ -1089,10 +1096,17 @@
((unsigned long)axi_data->src_info[VFE_PIX_0].
pixel_clock) * ISP_DEFAULT_FORMAT_FACTOR / ISP_Q2;
total_bandwidth = total_pix_bandwidth + total_rdi_bandwidth;
-
+ total_streams = num_pix_streams + num_rdi_streams;
+ if (total_streams == 1) {
+ rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id,
+ (total_bandwidth - MSM_ISP_MIN_AB) , (total_bandwidth *
+ ISP_BUS_UTILIZATION_FACTOR / ISP_Q2 - MSM_ISP_MIN_IB));
+ }
+ else {
rc = msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id,
total_bandwidth, total_bandwidth *
ISP_BUS_UTILIZATION_FACTOR / ISP_Q2);
+ }
if (rc < 0)
pr_err("%s: update failed\n", __func__);
@@ -1318,9 +1332,9 @@
if (cur_stream_cnt == 0) {
vfe_dev->ignore_error = 1;
if (camif_update == DISABLE_CAMIF_IMMEDIATELY) {
- vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
+ vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1);
}
- vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, ISP_RST_HARD);
+ vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, ISP_RST_HARD, 1);
vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
vfe_dev->ignore_error = 0;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index 7d282bd..2314300 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -37,6 +37,10 @@
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd);
+void msm_isp_calculate_framedrop(
+ struct msm_vfe_axi_shared_data *axi_data,
+ struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
+
int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg);
int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index cb46e9c..f44f026 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -631,6 +631,33 @@
}
break;
}
+ case VFE_HW_UPDATE_LOCK: {
+ uint32_t update_id =
+ vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id;
+ if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id != *cfg_data
+ || update_id == *cfg_data) {
+ pr_err("hw update lock failed,acquire id %u\n",
+ *cfg_data);
+ pr_err("hw update lock failed,current id %lu\n",
+ vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
+ pr_err("hw update lock failed,last id %u\n",
+ update_id);
+ return -EINVAL;
+ }
+ break;
+ }
+ case VFE_HW_UPDATE_UNLOCK: {
+ if (vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id
+ != *cfg_data) {
+ pr_err("hw update across frame boundary,begin id %u\n",
+ *cfg_data);
+ pr_err("hw update across frame boundary,end id %lu\n",
+ vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
+ vfe_dev->axi_data.src_info[VFE_PIX_0].last_updt_frm_id =
+ vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+ }
+ break;
+ }
case VFE_READ: {
int i;
uint32_t *data_ptr = cfg_data +
@@ -720,7 +747,7 @@
}
for (i = 0; i < proc_cmd->num_cfg; i++)
- msm_isp_send_hw_cmd(vfe_dev, ®_cfg_cmd[i],
+ rc = msm_isp_send_hw_cmd(vfe_dev, ®_cfg_cmd[i],
cfg_data, proc_cmd->cmd_len);
if (copy_to_user(proc_cmd->cfg_data,
@@ -981,6 +1008,125 @@
vfe_dev->error_info.error_count++;
}
+static inline void msm_isp_process_overflow_irq(
+ struct vfe_device *vfe_dev,
+ uint32_t *irq_status0, uint32_t *irq_status1)
+{
+ uint32_t overflow_mask;
+ uint32_t halt_restart_mask0, halt_restart_mask1;
+ /*Mask out all other irqs if recovery is started*/
+ if (atomic_read(&vfe_dev->error_info.overflow_state) !=
+ NO_OVERFLOW) {
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ get_halt_restart_mask(&halt_restart_mask0,
+ &halt_restart_mask1);
+ *irq_status0 &= halt_restart_mask0;
+ *irq_status1 &= halt_restart_mask1;
+ return;
+ }
+
+ /*Check if any overflow bit is set*/
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ get_overflow_mask(&overflow_mask);
+ overflow_mask &= *irq_status1;
+ if (overflow_mask) {
+ pr_warning("%s: Bus overflow detected: 0x%x\n",
+ __func__, overflow_mask);
+ atomic_set(&vfe_dev->error_info.overflow_state,
+ OVERFLOW_DETECTED);
+ pr_warning("%s: Start bus overflow recovery\n", __func__);
+ /*Store current IRQ mask*/
+ vfe_dev->hw_info->vfe_ops.core_ops.get_irq_mask(vfe_dev,
+ &vfe_dev->error_info.overflow_recover_irq_mask0,
+ &vfe_dev->error_info.overflow_recover_irq_mask1);
+ /*Stop CAMIF Immediately*/
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY);
+ /*Halt the hardware & Clear all other IRQ mask*/
+ vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 0);
+ /*Update overflow state*/
+ atomic_set(&vfe_dev->error_info.overflow_state, HALT_REQUESTED);
+ *irq_status0 = 0;
+ *irq_status1 = 0;
+ }
+}
+
+static inline void msm_isp_reset_burst_count(
+ struct vfe_device *vfe_dev)
+{
+ int i;
+ struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+ struct msm_vfe_axi_stream *stream_info;
+ struct msm_vfe_axi_stream_request_cmd framedrop_info;
+ for (i = 0; i < MAX_NUM_STREAM; i++) {
+ stream_info = &axi_data->stream_info[i];
+ if (stream_info->state != ACTIVE)
+ continue;
+ if (stream_info->stream_type == BURST_STREAM &&
+ stream_info->num_burst_capture != 0) {
+ framedrop_info.burst_count =
+ stream_info->num_burst_capture;
+ framedrop_info.frame_skip_pattern =
+ stream_info->frame_skip_pattern;
+ framedrop_info.init_frame_drop = 0;
+ msm_isp_calculate_framedrop(&vfe_dev->axi_data,
+ &framedrop_info);
+ }
+ }
+}
+
+static void msm_isp_process_overflow_recovery(
+ struct vfe_device *vfe_dev,
+ uint32_t irq_status0, uint32_t irq_status1)
+{
+ uint32_t halt_restart_mask0, halt_restart_mask1;
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ get_halt_restart_mask(&halt_restart_mask0,
+ &halt_restart_mask1);
+ irq_status0 &= halt_restart_mask0;
+ irq_status1 &= halt_restart_mask1;
+ if (irq_status0 == 0 && irq_status1 == 0)
+ return;
+
+ switch (atomic_read(&vfe_dev->error_info.overflow_state)) {
+ case HALT_REQUESTED: {
+ pr_err("%s: Halt done, Restart Pending\n", __func__);
+ /*Reset the hardware*/
+ vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev,
+ ISP_RST_SOFT, 0);
+ /*Update overflow state*/
+ atomic_set(&vfe_dev->error_info.overflow_state,
+ RESTART_REQUESTED);
+ }
+ break;
+ case RESTART_REQUESTED: {
+ pr_err("%s: Restart done, Resuming\n", __func__);
+ /*Reset the burst stream frame drop pattern, in the
+ *case where bus overflow happens during the burstshot,
+ *the framedrop pattern might be updated after reg update
+ *to skip all the frames after the burst shot. The burst shot
+ *might not be completed due to the overflow, so the framedrop
+ *pattern need to change back to the original settings in order
+ *to recovr from overflow.
+ */
+ msm_isp_reset_burst_count(vfe_dev);
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ reload_wm(vfe_dev, 0xFFFFFFFF);
+ vfe_dev->hw_info->vfe_ops.core_ops.restore_irq_mask(vfe_dev);
+ vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev);
+ memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
+ atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ update_camif_state(vfe_dev, ENABLE_CAMIF);
+ }
+ break;
+ case NO_OVERFLOW:
+ case OVERFLOW_DETECTED:
+ default:
+ break;
+ }
+}
+
irqreturn_t msm_isp_process_irq(int irq_num, void *data)
{
unsigned long flags;
@@ -991,6 +1137,8 @@
vfe_dev->hw_info->vfe_ops.irq_ops.
read_irq_status(vfe_dev, &irq_status0, &irq_status1);
+ msm_isp_process_overflow_irq(vfe_dev,
+ &irq_status0, &irq_status1);
vfe_dev->hw_info->vfe_ops.core_ops.
get_error_mask(&error_mask0, &error_mask1);
error_mask0 &= irq_status0;
@@ -1055,6 +1203,13 @@
irq_status1 = queue_cmd->vfeInterruptStatus1;
ts = queue_cmd->ts;
spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
+ if (atomic_read(&vfe_dev->error_info.overflow_state) !=
+ NO_OVERFLOW) {
+ pr_err("There is Overflow, kicking up recovery !!!!");
+ msm_isp_process_overflow_recovery(vfe_dev,
+ irq_status0, irq_status1);
+ continue;
+ }
ISP_DBG("%s: status0: 0x%x status1: 0x%x\n",
__func__, irq_status0, irq_status1);
irq_ops->process_reset_irq(vfe_dev,
@@ -1105,7 +1260,10 @@
return -EBUSY;
}
- rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, ISP_RST_HARD);
+ memset(&vfe_dev->error_info, 0, sizeof(vfe_dev->error_info));
+ atomic_set(&vfe_dev->error_info.overflow_state, NO_OVERFLOW);
+ rc = vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev,
+ ISP_RST_HARD, 1);
if (rc <= 0) {
pr_err("%s: reset timeout\n", __func__);
mutex_unlock(&vfe_dev->core_mutex);
@@ -1157,7 +1315,7 @@
return -ENODEV;
}
- rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
+ rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1);
if (rc <= 0)
pr_err("%s: halt timeout rc=%ld\n", __func__, rc);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index d9d65a7..810357e 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1289,7 +1289,7 @@
default:
goto unknown_value;
}
- /* H263 */
+ /* H263 */
case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
switch (value) {
case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
@@ -1382,6 +1382,17 @@
default:
goto unknown_value;
}
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
+ return HAL_H264_DB_MODE_DISABLE;
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
+ return HAL_H264_DB_MODE_ALL_BOUNDARY;
+ case L_MODE:
+ return HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
+ default:
+ goto unknown_value;
+ }
}
unknown_value:
@@ -1990,23 +2001,58 @@
break;
}
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
- property_id =
- HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
- h264_db_control.mode = ctrl->val;
+ {
+ struct v4l2_ctrl *alpha, *beta;
+
+ alpha = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+ beta = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+ property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.slice_alpha_offset = alpha->val;
+ h264_db_control.slice_beta_offset = beta->val;
+ h264_db_control.mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ ctrl->val);
pdata = &h264_db_control;
break;
+ }
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
- property_id =
- HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ {
+ struct v4l2_ctrl *mode, *beta;
+
+ mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+ beta = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+ property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
h264_db_control.slice_alpha_offset = ctrl->val;
+ h264_db_control.slice_beta_offset = beta->val;
+ h264_db_control.mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ mode->val);
pdata = &h264_db_control;
break;
+ }
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
- property_id =
- HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ {
+ struct v4l2_ctrl *mode, *alpha;
+
+ mode = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+ alpha = TRY_GET_CTRL(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+ property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.slice_alpha_offset = alpha->val;
h264_db_control.slice_beta_offset = ctrl->val;
+ h264_db_control.mode = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ mode->val);
pdata = &h264_db_control;
break;
+ }
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
property_id =
HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index dbc7d5c..36bf643 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -698,11 +698,11 @@
struct mmc_context_info *context_info = &host->context_info;
bool pending_is_urgent = false;
bool is_urgent = false;
- int err;
+ int err, ret;
unsigned long flags;
while (1) {
- wait_io_event_interruptible(context_info->wait,
+ ret = wait_io_event_interruptible(context_info->wait,
(context_info->is_done_rcv ||
context_info->is_new_req ||
context_info->is_urgent));
@@ -755,7 +755,7 @@
err = MMC_BLK_NEW_REQUEST;
break; /* return err */
}
- } else {
+ } else if (context_info->is_urgent) {
/*
* The case when block layer sent next urgent
* notification before it receives end_io on
@@ -807,6 +807,11 @@
pending_is_urgent = true;
continue; /* wait for done/new/urgent event */
}
+ } else {
+ pr_warn("%s: mmc thread unblocked from waiting by signal, ret=%d\n",
+ mmc_hostname(host),
+ ret);
+ continue;
}
} /* while */
return err;
@@ -3234,7 +3239,8 @@
mmc_release_host(host);
mmc_rpm_release(host, &host->class_dev);
out:
- if (extend_wakelock)
+ /* only extend the wakelock, if suspend has not started yet */
+ if (extend_wakelock && !host->rescan_disable)
wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
if (host->caps & MMC_CAP_NEEDS_POLL)
@@ -3619,16 +3625,15 @@
spin_unlock_irqrestore(&host->lock, flags);
break;
}
+
+ /* since its suspending anyway, disable rescan */
+ host->rescan_disable = 1;
spin_unlock_irqrestore(&host->lock, flags);
/* Wait for pending detect work to be completed */
if (!(host->caps & MMC_CAP_NEEDS_POLL))
flush_work(&host->detect.work);
- spin_lock_irqsave(&host->lock, flags);
- host->rescan_disable = 1;
- spin_unlock_irqrestore(&host->lock, flags);
-
/*
* In some cases, the detect work might be scheduled
* just before rescan_disable is set to true.
@@ -3636,6 +3641,13 @@
*/
cancel_delayed_work_sync(&host->detect);
+ /*
+ * It is possible that the wake-lock has been acquired, since
+ * its being suspended, release the wakelock
+ */
+ if (wake_lock_active(&host->detect_wake_lock))
+ wake_unlock(&host->detect_wake_lock);
+
if (!host->bus_ops || host->bus_ops->suspend)
break;
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 179632c..783f512 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1399,7 +1399,11 @@
*/
#ifdef CONFIG_MMC_PARANOID_SD_INIT
retries = 5;
- while (retries) {
+ /*
+ * Some bad cards may take a long time to init, give preference to
+ * suspend in those cases.
+ */
+ while (retries && !host->rescan_disable) {
err = mmc_sd_init_card(host, host->ocr, NULL);
if (err) {
retries--;
@@ -1417,6 +1421,9 @@
mmc_hostname(host), err);
goto err;
}
+
+ if (host->rescan_disable)
+ goto err;
#else
err = mmc_sd_init_card(host, host->ocr, NULL);
if (err)
@@ -1440,9 +1447,9 @@
mmc_claim_host(host);
err:
mmc_detach_bus(host);
-
- pr_err("%s: error %d whilst initialising SD card\n",
- mmc_hostname(host), err);
+ if (err)
+ pr_err("%s: error %d whilst initialising SD card: rescan: %d\n",
+ mmc_hostname(host), err, host->rescan_disable);
return err;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index e03d5be..05264b4 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -129,10 +129,10 @@
#define WCNSS_TSTBUS_CTRL_WRFIFO (0x04 << 1)
#define WCNSS_TSTBUS_CTRL_RDFIFO (0x05 << 1)
#define WCNSS_TSTBUS_CTRL_CTRL (0x07 << 1)
-#define WCNSS_TSTBUS_CTRL_AXIM_CFG0 (0x00 << 6)
-#define WCNSS_TSTBUS_CTRL_AXIM_CFG1 (0x01 << 6)
-#define WCNSS_TSTBUS_CTRL_CTRL_CFG0 (0x00 << 12)
-#define WCNSS_TSTBUS_CTRL_CTRL_CFG1 (0x01 << 12)
+#define WCNSS_TSTBUS_CTRL_AXIM_CFG0 (0x00 << 8)
+#define WCNSS_TSTBUS_CTRL_AXIM_CFG1 (0x01 << 8)
+#define WCNSS_TSTBUS_CTRL_CTRL_CFG0 (0x00 << 28)
+#define WCNSS_TSTBUS_CTRL_CTRL_CFG1 (0x01 << 28)
#define MSM_PRONTO_CCPU_BASE 0xfb205050
#define CCU_PRONTO_INVALID_ADDR_OFFSET 0x08
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index b5641b6..c4e5962 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -4074,7 +4074,16 @@
} else {
motg->ext_chg_active = false;
complete(&motg->ext_chg_wait);
- pm_runtime_put(motg->phy.dev);
+ /*
+ * If usb cable is disconnected and then userspace
+ * calls ioctl to unblock low power mode, make sure
+ * otg_sm work for usb disconnect is processed first
+ * followed by decrementing the PM usage counters.
+ */
+ flush_work(&motg->sm_work);
+ pm_runtime_put_noidle(motg->phy.dev);
+ motg->pm_done = 1;
+ pm_runtime_suspend(motg->phy.dev);
}
break;
case MSM_USB_EXT_CHG_VOLTAGE_INFO:
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index dd8eec5..40a458c 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -1518,6 +1518,8 @@
if (!gpio_is_valid(ctrl_pdata->mode_gpio))
pr_info("%s:%d, mode gpio not specified\n",
__func__, __LINE__);
+ } else {
+ ctrl_pdata->mode_gpio = -EINVAL;
}
if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 1e17205..33a0806 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -298,6 +298,7 @@
u32 hist_cnt_time;
u32 frame_cnt;
struct completion comp;
+ struct completion first_kick;
u32 data[HIST_V_SIZE];
struct mutex hist_mutex;
spinlock_t hist_lock;
@@ -688,7 +689,7 @@
int mdss_mdp_data_check(struct mdss_mdp_data *data,
struct mdss_mdp_plane_sizes *ps);
int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
- struct mdss_mdp_plane_sizes *ps, u32 bwc_mode);
+ struct mdss_mdp_plane_sizes *ps, u32 bwc_mode, bool rotation);
int mdss_mdp_get_rau_strides(u32 w, u32 h, struct mdss_mdp_format_params *fmt,
struct mdss_mdp_plane_sizes *ps);
void mdss_mdp_data_calc_offset(struct mdss_mdp_data *data, u16 x, u16 y,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 27a7707..02e7b75 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 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
@@ -131,13 +131,17 @@
struct mdss_mdp_format_params *fmt;
u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
u32 opmode = ctx->opmode;
+ bool rotation = false;
struct mdss_data_type *mdata;
pr_debug("wb_num=%d format=%d\n", ctx->wb_num, format);
+ if (ctx->rot90)
+ rotation = true;
+
mdss_mdp_get_plane_sizes(format, ctx->width, ctx->height,
&ctx->dst_planes,
- ctx->opmode & MDSS_MDP_OP_BWC_EN);
+ ctx->opmode & MDSS_MDP_OP_BWC_EN, rotation);
fmt = mdss_mdp_get_format_params(format);
if (!fmt) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index b76d62c..faa60fe 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1251,8 +1251,8 @@
}
}
- if (cnt == 0 && !list_empty(&mdp5_data->pipes_cleanup)) {
- pr_debug("overlay release on fb%d called without commit!",
+ if (!mfd->ref_cnt && !list_empty(&mdp5_data->pipes_cleanup)) {
+ pr_debug("fb%d:: free pipes present in cleanup list",
mfd->index);
cnt++;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index c522857..32b8cbf 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -270,7 +270,7 @@
}
}
rc = mdss_mdp_get_plane_sizes(format, width, pipe->src.h,
- &ps, 0);
+ &ps, 0, 0);
if (rc)
return rc;
@@ -883,6 +883,7 @@
u32 decimation;
struct mdss_mdp_img_rect sci, dst, src;
int ret = 0;
+ bool rotation = false;
pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
pipe->num, pipe->img_width, pipe->img_height,
@@ -891,8 +892,12 @@
width = pipe->img_width;
height = pipe->img_height;
+
+ if (pipe->flags & MDP_SOURCE_ROTATED_90)
+ rotation = true;
+
mdss_mdp_get_plane_sizes(pipe->src_fmt->format, width, height,
- &pipe->src_planes, pipe->bwc_mode);
+ &pipe->src_planes, pipe->bwc_mode, rotation);
if (data != NULL) {
ret = mdss_mdp_data_check(data, &pipe->src_planes);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 6b497bb..0c6eb2a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -81,6 +81,8 @@
#define MDSS_BLOCK_DISP_NUM (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0)
#define HIST_WAIT_TIMEOUT(frame) ((75 * HZ * (frame)) / 1000)
+#define HIST_KICKOFF_WAIT_FRACTION 4
+
/* hist collect state */
enum {
HIST_UNKNOWN,
@@ -1351,6 +1353,7 @@
/* Kick off collection */
writel_relaxed(1, base + kick_base);
hist_info->col_state = HIST_START;
+ complete(&hist_info->first_kick);
}
}
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
@@ -1788,6 +1791,8 @@
&mdss_pp_res->dspp_hist[i].hist_lock);
init_completion(
&mdss_pp_res->dspp_hist[i].comp);
+ init_completion(
+ &mdss_pp_res->dspp_hist[i].first_kick);
}
}
}
@@ -1797,6 +1802,7 @@
mutex_init(&vig[i].pp_res.hist.hist_mutex);
spin_lock_init(&vig[i].pp_res.hist.hist_lock);
init_completion(&vig[i].pp_res.hist.comp);
+ init_completion(&vig[i].pp_res.hist.first_kick);
}
if (!mdata->pp_bus_hdl) {
pp_bus_pdata = &mdp_pp_bus_scale_table;
@@ -3006,6 +3012,7 @@
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
hist_info->frame_cnt = req->frame_cnt;
INIT_COMPLETION(hist_info->comp);
+ INIT_COMPLETION(hist_info->first_kick);
hist_info->hist_cnt_read = 0;
hist_info->hist_cnt_sent = 0;
hist_info->hist_cnt_time = 0;
@@ -3131,6 +3138,7 @@
spin_unlock_irqrestore(&hist_info->hist_lock, flag);
mdss_mdp_hist_intr_req(&mdata->hist_intr, done_bit, false);
complete_all(&hist_info->comp);
+ complete_all(&hist_info->first_kick);
writel_relaxed(BIT(1), ctl_base);/* cancel */
ret = 0;
exit:
@@ -3363,7 +3371,7 @@
struct pp_hist_col_info *hist_info,
char __iomem *ctl_base, u32 expect_sum)
{
- int wait_ret, ret = 0;
+ int kick_ret, wait_ret, ret = 0;
u32 timeout, sum;
char __iomem *v_base;
unsigned long flag;
@@ -3389,12 +3397,26 @@
pipe = container_of(res, struct mdss_mdp_pipe, pp_res);
pipe->params_changed++;
}
- wait_ret = wait_for_completion_killable_timeout(
+ kick_ret = wait_for_completion_killable_timeout(
+ &(hist_info->first_kick), timeout /
+ HIST_KICKOFF_WAIT_FRACTION);
+ if (kick_ret != 0)
+ wait_ret = wait_for_completion_killable_timeout(
&(hist_info->comp), timeout);
mutex_lock(&hist_info->hist_mutex);
spin_lock_irqsave(&hist_info->hist_lock, flag);
- if (wait_ret == 0) {
+ if (kick_ret == 0) {
+ ret = -ENODATA;
+ pr_debug("histogram kickoff not done yet");
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+ goto hist_collect_exit;
+ } else if (kick_ret < 0) {
+ ret = -EINTR;
+ pr_debug("histogram first kickoff interrupted");
+ spin_unlock_irqrestore(&hist_info->hist_lock, flag);
+ goto hist_collect_exit;
+ } else if (wait_ret == 0) {
ret = -ETIMEDOUT;
pr_debug("bin collection timedout, state %d",
hist_info->col_state);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 69506d4..9336582 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -320,7 +320,7 @@
}
int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
- struct mdss_mdp_plane_sizes *ps, u32 bwc_mode)
+ struct mdss_mdp_plane_sizes *ps, u32 bwc_mode, bool rotation)
{
struct mdss_mdp_format_params *fmt;
int i, rc;
@@ -374,9 +374,19 @@
u8 hmap[] = { 1, 2, 1, 2 };
u8 vmap[] = { 1, 1, 2, 2 };
u8 horiz, vert, stride_align, height_align;
+ u32 chroma_samp;
- horiz = hmap[fmt->chroma_sample];
- vert = vmap[fmt->chroma_sample];
+ chroma_samp = fmt->chroma_sample;
+
+ if (rotation) {
+ if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
+ chroma_samp = MDSS_MDP_CHROMA_H1V2;
+ else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
+ chroma_samp = MDSS_MDP_CHROMA_H2V1;
+ }
+
+ horiz = hmap[chroma_samp];
+ vert = vmap[chroma_samp];
switch (format) {
case MDP_Y_CR_CB_GH2V2:
diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h
index 18513e3..74f6714 100644
--- a/include/linux/dma-attrs.h
+++ b/include/linux/dma-attrs.h
@@ -17,6 +17,7 @@
DMA_ATTR_NON_CONSISTENT,
DMA_ATTR_NO_KERNEL_MAPPING,
DMA_ATTR_STRONGLY_ORDERED,
+ DMA_ATTR_SKIP_ZEROING,
DMA_ATTR_MAX,
};
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 3828221..30e7d06 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -240,6 +240,8 @@
VFE_READ_DMI_64BIT,
GET_SOC_HW_VER,
GET_MAX_CLK_RATE,
+ VFE_HW_UPDATE_LOCK,
+ VFE_HW_UPDATE_UNLOCK,
};
struct msm_vfe_cfg_cmd2 {
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 2a89d01..61d82fb 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -374,7 +374,7 @@
#endif
}
-static int unix_release_sock(struct sock *sk, int embrion)
+static void unix_release_sock(struct sock *sk, int embrion)
{
struct unix_sock *u = unix_sk(sk);
struct path path;
@@ -443,8 +443,6 @@
if (unix_tot_inflight)
unix_gc(); /* Garbage collect fds */
-
- return 0;
}
static void init_peercred(struct sock *sk)
@@ -694,9 +692,10 @@
if (!sk)
return 0;
+ unix_release_sock(sk, 0);
sock->sk = NULL;
- return unix_release_sock(sk, 0);
+ return 0;
}
static int unix_autobind(struct socket *sock)
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 8aa1e35..23ed60a 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2413,6 +2413,21 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
},
+ {
+ .name = "VoWLAN",
+ .stream_name = "VoWLAN",
+ .cpu_dai_name = "VoWLAN",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOWLAN,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 08448fe..b49ce46 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -31,6 +31,7 @@
#include <linux/msm_audio_ion.h>
#include <linux/of_device.h>
+#include <sound/tlv.h>
#include <sound/pcm_params.h>
#include "msm-pcm-q6-v2.h"
@@ -38,6 +39,10 @@
static struct audio_locks the_locks;
+#define PCM_MASTER_VOL_MAX_STEPS 0x2000
+static const DECLARE_TLV_DB_LINEAR(msm_pcm_vol_gain, 0,
+ PCM_MASTER_VOL_MAX_STEPS);
+
struct snd_msm {
struct snd_card *card;
struct snd_pcm *pcm;
@@ -819,6 +824,94 @@
.mmap = msm_pcm_mmap,
};
+static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
+{
+ int rc = 0;
+
+ if (prtd && prtd->audio_client) {
+ pr_debug("%s: channels %d volume 0x%x\n", __func__,
+ prtd->channel_mode, volume);
+ rc = q6asm_set_volume(prtd->audio_client, volume);
+ if (rc < 0) {
+ pr_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
+ }
+ }
+ return rc;
+}
+
+static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+
+ pr_debug("%s\n", __func__);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ ucontrol->value.integer.value[0] = prtd->volume;
+ return 0;
+}
+
+static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream =
+ vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct msm_audio *prtd;
+ int volume = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: volume : 0x%x\n", __func__, volume);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ rc = msm_pcm_set_volume(prtd, volume);
+ prtd->volume = volume;
+ }
+ return rc;
+}
+
+static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret = 0;
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_volume *volume_info;
+ struct snd_kcontrol *kctl;
+
+ dev_dbg(rtd->dev, "%s, Volume control add\n", __func__);
+ ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, rtd->dai_link->be_id,
+ &volume_info);
+ if (ret < 0) {
+ pr_err("%s volume control failed ret %d\n", __func__, ret);
+ return ret;
+ }
+ kctl = volume_info->kctl;
+ kctl->put = msm_pcm_volume_ctl_put;
+ kctl->get = msm_pcm_volume_ctl_get;
+ kctl->tlv.p = msm_pcm_vol_gain;
+ return 0;
+}
+
static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -905,6 +998,10 @@
__func__, kctl->id.name);
kctl->put = msm_pcm_chmap_ctl_put;
kctl->get = msm_pcm_chmap_ctl_get;
+ ret = msm_pcm_add_volume_control(rtd);
+ if (ret)
+ pr_err("%s: Could not add pcm Volume Control %d\n",
+ __func__, ret);
return ret;
}