Merge "msm: ipa: fix hdr table full condition"
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 3a09b28..d268032 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -347,6 +347,8 @@
- clocks: phandle reference to the parent
clock.
+ - qcom,mclk-clk-reg: Indicate the register address for mclk.
+
* audio_slimslave
Required properties:
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 958194b..4901fa0 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -70,6 +70,7 @@
2: 38.4 MHz
3: 52 MHz
Defaults to 26 MHz if not specified.
+- extcon: phandle to external connector (Refer Documentation/devicetree/bindings/extcon/extcon-gpio.txt for more details).
Note: If above properties are not defined it can be assumed that the supply
regulators or clocks are always on.
diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
index d060641..9edea10 100644
--- a/arch/arm/include/asm/topology.h
+++ b/arch/arm/include/asm/topology.h
@@ -24,6 +24,7 @@
void init_cpu_topology(void);
void store_cpu_topology(unsigned int cpuid);
const struct cpumask *cpu_coregroup_mask(int cpu);
+unsigned long arch_get_cpu_efficiency(int cpu);
#ifdef CONFIG_CPU_FREQ
#define arch_scale_freq_capacity cpufreq_scale_freq_capacity
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index bd884da..2b6c530 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -196,6 +196,14 @@
return 0;
}
+static DEFINE_PER_CPU(unsigned long, cpu_efficiency) = SCHED_CAPACITY_SCALE;
+
+unsigned long arch_get_cpu_efficiency(int cpu)
+{
+ return per_cpu(cpu_efficiency, cpu);
+}
+EXPORT_SYMBOL(arch_get_cpu_efficiency);
+
#ifdef CONFIG_OF
struct cpu_efficiency {
const char *compatible;
@@ -272,6 +280,7 @@
for_each_possible_cpu(cpu) {
const u32 *rate;
int len;
+ u32 efficiency;
/* too early to use cpu->of_node */
cn = of_get_cpu_node(cpu, NULL);
@@ -280,12 +289,26 @@
continue;
}
- for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++)
- if (of_device_is_compatible(cn, cpu_eff->compatible))
- break;
+ /*
+ * The CPU efficiency value passed from the device tree
+ * overrides the value defined in the table_efficiency[]
+ */
+ if (of_property_read_u32(cn, "efficiency", &efficiency) < 0) {
- if (cpu_eff->compatible == NULL)
- continue;
+ for (cpu_eff = table_efficiency;
+ cpu_eff->compatible; cpu_eff++)
+
+ if (of_device_is_compatible(cn,
+ cpu_eff->compatible))
+ break;
+
+ if (cpu_eff->compatible == NULL)
+ continue;
+
+ efficiency = cpu_eff->efficiency;
+ }
+
+ per_cpu(cpu_efficiency, cpu) = efficiency;
rate = of_get_property(cn, "clock-frequency", &len);
if (!rate || len != 4) {
@@ -294,7 +317,7 @@
continue;
}
- capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency;
+ capacity = ((be32_to_cpup(rate)) >> 20) * efficiency;
/* Save min capacity of the system */
if (capacity < min_capacity)
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 7bef48d..5969c1d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -412,6 +412,11 @@
clock-frequency = <19200000>;
};
+ qcom,sps {
+ compatible = "qcom,msm_sps_4k";
+ qcom,pipe-attr-ee;
+ };
+
timer@0x17c90000{
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 885234f..91b8738 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -343,17 +343,17 @@
clock-names = "gcc_ahb_clk",
"gcc_axi_clk",
"soc_ahb_clk",
- "cpas_ahb_clk",
"slow_ahb_clk_src",
+ "cpas_ahb_clk",
"camnoc_axi_clk";
clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
<&clock_gcc GCC_CAMERA_AXI_CLK>,
<&clock_camcc CAM_CC_SOC_AHB_CLK>,
- <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+ <&clock_camcc CAM_CC_CPAS_AHB_CLK>,
<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>;
src-clock-name = "slow_ahb_clk_src";
- clock-rates = <0 0 0 0 80000000 0>;
+ clock-rates = <0 0 0 80000000 0 0>;
qcom,msm-bus,name = "cam_ahb";
qcom,msm-bus,num-cases = <4>;
qcom,msm-bus,num-paths = <1>;
@@ -772,6 +772,7 @@
camss-vdd-supply = <&titan_top_gdsc>;
clock-names = "gcc_cam_ahb_clk",
"gcc_cam_axi_clk",
+ "soc_fast_ahb",
"soc_ahb_clk",
"cpas_ahb_clk",
"camnoc_axi_clk",
@@ -780,6 +781,7 @@
"icp_clk_src";
clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
<&clock_gcc GCC_CAMERA_AXI_CLK>,
+ <&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>,
<&clock_camcc CAM_CC_SOC_AHB_CLK>,
<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
@@ -787,7 +789,7 @@
<&clock_camcc CAM_CC_ICP_CLK>,
<&clock_camcc CAM_CC_ICP_CLK_SRC>;
- clock-rates = <0 0 0 80000000 0 0 0 600000000>;
+ clock-rates = <0 0 400000000 0 0 0 0 0 600000000>;
fw_name = "CAMERA_ICP.elf";
status = "ok";
};
@@ -808,7 +810,7 @@
<&clock_camcc CAM_CC_IPE_0_CLK>,
<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
- clock-rates = <80000000 400000000 0 0 600000000>;
+ clock-rates = <0 0 0 0 600000000>;
status = "ok";
};
@@ -828,7 +830,7 @@
<&clock_camcc CAM_CC_IPE_1_CLK>,
<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
- clock-rates = <80000000 400000000 0 0 600000000>;
+ clock-rates = <0 0 0 0 600000000>;
status = "ok";
};
@@ -848,7 +850,7 @@
<&clock_camcc CAM_CC_BPS_CLK>,
<&clock_camcc CAM_CC_BPS_CLK_SRC>;
- clock-rates = <80000000 400000000 0 0 600000000>;
+ clock-rates = <0 0 0 0 600000000>;
status = "ok";
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 5e370d6..8ace432 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -155,6 +155,8 @@
qcom,vddp-ref-clk-supply = <&pm8998_l2>;
qcom,vddp-ref-clk-max-microamp = <100>;
+ extcon = <&extcon_storage_cd>;
+
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index e5ea108..1ce68e1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -278,7 +278,7 @@
qcom,gmu-pwrlevel@1 {
reg = <1>;
- qcom,gmu-freq = <19200000>;
+ qcom,gmu-freq = <200000000>;
};
qcom,gmu-pwrlevel@2 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index dc3f14f..ab266ef 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -221,6 +221,8 @@
qcom,vddp-ref-clk-supply = <&pm8998_l2>;
qcom,vddp-ref-clk-max-microamp = <100>;
+ extcon = <&extcon_storage_cd>;
+
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 8ed3edb..c2fbed5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -201,6 +201,8 @@
qcom,vddp-ref-clk-supply = <&pm8998_l2>;
qcom,vddp-ref-clk-max-microamp = <100>;
+ extcon = <&extcon_storage_cd>;
+
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 2a29283..08c7cf0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -86,8 +86,6 @@
qcom,sde-dither-version = <0x00010000>;
qcom,sde-dither-size = <0x20>;
- qcom,sde-intf-max-prefetch-lines = <0x15 0x15 0x15 0x15>;
-
qcom,sde-sspp-type = "vig", "vig", "vig", "vig",
"dma", "dma", "dma", "dma";
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 0c69886..fd79016 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -172,8 +172,7 @@
sde_cstate = to_sde_crtc_state(state);
- /* swap state and obtain new values */
- sde_cstate->cur_perf = sde_cstate->new_perf;
+ /* obtain new values */
_sde_core_perf_calc_crtc(kms, crtc, state, &sde_cstate->new_perf);
bw_sum_of_intfs = sde_cstate->new_perf.bw_ctl;
@@ -204,11 +203,9 @@
if (!sde_cstate->bw_control) {
SDE_DEBUG("bypass bandwidth check\n");
} else if (!threshold) {
- sde_cstate->new_perf = sde_cstate->cur_perf;
SDE_ERROR("no bandwidth limits specified\n");
return -E2BIG;
} else if (bw > threshold) {
- sde_cstate->new_perf = sde_cstate->cur_perf;
SDE_ERROR("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
return -E2BIG;
}
@@ -347,6 +344,7 @@
void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc)
{
struct drm_crtc *tmp_crtc;
+ struct sde_crtc *sde_crtc;
struct sde_crtc_state *sde_cstate;
struct sde_kms *kms;
@@ -361,6 +359,7 @@
return;
}
+ sde_crtc = to_sde_crtc(crtc);
sde_cstate = to_sde_crtc_state(crtc->state);
/* only do this for command mode rt client (non-rsc client) */
@@ -383,8 +382,7 @@
/* Release the bandwidth */
if (kms->perf.enable_bw_release) {
trace_sde_cmd_release_bw(crtc->base.id);
- sde_cstate->cur_perf.bw_ctl = 0;
- sde_cstate->new_perf.bw_ctl = 0;
+ sde_crtc->cur_perf.bw_ctl = 0;
SDE_DEBUG("Release BW crtc=%d\n", crtc->base.id);
_sde_core_perf_crtc_update_bus(kms, crtc);
}
@@ -447,7 +445,7 @@
SDE_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n",
crtc->base.id, stop_req, kms->perf.core_clk_rate);
- old = &sde_cstate->cur_perf;
+ old = &sde_crtc->cur_perf;
new = &sde_cstate->new_perf;
if (_sde_core_perf_crtc_is_power_on(crtc) && !stop_req) {
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index e13bcc9..075864b 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -3422,16 +3422,18 @@
static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v)
{
struct drm_crtc *crtc = (struct drm_crtc *) s->private;
+ struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state);
struct sde_crtc_res *res;
seq_printf(s, "num_connectors: %d\n", cstate->num_connectors);
seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc));
seq_printf(s, "intf_mode: %d\n", sde_crtc_get_intf_mode(crtc));
- seq_printf(s, "bw_ctl: %llu\n", cstate->cur_perf.bw_ctl);
- seq_printf(s, "core_clk_rate: %llu\n", cstate->cur_perf.core_clk_rate);
+ seq_printf(s, "bw_ctl: %llu\n", sde_crtc->cur_perf.bw_ctl);
+ seq_printf(s, "core_clk_rate: %llu\n",
+ sde_crtc->cur_perf.core_clk_rate);
seq_printf(s, "max_per_pipe_ib: %llu\n",
- cstate->cur_perf.max_per_pipe_ib);
+ sde_crtc->cur_perf.max_per_pipe_ib);
seq_printf(s, "rp.%d: ", cstate->rp.sequence_id);
list_for_each_entry(res, &cstate->rp.res_list, list)
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 69a9270..a622d9c 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -141,6 +141,7 @@
* @event_lock : Spinlock around event handling code
* @misr_enable : boolean entry indicates misr enable/disable status.
* @power_event : registered power event handle
+ * @cur_perf : current performance committed to clock/bandwidth driver
*/
struct sde_crtc {
struct drm_crtc base;
@@ -193,6 +194,8 @@
bool misr_enable;
struct sde_power_event *power_event;
+
+ struct sde_core_perf_params cur_perf;
};
#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
@@ -268,8 +271,7 @@
* @property_blobs: Reference pointers for blob properties
* @num_dim_layers: Number of dim layers
* @dim_layer: Dim layer configs
- * @cur_perf: current performance state
- * @new_perf: new performance state
+ * @new_perf: new performance state being requested
* @sbuf_cfg: stream buffer configuration
* @sbuf_prefill_line: number of line for inline rotator prefetch
* @sbuf_flush_mask: flush mask for inline rotator
@@ -296,7 +298,6 @@
uint32_t num_dim_layers;
struct sde_hw_dim_layer dim_layer[SDE_MAX_DIM_LAYERS];
- struct sde_core_perf_params cur_perf;
struct sde_core_perf_params new_perf;
struct sde_ctl_sbuf_cfg sbuf_cfg;
u32 sbuf_prefill_line;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 306bb86..eb62716 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -1407,6 +1407,8 @@
intf->len = DEFAULT_SDE_HW_BLOCK_LEN;
intf->prog_fetch_lines_worst_case =
+ !prop_exists[INTF_PREFETCH] ?
+ sde_cfg->perf.min_prefill_lines :
PROP_VALUE_ACCESS(prop_value, INTF_PREFETCH, i);
of_property_read_string_index(np,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
index ad2910e..304106d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
@@ -15,6 +15,7 @@
#include "sde_hw_catalog.h"
#include "sde_hw_cdm.h"
#include "sde_dbg.h"
+#include "sde_kms.h"
#define CDM_CSC_10_OPMODE 0x000
#define CDM_CSC_10_BASE 0x004
@@ -267,6 +268,11 @@
ops->disable = sde_hw_cdm_disable;
}
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx,
void __iomem *addr,
struct sde_mdss_cfg *m,
@@ -274,6 +280,7 @@
{
struct sde_hw_cdm *c;
struct sde_cdm_cfg *cfg;
+ int rc;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
@@ -286,12 +293,19 @@
}
c->idx = idx;
- c->cdm_hw_cap = cfg;
- _setup_cdm_ops(&c->ops, c->cdm_hw_cap->features);
+ c->caps = cfg;
+ _setup_cdm_ops(&c->ops, c->caps->features);
c->hw_mdp = hw_mdp;
+ rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_CDM, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
+
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
/*
* Perform any default initialization for the chroma down module
* @setup default csc coefficients
@@ -299,9 +313,16 @@
sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg);
return c;
+
+blk_init_error:
+ kzfree(c);
+
+ return ERR_PTR(rc);
}
void sde_hw_cdm_destroy(struct sde_hw_cdm *cdm)
{
+ if (cdm)
+ sde_hw_blk_destroy(&cdm->base);
kfree(cdm);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.h b/drivers/gpu/drm/msm/sde/sde_hw_cdm.h
index a0afd89..2b3683d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.h
@@ -15,6 +15,7 @@
#include "sde_hw_mdss.h"
#include "sde_hw_top.h"
+#include "sde_hw_blk.h"
struct sde_hw_cdm;
@@ -92,11 +93,11 @@
};
struct sde_hw_cdm {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
/* chroma down */
- const struct sde_cdm_cfg *cdm_hw_cap;
+ const struct sde_cdm_cfg *caps;
enum sde_cdm idx;
/* mdp top hw driver */
@@ -107,6 +108,16 @@
};
/**
+ * sde_hw_cdm - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_cdm *to_sde_hw_cdm(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_cdm, base);
+}
+
+/**
* sde_hw_cdm_init - initializes the cdm hw driver object.
* should be called once before accessing every cdm.
* @idx: cdm index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index a62aa6e..b71864c 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -14,6 +14,7 @@
#include "sde_hwio.h"
#include "sde_hw_ctl.h"
#include "sde_dbg.h"
+#include "sde_kms.h"
#define CTL_LAYER(lm) \
(((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004))
@@ -562,12 +563,18 @@
}
};
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx,
void __iomem *addr,
struct sde_mdss_cfg *m)
{
struct sde_hw_ctl *c;
struct sde_ctl_cfg *cfg;
+ int rc;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
@@ -586,13 +593,26 @@
c->mixer_count = m->mixer_count;
c->mixer_hw_caps = m->mixer;
+ rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_CTL, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
+
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
c->hw.blk_off + c->hw.length, c->hw.xin_id);
return c;
+
+blk_init_error:
+ kzfree(c);
+
+ return ERR_PTR(rc);
}
void sde_hw_ctl_destroy(struct sde_hw_ctl *ctx)
{
+ if (ctx)
+ sde_hw_blk_destroy(&ctx->base);
kfree(ctx);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index ace05e8..59047d0 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -17,6 +17,7 @@
#include "sde_hw_util.h"
#include "sde_hw_catalog.h"
#include "sde_hw_sspp.h"
+#include "sde_hw_blk.h"
/**
* sde_ctl_mode_sel: Interface mode selection
@@ -209,16 +210,17 @@
/**
* struct sde_hw_ctl : CTL PATH driver object
+ * @base: hardware block base structure
* @hw: block register map object
* @idx: control path index
- * @ctl_hw_caps: control path capabilities
+ * @caps: control path capabilities
* @mixer_count: number of mixers
* @mixer_hw_caps: mixer hardware capabilities
* @pending_flush_mask: storage for pending ctl_flush managed via ops
* @ops: operation list
*/
struct sde_hw_ctl {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
/* ctl path */
@@ -233,6 +235,16 @@
};
/**
+ * sde_hw_ctl - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_ctl *to_sde_hw_ctl(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_ctl, base);
+}
+
+/**
* sde_hw_ctl_init(): Initializes the ctl_path hw driver object.
* should be called before accessing every ctl path registers.
* @idx: ctl_path index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c
index 62193f9..1a346f0 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c
@@ -16,6 +16,7 @@
#include "sde_hw_dsc.h"
#include "sde_hw_pingpong.h"
#include "sde_dbg.h"
+#include "sde_kms.h"
#define DSC_COMMON_MODE 0x000
#define DSC_ENC 0X004
@@ -200,12 +201,18 @@
ops->dsc_config_thresh = sde_hw_dsc_config_thresh;
};
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_dsc *sde_hw_dsc_init(enum sde_dsc idx,
void __iomem *addr,
struct sde_mdss_cfg *m)
{
struct sde_hw_dsc *c;
struct sde_dsc_cfg *cfg;
+ int rc;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
@@ -218,16 +225,29 @@
}
c->idx = idx;
- c->dsc_hw_cap = cfg;
- _setup_dsc_ops(&c->ops, c->dsc_hw_cap->features);
+ c->caps = cfg;
+ _setup_dsc_ops(&c->ops, c->caps->features);
+
+ rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_DSC, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
c->hw.blk_off + c->hw.length, c->hw.xin_id);
return c;
+
+blk_init_error:
+ kzfree(c);
+
+ return ERR_PTR(rc);
}
void sde_hw_dsc_destroy(struct sde_hw_dsc *dsc)
{
+ if (dsc)
+ sde_hw_blk_destroy(&dsc->base);
kfree(dsc);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dsc.h b/drivers/gpu/drm/msm/sde/sde_hw_dsc.h
index 0703531..d1678f4 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dsc.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dsc.h
@@ -13,6 +13,11 @@
#ifndef _SDE_HW_DSC_H
#define _SDE_HW_DSC_H
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+#include "sde_hw_util.h"
+#include "sde_hw_blk.h"
+
struct sde_hw_dsc;
struct msm_display_dsc_info;
@@ -52,18 +57,28 @@
};
struct sde_hw_dsc {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
/* dsc */
enum sde_dsc idx;
- const struct sde_dsc_cfg *dsc_hw_cap;
+ const struct sde_dsc_cfg *caps;
/* ops */
struct sde_hw_dsc_ops ops;
};
/**
+ * sde_hw_dsc - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_dsc *to_sde_hw_dsc(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_dsc, base);
+}
+
+/**
* sde_hw_dsc_init - initializes the dsc block for the passed
* dsc idx.
* @idx: DSC index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index 586d1f1..e766cdb 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -17,6 +17,7 @@
#include "sde_hw_color_processing.h"
#include "sde_dbg.h"
#include "sde_ad4.h"
+#include "sde_kms.h"
static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
struct sde_mdss_cfg *m,
@@ -118,12 +119,18 @@
}
}
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
void __iomem *addr,
struct sde_mdss_cfg *m)
{
struct sde_hw_dspp *c;
struct sde_dspp_cfg *cfg;
+ int rc;
if (!addr || !m)
return ERR_PTR(-EINVAL);
@@ -143,15 +150,28 @@
c->cap = cfg;
_setup_dspp_ops(c, c->cap->features);
+ rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_DSPP, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
+
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
c->hw.blk_off + c->hw.length, c->hw.xin_id);
return c;
+
+blk_init_error:
+ kzfree(c);
+
+ return ERR_PTR(rc);
}
void sde_hw_dspp_destroy(struct sde_hw_dspp *dspp)
{
- if (dspp)
+ if (dspp) {
reg_dmav1_deinit_dspp_ops(dspp->idx);
+ sde_hw_blk_destroy(&dspp->base);
+ }
kfree(dspp);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
index 70b3e56..0baa970 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
@@ -13,6 +13,8 @@
#ifndef _SDE_HW_DSPP_H
#define _SDE_HW_DSPP_H
+#include "sde_hw_blk.h"
+
struct sde_hw_dspp;
/**
@@ -166,17 +168,14 @@
/**
* struct sde_hw_dspp - dspp description
- * @base_off: MDP register mapped offset
- * @blk_off: DSPP offset relative to mdss offset
- * @length Length of register block offset
- * @hwversion Mdss hw version number
- * @idx: DSPP index
- * @dspp_hw_cap: Pointer to layer_cfg
- * @highest_bank_bit:
- * @ops: Pointer to operations possible for this dspp
+ * @base: Hardware block base structure
+ * @hw: Block hardware details
+ * @idx: DSPP index
+ * @cap: Pointer to layer_cfg
+ * @ops: Pointer to operations possible for this DSPP
*/
struct sde_hw_dspp {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
/* dspp */
@@ -188,6 +187,16 @@
};
/**
+ * sde_hw_dspp - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_dspp *to_sde_hw_dspp(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_dspp, base);
+}
+
+/**
* sde_hw_dspp_init - initializes the dspp hw driver object.
* should be called once before accessing every dspp.
* @idx: DSPP index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index be83afe..35f1800 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -14,6 +14,7 @@
#include "sde_hw_catalog.h"
#include "sde_hw_intf.h"
#include "sde_dbg.h"
+#include "sde_kms.h"
#define INTF_TIMING_ENGINE_EN 0x000
#define INTF_CONFIG 0x004
@@ -301,12 +302,18 @@
ops->setup_rot_start = sde_hw_intf_setup_rot_start;
}
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx,
void __iomem *addr,
struct sde_mdss_cfg *m)
{
struct sde_hw_intf *c;
struct sde_intf_cfg *cfg;
+ int rc;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
@@ -327,14 +334,27 @@
c->mdss = m;
_setup_intf_ops(&c->ops, c->cap->features);
+ rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_INTF, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
+
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
c->hw.blk_off + c->hw.length, c->hw.xin_id);
return c;
+
+blk_init_error:
+ kzfree(c);
+
+ return ERR_PTR(rc);
}
void sde_hw_intf_destroy(struct sde_hw_intf *intf)
{
+ if (intf)
+ sde_hw_blk_destroy(&intf->base);
kfree(intf);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.h b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
index d24e83a..83e206d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
@@ -16,6 +16,7 @@
#include "sde_hw_catalog.h"
#include "sde_hw_mdss.h"
#include "sde_hw_util.h"
+#include "sde_hw_blk.h"
struct sde_hw_intf;
@@ -86,7 +87,7 @@
};
struct sde_hw_intf {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
/* intf */
@@ -99,6 +100,16 @@
};
/**
+ * to_sde_hw_intf - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_intf *to_sde_hw_intf(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_intf, base);
+}
+
+/**
* sde_hw_intf_init(): Initializes the intf driver for the passed
* interface idx.
* @idx: interface index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index fedc72c..3d282ee 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -16,6 +16,7 @@
#include "sde_hw_lm.h"
#include "sde_hw_mdss.h"
#include "sde_dbg.h"
+#include "sde_kms.h"
#define LM_OP_MODE 0x00
#define LM_OUT_SIZE 0x04
@@ -277,12 +278,18 @@
}
};
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx,
void __iomem *addr,
struct sde_mdss_cfg *m)
{
struct sde_hw_mixer *c;
struct sde_lm_cfg *cfg;
+ int rc;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
@@ -299,13 +306,26 @@
c->cap = cfg;
_setup_mixer_ops(m, &c->ops, c->cap->features);
+ rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_LM, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
+
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
c->hw.blk_off + c->hw.length, c->hw.xin_id);
return c;
+
+blk_init_error:
+ kzfree(c);
+
+ return ERR_PTR(rc);
}
void sde_hw_lm_destroy(struct sde_hw_mixer *lm)
{
+ if (lm)
+ sde_hw_blk_destroy(&lm->base);
kfree(lm);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.h b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
index 45c0fc9..8a146bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
@@ -15,6 +15,7 @@
#include "sde_hw_mdss.h"
#include "sde_hw_util.h"
+#include "sde_hw_blk.h"
struct sde_hw_mixer;
@@ -89,7 +90,7 @@
};
struct sde_hw_mixer {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
/* lm */
@@ -106,6 +107,16 @@
};
/**
+ * to_sde_hw_mixer - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_mixer *to_sde_hw_mixer(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_mixer, base);
+}
+
+/**
* sde_hw_lm_init(): Initializes the mixer hw driver object.
* should be called once before accessing every mixer.
* @idx: mixer index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index a77b8d3..a1bd6ce 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -15,6 +15,7 @@
#include "sde_hw_catalog.h"
#include "sde_hw_pingpong.h"
#include "sde_dbg.h"
+#include "sde_kms.h"
#define PP_TEAR_CHECK_EN 0x000
#define PP_SYNC_CONFIG_VSYNC 0x004
@@ -162,12 +163,18 @@
ops->disable_dsc = sde_hw_pp_dsc_disable;
};
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_pingpong *sde_hw_pingpong_init(enum sde_pingpong idx,
void __iomem *addr,
struct sde_mdss_cfg *m)
{
struct sde_hw_pingpong *c;
struct sde_pingpong_cfg *cfg;
+ int rc;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
@@ -180,16 +187,29 @@
}
c->idx = idx;
- c->pingpong_hw_cap = cfg;
- _setup_pingpong_ops(&c->ops, c->pingpong_hw_cap->features);
+ c->caps = cfg;
+ _setup_pingpong_ops(&c->ops, c->caps->features);
+
+ rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_PINGPONG, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
c->hw.blk_off + c->hw.length, c->hw.xin_id);
return c;
+
+blk_init_error:
+ kzfree(c);
+
+ return ERR_PTR(rc);
}
void sde_hw_pingpong_destroy(struct sde_hw_pingpong *pp)
{
+ if (pp)
+ sde_hw_blk_destroy(&pp->base);
kfree(pp);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
index 90f6171..800c40d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
@@ -13,6 +13,11 @@
#ifndef _SDE_HW_PINGPONG_H
#define _SDE_HW_PINGPONG_H
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+#include "sde_hw_util.h"
+#include "sde_hw_blk.h"
+
struct sde_hw_pingpong;
struct sde_hw_tear_check {
@@ -101,18 +106,28 @@
};
struct sde_hw_pingpong {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
/* pingpong */
enum sde_pingpong idx;
- const struct sde_pingpong_cfg *pingpong_hw_cap;
+ const struct sde_pingpong_cfg *caps;
/* ops */
struct sde_hw_pingpong_ops ops;
};
/**
+ * sde_hw_pingpong - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_pingpong *to_sde_hw_pingpong(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_pingpong, base);
+}
+
+/**
* sde_hw_pingpong_init - initializes the pingpong driver for the passed
* pingpong idx.
* @idx: Pingpong index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index d5f03a6a..bbd5931 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -900,8 +900,7 @@
c->caps = cfg;
_setup_rot_ops(&c->ops, c->caps->features);
- rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx,
- &sde_hw_rot_ops);
+ rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx, &sde_hw_rot_ops);
if (rc) {
SDE_ERROR("failed to init hw blk %d\n", rc);
goto blk_init_error;
@@ -922,9 +921,11 @@
*/
void sde_hw_rot_destroy(struct sde_hw_rot *hw_rot)
{
- sde_hw_blk_destroy(&hw_rot->base);
- kfree(hw_rot->downscale_caps);
- kfree(hw_rot->format_caps);
+ if (hw_rot) {
+ sde_hw_blk_destroy(&hw_rot->base);
+ kfree(hw_rot->downscale_caps);
+ kfree(hw_rot->format_caps);
+ }
kfree(hw_rot);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index bb9f9c0..bc1b1e7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -16,6 +16,7 @@
#include "sde_hw_sspp.h"
#include "sde_hw_color_processing.h"
#include "sde_dbg.h"
+#include "sde_kms.h"
#define SDE_FETCH_CONFIG_RESET_VALUE 0x00000087
@@ -1216,12 +1217,18 @@
return ERR_PTR(-ENOMEM);
}
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx,
void __iomem *addr,
struct sde_mdss_cfg *catalog)
{
struct sde_hw_pipe *hw_pipe;
struct sde_sspp_cfg *cfg;
+ int rc;
if (!addr || !catalog)
return ERR_PTR(-EINVAL);
@@ -1243,6 +1250,12 @@
hw_pipe->cap = cfg;
_setup_layer_ops(hw_pipe, hw_pipe->cap->features);
+ rc = sde_hw_blk_init(&hw_pipe->base, SDE_HW_BLK_SSPP, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
+
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
hw_pipe->hw.blk_off,
hw_pipe->hw.blk_off + hw_pipe->hw.length,
@@ -1257,10 +1270,17 @@
hw_pipe->hw.xin_id);
return hw_pipe;
+
+blk_init_error:
+ kzfree(hw_pipe);
+
+ return ERR_PTR(rc);
}
void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx)
{
+ if (ctx)
+ sde_hw_blk_destroy(&ctx->base);
kfree(ctx);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index d52c0e5..e4be055 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -16,6 +16,7 @@
#include "sde_hw_catalog.h"
#include "sde_hw_mdss.h"
#include "sde_hw_util.h"
+#include "sde_hw_blk.h"
#include "sde_formats.h"
#include "sde_color_processing.h"
@@ -610,20 +611,16 @@
/**
* struct sde_hw_pipe - pipe description
- * @base_off: mdp register mapped offset
- * @blk_off: pipe offset relative to mdss offset
- * @length length of register block offset
- * @hwversion mdss hw version number
- * @catalog: back pointer to catalog
- * @mdp: pointer to associated mdp portion of the catalog
- * @idx: pipe index
- * @type : pipe type, VIG/DMA/RGB/CURSOR, certain operations are not
- * supported for each pipe type
- * @pipe_hw_cap: pointer to layer_cfg
- * @ops: pointer to operations possible for this pipe
+ * @base: hardware block base structure
+ * @hw: block hardware details
+ * @catalog: back pointer to catalog
+ * @mdp: pointer to associated mdp portion of the catalog
+ * @idx: pipe index
+ * @cap: pointer to layer_cfg
+ * @ops: pointer to operations possible for this pipe
*/
struct sde_hw_pipe {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
struct sde_mdss_cfg *catalog;
struct sde_mdp_cfg *mdp;
@@ -637,6 +634,16 @@
};
/**
+ * sde_hw_pipe - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_pipe *to_sde_hw_pipe(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_pipe, base);
+}
+
+/**
* sde_hw_sspp_init - initializes the sspp hw driver object.
* Should be called once before accessing every pipe.
* @idx: Pipe index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index 19f999e..b773187 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -14,6 +14,7 @@
#include "sde_hw_catalog.h"
#include "sde_hw_top.h"
#include "sde_dbg.h"
+#include "sde_kms.h"
#define SSPP_SPARE 0x28
#define UBWC_STATIC 0x144
@@ -152,8 +153,8 @@
if (clk_ctrl <= SDE_CLK_CTRL_NONE || clk_ctrl >= SDE_CLK_CTRL_MAX)
return false;
- reg_off = mdp->cap->clk_ctrls[clk_ctrl].reg_off;
- bit_off = mdp->cap->clk_ctrls[clk_ctrl].bit_off;
+ reg_off = mdp->caps->clk_ctrls[clk_ctrl].reg_off;
+ bit_off = mdp->caps->clk_ctrls[clk_ctrl].bit_off;
reg_val = SDE_REG_READ(c, reg_off);
@@ -337,12 +338,18 @@
return ERR_PTR(-EINVAL);
}
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
void __iomem *addr,
const struct sde_mdss_cfg *m)
{
struct sde_hw_mdp *mdp;
const struct sde_mdp_cfg *cfg;
+ int rc;
if (!addr || !m)
return ERR_PTR(-EINVAL);
@@ -361,8 +368,14 @@
* Assign ops
*/
mdp->idx = idx;
- mdp->cap = cfg;
- _setup_mdp_ops(&mdp->ops, mdp->cap->features);
+ mdp->caps = cfg;
+ _setup_mdp_ops(&mdp->ops, mdp->caps->features);
+
+ rc = sde_hw_blk_init(&mdp->base, SDE_HW_BLK_TOP, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
mdp->hw.blk_off, mdp->hw.blk_off + mdp->hw.length,
@@ -370,10 +383,17 @@
sde_dbg_set_sde_top_offset(mdp->hw.blk_off);
return mdp;
+
+blk_init_error:
+ kzfree(mdp);
+
+ return ERR_PTR(rc);
}
void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp)
{
+ if (mdp)
+ sde_hw_blk_destroy(&mdp->base);
kfree(mdp);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index faf25c7..573780e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -16,6 +16,7 @@
#include "sde_hw_catalog.h"
#include "sde_hw_mdss.h"
#include "sde_hw_util.h"
+#include "sde_hw_blk.h"
struct sde_hw_mdp;
@@ -179,19 +180,29 @@
};
struct sde_hw_mdp {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
- /* intf */
+ /* top */
enum sde_mdp idx;
- const struct sde_mdp_cfg *cap;
+ const struct sde_mdp_cfg *caps;
/* ops */
struct sde_hw_mdp_ops ops;
};
/**
- * sde_hw_intf_init - initializes the intf driver for the passed interface idx
+ * to_sde_hw_mdp - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_mdp *to_sde_hw_mdp(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_mdp, base);
+}
+
+/**
+ * sde_hw_mdptop_init - initializes the top driver for the passed idx
* @idx: Interface index for which driver object is required
* @addr: Mapped register io address of MDP
* @m: Pointer to mdss catalog data
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.c b/drivers/gpu/drm/msm/sde/sde_hw_wb.c
index 378b904..e1bd841 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_wb.c
@@ -16,6 +16,7 @@
#include "sde_hw_wb.h"
#include "sde_formats.h"
#include "sde_dbg.h"
+#include "sde_kms.h"
#define WB_DST_FORMAT 0x000
#define WB_DST_OP_MODE 0x004
@@ -262,6 +263,11 @@
ops->setup_cdp = sde_hw_wb_setup_cdp;
}
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx,
void __iomem *addr,
struct sde_mdss_cfg *m,
@@ -269,6 +275,7 @@
{
struct sde_hw_wb *c;
struct sde_wb_cfg *cfg;
+ int rc;
if (!addr || !m || !hw_mdp)
return ERR_PTR(-EINVAL);
@@ -292,13 +299,26 @@
_setup_wb_ops(&c->ops, c->caps->features);
c->hw_mdp = hw_mdp;
+ rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_WB, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
+
sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
c->hw.blk_off + c->hw.length, c->hw.xin_id);
return c;
+
+blk_init_error:
+ kzfree(c);
+
+ return ERR_PTR(rc);
}
void sde_hw_wb_destroy(struct sde_hw_wb *hw_wb)
{
+ if (hw_wb)
+ sde_hw_blk_destroy(&hw_wb->base);
kfree(hw_wb);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.h b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
index ca3c386..70fe8a5 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_wb.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
@@ -131,16 +131,17 @@
/**
* struct sde_hw_wb : WB driver object
- * @struct sde_hw_blk_reg_map *hw;
+ * @base: hardware block base structure
+ * @hw: block hardware details
* @catalog: back pointer to catalog
- * @mdp: pointer to associated mdp portion of the catalog
- * @idx
- * @wb_hw_caps
- * @ops
+ * @mdp: pointer to associated mdp portion of the catalog
+ * @idx: hardware index number within type
+ * @wb_hw_caps: hardware capabilities
+ * @ops: function pointers
* @hw_mdp: MDP top level hardware block
*/
struct sde_hw_wb {
- /* base */
+ struct sde_hw_blk base;
struct sde_hw_blk_reg_map hw;
struct sde_mdss_cfg *catalog;
struct sde_mdp_cfg *mdp;
@@ -156,6 +157,16 @@
};
/**
+ * sde_hw_wb - convert base object sde_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
+static inline struct sde_hw_wb *to_sde_hw_wb(struct sde_hw_blk *hw)
+{
+ return container_of(hw, struct sde_hw_wb, base);
+}
+
+/**
* sde_hw_wb_init(): Initializes and return writeback hw driver object.
* @idx: wb_path index for which driver object is required
* @addr: mapped register io address of MDP
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index 6ad2c43..0382ed0 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -106,10 +106,8 @@
struct sde_rm_rsvp *rsvp;
struct sde_rm_rsvp *rsvp_nxt;
enum sde_hw_blk_type type;
- const char *type_name;
uint32_t id;
- void *catalog;
- void *hw;
+ struct sde_hw_blk *hw;
};
/**
@@ -143,12 +141,12 @@
if (!blk->rsvp && !blk->rsvp_nxt)
continue;
- SDE_DEBUG("%d rsvp[s%ue%u->s%ue%u] %s %d\n", stage,
+ SDE_DEBUG("%d rsvp[s%ue%u->s%ue%u] %d %d\n", stage,
(blk->rsvp) ? blk->rsvp->seq : 0,
(blk->rsvp) ? blk->rsvp->enc_id : 0,
(blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0,
(blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0,
- blk->type_name, blk->id);
+ blk->type, blk->id);
SDE_EVT32(stage,
(blk->rsvp) ? blk->rsvp->seq : 0,
@@ -205,9 +203,8 @@
if ((i->enc_id == 0) || (rsvp && rsvp->enc_id == i->enc_id)) {
i->hw = i->blk->hw;
- SDE_DEBUG("found type %d %s id %d for enc %d\n",
- i->type, i->blk->type_name, i->blk->id,
- i->enc_id);
+ SDE_DEBUG("found type %d id %d for enc %d\n",
+ i->type, i->blk->id, i->enc_id);
return true;
}
}
@@ -314,7 +311,6 @@
{
struct sde_rm_hw_blk *blk;
struct sde_hw_mdp *hw_mdp;
- const char *name;
void *hw;
hw_mdp = rm->hw_mdp;
@@ -322,39 +318,30 @@
switch (type) {
case SDE_HW_BLK_LM:
hw = sde_hw_lm_init(id, mmio, cat);
- name = "lm";
break;
case SDE_HW_BLK_DSPP:
hw = sde_hw_dspp_init(id, mmio, cat);
- name = "dspp";
break;
case SDE_HW_BLK_CTL:
hw = sde_hw_ctl_init(id, mmio, cat);
- name = "ctl";
break;
case SDE_HW_BLK_CDM:
hw = sde_hw_cdm_init(id, mmio, cat, hw_mdp);
- name = "cdm";
break;
case SDE_HW_BLK_PINGPONG:
hw = sde_hw_pingpong_init(id, mmio, cat);
- name = "pp";
break;
case SDE_HW_BLK_INTF:
hw = sde_hw_intf_init(id, mmio, cat);
- name = "intf";
break;
case SDE_HW_BLK_WB:
hw = sde_hw_wb_init(id, mmio, cat, hw_mdp);
- name = "wb";
break;
case SDE_HW_BLK_DSC:
hw = sde_hw_dsc_init(id, mmio, cat);
- name = "dsc";
break;
case SDE_HW_BLK_ROT:
hw = sde_hw_rot_init(id, mmio, cat);
- name = "rot";
break;
case SDE_HW_BLK_SSPP:
/* SSPPs are not managed by the resource manager */
@@ -378,10 +365,8 @@
return -ENOMEM;
}
- blk->type_name = name;
blk->type = type;
blk->id = id;
- blk->catalog = hw_catalog_info;
blk->hw = hw;
list_add_tail(&blk->list, &rm->hw_blks[type]);
@@ -561,8 +546,8 @@
struct sde_rm_hw_blk **pp,
struct sde_rm_hw_blk *primary_lm)
{
- struct sde_lm_cfg *lm_cfg = (struct sde_lm_cfg *)lm->catalog;
- struct sde_pingpong_cfg *pp_cfg;
+ const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap;
+ const struct sde_pingpong_cfg *pp_cfg;
struct sde_rm_hw_iter iter;
*dspp = NULL;
@@ -573,8 +558,8 @@
/* Check if this layer mixer is a peer of the proposed primary LM */
if (primary_lm) {
- struct sde_lm_cfg *prim_lm_cfg =
- (struct sde_lm_cfg *)primary_lm->catalog;
+ const struct sde_lm_cfg *prim_lm_cfg =
+ to_sde_hw_mixer(primary_lm->hw)->cap;
if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) {
SDE_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id,
@@ -640,7 +625,7 @@
return false;
}
- pp_cfg = (struct sde_pingpong_cfg *)((*pp)->catalog);
+ pp_cfg = to_sde_hw_pingpong((*pp)->hw)->caps;
if ((reqs->topology->top_name == SDE_RM_TOPOLOGY_PPSPLIT) &&
!(test_bit(SDE_PINGPONG_SPLIT, &pp_cfg->features))) {
SDE_DEBUG("pp %d doesn't support ppsplit\n", pp_cfg->id);
@@ -728,9 +713,9 @@
rc = -ENAVAIL;
sde_rm_init_hw_iter(&iter_i, 0, SDE_HW_BLK_PINGPONG);
while (_sde_rm_get_hw_locked(rm, &iter_i)) {
- struct sde_pingpong_cfg *pp_cfg =
- (struct sde_pingpong_cfg *)
- (iter_i.blk->catalog);
+ const struct sde_hw_pingpong *pp =
+ to_sde_hw_pingpong(iter_i.blk->hw);
+ const struct sde_pingpong_cfg *pp_cfg = pp->caps;
if (!(test_bit(SDE_PINGPONG_SLAVE, &pp_cfg->features)))
continue;
@@ -759,17 +744,17 @@
sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_CTL);
while (_sde_rm_get_hw_locked(rm, &iter)) {
- unsigned long caps;
+ const struct sde_hw_ctl *ctl = to_sde_hw_ctl(iter.blk->hw);
+ unsigned long features = ctl->caps->features;
bool has_split_display, has_ppsplit;
if (RESERVED_BY_OTHER(iter.blk, rsvp))
continue;
- caps = ((struct sde_ctl_cfg *)iter.blk->catalog)->features;
- has_split_display = BIT(SDE_CTL_SPLIT_DISPLAY) & caps;
- has_ppsplit = BIT(SDE_CTL_PINGPONG_SPLIT) & caps;
+ has_split_display = BIT(SDE_CTL_SPLIT_DISPLAY) & features;
+ has_ppsplit = BIT(SDE_CTL_PINGPONG_SPLIT) & features;
- SDE_DEBUG("ctl %d caps 0x%lX\n", iter.blk->id, caps);
+ SDE_DEBUG("ctl %d caps 0x%lX\n", iter.blk->id, features);
if (top->needs_split_display != has_split_display)
continue;
@@ -833,24 +818,23 @@
enum sde_hw_blk_type type)
{
struct sde_rm_hw_iter iter;
- struct sde_cdm_cfg *cdm;
sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_CDM);
while (_sde_rm_get_hw_locked(rm, &iter)) {
+ const struct sde_hw_cdm *cdm = to_sde_hw_cdm(iter.blk->hw);
+ const struct sde_cdm_cfg *caps = cdm->caps;
bool match = false;
if (RESERVED_BY_OTHER(iter.blk, rsvp))
continue;
- cdm = (struct sde_cdm_cfg *)(iter.blk->catalog);
-
if (type == SDE_HW_BLK_INTF && id != INTF_MAX)
- match = test_bit(id, &cdm->intf_connect);
+ match = test_bit(id, &caps->intf_connect);
else if (type == SDE_HW_BLK_WB && id != WB_MAX)
- match = test_bit(id, &cdm->wb_connect);
+ match = test_bit(id, &caps->wb_connect);
SDE_DEBUG("type %d id %d, cdm intfs %lu wbs %lu match %d\n",
- type, id, cdm->intf_connect, cdm->wb_connect,
+ type, id, caps->intf_connect, caps->wb_connect,
match);
if (!match)
@@ -1112,15 +1096,15 @@
list_for_each_entry(blk, &rm->hw_blks[type], list) {
if (blk->rsvp == rsvp) {
blk->rsvp = NULL;
- SDE_DEBUG("rel rsvp %d enc %d %s %d\n",
+ SDE_DEBUG("rel rsvp %d enc %d %d %d\n",
rsvp->seq, rsvp->enc_id,
- blk->type_name, blk->id);
+ blk->type, blk->id);
}
if (blk->rsvp_nxt == rsvp) {
blk->rsvp_nxt = NULL;
- SDE_DEBUG("rel rsvp_nxt %d enc %d %s %d\n",
+ SDE_DEBUG("rel rsvp_nxt %d enc %d %d %d\n",
rsvp->seq, rsvp->enc_id,
- blk->type_name, blk->id);
+ blk->type, blk->id);
}
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h
index f731a30..6962bef 100644
--- a/drivers/gpu/drm/msm/sde/sde_trace.h
+++ b/drivers/gpu/drm/msm/sde/sde_trace.h
@@ -159,25 +159,37 @@
__get_str(counter_name), __entry->value)
)
+#define SDE_TRACE_EVTLOG_SIZE 15
TRACE_EVENT(sde_evtlog,
- TP_PROTO(const char *tag, u32 tag_id, u64 value1, u64 value2),
- TP_ARGS(tag, tag_id, value1, value2),
+ TP_PROTO(const char *tag, u32 tag_id, u32 cnt, u32 data[]),
+ TP_ARGS(tag, tag_id, cnt, data),
TP_STRUCT__entry(
__field(int, pid)
__string(evtlog_tag, tag)
__field(u32, tag_id)
- __field(u64, value1)
- __field(u64, value2)
+ __array(u32, data, SDE_TRACE_EVTLOG_SIZE)
),
TP_fast_assign(
__entry->pid = current->tgid;
__assign_str(evtlog_tag, tag);
__entry->tag_id = tag_id;
- __entry->value1 = value1;
- __entry->value2 = value2;
+ if (cnt > SDE_TRACE_EVTLOG_SIZE)
+ cnt = SDE_TRACE_EVTLOG_SIZE;
+ memcpy(__entry->data, data, cnt * sizeof(u32));
+ memset(&__entry->data[cnt], 0,
+ (SDE_TRACE_EVTLOG_SIZE - cnt) * sizeof(u32));
),
- TP_printk("%d|%s:%d|%llu|%llu", __entry->pid, __get_str(evtlog_tag),
- __entry->tag_id, __entry->value1, __entry->value2)
+ TP_printk("%d|%s:%d|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
+ __entry->pid, __get_str(evtlog_tag),
+ __entry->tag_id,
+ __entry->data[0], __entry->data[1],
+ __entry->data[2], __entry->data[3],
+ __entry->data[4], __entry->data[5],
+ __entry->data[6], __entry->data[7],
+ __entry->data[8], __entry->data[9],
+ __entry->data[10], __entry->data[11],
+ __entry->data[12], __entry->data[13],
+ __entry->data[14])
)
TRACE_EVENT(sde_perf_crtc_update,
diff --git a/drivers/gpu/drm/msm/sde_dbg_evtlog.c b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
index 699396f..67c664f 100644
--- a/drivers/gpu/drm/msm/sde_dbg_evtlog.c
+++ b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
@@ -99,8 +99,7 @@
evtlog->curr = (evtlog->curr + 1) % SDE_EVTLOG_ENTRY;
evtlog->last++;
- trace_sde_evtlog(name, line, i > 0 ? log->data[0] : 0,
- i > 1 ? log->data[1] : 0);
+ trace_sde_evtlog(name, line, log->data_cnt, log->data);
exit:
spin_unlock_irqrestore(&evtlog->spin_lock, flags);
}
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index dbacb20..58ef5ee 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -798,8 +798,19 @@
#define A6XX_GMU_CM3_CFG 0x1F82D
#define A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE 0x1F840
#define A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0 0x1F841
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1 0x1F842
#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L 0x1F844
#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H 0x1F845
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_L 0x1F846
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_H 0x1F847
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_L 0x1F848
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_H 0x1F849
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_L 0x1F84A
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_H 0x1F84B
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L 0x1F84C
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H 0x1F84D
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L 0x1F84E
+#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H 0x1F84F
#define A6XX_GMU_PWR_COL_INTER_FRAME_CTRL 0x1F8C0
#define A6XX_GMU_PWR_COL_INTER_FRAME_HYST 0x1F8C1
#define A6XX_GMU_PWR_COL_SPTPRAC_HYST 0x1F8C2
@@ -852,6 +863,7 @@
#define A6XX_GPU_GMU_AO_GMU_CGC_DELAY_CNTL 0x23B0A
#define A6XX_GPU_GMU_AO_GMU_CGC_HYST_CNTL 0x23B0B
#define A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS 0x23B0C
+#define A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2 0x23B0D
#define A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK 0x23B0E
#define A6XX_GMU_AHB_FENCE_STATUS 0x23B13
#define A6XX_GMU_RBBM_INT_UNMASKED_STATUS 0x23B15
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index f581cff..3672273 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2855,8 +2855,14 @@
gpu_busy += adj;
}
- stats->busy_time = adreno_ticks_to_us(gpu_busy,
- kgsl_pwrctrl_active_freq(pwr));
+ if (kgsl_gmu_isenabled(device)) {
+ /* clock sourced from XO */
+ stats->busy_time = gpu_busy * 10 / 192;
+ } else {
+ /* clock sourced from GFX3D */
+ stats->busy_time = adreno_ticks_to_us(gpu_busy,
+ kgsl_pwrctrl_active_freq(pwr));
+ }
}
if (device->pwrctrl.bus_control) {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 26c5505..7a6581c 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -641,6 +641,7 @@
ADRENO_REG_GMU_HOST2GMU_INTR_SET,
ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
+ ADRENO_REG_GPMU_POWER_COUNTER_ENABLE,
ADRENO_REG_REGISTER_MAX,
};
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 314ac85a..13c36e6 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -3017,6 +3017,8 @@
A5XX_VBIF_XIN_HALT_CTRL1),
ADRENO_REG_DEFINE(ADRENO_REG_VBIF_VERSION,
A5XX_VBIF_VERSION),
+ ADRENO_REG_DEFINE(ADRENO_REG_GPMU_POWER_COUNTER_ENABLE,
+ A5XX_GPMU_POWER_COUNTER_ENABLE),
};
static const struct adreno_reg_offsets a5xx_reg_offsets = {
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 314b2d8..33854ea 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -1202,7 +1202,7 @@
OOB_BOOT_SLUMBER_CLEAR_MASK);
if (ret)
- dev_err(&gmu->pdev->dev, "OOB set after GMU booted timed out\n");
+ dev_err(&gmu->pdev->dev, "Boot OOB timed out\n");
return ret;
}
@@ -1222,6 +1222,9 @@
int perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1;
int ret, state;
+ /* Disable the power counter so that the GMU is not busy */
+ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0);
+
if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
ret = hfi_notify_slumber(gmu, perf_idx, bus_level);
return ret;
@@ -1238,7 +1241,7 @@
a6xx_oob_clear(adreno_dev, OOB_BOOT_SLUMBER_CLEAR_MASK);
if (ret)
- dev_err(&gmu->pdev->dev, "OOB set for slumber timed out\n");
+ dev_err(&gmu->pdev->dev, "Notify slumber OOB timed out\n");
else {
kgsl_gmu_regread(device,
A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, &state);
@@ -1286,6 +1289,9 @@
/* Turn on the HM and SPTP head switches */
ret = a6xx_hm_sptprac_enable(device);
+ /* Enable the power counter because it was disabled before slumber */
+ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1);
+
return ret;
error_rsc:
dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n");
@@ -1466,7 +1472,7 @@
OOB_DCVS_CLEAR_MASK);
if (ret) {
- dev_err(&gmu->pdev->dev, "OOB set after GMU booted timed out\n");
+ dev_err(&gmu->pdev->dev, "DCVS OOB timed out\n");
goto done;
}
@@ -1495,10 +1501,17 @@
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct gmu_device *gmu = &device->gmu;
+ unsigned int status, status2;
if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS,
0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) {
- dev_err(&gmu->pdev->dev, "GMU is not idling\n");
+ kgsl_gmu_regread(device,
+ A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, &status);
+ kgsl_gmu_regread(device,
+ A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2, &status2);
+ dev_err(&gmu->pdev->dev,
+ "GMU not idling: status=0x%x, status2=0x%x\n",
+ status, status2);
return -ETIMEDOUT;
}
@@ -1566,6 +1579,8 @@
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
unsigned int reg;
+ unsigned long time;
+ bool vbif_acked = false;
/*
* For the soft reset case with GMU enabled this part is done
@@ -1584,12 +1599,19 @@
adreno_readreg(adreno_dev, ADRENO_REG_RBBM_SW_RESET_CMD, ®);
adreno_writereg(adreno_dev, ADRENO_REG_RBBM_SW_RESET_CMD, 0);
- /* Check VBIF status after reset */
- if (timed_poll_check(device,
- A6XX_RBBM_VBIF_GX_RESET_STATUS,
- VBIF_RESET_ACK_MASK,
- VBIF_RESET_ACK_TIMEOUT,
- VBIF_RESET_ACK_MASK))
+ /* Wait for the VBIF reset ack to complete */
+ time = jiffies + msecs_to_jiffies(VBIF_RESET_ACK_TIMEOUT);
+
+ do {
+ kgsl_regread(device, A6XX_RBBM_VBIF_GX_RESET_STATUS, ®);
+ if ((reg & VBIF_RESET_ACK_MASK) == VBIF_RESET_ACK_MASK) {
+ vbif_acked = true;
+ break;
+ }
+ cpu_relax();
+ } while (!time_after(jiffies, time));
+
+ if (!vbif_acked)
return -ETIMEDOUT;
a6xx_sptprac_enable(adreno_dev);
@@ -2431,12 +2453,47 @@
A6XX_CP_ALWAYS_ON_COUNTER_HI, -1 },
};
+static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = {
+ /*
+ * A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0 is used for the GPU
+ * busy count (see the PWR group above). Mark it as broken
+ * so it's not re-used.
+ */
+ { KGSL_PERFCOUNTER_BROKEN, 0, 0,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H, -1,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_L,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_1_H, -1,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_L,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_2_H, -1,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_L,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_H, -1,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H, -1,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H, -1,
+ A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, },
+};
+
#define A6XX_PERFCOUNTER_GROUP(offset, name) \
ADRENO_PERFCOUNTER_GROUP(a6xx, offset, name)
#define A6XX_PERFCOUNTER_GROUP_FLAGS(offset, name, flags) \
ADRENO_PERFCOUNTER_GROUP_FLAGS(a6xx, offset, name, flags)
+#define A6XX_POWER_COUNTER_GROUP(offset, name) \
+ ADRENO_POWER_COUNTER_GROUP(a6xx, offset, name)
+
static struct adreno_perfcount_group a6xx_perfcounter_groups
[KGSL_PERFCOUNTER_GROUP_MAX] = {
A6XX_PERFCOUNTER_GROUP(CP, cp),
@@ -2462,6 +2519,7 @@
ADRENO_PERFCOUNTER_GROUP_FIXED),
A6XX_PERFCOUNTER_GROUP_FLAGS(ALWAYSON, alwayson,
ADRENO_PERFCOUNTER_GROUP_FIXED),
+ A6XX_POWER_COUNTER_GROUP(GPMU, gpmu),
};
static struct adreno_perfcounters a6xx_perfcounters = {
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index bca3dd0..54acd73 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -206,8 +206,38 @@
};
static const unsigned int a6xx_gmu_registers[] = {
- /* GMU */
+ /* GMU GX */
+ 0x1A800, 0x1A800, 0x1A810, 0x1A813, 0x1A816, 0x1A816, 0x1A818, 0x1A81B,
+ 0x1A81E, 0x1A81E, 0x1A820, 0x1A823, 0x1A826, 0x1A826, 0x1A828, 0x1A82B,
+ 0x1A82E, 0x1A82E, 0x1A830, 0x1A833, 0x1A836, 0x1A836, 0x1A838, 0x1A83B,
+ 0x1A83E, 0x1A83E, 0x1A840, 0x1A843, 0x1A846, 0x1A846, 0x1A880, 0x1A884,
+ 0x1A900, 0x1A92B, 0x1A940, 0x1A940,
+ /* GMU TCM */
0x1B400, 0x1C3FF, 0x1C400, 0x1D3FF,
+ /* GMU CX */
+ 0x1F400, 0x1F407, 0x1F410, 0x1F412, 0x1F500, 0x1F500, 0x1F507, 0x1F50A,
+ 0x1F800, 0x1F804, 0x1F807, 0x1F808, 0x1F80B, 0x1F80C, 0x1F80F, 0x1F81C,
+ 0x1F824, 0x1F82A, 0x1F82D, 0x1F830, 0x1F840, 0x1F853, 0x1F887, 0x1F889,
+ 0x1F8A0, 0x1F8A2, 0x1F8A4, 0x1F8AF, 0x1F8C0, 0x1F8C3, 0x1F8D0, 0x1F8D0,
+ 0x1F8E4, 0x1F8E4, 0x1F8E8, 0x1F8EC, 0x1F900, 0x1F903, 0x1F940, 0x1F940,
+ 0x1F942, 0x1F944, 0x1F94C, 0x1F94D, 0x1F94F, 0x1F951, 0x1F954, 0x1F954,
+ 0x1F957, 0x1F958, 0x1F95D, 0x1F95D, 0x1F962, 0x1F962, 0x1F964, 0x1F965,
+ 0x1F980, 0x1F986, 0x1F990, 0x1F99E, 0x1F9C0, 0x1F9C0, 0x1F9C5, 0x1F9CC,
+ 0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA03,
+ /* GPU RSCC */
+ 0x23740, 0x23742, 0x23744, 0x23747, 0x2374C, 0x23787, 0x237EC, 0x237EF,
+ 0x237F4, 0x2382F, 0x23894, 0x23897, 0x2389C, 0x238D7, 0x2393C, 0x2393F,
+ 0x23944, 0x2397F,
+ /* GMU AO */
+ 0x23B00, 0x23B16, 0x23C00, 0x23C00,
+ /* GPU CC */
+ 0x24000, 0x24012, 0x24040, 0x24052, 0x24400, 0x24404, 0x24407, 0x2440B,
+ 0x24415, 0x2441C, 0x2441E, 0x2442D, 0x2443C, 0x2443D, 0x2443F, 0x24440,
+ 0x24442, 0x24449, 0x24458, 0x2445A, 0x24540, 0x2455E, 0x24800, 0x24802,
+ 0x24C00, 0x24C02, 0x25400, 0x25402, 0x25800, 0x25802, 0x25C00, 0x25C02,
+ 0x26000, 0x26002,
+ /* GPU CC ACD */
+ 0x26400, 0x26416, 0x26420, 0x26427,
};
static const struct adreno_vbif_snapshot_registers
diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c
index cd95003..0da4da9 100644
--- a/drivers/gpu/msm/adreno_perfcounter.c
+++ b/drivers/gpu/msm/adreno_perfcounter.c
@@ -654,7 +654,7 @@
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct adreno_perfcount_register *reg;
- unsigned int shift = counter << 3;
+ unsigned int shift = (counter << 3) % (sizeof(unsigned int) * 8);
if (adreno_is_a530(adreno_dev)) {
if (countable > 43)
@@ -662,13 +662,16 @@
} else if (adreno_is_a540(adreno_dev)) {
if (countable > 47)
return;
+ } else if (adreno_is_a6xx(adreno_dev)) {
+ if (countable > 34)
+ return;
} else
/* return on platforms that have no GPMU */
return;
reg = &counters->groups[group].regs[counter];
kgsl_regrmw(device, reg->select, 0xff << shift, countable << shift);
- kgsl_regwrite(device, A5XX_GPMU_POWER_COUNTER_ENABLE, 1);
+ adreno_writereg(adreno_dev, ADRENO_REG_GPMU_POWER_COUNTER_ENABLE, 1);
reg->value = 0;
}
@@ -684,7 +687,7 @@
reg = &counters->groups[group].regs[counter];
kgsl_regwrite(device, reg->select, countable);
- kgsl_regwrite(device, A5XX_GPMU_POWER_COUNTER_ENABLE, 1);
+ adreno_writereg(adreno_dev, ADRENO_REG_GPMU_POWER_COUNTER_ENABLE, 1);
reg->value = 0;
}
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c
index 8a57ed2..d26e0d0 100644
--- a/drivers/hwtracing/coresight/coresight-cti.c
+++ b/drivers/hwtracing/coresight/coresight-cti.c
@@ -64,7 +64,7 @@
#define ITCHIN (0xEF4)
#define ITTRIGIN (0xEF8)
-#define CTI_MAX_TRIGGERS (8)
+#define CTI_MAX_TRIGGERS (32)
#define CTI_MAX_CHANNELS (4)
#define AFFINITY_LEVEL_L2 1
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
index 8d9f4a5..9a30d64 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
@@ -1330,15 +1330,22 @@
cpas_hw_intf->hw_ops.write = NULL;
cpas_hw_intf->hw_ops.process_cmd = cam_cpas_hw_process_cmd;
+ cpas_core->work_queue = alloc_workqueue("cam-cpas",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, CAM_CPAS_INFLIGHT_WORKS);
+ if (!cpas_core->work_queue) {
+ rc = -ENOMEM;
+ goto release_mem;
+ }
+
internal_ops = &cpas_core->internal_ops;
rc = cam_cpas_util_get_internal_ops(pdev, cpas_hw_intf, internal_ops);
- if (rc != 0)
- goto release_mem;
+ if (rc)
+ goto release_workq;
rc = cam_cpas_soc_init_resources(&cpas_hw->soc_info,
internal_ops->handle_irq, cpas_hw);
if (rc)
- goto release_mem;
+ goto release_workq;
soc_private = (struct cam_cpas_private_soc *)
cpas_hw->soc_info.soc_private;
@@ -1423,6 +1430,9 @@
cam_cpas_util_client_cleanup(cpas_hw);
deinit_platform_res:
cam_cpas_soc_deinit_resources(&cpas_hw->soc_info);
+release_workq:
+ flush_workqueue(cpas_core->work_queue);
+ destroy_workqueue(cpas_core->work_queue);
release_mem:
mutex_destroy(&cpas_hw->hw_mutex);
kfree(cpas_core);
@@ -1454,6 +1464,8 @@
cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client);
cam_cpas_util_client_cleanup(cpas_hw);
cam_cpas_soc_deinit_resources(&cpas_hw->soc_info);
+ flush_workqueue(cpas_core->work_queue);
+ destroy_workqueue(cpas_core->work_queue);
mutex_destroy(&cpas_hw->hw_mutex);
kfree(cpas_core);
kfree(cpas_hw);
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
index 52649ec..6d4fafe 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
@@ -17,6 +17,7 @@
#include "cam_cpas_hw_intf.h"
#define CPAS_MAX_CLIENTS 20
+#define CAM_CPAS_INFLIGHT_WORKS 5
#define CAM_CPAS_GET_CLIENT_IDX(handle) (handle)
#define CAM_CPAS_GET_CLIENT_HANDLE(indx) (indx)
@@ -169,6 +170,7 @@
* @ahb_bus_client: AHB Bus client info
* @axi_ports_list_head: Head pointing to list of AXI ports
* @internal_ops: CPAS HW internal ops
+ * @work_queue: Work queue handle
*
*/
struct cam_cpas {
@@ -182,6 +184,7 @@
struct cam_cpas_bus_client ahb_bus_client;
struct list_head axi_ports_list_head;
struct cam_cpas_internal_ops internal_ops;
+ struct workqueue_struct *work_queue;
};
int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops);
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
index d26c2b6..b901410 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
@@ -12,6 +12,7 @@
#include <linux/delay.h>
#include <linux/timer.h>
+#include <linux/slab.h>
#include "cam_cpas_hw_intf.h"
#include "cam_cpas_hw.h"
@@ -105,15 +106,64 @@
static int cam_cpastop_handle_errlogger(struct cam_cpas *cpas_core,
struct cam_hw_soc_info *soc_info)
{
- uint32_t reg_value;
+ uint32_t reg_value[4];
int i;
+ int size = camnoc_info->error_logger_size;
int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
- for (i = 0; i < camnoc_info->error_logger_size; i++) {
- reg_value = cam_io_r_mb(
+ for (i = 0; (i + 3) < size; i = i + 4) {
+ reg_value[0] = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->error_logger[i]);
- pr_err("ErrorLogger[%d] : 0x%x\n", i, reg_value);
+ reg_value[1] = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->error_logger[i + 1]);
+ reg_value[2] = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->error_logger[i + 2]);
+ reg_value[3] = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->error_logger[i + 3]);
+ pr_err("offset[0x%x] values [0x%x] [0x%x] [0x%x] [0x%x]\n",
+ camnoc_info->error_logger[i], reg_value[0],
+ reg_value[1], reg_value[2], reg_value[3]);
+ }
+
+ if ((i + 2) < size) {
+ reg_value[0] = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->error_logger[i]);
+ reg_value[1] = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->error_logger[i + 1]);
+ reg_value[2] = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->error_logger[i + 2]);
+ pr_err("offset[0x%x] values [0x%x] [0x%x] [0x%x]\n",
+ camnoc_info->error_logger[i], reg_value[0],
+ reg_value[1], reg_value[2]);
+ i = i + 3;
+ }
+
+ if ((i + 1) < size) {
+ reg_value[0] = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->error_logger[i]);
+ reg_value[1] = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->error_logger[i + 1]);
+ pr_err("offset[0x%x] values [0x%x] [0x%x]\n",
+ camnoc_info->error_logger[i], reg_value[0],
+ reg_value[1]);
+ i = i + 2;
+ }
+
+ if (i < size) {
+ reg_value[0] = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->error_logger[i]);
+ pr_err("offset[0x%x] values [0x%x]\n",
+ camnoc_info->error_logger[i], reg_value[0]);
}
return 0;
@@ -128,9 +178,10 @@
reg_value = cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->irq_err[i].err_status.offset);
- pr_err("Dumping ubwc error status : 0x%x\n", reg_value);
+ pr_err("Dumping ubwc error status [%d]: offset[0x%x] value[0x%x]\n",
+ i, camnoc_info->irq_err[i].err_status.offset, reg_value);
- return 0;
+ return reg_value;
}
static int cam_cpastop_handle_ahb_timeout_err(struct cam_hw_info *cpas_hw)
@@ -172,61 +223,126 @@
return 0;
}
-irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data)
+static void cam_cpastop_notify_clients(struct cam_cpas *cpas_core,
+ enum cam_camnoc_hw_irq_type irq_type, uint32_t irq_data)
{
- uint32_t irq_status;
- struct cam_hw_info *cpas_hw = (struct cam_hw_info *)data;
- struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
- struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
- int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
+ int i;
+ struct cam_cpas_client *cpas_client;
+
+ CPAS_CDBG("Notify CB : num_clients=%d, registered=%d, started=%d\n",
+ cpas_core->num_clients, cpas_core->registered_clients,
+ cpas_core->streamon_clients);
+
+ for (i = 0; i < cpas_core->num_clients; i++) {
+ if (CAM_CPAS_CLIENT_STARTED(cpas_core, i)) {
+ cpas_client = cpas_core->cpas_client[i];
+ if (cpas_client->data.cam_cpas_client_cb) {
+ CPAS_CDBG("Calling client CB %d : %d 0x%x\n",
+ i, irq_type, irq_data);
+ cpas_client->data.cam_cpas_client_cb(
+ cpas_client->data.client_handle,
+ cpas_client->data.userdata,
+ (enum cam_camnoc_irq_type)irq_type,
+ irq_data);
+ }
+ }
+ }
+}
+
+static void cam_cpastop_work(struct work_struct *work)
+{
+ struct cam_cpas_work_payload *payload;
+ struct cam_hw_info *cpas_hw;
+ struct cam_cpas *cpas_core;
+ struct cam_hw_soc_info *soc_info;
int i;
enum cam_camnoc_hw_irq_type irq_type;
+ uint32_t irq_data;
- irq_status = cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base +
- camnoc_info->irq_sbm->sbm_status.offset);
+ payload = container_of(work, struct cam_cpas_work_payload, work);
+ if (!payload) {
+ pr_err("NULL payload");
+ return;
+ }
- pr_err("IRQ callback, irq_status=0x%x\n", irq_status);
+ cpas_hw = payload->hw;
+ cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+ soc_info = &cpas_hw->soc_info;
for (i = 0; i < camnoc_info->irq_err_size; i++) {
- if ((irq_status & camnoc_info->irq_err[i].sbm_port) &&
+ if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) &&
(camnoc_info->irq_err[i].enable)) {
irq_type = camnoc_info->irq_err[i].irq_type;
pr_err("Error occurred, type=%d\n", irq_type);
+ irq_data = 0;
switch (irq_type) {
case CAM_CAMNOC_HW_IRQ_SLAVE_ERROR:
- cam_cpastop_handle_errlogger(cpas_core,
- soc_info);
+ irq_data = cam_cpastop_handle_errlogger(
+ cpas_core, soc_info);
break;
case CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR:
case CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR:
case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR:
case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR:
- cam_cpastop_handle_ubwc_err(cpas_core,
- soc_info, i);
+ irq_data = cam_cpastop_handle_ubwc_err(
+ cpas_core, soc_info, i);
break;
case CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT:
- cam_cpastop_handle_ahb_timeout_err(cpas_hw);
+ irq_data = cam_cpastop_handle_ahb_timeout_err(
+ cpas_hw);
break;
case CAM_CAMNOC_HW_IRQ_CAMNOC_TEST:
CPAS_CDBG("TEST IRQ\n");
break;
default:
+ pr_err("Invalid IRQ type\n");
break;
}
- irq_status &= ~camnoc_info->irq_err[i].sbm_port;
+ cam_cpastop_notify_clients(cpas_core, irq_type,
+ irq_data);
+
+ payload->irq_status &=
+ ~camnoc_info->irq_err[i].sbm_port;
}
}
- if (irq_status)
- pr_err("IRQ not handled, irq_status=0x%x\n", irq_status);
+ if (payload->irq_status)
+ pr_err("IRQ not handled irq_status=0x%x\n",
+ payload->irq_status);
+
+ kfree(payload);
+}
+
+static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data)
+{
+ struct cam_hw_info *cpas_hw = (struct cam_hw_info *)data;
+ struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+ struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
+ int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
+ struct cam_cpas_work_payload *payload;
+
+ payload = kzalloc(sizeof(struct cam_cpas_work_payload), GFP_ATOMIC);
+ if (!payload)
+ return IRQ_HANDLED;
+
+ payload->irq_status = cam_io_r_mb(
+ soc_info->reg_map[camnoc_index].mem_base +
+ camnoc_info->irq_sbm->sbm_status.offset);
+
+ CPAS_CDBG("IRQ callback, irq_status=0x%x\n", payload->irq_status);
+
+ payload->hw = cpas_hw;
+ INIT_WORK((struct work_struct *)&payload->work, cam_cpastop_work);
if (TEST_IRQ_ENABLE)
cam_cpastop_disable_test_irq(cpas_hw);
cam_cpastop_reset_irq(cpas_hw);
+ queue_work(cpas_core->work_queue, &payload->work);
+
return IRQ_HANDLED;
}
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
index c61204a..d5bb363 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.h
@@ -195,4 +195,20 @@
struct cam_cpas_hw_errata_wa_list *errata_wa_list;
};
+/**
+ * struct cam_cpas_work_payload : Struct for cpas work payload data
+ *
+ * @hw: Pointer to HW info
+ * @irq_status: IRQ status value
+ * @irq_data: IRQ data
+ * @work: Work handle
+ *
+ */
+struct cam_cpas_work_payload {
+ struct cam_hw_info *hw;
+ uint32_t irq_status;
+ uint32_t irq_data;
+ struct work_struct work;
+};
+
#endif /* _CAM_CPASTOP_HW_H_ */
diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c
index e8ba149..27249ee 100644
--- a/drivers/mfd/wcd934x-regmap.c
+++ b/drivers/mfd/wcd934x-regmap.c
@@ -1937,7 +1937,6 @@
case WCD934X_BIAS_VBG_FINE_ADJ:
case WCD934X_CODEC_CPR_SVS_CX_VDD:
case WCD934X_CODEC_CPR_SVS2_CX_VDD:
- case WCD934X_CDC_TOP_TOP_CFG1:
case WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
return true;
}
diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
index b97a584..5c7dd9f 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
@@ -149,6 +149,8 @@
case AUDIO_START: {
pr_debug("%s: AUDIO_START\n", __func__);
+ mutex_lock(&effects->lock);
+
rc = q6asm_open_read_write_v2(effects->ac,
FORMAT_LINEAR_PCM,
FORMAT_MULTI_CHANNEL_LINEAR_PCM,
@@ -160,6 +162,7 @@
pr_err("%s: Open failed for hw accelerated effects:rc=%d\n",
__func__, rc);
rc = -EINVAL;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
effects->opened = 1;
@@ -176,6 +179,7 @@
pr_err("%s: Write buffer Allocation failed rc = %d\n",
__func__, rc);
rc = -ENOMEM;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
atomic_set(&effects->in_count, effects->config.input.num_buf);
@@ -186,6 +190,7 @@
pr_err("%s: Read buffer Allocation failed rc = %d\n",
__func__, rc);
rc = -ENOMEM;
+ mutex_unlock(&effects->lock);
goto readbuf_fail;
}
atomic_set(&effects->out_count, effects->config.output.num_buf);
@@ -200,6 +205,7 @@
if (rc < 0) {
pr_err("%s: pcm read block config failed\n", __func__);
rc = -EINVAL;
+ mutex_unlock(&effects->lock);
goto cfg_fail;
}
pr_debug("%s: dec: sample_rate: %d, num_channels: %d, bit_width: %d\n",
@@ -214,6 +220,7 @@
pr_err("%s: pcm write format block config failed\n",
__func__);
rc = -EINVAL;
+ mutex_unlock(&effects->lock);
goto cfg_fail;
}
@@ -226,6 +233,7 @@
effects->started = 0;
pr_err("%s: ASM run state failed\n", __func__);
}
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_WRITE: {
@@ -287,8 +295,11 @@
uint32_t idx = 0;
uint32_t size = 0;
+ mutex_lock(&effects->lock);
+
if (!effects->started) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
@@ -305,11 +316,13 @@
if (!rc) {
pr_err("%s: read wait_event_timeout\n", __func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
if (!atomic_read(&effects->in_count)) {
pr_err("%s: pcm stopped in_count 0\n", __func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
@@ -317,15 +330,18 @@
if (bufptr) {
if (!((void *)arg)) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
if ((effects->config.buf_cfg.input_len > size) ||
copy_to_user((void *)arg, bufptr,
effects->config.buf_cfg.input_len)) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
}
+ mutex_unlock(&effects->lock);
break;
}
default:
@@ -459,6 +475,7 @@
switch (cmd) {
case AUDIO_SET_EFFECTS_CONFIG: {
pr_debug("%s: AUDIO_SET_EFFECTS_CONFIG\n", __func__);
+ mutex_lock(&effects->lock);
memset(&effects->config, 0, sizeof(effects->config));
if (copy_from_user(&effects->config, (void *)arg,
sizeof(effects->config))) {
@@ -476,6 +493,7 @@
effects->config.input.num_buf,
effects->config.input.sample_rate,
effects->config.input.num_channels);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_BUF_LEN: {
@@ -497,6 +515,7 @@
buf_avail.input_num_avail = atomic_read(&effects->in_count);
buf_avail.output_num_avail = atomic_read(&effects->out_count);
+ mutex_lock(&effects->lock);
pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
__func__, buf_avail.output_num_avail,
buf_avail.input_num_avail);
@@ -506,16 +525,20 @@
__func__);
rc = -EFAULT;
}
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_PP_PARAMS: {
+ mutex_lock(&effects->lock);
if (copy_from_user(argvalues, (void *)arg,
MAX_PP_PARAMS_SZ*sizeof(long))) {
pr_err("%s: copy from user for pp params failed\n",
__func__);
+ mutex_unlock(&effects->lock);
return -EFAULT;
}
rc = audio_effects_set_pp_param(effects, argvalues);
+ mutex_unlock(&effects->lock);
break;
}
default:
@@ -582,12 +605,14 @@
struct msm_hwacc_effects_config32 config32;
struct msm_hwacc_effects_config *config = &effects->config;
+ mutex_lock(&effects->lock);
memset(&effects->config, 0, sizeof(effects->config));
if (copy_from_user(&config32, (void *)arg,
sizeof(config32))) {
pr_err("%s: copy to user for AUDIO_SET_EFFECTS_CONFIG failed\n",
__func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
break;
}
config->input.buf_size = config32.input.buf_size;
@@ -624,17 +649,20 @@
effects->config.input.num_buf,
effects->config.input.sample_rate,
effects->config.input.num_channels);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_BUF_LEN32: {
struct msm_hwacc_buf_cfg32 buf_cfg32;
struct msm_hwacc_effects_config *config = &effects->config;
+ mutex_lock(&effects->lock);
if (copy_from_user(&buf_cfg32, (void *)arg,
sizeof(buf_cfg32))) {
pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n",
__func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
break;
}
config->buf_cfg.input_len = buf_cfg32.input_len;
@@ -642,6 +670,7 @@
pr_debug("%s: write buf len: %d, read buf len: %d\n",
__func__, effects->config.buf_cfg.output_len,
effects->config.buf_cfg.input_len);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_GET_BUF_AVAIL32: {
@@ -649,6 +678,7 @@
memset(&buf_avail, 0, sizeof(buf_avail));
+ mutex_lock(&effects->lock);
buf_avail.input_num_avail = atomic_read(&effects->in_count);
buf_avail.output_num_avail = atomic_read(&effects->out_count);
pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
@@ -660,22 +690,26 @@
__func__);
rc = -EFAULT;
}
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_PP_PARAMS32: {
long argvalues[MAX_PP_PARAMS_SZ] = {0};
int argvalues32[MAX_PP_PARAMS_SZ] = {0};
+ mutex_lock(&effects->lock);
if (copy_from_user(argvalues32, (void *)arg,
MAX_PP_PARAMS_SZ*sizeof(int))) {
pr_err("%s: copy from user failed for pp params\n",
__func__);
+ mutex_unlock(&effects->lock);
return -EFAULT;
}
for (i = 0; i < MAX_PP_PARAMS_SZ; i++)
argvalues[i] = argvalues32[i];
rc = audio_effects_set_pp_param(effects, argvalues);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_START32: {
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
index c964dcb..3da46b6 100644
--- a/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
@@ -179,7 +179,7 @@
};
/* The opened devices container */
-static int s_opened_devs[MAX_DEVS_NUMBER];
+static atomic_t s_opened_devs[MAX_DEVS_NUMBER];
static struct wakeup_source usf_wakeup_source;
@@ -2348,14 +2348,11 @@
uint16_t ind = 0;
for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
- if (minor == s_opened_devs[ind]) {
+ if (minor == atomic_cmpxchg(&s_opened_devs[ind], 0, minor)) {
pr_err("%s: device %d is already opened\n",
__func__, minor);
return USF_UNDEF_DEV_ID;
- }
-
- if (s_opened_devs[ind] == 0) {
- s_opened_devs[ind] = minor;
+ } else {
pr_debug("%s: device %d is added; ind=%d\n",
__func__, minor, ind);
return ind;
@@ -2410,7 +2407,7 @@
usf_disable(&usf->usf_tx);
usf_disable(&usf->usf_rx);
- s_opened_devs[usf->dev_ind] = 0;
+ atomic_set(&s_opened_devs[usf->dev_ind], 0);
wakeup_source_trash(&usf_wakeup_source);
mutex_unlock(&usf->mutex);
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index a0fa943..771a1f9 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -4721,16 +4721,18 @@
}
}
-void msm_pcie_destroy_irq(unsigned int irq)
+void msm_pcie_destroy_irq(unsigned int irq, struct pci_dev *pdev)
{
int pos;
- struct pci_dev *pdev = irq_get_chip_data(irq);
struct msi_desc *entry = irq_get_msi_desc(irq);
struct msi_desc *firstentry;
struct msm_pcie_dev_t *dev;
u32 nvec;
int firstirq;
+ if (!pdev)
+ pdev = irq_get_chip_data(irq);
+
if (!pdev) {
pr_err("PCIe: pci device is null. IRQ:%d\n", irq);
return;
@@ -4789,7 +4791,7 @@
void arch_teardown_msi_irq(unsigned int irq)
{
PCIE_GEN_DBG("irq %d deallocated\n", irq);
- msm_pcie_destroy_irq(irq);
+ msm_pcie_destroy_irq(irq, NULL);
}
void arch_teardown_msi_irqs(struct pci_dev *dev)
@@ -4809,7 +4811,7 @@
continue;
nvec = 1 << entry->msi_attrib.multiple;
for (i = 0; i < nvec; i++)
- arch_teardown_msi_irq(entry->irq + i);
+ msm_pcie_destroy_irq(entry->irq + i, dev);
}
}
@@ -5004,7 +5006,6 @@
firstirq = irq;
irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
- irq_set_chip_data(irq, pdev);
}
/* write msi vector and data */
diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c
index 009e27bf..1ad6f62 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-lpi.c
@@ -118,12 +118,12 @@
0x00005010,
0x00005020,
0x00005030,
- 0x00005040,
- 0x00005050,
0x00006000,
0x00006010,
0x00007000,
0x00007010,
+ 0x00005040,
+ 0x00005050,
0x00008000,
0x00008010,
0x00008020,
@@ -406,13 +406,19 @@
static int lpi_notifier_service_cb(struct notifier_block *this,
unsigned long opcode, void *ptr)
{
+ static bool initial_boot = true;
+
pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
switch (opcode) {
case AUDIO_NOTIFIER_SERVICE_DOWN:
+ if (initial_boot)
+ break;
lpi_dev_up = false;
break;
case AUDIO_NOTIFIER_SERVICE_UP:
+ if (initial_boot)
+ initial_boot = false;
lpi_dev_up = true;
break;
default:
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index cd76ca2..8c43c4e 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -310,6 +310,7 @@
POWER_SUPPLY_ATTR(ctm_current_max),
POWER_SUPPLY_ATTR(hw_current_max),
POWER_SUPPLY_ATTR(real_type),
+ POWER_SUPPLY_ATTR(pr_swap),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index bf5f952..8641a45 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -551,8 +551,6 @@
power_supply_set_property(chip->main_psy,
POWER_SUPPLY_PROP_CURRENT_MAX,
&pval);
- /* wait for ICL change */
- msleep(100);
}
/* set the effective ICL */
@@ -560,9 +558,6 @@
power_supply_set_property(chip->main_psy,
POWER_SUPPLY_PROP_CURRENT_MAX,
&pval);
- if (rerun_aicl)
- /* wait for ICL change */
- msleep(100);
vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0);
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index e3ecf49..73d54c6 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -491,7 +491,7 @@
int i, mask = 0xff;
int64_t temp;
- temp = DIV_ROUND_CLOSEST(val * sp[id].numrtr, sp[id].denmtr);
+ temp = (int64_t)div_s64((s64)val * sp[id].numrtr, sp[id].denmtr);
pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val);
for (i = 0; i < sp[id].len; i++) {
buf[i] = temp & mask;
@@ -1320,9 +1320,16 @@
return rc;
}
- cc_soc_delta_pct = DIV_ROUND_CLOSEST(
- abs(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
- CC_SOC_30BIT);
+ cc_soc_delta_pct =
+ div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
+ CC_SOC_30BIT);
+
+ /* If the delta is < 50%, then skip processing full data */
+ if (cc_soc_delta_pct < 50) {
+ pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
+ return -ERANGE;
+ }
+
delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
100);
chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
@@ -1392,7 +1399,6 @@
return rc;
}
-#define FULL_SOC_RAW 255
static void fg_cap_learning_update(struct fg_chip *chip)
{
int rc, batt_soc, batt_soc_msb;
@@ -3937,7 +3943,7 @@
}
#define DEFAULT_CUTOFF_VOLT_MV 3200
-#define DEFAULT_EMPTY_VOLT_MV 2800
+#define DEFAULT_EMPTY_VOLT_MV 2850
#define DEFAULT_RECHARGE_VOLT_MV 4250
#define DEFAULT_CHG_TERM_CURR_MA 100
#define DEFAULT_CHG_TERM_BASE_CURR_MA 75
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 7a6f2ea..becce31 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -432,6 +432,7 @@
POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
POWER_SUPPLY_PROP_HW_CURRENT_MAX,
POWER_SUPPLY_PROP_REAL_TYPE,
+ POWER_SUPPLY_PROP_PR_SWAP,
};
static int smb2_usb_get_prop(struct power_supply *psy,
@@ -454,8 +455,7 @@
if (!val->intval)
break;
- rc = smblib_get_prop_typec_mode(chg, val);
- if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+ if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
chg->micro_usb_mode) &&
chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
val->intval = 0;
@@ -492,7 +492,7 @@
else if (chip->bad_part)
val->intval = POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
else
- rc = smblib_get_prop_typec_mode(chg, val);
+ val->intval = chg->typec_mode;
break;
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
if (chg->micro_usb_mode)
@@ -536,6 +536,9 @@
case POWER_SUPPLY_PROP_HW_CURRENT_MAX:
rc = smblib_get_charge_current(chg, &val->intval);
break;
+ case POWER_SUPPLY_PROP_PR_SWAP:
+ rc = smblib_get_prop_pr_swap_in_progress(chg, val);
+ break;
default:
pr_err("get prop %d is not supported in usb\n", psp);
rc = -EINVAL;
@@ -594,6 +597,9 @@
rc = vote(chg->usb_icl_votable, CTM_VOTER,
val->intval >= 0, val->intval);
break;
+ case POWER_SUPPLY_PROP_PR_SWAP:
+ rc = smblib_set_prop_pr_swap_in_progress(chg, val);
+ break;
default:
pr_err("set prop %d is not supported\n", psp);
rc = -EINVAL;
@@ -671,8 +677,7 @@
if (!val->intval)
break;
- rc = smblib_get_prop_typec_mode(chg, val);
- if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+ if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
chg->micro_usb_mode) &&
chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
val->intval = 1;
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 20ff26a..6ead522 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -637,6 +637,7 @@
/* reset both usbin current and voltage votes */
vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+ vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
@@ -839,7 +840,6 @@
{
int rc = 0;
bool override;
- union power_supply_propval pval;
/* suspend and return if 25mA or less is requested */
if (icl_ua < USBIN_25MA)
@@ -849,14 +849,8 @@
if (icl_ua == INT_MAX)
goto override_suspend_config;
- rc = smblib_get_prop_typec_mode(chg, &pval);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
- goto enable_icl_changed_interrupt;
- }
-
/* configure current */
- if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+ if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
rc = set_sdp_current(chg, icl_ua);
if (rc < 0) {
@@ -864,6 +858,7 @@
goto enable_icl_changed_interrupt;
}
} else {
+ set_sdp_current(chg, 100000);
rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
@@ -877,7 +872,7 @@
if (icl_ua == INT_MAX) {
/* remove override if no voters - hw defaults is desired */
override = false;
- } else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
+ } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
/* For std cable with type = SDP never override */
override = false;
@@ -917,15 +912,8 @@
int rc = 0;
u8 load_cfg;
bool override;
- union power_supply_propval pval;
- rc = smblib_get_prop_typec_mode(chg, &pval);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
- return rc;
- }
-
- if ((pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+ if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
|| chg->micro_usb_mode)
&& (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
rc = get_sdp_current(chg, icl_ua);
@@ -1895,38 +1883,18 @@
return rc;
smblib_dbg(chg, PR_MISC, "re-running AICL\n");
- switch (chg->smb_version) {
- case PMI8998_SUBTYPE:
- rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
- &settled_icl_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
- return rc;
- }
-
- vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
- max(settled_icl_ua - chg->param.usb_icl.step_u,
- chg->param.usb_icl.step_u));
- vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
- break;
- case PM660_SUBTYPE:
- /*
- * Use restart_AICL instead of trigger_AICL as it runs the
- * complete AICL instead of starting from the last settled
- * value.
- */
- rc = smblib_masked_write(chg, CMD_HVDCP_2_REG,
- RESTART_AICL_BIT, RESTART_AICL_BIT);
- if (rc < 0)
- smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
- rc);
- break;
- default:
- smblib_dbg(chg, PR_PARALLEL, "unknown SMB chip %d\n",
- chg->smb_version);
- return -EINVAL;
+ rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
+ &settled_icl_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
+ return rc;
}
+ vote(chg->usb_icl_votable, AICL_RERUN_VOTER, true,
+ max(settled_icl_ua - chg->param.usb_icl.step_u,
+ chg->param.usb_icl.step_u));
+ vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0);
+
return 0;
}
@@ -1961,6 +1929,7 @@
int smblib_dp_dm(struct smb_charger *chg, int val)
{
int target_icl_ua, rc = 0;
+ union power_supply_propval pval;
switch (val) {
case POWER_SUPPLY_DP_DM_DP_PULSE:
@@ -1978,10 +1947,35 @@
rc, chg->pulse_cnt);
break;
case POWER_SUPPLY_DP_DM_ICL_DOWN:
- chg->usb_icl_delta_ua -= 100000;
target_icl_ua = get_effective_result(chg->usb_icl_votable);
+ if (target_icl_ua < 0) {
+ /* no client vote, get the ICL from charger */
+ rc = power_supply_get_property(chg->usb_psy,
+ POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ smblib_err(chg,
+ "Couldn't get max current rc=%d\n",
+ rc);
+ return rc;
+ }
+ target_icl_ua = pval.intval;
+ }
+
+ /*
+ * Check if any other voter voted on USB_ICL in case of
+ * voter other than SW_QC3_VOTER reset and restart reduction
+ * again.
+ */
+ if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
+ SW_QC3_VOTER))
+ chg->usb_icl_delta_ua = 0;
+
+ chg->usb_icl_delta_ua += 100000;
vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
- target_icl_ua + chg->usb_icl_delta_ua);
+ target_icl_ua - 100000);
+ smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
+ target_icl_ua, chg->usb_icl_delta_ua);
break;
case POWER_SUPPLY_DP_DM_ICL_UP:
default:
@@ -2217,8 +2211,6 @@
static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
{
switch (chg->typec_status[0]) {
- case 0:
- return POWER_SUPPLY_TYPEC_NONE;
case UFP_TYPEC_RDSTD_BIT:
return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
case UFP_TYPEC_RD1P5_BIT:
@@ -2229,7 +2221,7 @@
break;
}
- return POWER_SUPPLY_TYPEC_NON_COMPLIANT;
+ return POWER_SUPPLY_TYPEC_NONE;
}
static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
@@ -2243,8 +2235,6 @@
return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
case DFP_RD_OPEN_BIT:
return POWER_SUPPLY_TYPEC_SINK;
- case DFP_RA_OPEN_BIT:
- return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
default:
break;
}
@@ -2252,20 +2242,12 @@
return POWER_SUPPLY_TYPEC_NONE;
}
-int smblib_get_prop_typec_mode(struct smb_charger *chg,
- union power_supply_propval *val)
+static int smblib_get_prop_typec_mode(struct smb_charger *chg)
{
- if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
- val->intval = POWER_SUPPLY_TYPEC_NONE;
- return 0;
- }
-
if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
- val->intval = smblib_get_prop_dfp_mode(chg);
+ return smblib_get_prop_dfp_mode(chg);
else
- val->intval = smblib_get_prop_ufp_mode(chg);
-
- return 0;
+ return smblib_get_prop_ufp_mode(chg);
}
int smblib_get_prop_typec_power_role(struct smb_charger *chg,
@@ -2553,24 +2535,12 @@
const union power_supply_propval *val)
{
int rc;
- bool orientation, cc_debounced, sink_attached, hvdcp;
+ bool orientation, sink_attached, hvdcp;
u8 stat;
if (!get_effective_result(chg->pd_allowed_votable))
return -EINVAL;
- rc = smblib_read(chg, APSD_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
- return rc;
- }
-
- cc_debounced = (bool)
- (chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- sink_attached = (bool)
- (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
- hvdcp = stat & QC_CHARGER_BIT;
-
chg->pd_active = val->intval;
if (chg->pd_active) {
vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
@@ -2622,6 +2592,14 @@
if (rc < 0)
smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
} else {
+ rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read APSD status rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ hvdcp = stat & QC_CHARGER_BIT;
vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
@@ -2641,8 +2619,8 @@
* and data could be interrupted. Non-legacy DCP could also draw
* more, but it may impact compliance.
*/
- if (!chg->typec_legacy_valid && cc_debounced &&
- !sink_attached && hvdcp)
+ sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
+ if (!chg->typec_legacy_valid && !sink_attached && hvdcp)
schedule_work(&chg->legacy_detection_work);
}
@@ -2764,6 +2742,7 @@
smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return rc;
}
+
ccout = (stat & CC_ATTACHED_BIT) ?
(!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
@@ -3600,6 +3579,7 @@
vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+ vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
/* reset hvdcp voters */
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
@@ -3630,6 +3610,11 @@
chg->pd_hard_reset = 0;
chg->typec_legacy_valid = false;
+ /* reset back to 120mS tCC debounce */
+ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
+
/* enable APSD CC trigger for next insertion */
rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
@@ -3670,12 +3655,29 @@
if (rc < 0)
smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
+ mutex_lock(&chg->vconn_oc_lock);
+ if (!chg->vconn_en)
+ goto unlock;
+
+ smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ VCONN_EN_VALUE_BIT, 0);
+ chg->vconn_en = false;
+
+unlock:
+ mutex_unlock(&chg->vconn_oc_lock);
+
+ /* clear exit sink based on cc */
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ EXIT_SNK_BASED_ON_CC_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
+ rc);
+
typec_sink_removal(chg);
smblib_update_usb_type(chg);
}
-static void smblib_handle_typec_insertion(struct smb_charger *chg,
- bool sink_attached)
+static void smblib_handle_typec_insertion(struct smb_charger *chg)
{
int rc;
@@ -3687,45 +3689,37 @@
smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
rc);
- if (sink_attached)
+ if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
typec_sink_insertion(chg);
else
typec_sink_removal(chg);
}
-static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
- bool rising, bool sink_attached)
+static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
{
- int rc;
- union power_supply_propval pval = {0, };
+ if (chg->pr_swap_in_progress)
+ return;
- if (rising) {
- if (!chg->typec_present) {
- chg->typec_present = true;
- smblib_dbg(chg, PR_MISC, "TypeC insertion\n");
- smblib_handle_typec_insertion(chg, sink_attached);
- }
- } else {
- if (chg->typec_present) {
- chg->typec_present = false;
- smblib_dbg(chg, PR_MISC, "TypeC removal\n");
- smblib_handle_typec_removal(chg);
- }
+ chg->typec_mode = smblib_get_prop_typec_mode(chg);
+ if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
+ chg->typec_present = true;
+ smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
+ smblib_typec_mode_name[chg->typec_mode]);
+ smblib_handle_typec_insertion(chg);
+ } else if (chg->typec_present &&
+ chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+ chg->typec_present = false;
+ smblib_dbg(chg, PR_MISC, "TypeC removal\n");
+ smblib_handle_typec_removal(chg);
}
- rc = smblib_get_prop_typec_mode(chg, &pval);
- if (rc < 0)
- smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
-
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
- rising ? "rising" : "falling",
- smblib_typec_mode_name[pval.intval]);
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
+ smblib_typec_mode_name[chg->typec_mode]);
}
static void smblib_usb_typec_change(struct smb_charger *chg)
{
int rc;
- bool debounce_done, sink_attached;
rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
chg->typec_status, 5);
@@ -3734,12 +3728,7 @@
return;
}
- debounce_done =
- (bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- sink_attached =
- (bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
-
- smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
+ smblib_handle_typec_cc_state_change(chg);
if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
@@ -3842,6 +3831,36 @@
return IRQ_HANDLED;
}
+/**************
+ * Additional USB PSY getters/setters
+ * that call interrupt functions
+ ***************/
+
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ val->intval = chg->pr_swap_in_progress;
+ return 0;
+}
+
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+ const union power_supply_propval *val)
+{
+ int rc;
+
+ chg->pr_swap_in_progress = val->intval;
+ /*
+ * call the cc changed irq to handle real removals while
+ * PR_SWAP was in progress
+ */
+ smblib_usb_typec_change(chg);
+ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
+ val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
+ return 0;
+}
+
/***************
* Work Queues *
***************/
@@ -4230,14 +4249,14 @@
chg->typec_legacy_valid = true;
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
- rp_high = smblib_get_prop_ufp_mode(chg) ==
- POWER_SUPPLY_TYPEC_SOURCE_HIGH;
+ rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
if (!legacy || !rp_high)
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
false, 0);
unlock:
chg->typec_en_dis_active = 0;
+ smblib_usb_typec_change(chg);
mutex_unlock(&chg->lock);
}
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 0c8e661..f39f2c9 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -321,6 +321,8 @@
u8 typec_status[5];
bool typec_legacy_valid;
int fake_input_current_limited;
+ bool pr_swap_in_progress;
+ int typec_mode;
/* workaround flag */
u32 wa_flags;
@@ -454,8 +456,6 @@
union power_supply_propval *val);
int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
union power_supply_propval *val);
-int smblib_get_prop_typec_mode(struct smb_charger *chg,
- union power_supply_propval *val);
int smblib_get_prop_typec_power_role(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_pd_allowed(struct smb_charger *chg,
@@ -508,6 +508,10 @@
int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua);
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+ union power_supply_propval *val);
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+ const union power_supply_propval *val);
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index 167666a..d8671ab 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -486,11 +486,11 @@
#define UFP_TYPEC_OPEN_OPEN_BIT BIT(0)
#define TYPE_C_STATUS_2_REG (USBIN_BASE + 0x0C)
-#define DFP_TYPEC_MASK 0x8F
#define DFP_RA_OPEN_BIT BIT(7)
#define TIMER_STAGE_BIT BIT(6)
#define EXIT_UFP_MODE_BIT BIT(5)
#define EXIT_DFP_MODE_BIT BIT(4)
+#define DFP_TYPEC_MASK GENMASK(3, 0)
#define DFP_RD_OPEN_BIT BIT(3)
#define DFP_RD_RA_VCONN_BIT BIT(2)
#define DFP_RD_RD_BIT BIT(1)
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index b92a482..a464a81 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -1416,6 +1416,7 @@
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_PARALLEL_MODE,
+ POWER_SUPPLY_PROP_INPUT_SUSPEND,
};
static int smb1351_parallel_set_chg_suspend(struct smb1351_charger *chip,
@@ -1702,6 +1703,9 @@
case POWER_SUPPLY_PROP_PARALLEL_MODE:
val->intval = chip->parallel_mode;
break;
+ case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+ val->intval = chip->parallel_charger_suspended;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 83374bb..ca0a2c6 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -248,7 +248,7 @@
val->intval = chg->usb_psy_desc.type;
break;
case POWER_SUPPLY_PROP_TYPEC_MODE:
- rc = smblib_get_prop_typec_mode(chg, val);
+ val->intval = chg->typec_mode;
break;
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
rc = smblib_get_prop_typec_power_role(chg, val);
@@ -941,13 +941,6 @@
return rc;
}
- rc = smblib_write(chg, THERMREG_SRC_CFG_REG,
- THERMREG_SKIN_ADC_SRC_EN_BIT);
- if (rc < 0) {
- pr_err("Couldn't enable connector thermreg source rc=%d\n", rc);
- return rc;
- }
-
return 0;
}
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 1b283b2..db4e7bb 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -83,6 +83,8 @@
tristate "QCOM specific hooks to UFS controller platform driver"
depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM
select PHY_QCOM_UFS
+ select EXTCON
+ select EXTCON_GPIO
help
This selects the QCOM specific additions to UFSHCD platform driver.
UFS host on QCOM needs some vendor specific configuration before
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index de6ecbd..7c5a1bc 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -327,6 +327,20 @@
return ret;
}
+static int ufshcd_parse_extcon_info(struct ufs_hba *hba)
+{
+ struct extcon_dev *extcon;
+
+ extcon = extcon_get_edev_by_phandle(hba->dev, 0);
+ if (IS_ERR(extcon) && PTR_ERR(extcon) != -ENODEV)
+ return PTR_ERR(extcon);
+
+ if (!IS_ERR(extcon))
+ hba->extcon = extcon;
+
+ return 0;
+}
+
#ifdef CONFIG_SMP
/**
* ufshcd_pltfrm_suspend - suspend power management function
@@ -449,6 +463,9 @@
ufshcd_parse_pm_levels(hba);
ufshcd_parse_gear_limits(hba);
ufshcd_parse_cmd_timeout(hba);
+ err = ufshcd_parse_extcon_info(hba);
+ if (err)
+ goto dealloc_host;
if (!dev->dma_mask)
dev->dma_mask = &dev->coherent_dma_mask;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 77ba414..d35c722 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -534,7 +534,7 @@
*val = ' ';
}
-#define UFSHCD_MAX_CMD_LOGGING 100
+#define UFSHCD_MAX_CMD_LOGGING 200
#ifdef CONFIG_TRACEPOINTS
static inline void ufshcd_add_command_trace(struct ufs_hba *hba,
@@ -610,7 +610,7 @@
ufshcd_cmd_log(hba, str, "dme", 0xff, cmd_id, 0xff);
}
-static void ufshcd_cmd_log_print(struct ufs_hba *hba)
+static void ufshcd_print_cmd_log(struct ufs_hba *hba)
{
int i;
int pos;
@@ -659,7 +659,7 @@
{
}
-static void ufshcd_cmd_log_print(struct ufs_hba *hba)
+static void ufshcd_print_cmd_log(struct ufs_hba *hba)
{
}
#endif
@@ -4334,6 +4334,7 @@
ufshcd_print_host_state(hba);
ufshcd_print_pwr_info(hba);
ufshcd_print_host_regs(hba);
+ ufshcd_print_cmd_log(hba);
}
ufshcd_save_tstamp_of_last_dme_cmd(hba);
@@ -6181,7 +6182,7 @@
ufshcd_print_host_state(hba);
ufshcd_print_pwr_info(hba);
ufshcd_print_tmrs(hba, hba->outstanding_tasks);
- ufshcd_cmd_log_print(hba);
+ ufshcd_print_cmd_log(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
}
}
@@ -6693,7 +6694,7 @@
hba = shost_priv(host);
tag = cmd->request->tag;
- ufshcd_cmd_log_print(hba);
+ ufshcd_print_cmd_log(hba);
lrbp = &hba->lrb[tag];
err = ufshcd_issue_tm_cmd(hba, lrbp->lun, 0, UFS_LOGICAL_RESET, &resp);
if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
@@ -6965,6 +6966,23 @@
return err;
}
+static int ufshcd_detect_device(struct ufs_hba *hba)
+{
+ int err = 0;
+
+ err = ufshcd_vops_full_reset(hba);
+ if (err)
+ dev_warn(hba->dev, "%s: full reset returned %d\n",
+ __func__, err);
+
+ err = ufshcd_reset_device(hba);
+ if (err)
+ dev_warn(hba->dev, "%s: device reset failed. err %d\n",
+ __func__, err);
+
+ return ufshcd_host_reset_and_restore(hba);
+}
+
/**
* ufshcd_reset_and_restore - reset and re-initialize host/device
* @hba: per-adapter instance
@@ -6981,26 +6999,10 @@
int retries = MAX_HOST_RESET_RETRIES;
do {
- err = ufshcd_vops_full_reset(hba);
- if (err)
- dev_warn(hba->dev, "%s: full reset returned %d\n",
- __func__, err);
-
- err = ufshcd_reset_device(hba);
- if (err)
- dev_warn(hba->dev, "%s: device reset failed. err %d\n",
- __func__, err);
-
- err = ufshcd_host_reset_and_restore(hba);
+ err = ufshcd_detect_device(hba);
} while (err && --retries);
/*
- * There is no point proceeding even after failing
- * to recover after multiple retries.
- */
- if (err)
- BUG();
- /*
* After reset the door-bell might be cleared, complete
* outstanding requests in s/w here.
*/
@@ -7703,10 +7705,8 @@
* If we failed to initialize the device or the device is not
* present, turn off the power/clocks etc.
*/
- if (ret && !ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress) {
+ if (ret && !ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress)
pm_runtime_put_sync(hba->dev);
- ufshcd_hba_exit(hba);
- }
trace_ufshcd_init(dev_name(hba->dev), ret,
ktime_to_us(ktime_sub(ktime_get(), start)),
@@ -7714,6 +7714,70 @@
return ret;
}
+static void ufshcd_card_detect_handler(struct work_struct *work)
+{
+ struct ufs_hba *hba;
+
+ hba = container_of(work, struct ufs_hba, card_detect_work);
+ if (hba->card_detect_event &&
+ (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)) {
+ dev_dbg(hba->dev, "%s: card detect notification received\n",
+ __func__);
+ pm_runtime_get_sync(hba->dev);
+ ufshcd_detect_device(hba);
+ pm_runtime_put_sync(hba->dev);
+ } else {
+ dev_dbg(hba->dev, "%s: card removed notification received\n",
+ __func__);
+ /* TODO: remove the scsi device instances */
+ }
+}
+
+static int ufshcd_card_detect_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct ufs_hba *hba = container_of(nb, struct ufs_hba, card_detect_nb);
+
+ hba->card_detect_event = event;
+ schedule_work(&hba->card_detect_work);
+
+ return NOTIFY_DONE;
+}
+
+static int ufshcd_extcon_register(struct ufs_hba *hba)
+{
+ int ret;
+
+ if (!hba->extcon)
+ return 0;
+
+ hba->card_detect_nb.notifier_call = ufshcd_card_detect_notifier;
+ ret = extcon_register_notifier(hba->extcon,
+ EXTCON_MECHANICAL,
+ &hba->card_detect_nb);
+ if (ret)
+ dev_err(hba->dev, "%s: extcon_register_notifier() failed, ret %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static int ufshcd_extcon_unregister(struct ufs_hba *hba)
+{
+ int ret;
+
+ if (!hba->extcon)
+ return 0;
+
+ ret = extcon_unregister_notifier(hba->extcon, EXTCON_MECHANICAL,
+ &hba->card_detect_nb);
+ if (ret)
+ dev_err(hba->dev, "%s: extcon_unregister_notifier() failed, ret %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
/**
* ufshcd_async_scan - asynchronous execution for probing hba
* @data: data pointer to pass to this function
@@ -7730,6 +7794,8 @@
ufshcd_hold_all(hba);
ufshcd_probe_hba(hba);
ufshcd_release_all(hba);
+
+ ufshcd_extcon_register(hba);
}
/**
@@ -8439,20 +8505,9 @@
err = ufshcd_vops_init(hba);
if (err)
- goto out;
-
- err = ufshcd_vops_setup_regulators(hba, true);
- if (err)
- goto out_exit;
-
- goto out;
-
-out_exit:
- ufshcd_vops_exit(hba);
-out:
- if (err)
dev_err(hba->dev, "%s: variant %s init failed err %d\n",
__func__, ufshcd_get_var_name(hba), err);
+out:
return err;
}
@@ -8461,8 +8516,6 @@
if (!hba->var || !hba->var->vops)
return;
- ufshcd_vops_setup_regulators(hba, false);
-
ufshcd_vops_exit(hba);
}
@@ -8521,6 +8574,7 @@
static void ufshcd_hba_exit(struct ufs_hba *hba)
{
if (hba->is_powered) {
+ ufshcd_extcon_unregister(hba);
ufshcd_variant_hba_exit(hba);
ufshcd_setup_vreg(hba, false);
if (ufshcd_is_clkscaling_supported(hba)) {
@@ -8825,10 +8879,8 @@
goto enable_gating;
/* UFS device & link must be active before we enter in this function */
- if (!ufshcd_is_ufs_dev_active(hba) || !ufshcd_is_link_active(hba)) {
- ret = -EINVAL;
- goto enable_gating;
- }
+ if (!ufshcd_is_ufs_dev_active(hba) || !ufshcd_is_link_active(hba))
+ goto set_vreg_lpm;
if (ufshcd_is_runtime_pm(pm_op)) {
if (ufshcd_can_autobkops_during_suspend(hba)) {
@@ -8864,6 +8916,7 @@
ufshcd_is_hibern8_on_idle_allowed(hba))
hba->hibern8_on_idle.state = HIBERN8_ENTERED;
+set_vreg_lpm:
ufshcd_vreg_set_lpm(hba);
disable_clks:
@@ -8966,6 +9019,9 @@
if (ret)
goto disable_vreg;
+ if (ufshcd_is_link_off(hba))
+ goto skip_dev_ops;
+
if (ufshcd_is_link_hibern8(hba)) {
ret = ufshcd_uic_hibern8_exit(hba);
if (!ret) {
@@ -9013,6 +9069,7 @@
if (hba->clk_scaling.is_allowed)
ufshcd_resume_clkscaling(hba);
+skip_dev_ops:
/* Schedule clock gating in case of no access to UFS device yet */
ufshcd_release_all(hba);
goto out;
@@ -10074,6 +10131,7 @@
/* Initialize work queues */
INIT_WORK(&hba->eh_work, ufshcd_err_handler);
INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler);
+ INIT_WORK(&hba->card_detect_work, ufshcd_card_detect_handler);
/* Initialize UIC command mutex */
mutex_init(&hba->uic_cmd_mutex);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index c61a753..a485885 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -57,6 +57,7 @@
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
+#include <linux/extcon.h>
#include "unipro.h"
#include <asm/irq.h>
@@ -724,6 +725,10 @@
* @ufs_stats: ufshcd statistics to be used via debugfs
* @debugfs_files: debugfs files associated with the ufs stats
* @ufshcd_dbg_print: Bitmask for enabling debug prints
+ * @extcon: pointer to external connector device
+ * @card_detect_nb: card detector notifier registered with @extcon
+ * @card_detect_work: work to exectute the card detect function
+ * @card_detect_event: card detect event, 0 = removed, 1 = inserted
* @vreg_info: UFS device voltage regulator information
* @clk_list_head: UFS host controller clocks list node head
* @pwr_info: holds current power mode
@@ -896,6 +901,11 @@
/* Bitmask for enabling debug prints */
u32 ufshcd_dbg_print;
+ struct extcon_dev *extcon;
+ struct notifier_block card_detect_nb;
+ struct work_struct card_detect_work;
+ unsigned long card_detect_event;
+
struct ufs_pa_layer_attr pwr_info;
struct ufs_pwr_mode_info max_pwr_info;
diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c
index 42f146d..585836a 100644
--- a/drivers/soc/qcom/dcc_v2.c
+++ b/drivers/soc/qcom/dcc_v2.c
@@ -1143,8 +1143,16 @@
mutex_lock(&drvdata->mutex);
- if (kstrtoul(buf, 16, &loop_cnt))
+ if (kstrtoul(buf, 16, &loop_cnt)) {
ret = -EINVAL;
+ goto err;
+ }
+
+ if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
+ dev_err(dev, "Select link list to program using curr_list\n");
+ ret = -EINVAL;
+ goto err;
+ }
entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
if (!entry) {
@@ -1154,6 +1162,7 @@
entry->loop_cnt = min_t(uint32_t, loop_cnt, MAX_LOOP_CNT);
entry->index = drvdata->nr_config[drvdata->curr_list]++;
+ entry->desc_type = DCC_LOOP_TYPE;
INIT_LIST_HEAD(&entry->list);
list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);
@@ -1221,12 +1230,13 @@
nval = sscanf(buf, "%x %x %d", &addr, &write_val, &apb_bus);
- if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
- dev_err(dev, "Select link list to program using curr_list\n");
- return -EINVAL;
+ if (nval <= 1 || nval > 3) {
+ ret = -EINVAL;
+ goto err;
}
- if (nval <= 1 || nval > 3) {
+ if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
+ dev_err(dev, "Select link list to program using curr_list\n");
ret = -EINVAL;
goto err;
}
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
index 5d860a3..efa2e42 100644
--- a/drivers/soc/qcom/qdsp6v2/apr.c
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -515,19 +515,19 @@
mutex_unlock(&svc->m_lock);
return NULL;
}
- if (!svc->port_cnt && !svc->svc_cnt)
+ if (!svc->svc_cnt)
clnt->svc_cnt++;
svc->port_cnt++;
svc->port_fn[temp_port] = svc_fn;
svc->port_priv[temp_port] = priv;
+ svc->svc_cnt++;
} else {
if (!svc->fn) {
- if (!svc->port_cnt && !svc->svc_cnt)
+ if (!svc->svc_cnt)
clnt->svc_cnt++;
svc->fn = svc_fn;
- if (svc->port_cnt)
- svc->svc_cnt++;
svc->priv = priv;
+ svc->svc_cnt++;
}
}
@@ -746,29 +746,28 @@
if (!handle)
return -EINVAL;
+ if (!svc->svc_cnt) {
+ pr_err("%s: svc already deregistered. svc = %pK\n",
+ __func__, svc);
+ return -EINVAL;
+ }
+
mutex_lock(&svc->m_lock);
dest_id = svc->dest_id;
client_id = svc->client_id;
clnt = &client[dest_id][client_id];
- if (svc->port_cnt > 0 || svc->svc_cnt > 0) {
+ if (svc->svc_cnt > 0) {
if (svc->port_cnt)
svc->port_cnt--;
- else if (svc->svc_cnt)
- svc->svc_cnt--;
- if (!svc->port_cnt && !svc->svc_cnt) {
+ svc->svc_cnt--;
+ if (!svc->svc_cnt) {
client[dest_id][client_id].svc_cnt--;
- svc->need_reset = 0x0;
- }
- } else if (client[dest_id][client_id].svc_cnt > 0) {
- client[dest_id][client_id].svc_cnt--;
- if (!client[dest_id][client_id].svc_cnt) {
- svc->need_reset = 0x0;
pr_debug("%s: service is reset %pK\n", __func__, svc);
}
}
- if (!svc->port_cnt && !svc->svc_cnt) {
+ if (!svc->svc_cnt) {
svc->priv = NULL;
svc->id = 0;
svc->fn = NULL;
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 40aac6a..92a97fae 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -97,8 +97,7 @@
unsigned long flags;
spin_lock_irqsave(&apr_ch->w_lock, flags);
- rc = glink_tx(apr_ch->handle, pkt_priv, data, len,
- GLINK_TX_REQ_INTENT | GLINK_TX_ATOMIC);
+ rc = glink_tx(apr_ch->handle, pkt_priv, data, len, GLINK_TX_ATOMIC);
spin_unlock_irqrestore(&apr_ch->w_lock, flags);
if (rc)
diff --git a/drivers/soc/qcom/qdsp6v2/audio_notifier.c b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
index 414c123..2320fea 100644
--- a/drivers/soc/qcom/qdsp6v2/audio_notifier.c
+++ b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
@@ -626,9 +626,11 @@
* If pdr registration failed, register clients on next service
* Do in late init to ensure that SSR subsystem is initialized
*/
+ mutex_lock(¬ifier_mutex);
if (!audio_notifer_is_service_enabled(AUDIO_NOTIFIER_PDR_SERVICE))
audio_notifer_reg_all_clients();
+ mutex_unlock(¬ifier_mutex);
return 0;
}
late_initcall(audio_notifier_late_init);
diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c
index 034ddd3..3313122 100644
--- a/drivers/soc/qcom/wcd-dsp-glink.c
+++ b/drivers/soc/qcom/wcd-dsp-glink.c
@@ -531,6 +531,13 @@
u8 *payload;
u32 ch_size, ch_cfg_size;
+ mutex_lock(&wpriv->glink_mutex);
+ if (wpriv->ch) {
+ dev_err(wpriv->dev, "%s: glink ch memory is already allocated\n",
+ __func__);
+ ret = -EINVAL;
+ goto done;
+ }
payload = (u8 *)pkt->payload;
no_of_channels = pkt->no_of_channels;
@@ -611,6 +618,7 @@
wpriv->no_of_channels = 0;
done:
+ mutex_unlock(&wpriv->glink_mutex);
return ret;
}
diff --git a/drivers/soundwire/soundwire.c b/drivers/soundwire/soundwire.c
index 68655a5..f0c7aa9 100644
--- a/drivers/soundwire/soundwire.c
+++ b/drivers/soundwire/soundwire.c
@@ -68,6 +68,27 @@
}
/**
+ * swr_remove_device - remove a soundwire device
+ * @swr_dev: soundwire device to remove
+ *
+ * Remove a soundwire device. Go through the soundwire
+ * device list that master has and remove swr_dev from
+ * it.
+ */
+void swr_remove_device(struct swr_device *swr_dev)
+{
+ struct swr_device *swr_dev_loop, *safe;
+
+ list_for_each_entry_safe(swr_dev_loop, safe,
+ &swr_dev->master->devices,
+ dev_list) {
+ if (swr_dev == swr_dev_loop)
+ list_del(&swr_dev_loop->dev_list);
+ }
+}
+EXPORT_SYMBOL(swr_remove_device);
+
+/**
* swr_new_device - instantiate a new soundwire device
* @master: Controller to which device is connected
* @info: Describes the soundwire device
@@ -128,47 +149,6 @@
EXPORT_SYMBOL(swr_new_device);
/**
- * swr_startup_devices - perform additional initialization for child devices
- *
- * @swr_dev: pointer to soundwire slave device
- *
- * Performs any additional initialization needed for a soundwire slave device.
- * This is a optional functionality defined by slave devices.
- * Removes the slave node from the list, in case there is any failure.
- */
-int swr_startup_devices(struct swr_device *swr_dev)
-{
- struct swr_driver *swr_drv;
- struct device *dev;
- int ret = 0;
-
- if (!swr_dev)
- return -EINVAL;
-
- dev = &swr_dev->dev;
- if (!dev)
- return -EINVAL;
-
- swr_drv = to_swr_driver(dev->driver);
- if (!swr_drv)
- return -EINVAL;
-
- if (swr_drv->startup) {
- ret = swr_drv->startup(swr_dev);
- if (ret)
- goto out;
-
- dev_dbg(&swr_dev->dev,
- "%s: startup complete for device %lx\n",
- __func__, swr_dev->addr);
- }
-
-out:
- return ret;
-}
-EXPORT_SYMBOL(swr_startup_devices);
-
-/**
* of_register_swr_devices - register child devices on to the soundwire bus
* @master: pointer to soundwire master device
*
@@ -202,14 +182,15 @@
}
info.addr = addr;
info.of_node = of_node_get(node);
+ master->num_dev++;
swr = swr_new_device(master, &info);
if (!swr) {
dev_err(&master->dev, "of_swr: Register failed %s\n",
node->full_name);
of_node_put(node);
+ master->num_dev--;
continue;
}
- master->num_dev++;
}
return 0;
}
@@ -605,7 +586,7 @@
dev = &swr_dev->dev;
sdrv = to_swr_driver(dev->driver);
if (!sdrv)
- return -EINVAL;
+ return 0;
if (sdrv->device_up)
return sdrv->device_up(to_swr_device(dev));
@@ -633,7 +614,7 @@
dev = &swr_dev->dev;
sdrv = to_swr_driver(dev->driver);
if (!sdrv)
- return -EINVAL;
+ return 0;
if (sdrv->device_down)
return sdrv->device_down(to_swr_device(dev));
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index ce2a367..e338d58 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -223,6 +223,12 @@
static struct dentry *debugfs_reg_dump;
static unsigned int read_data;
+
+static bool swrm_is_msm_variant(int val)
+{
+ return (val == SWRM_VERSION_1_3);
+}
+
static int swrm_debug_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -513,8 +519,17 @@
__func__, val, ret);
goto err;
}
- if (cmd_id == 0xF)
- wait_for_completion_timeout(&swrm->broadcast, (2 * HZ/10));
+ if (cmd_id == 0xF) {
+ /*
+ * sleep for 10ms for MSM soundwire variant to allow broadcast
+ * command to complete.
+ */
+ if (swrm_is_msm_variant(swrm->version))
+ usleep_range(10000, 10100);
+ else
+ wait_for_completion_timeout(&swrm->broadcast,
+ (2 * HZ/10));
+ }
err:
return ret;
}
@@ -1355,7 +1370,6 @@
{
struct swr_mstr_ctrl *swrm;
struct swr_ctrl_platform_data *pdata;
- struct swr_device *swr_dev, *safe;
int ret;
/* Allocate soundwire master driver structure */
@@ -1454,9 +1468,6 @@
goto err_mstr_fail;
}
- if (pdev->dev.of_node)
- of_register_swr_devices(&swrm->master);
-
/* Add devices registered with board-info as the
* controller will be up now
*/
@@ -1471,16 +1482,13 @@
mutex_unlock(&swrm->mlock);
goto err_mstr_fail;
}
+ swrm->version = swrm->read(swrm->handle, SWRM_COMP_HW_VERSION);
- /* Enumerate slave devices */
- list_for_each_entry_safe(swr_dev, safe, &swrm->master.devices,
- dev_list) {
- ret = swr_startup_devices(swr_dev);
- if (ret)
- list_del(&swr_dev->dev_list);
- }
mutex_unlock(&swrm->mlock);
+ if (pdev->dev.of_node)
+ of_register_swr_devices(&swrm->master);
+
dbgswrm = swrm;
debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
if (!IS_ERR(debugfs_swrm_dent)) {
diff --git a/drivers/soundwire/swr-wcd-ctrl.h b/drivers/soundwire/swr-wcd-ctrl.h
index 8992318..b7a3eda 100644
--- a/drivers/soundwire/swr-wcd-ctrl.h
+++ b/drivers/soundwire/swr-wcd-ctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -23,6 +23,10 @@
#define SWR_MSTR_PORT_LEN 8 /* Number of master ports */
+#define SWRM_VERSION_1_0 0x01010000
+#define SWRM_VERSION_1_2 0x01030000
+#define SWRM_VERSION_1_3 0x01040000
+
enum {
SWR_MSTR_PAUSE,
SWR_MSTR_RESUME,
@@ -88,6 +92,7 @@
int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
void *data), void *swr_handle, int type);
int irq;
+ int version;
int num_enum_slaves;
int slave_status;
struct swr_mstr_port *mstr_port;
diff --git a/drivers/soundwire/swrm_registers.h b/drivers/soundwire/swrm_registers.h
index c6923f3..50c3ecf 100644
--- a/drivers/soundwire/swrm_registers.h
+++ b/drivers/soundwire/swrm_registers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
#define SWRM_BASE_ADDRESS 0x00
+#define SWRM_COMP_HW_VERSION SWRM_BASE_ADDRESS
#define SWRM_COMP_CFG_ADDR (SWRM_BASE_ADDRESS+0x00000004)
#define SWRM_COMP_CFG_RMSK 0x3
#define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_BMSK 0x2
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 8c06e6a..f383e32 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -594,6 +594,8 @@
static void pd_send_hard_reset(struct usbpd *pd)
{
+ union power_supply_propval val = {0};
+
usbpd_dbg(&pd->dev, "send hard reset");
/* Force CC logic to source/sink to keep Rp/Rd unchanged */
@@ -601,6 +603,7 @@
pd->hard_reset_count++;
pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
pd->in_pr_swap = false;
+ power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val);
}
static void kick_sm(struct usbpd *pd, int ms)
@@ -744,6 +747,15 @@
break;
/* Source states */
+ case PE_SRC_DISABLED:
+ /* are we still connected? */
+ if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+ pd->current_pr = PR_NONE;
+ kick_sm(pd, 0);
+ }
+
+ break;
+
case PE_SRC_STARTUP:
if (pd->current_dr == DR_NONE) {
pd->current_dr = DR_DFP;
@@ -787,6 +799,9 @@
if (pd->in_pr_swap) {
kick_sm(pd, SWAP_SOURCE_START_TIME);
pd->in_pr_swap = false;
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
break;
}
@@ -869,6 +884,10 @@
case PE_SRC_HARD_RESET:
case PE_SNK_HARD_RESET:
+ /* are we still connected? */
+ if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE)
+ pd->current_pr = PR_NONE;
+
/* hard reset may sleep; handle it in the workqueue */
kick_sm(pd, 0);
break;
@@ -1572,7 +1591,6 @@
memset(&pd->received_pdos, 0, sizeof(pd->received_pdos));
rx_msg_cleanup(pd);
- val.intval = 0;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
@@ -1602,6 +1620,10 @@
usleep_range(ERROR_RECOVERY_TIME * USEC_PER_MSEC,
(ERROR_RECOVERY_TIME + 5) * USEC_PER_MSEC);
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
+
/* set due to dual_role class "mode" change */
if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
val.intval = pd->forced_pr;
@@ -1637,6 +1659,10 @@
POWER_SUPPLY_PROP_VOLTAGE_MIN, &val);
pd->in_pr_swap = false;
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
+
pd->in_explicit_contract = false;
pd->selected_pdo = pd->requested_pdo = 0;
pd->rdo = 0;
@@ -1897,6 +1923,9 @@
case PE_SNK_WAIT_FOR_CAPABILITIES:
pd->in_pr_swap = false;
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) {
val.intval = 0;
@@ -1916,15 +1945,6 @@
POWER_SUPPLY_PROP_PD_ACTIVE, &val);
} else if (pd->hard_reset_count < 3) {
usbpd_set_state(pd, PE_SNK_HARD_RESET);
- } else if (pd->pd_connected) {
- usbpd_info(&pd->dev, "Sink hard reset count exceeded, forcing reconnect\n");
-
- val.intval = 0;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_IN_HARD_RESET,
- &val);
-
- usbpd_set_state(pd, PE_ERROR_RECOVERY);
} else {
usbpd_dbg(&pd->dev, "Sink hard reset count exceeded, disabling PD\n");
@@ -2072,6 +2092,9 @@
}
pd->in_pr_swap = true;
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
break;
} else if (IS_CTRL(rx_msg, MSG_VCONN_SWAP)) {
@@ -2215,6 +2238,9 @@
case PE_PRS_SRC_SNK_TRANSITION_TO_OFF:
pd->in_pr_swap = true;
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
pd->in_explicit_contract = false;
if (pd->vbus_enabled) {
@@ -2255,6 +2281,9 @@
}
pd->in_pr_swap = true;
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
break;
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 72f0721..bbc65ef 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -450,6 +450,12 @@
};
#define SOFTIRQ_STOP_IDLE_MASK (~(1 << RCU_SOFTIRQ))
+/* Softirq's where the handling might be long: */
+#define LONG_SOFTIRQ_MASK ((1 << NET_TX_SOFTIRQ) | \
+ (1 << NET_RX_SOFTIRQ) | \
+ (1 << BLOCK_SOFTIRQ) | \
+ (1 << IRQ_POLL_SOFTIRQ) | \
+ (1 << TASKLET_SOFTIRQ))
/* map softirq index to softirq name. update 'softirq_to_name' in
* kernel/softirq.c when adding a new softirq.
@@ -485,6 +491,7 @@
extern void raise_softirq(unsigned int nr);
DECLARE_PER_CPU(struct task_struct *, ksoftirqd);
+DECLARE_PER_CPU(__u32, active_softirqs);
static inline struct task_struct *this_cpu_ksoftirqd(void)
{
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 72f9211..4381570 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -248,6 +248,7 @@
POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
POWER_SUPPLY_PROP_HW_CURRENT_MAX,
POWER_SUPPLY_PROP_REAL_TYPE,
+ POWER_SUPPLY_PROP_PR_SWAP,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/linux/soundwire/soundwire.h b/include/linux/soundwire/soundwire.h
index 752a001..a60d78c 100644
--- a/include/linux/soundwire/soundwire.h
+++ b/include/linux/soundwire/soundwire.h
@@ -196,7 +196,6 @@
* @shutdown: standard shutdown callback used during power down/halt
* @suspend: standard suspend callback used during system suspend
* @resume: standard resume callback used during system resume
- * @startup: additional init operation for slave devices
* @driver: soundwire device drivers should initialize name and
* owner field of this structure
* @id_table: list of soundwire devices supported by this driver
@@ -210,7 +209,6 @@
int (*device_up)(struct swr_device *swr);
int (*device_down)(struct swr_device *swr);
int (*reset_device)(struct swr_device *swr);
- int (*startup)(struct swr_device *swr);
struct device_driver driver;
const struct swr_device_id *id_table;
};
@@ -309,4 +307,6 @@
extern int swr_slvdev_datapath_control(struct swr_device *swr_dev, u8 dev_num,
bool enable);
extern int swr_remove_from_group(struct swr_device *dev, u8 dev_num);
+
+extern void swr_remove_device(struct swr_device *swr_dev);
#endif /* _LINUX_SOUNDWIRE_H */
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 7a09cb1..27963e8 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -444,6 +444,11 @@
*/
} __packed;
+#define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213
+#define ASM_STREAM_PP_EVENT 0x00013214
+#define DSP_STREAM_CMD "ADSP Stream Cmd"
+#define DSP_STREAM_CALLBACK "ADSP Stream Callback Event"
+
/* set customized mixing on matrix mixer */
#define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344
struct adm_cmd_set_pspd_mtmx_strtr_params_v5 {
@@ -5054,6 +5059,7 @@
#define ASM_MEDIA_FMT_VORBIS 0x00010C15
#define ASM_MEDIA_FMT_APE 0x00012F32
#define ASM_MEDIA_FMT_DSD 0x00012F3E
+#define ASM_MEDIA_FMT_TRUEHD 0x00013215
/* Media format ID for adaptive transform acoustic coding. This
* ID is used by the #ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED command
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 6bc93f5..dd3a043 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -55,6 +55,7 @@
#define FORMAT_DSD 0x001d
#define FORMAT_APTX 0x001e
#define FORMAT_GEN_COMPR 0x001f
+#define FORMAT_TRUEHD 0x0020
#define ENCDEC_SBCBITRATE 0x0001
#define ENCDEC_IMMEDIATE_DECODE 0x0002
@@ -211,6 +212,7 @@
int session;
app_cb cb;
atomic_t cmd_state;
+ atomic_t cmd_state_pp;
/* Relative or absolute TS */
atomic_t time_flag;
atomic_t nowait_cmd_cnt;
@@ -617,6 +619,9 @@
int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
uint32_t params_length);
+int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode,
+ void *param, uint32_t params_length);
+
/* Client can set the IO mode to either AIO/SIO mode */
int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);
diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h
index 09593e7..8c84053 100644
--- a/include/uapi/sound/compress_params.h
+++ b/include/uapi/sound/compress_params.h
@@ -105,7 +105,8 @@
#define SND_AUDIOCODEC_APE ((__u32) 0x00000021)
#define SND_AUDIOCODEC_DSD ((__u32) 0x00000022)
#define SND_AUDIOCODEC_APTX ((__u32) 0x00000023)
-#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_APTX
+#define SND_AUDIOCODEC_TRUEHD ((__u32) 0x00000024)
+#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_TRUEHD
/*
* Profile and modes are listed with bit masks. This allows for a
diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c
index 11e9705..ba5e3e2 100644
--- a/kernel/sched/cpupri.c
+++ b/kernel/sched/cpupri.c
@@ -27,6 +27,8 @@
* of the License.
*/
+#include "sched.h"
+
#include <linux/gfp.h>
#include <linux/sched.h>
#include <linux/sched/rt.h>
@@ -51,6 +53,27 @@
}
/**
+ * drop_nopreempt_cpus - remove a cpu from the mask if it is likely
+ * non-preemptible
+ * @lowest_mask: mask with selected CPUs (non-NULL)
+ */
+static void
+drop_nopreempt_cpus(struct cpumask *lowest_mask)
+{
+ unsigned int cpu = cpumask_first(lowest_mask);
+
+ while (cpu < nr_cpu_ids) {
+ /* unlocked access */
+ struct task_struct *task = READ_ONCE(cpu_rq(cpu)->curr);
+
+ if (task_may_not_preempt(task, cpu))
+ cpumask_clear_cpu(cpu, lowest_mask);
+
+ cpu = cpumask_next(cpu, lowest_mask);
+ }
+}
+
+/**
* cpupri_find - find the best (lowest-pri) CPU in the system
* @cp: The cpupri context
* @p: The task
@@ -70,9 +93,11 @@
{
int idx = 0;
int task_pri = convert_prio(p->prio);
+ bool drop_nopreempts = task_pri <= MAX_RT_PRIO;
BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES);
+retry:
for (idx = 0; idx < task_pri; idx++) {
struct cpupri_vec *vec = &cp->pri_to_cpu[idx];
int skip = 0;
@@ -108,7 +133,8 @@
if (lowest_mask) {
cpumask_and(lowest_mask, tsk_cpus_allowed(p), vec->mask);
-
+ if (drop_nopreempts)
+ drop_nopreempt_cpus(lowest_mask);
/*
* We have to ensure that we have at least one bit
* still set in the array, since the map could have
@@ -123,7 +149,14 @@
return 1;
}
-
+ /*
+ * If we can't find any non-preemptible cpu's, retry so we can
+ * find the lowest priority target and avoid priority inversion.
+ */
+ if (drop_nopreempts) {
+ drop_nopreempts = false;
+ goto retry;
+ }
return 0;
}
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 2703e0d..ec90319 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -6,6 +6,7 @@
#include "sched.h"
#include "walt.h"
+#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/irq_work.h>
#include <trace/events/sched.h>
@@ -1489,11 +1490,30 @@
#ifdef CONFIG_SMP
static int find_lowest_rq(struct task_struct *task);
+/*
+ * Return whether the task on the given cpu is currently non-preemptible
+ * while handling a potentially long softint, or if the task is likely
+ * to block preemptions soon because it is a ksoftirq thread that is
+ * handling slow softints.
+ */
+bool
+task_may_not_preempt(struct task_struct *task, int cpu)
+{
+ __u32 softirqs = per_cpu(active_softirqs, cpu) |
+ __IRQ_STAT(cpu, __softirq_pending);
+ struct task_struct *cpu_ksoftirqd = per_cpu(ksoftirqd, cpu);
+
+ return ((softirqs & LONG_SOFTIRQ_MASK) &&
+ (task == cpu_ksoftirqd ||
+ task_thread_info(task)->preempt_count & SOFTIRQ_MASK));
+}
+
static int
select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
{
struct task_struct *curr;
struct rq *rq;
+ bool may_not_preempt;
#ifdef CONFIG_SCHED_HMP
return select_task_rq_rt_hmp(p, cpu, sd_flag, flags);
@@ -1509,7 +1529,17 @@
curr = READ_ONCE(rq->curr); /* unlocked access */
/*
- * If the current task on @p's runqueue is an RT task, then
+ * If the current task on @p's runqueue is a softirq task,
+ * it may run without preemption for a time that is
+ * ill-suited for a waiting RT task. Therefore, try to
+ * wake this RT task on another runqueue.
+ *
+ * Also, if the current task on @p's runqueue is an RT task, then
+ * it may run without preemption for a time that is
+ * ill-suited for a waiting RT task. Therefore, try to
+ * wake this RT task on another runqueue.
+ *
+ * Also, if the current task on @p's runqueue is an RT task, then
* try to see if we can wake this RT task up on another
* runqueue. Otherwise simply start this RT task
* on its current runqueue.
@@ -1530,18 +1560,22 @@
* This test is optimistic, if we get it wrong the load-balancer
* will have to sort it out.
*/
- if (energy_aware() ||
- (curr && unlikely(rt_task(curr)) &&
+ may_not_preempt = task_may_not_preempt(curr, cpu);
+ if (energy_aware() || may_not_preempt ||
+ (unlikely(rt_task(curr)) &&
(tsk_nr_cpus_allowed(curr) < 2 ||
curr->prio <= p->prio))) {
int target = find_lowest_rq(p);
/*
- * Don't bother moving it if the destination CPU is
- * not running a lower priority task.
+ * If cpu is non-preemptible, prefer remote cpu
+ * even if it's running a higher-prio task.
+ * Otherwise: Don't bother moving it if the
+ * destination CPU is not running a lower priority task.
*/
if (target != -1 &&
- p->prio < cpu_rq(target)->rt.highest_prio.curr)
+ (may_not_preempt ||
+ p->prio < cpu_rq(target)->rt.highest_prio.curr))
cpu = target;
}
rcu_read_unlock();
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 3194ae6..28d660b 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -2089,6 +2089,11 @@
__release(rq2->lock);
}
+/*
+ * task_may_not_preempt - check whether a task may not be preemptible soon
+ */
+extern bool task_may_not_preempt(struct task_struct *task, int cpu);
+
#else /* CONFIG_SMP */
/*
@@ -2681,6 +2686,15 @@
extern void clear_ed_task(struct task_struct *p, struct rq *rq);
extern bool early_detection_notify(struct rq *rq, u64 wallclock);
+#ifdef CONFIG_SCHED_HMP
+extern unsigned int power_cost(int cpu, u64 demand);
+#else
+static inline unsigned int power_cost(int cpu, u64 demand)
+{
+ return cpu_max_possible_capacity(cpu);
+}
+#endif
+
#else /* CONFIG_SCHED_WALT */
struct hmp_sched_stats;
@@ -2835,6 +2849,11 @@
return 0;
}
+static inline unsigned int power_cost(int cpu, u64 demand)
+{
+ return SCHED_CAPACITY_SCALE;
+}
+
#endif /* CONFIG_SCHED_WALT */
#ifdef CONFIG_SCHED_HMP
@@ -2849,7 +2868,6 @@
check_for_freq_change(struct rq *rq, bool check_pred, bool check_groups);
extern void fixup_nr_big_tasks(struct hmp_sched_stats *stats,
struct task_struct *p, s64 delta);
-extern unsigned int power_cost(int cpu, u64 demand);
extern unsigned int cpu_temp(int cpu);
extern void pre_big_task_count_change(const struct cpumask *cpus);
extern void post_big_task_count_change(const struct cpumask *cpus);
@@ -2906,11 +2924,6 @@
static inline void fixup_nr_big_tasks(struct hmp_sched_stats *stats,
struct task_struct *p, s64 delta) { }
-static inline unsigned int power_cost(int cpu, u64 demand)
-{
- return SCHED_CAPACITY_SCALE;
-}
-
static inline unsigned int cpu_temp(int cpu)
{
return 0;
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index b38ec53..65f4148 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -935,7 +935,7 @@
if (!sync_cpu_available) {
rq->window_start = 1;
sync_cpu_available = 1;
- atomic_set(&walt_irq_work_lastq_ws, rq->window_start);
+ atomic64_set(&walt_irq_work_lastq_ws, rq->window_start);
} else {
struct rq *sync_rq = cpu_rq(cpumask_any(cpu_online_mask));
@@ -1934,7 +1934,7 @@
if (old_window_start == rq->window_start)
return;
- result = atomic_cmpxchg(&walt_irq_work_lastq_ws, old_window_start,
+ result = atomic64_cmpxchg(&walt_irq_work_lastq_ws, old_window_start,
rq->window_start);
if (result == old_window_start)
irq_work_queue(&rq->irq_work);
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 744fa61..bde8e33 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -57,6 +57,13 @@
DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
+/*
+ * active_softirqs -- per cpu, a mask of softirqs that are being handled,
+ * with the expectation that approximate answers are acceptable and therefore
+ * no synchronization.
+ */
+DEFINE_PER_CPU(__u32, active_softirqs);
+
const char * const softirq_to_name[NR_SOFTIRQS] = {
"HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "IRQ_POLL",
"TASKLET", "SCHED", "HRTIMER", "RCU"
@@ -264,6 +271,7 @@
restart:
/* Reset the pending bitmask before enabling irqs */
set_softirq_pending(0);
+ __this_cpu_write(active_softirqs, pending);
local_irq_enable();
@@ -293,6 +301,7 @@
pending >>= softirq_bit;
}
+ __this_cpu_write(active_softirqs, 0);
rcu_bh_qs();
local_irq_disable();
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 9792763..2aef653 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -49,7 +49,6 @@
#include <linux/sched/deadline.h>
#include <linux/timer.h>
#include <linux/freezer.h>
-#include <linux/delay.h>
#include <asm/uaccess.h>
@@ -1579,41 +1578,22 @@
}
#ifdef CONFIG_HOTPLUG_CPU
-static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
- struct hrtimer_cpu_base *new_base,
- unsigned int i, bool wait,
+static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
+ struct hrtimer_clock_base *new_base,
bool remove_pinned)
{
struct hrtimer *timer;
struct timerqueue_node *node;
struct timerqueue_head pinned;
int is_pinned;
- struct hrtimer_clock_base *old_c_base = &old_base->clock_base[i];
- struct hrtimer_clock_base *new_c_base = &new_base->clock_base[i];
+ bool is_hotplug = !cpu_online(old_base->cpu_base->cpu);
timerqueue_init_head(&pinned);
- while ((node = timerqueue_getnext(&old_c_base->active))) {
+ while ((node = timerqueue_getnext(&old_base->active))) {
timer = container_of(node, struct hrtimer, node);
- if (wait) {
- /* Ensure timers are done running before continuing */
- while (hrtimer_callback_running(timer)) {
- raw_spin_unlock(&old_base->lock);
- raw_spin_unlock(&new_base->lock);
- cpu_relax();
- /*
- * cpu_relax may just be a barrier. Grant the
- * run_hrtimer_list code some time to obtain
- * the spinlock.
- */
- udelay(1);
- raw_spin_lock(&new_base->lock);
- raw_spin_lock_nested(&old_base->lock,
- SINGLE_DEPTH_NESTING);
- }
- } else {
+ if (is_hotplug)
BUG_ON(hrtimer_callback_running(timer));
- }
debug_deactivate(timer);
/*
@@ -1621,7 +1601,7 @@
* timer could be seen as !active and just vanish away
* under us on another CPU
*/
- __remove_hrtimer(timer, old_c_base, HRTIMER_STATE_ENQUEUED, 0);
+ __remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0);
is_pinned = timer->state & HRTIMER_STATE_PINNED;
if (!remove_pinned && is_pinned) {
@@ -1629,7 +1609,7 @@
continue;
}
- timer->base = new_c_base;
+ timer->base = new_base;
/*
* Enqueue the timers on the new cpu. This does not
* reprogram the event device in case the timer
@@ -1638,7 +1618,7 @@
* sort out already expired timers and reprogram the
* event device.
*/
- enqueue_hrtimer(timer, new_c_base);
+ enqueue_hrtimer(timer, new_base);
}
/* Re-queue pinned timers for non-hotplug usecase */
@@ -1646,12 +1626,11 @@
timer = container_of(node, struct hrtimer, node);
timerqueue_del(&pinned, &timer->node);
- enqueue_hrtimer(timer, old_c_base);
+ enqueue_hrtimer(timer, old_base);
}
}
-static void
-__migrate_hrtimers(unsigned int scpu, bool wait, bool remove_pinned)
+static void __migrate_hrtimers(unsigned int scpu, bool remove_pinned)
{
struct hrtimer_cpu_base *old_base, *new_base;
unsigned long flags;
@@ -1668,8 +1647,8 @@
raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
- migrate_hrtimer_list(old_base, new_base, i, wait,
- remove_pinned);
+ migrate_hrtimer_list(&old_base->clock_base[i],
+ &new_base->clock_base[i], remove_pinned);
}
raw_spin_unlock(&old_base->lock);
@@ -1685,13 +1664,13 @@
BUG_ON(cpu_online(scpu));
tick_cancel_sched_timer(scpu);
- __migrate_hrtimers(scpu, false, true);
+ __migrate_hrtimers(scpu, true);
return 0;
}
void hrtimer_quiesce_cpu(void *cpup)
{
- __migrate_hrtimers(*(int *)cpup, true, false);
+ __migrate_hrtimers(*(int *)cpup, false);
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/sound/soc/codecs/audio-ext-clk-up.c b/sound/soc/codecs/audio-ext-clk-up.c
index 39986d6..f12f4ca 100644
--- a/sound/soc/codecs/audio-ext-clk-up.c
+++ b/sound/soc/codecs/audio-ext-clk-up.c
@@ -34,6 +34,7 @@
struct pinctrl *pinctrl;
struct pinctrl_state *sleep;
struct pinctrl_state *active;
+ char __iomem *base;
};
struct audio_ext_ap_clk {
@@ -192,8 +193,10 @@
pr_err("%s afe_set_digital_codec_core_clock failed\n",
__func__);
return ret;
- }
+ }
+ if (pnctrl_info->base)
+ iowrite32(1, pnctrl_info->base);
return 0;
}
@@ -219,6 +222,8 @@
if (ret < 0)
pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n",
__func__, ret);
+ if (pnctrl_info->base)
+ iowrite32(0, pnctrl_info->base);
}
static int audio_ext_lpass_mclk2_prepare(struct clk_hw *hw)
@@ -381,9 +386,11 @@
static int audio_get_pinctrl(struct platform_device *pdev,
enum audio_clk_mux mux)
{
+ struct device *dev = &pdev->dev;
struct pinctrl_info *pnctrl_info;
struct pinctrl *pinctrl;
int ret;
+ u32 reg;
switch (mux) {
case AP_CLK2:
@@ -396,21 +403,20 @@
pnctrl_info = &audio_lpass_mclk2.pnctrl_info;
break;
default:
- dev_err(&pdev->dev, "%s Not a valid MUX ID: %d\n",
+ dev_err(dev, "%s Not a valid MUX ID: %d\n",
__func__, mux);
return -EINVAL;
}
- pnctrl_info = &audio_ap_clk2.pnctrl_info;
if (pnctrl_info->pinctrl) {
- dev_dbg(&pdev->dev, "%s: already requested before\n",
+ dev_dbg(dev, "%s: already requested before\n",
__func__);
return -EINVAL;
}
- pinctrl = devm_pinctrl_get(&pdev->dev);
+ pinctrl = devm_pinctrl_get(dev);
if (IS_ERR_OR_NULL(pinctrl)) {
- dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n",
+ dev_dbg(dev, "%s: Unable to get pinctrl handle\n",
__func__);
return -EINVAL;
}
@@ -418,13 +424,13 @@
/* get all state handles from Device Tree */
pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep");
if (IS_ERR(pnctrl_info->sleep)) {
- dev_err(&pdev->dev, "%s: could not get sleep pinstate\n",
+ dev_err(dev, "%s: could not get sleep pinstate\n",
__func__);
goto err;
}
pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active");
if (IS_ERR(pnctrl_info->active)) {
- dev_err(&pdev->dev, "%s: could not get active pinstate\n",
+ dev_err(dev, "%s: could not get active pinstate\n",
__func__);
goto err;
}
@@ -432,10 +438,22 @@
ret = pinctrl_select_state(pnctrl_info->pinctrl,
pnctrl_info->sleep);
if (ret) {
- dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n",
+ dev_err(dev, "%s: Disable TLMM pins failed with %d\n",
__func__, ret);
goto err;
}
+
+ ret = of_property_read_u32(dev->of_node, "qcom,mclk-clk-reg", ®);
+ if (ret < 0) {
+ dev_dbg(dev, "%s: miss mclk reg\n", __func__);
+ } else {
+ pnctrl_info->base = ioremap(reg, sizeof(u32));
+ if (pnctrl_info->base == NULL) {
+ dev_err(dev, "%s ioremap failed\n", __func__);
+ goto err;
+ }
+ }
+
return 0;
err:
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
index 0942d4a..fcabe77 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -854,8 +854,8 @@
if (!msm_sdw->comp_enabled[comp])
return 0;
- comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 8);
- rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 20);
+ comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 0x20);
+ rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 0x1E0);
if (SND_SOC_DAPM_EVENT_ON(event)) {
/* Enable Compander Clock */
@@ -1044,7 +1044,7 @@
* Add sleep as SWR slave access read takes time.
* Allow for RD_DONE to complete for previous register if any.
*/
- usleep_range(50, 55);
+ usleep_range(100, 105);
/* read_lock */
mutex_lock(&msm_sdw->sdw_read_lock);
@@ -1079,6 +1079,11 @@
sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+ /*
+ * Add sleep as SWR slave write takes time.
+ * Allow for any previous pending write to complete.
+ */
+ usleep_range(50, 55);
for (i = 0; i < len; i += 2) {
/* First Write the Data to register */
ret = regmap_bulk_write(msm_sdw->regmap,
@@ -1656,12 +1661,15 @@
service_nb);
bool adsp_ready = false;
unsigned long timeout;
+ static bool initial_boot = true;
pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
mutex_lock(&msm_sdw->codec_mutex);
switch (opcode) {
case AUDIO_NOTIFIER_SERVICE_DOWN:
+ if (initial_boot)
+ break;
msm_sdw->int_mclk1_enabled = false;
msm_sdw->dev_up = false;
for (i = 0; i < msm_sdw->nr; i++)
@@ -1669,6 +1677,8 @@
SWR_DEVICE_DOWN, NULL);
break;
case AUDIO_NOTIFIER_SERVICE_UP:
+ if (initial_boot)
+ initial_boot = false;
if (!q6core_is_adsp_ready()) {
dev_dbg(msm_sdw->dev, "ADSP isn't ready\n");
timeout = jiffies +
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
index 5f8e3fd..43d54d6 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -37,9 +37,10 @@
#define DRV_NAME "pmic_analog_codec"
#define SDM660_CDC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
- SNDRV_PCM_RATE_48000)
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_192000)
#define SDM660_CDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_3LE)
#define MSM_DIG_CDC_STRING_LEN 80
#define MSM_ANLG_CDC_VERSION_ENTRY_SIZE 32
@@ -1435,11 +1436,11 @@
if (enable) {
snd_soc_update_bits(codec,
MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30);
+ msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON);
snd_soc_update_bits(codec,
MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
snd_soc_update_bits(codec,
MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C);
- msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON);
} else {
snd_soc_update_bits(codec,
MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00);
@@ -3180,7 +3181,7 @@
.name = "msm_anlg_cdc_i2s_rx1",
.id = AIF1_PB,
.playback = {
- .stream_name = "Playback",
+ .stream_name = "PDM Playback",
.rates = SDM660_CDC_RATES,
.formats = SDM660_CDC_FORMATS,
.rate_max = 192000,
@@ -3194,7 +3195,7 @@
.name = "msm_anlg_cdc_i2s_tx1",
.id = AIF1_CAP,
.capture = {
- .stream_name = "Record",
+ .stream_name = "PDM Capture",
.rates = SDM660_CDC_RATES,
.formats = SDM660_CDC_FORMATS,
.rate_max = 48000,
@@ -3759,8 +3760,8 @@
snd_soc_write(codec,
MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93);
- atomic_set(&pdata->int_mclk0_enabled, false);
msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_DOWN);
+ atomic_set(&pdata->int_mclk0_enabled, false);
set_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask);
snd_soc_card_change_online_state(codec->component.card, 0);
@@ -3796,6 +3797,9 @@
msm_anlg_cdc_configure_cap(codec, false, false);
wcd_mbhc_stop(&sdm660_cdc_priv->mbhc);
wcd_mbhc_deinit(&sdm660_cdc_priv->mbhc);
+ /* Disable mechanical detection and set type to insertion */
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1,
+ 0xA0, 0x20);
ret = wcd_mbhc_init(&sdm660_cdc_priv->mbhc, codec, &mbhc_cb,
&intr_ids, wcd_mbhc_registers, true);
if (ret)
@@ -3818,17 +3822,22 @@
bool adsp_ready = false;
bool timedout;
unsigned long timeout;
+ static bool initial_boot = true;
codec = sdm660_cdc_priv->codec;
dev_dbg(codec->dev, "%s: Service opcode 0x%lx\n", __func__, opcode);
switch (opcode) {
case AUDIO_NOTIFIER_SERVICE_DOWN:
+ if (initial_boot)
+ break;
dev_dbg(codec->dev,
"ADSP is about to power down. teardown/reset codec\n");
msm_anlg_cdc_device_down(codec);
break;
case AUDIO_NOTIFIER_SERVICE_UP:
+ if (initial_boot)
+ initial_boot = false;
dev_dbg(codec->dev,
"ADSP is about to power up. bring up codec\n");
@@ -4158,6 +4167,8 @@
snd_soc_dapm_ignore_suspend(dapm, "PDM Playback");
snd_soc_dapm_ignore_suspend(dapm, "PDM Capture");
+ snd_soc_dapm_sync(dapm);
+
return 0;
}
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
index 9d16521..b7efd15 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -1028,7 +1028,7 @@
break;
case DIG_CDC_EVENT_PRE_RX1_INT_ON:
snd_soc_update_bits(codec,
- MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x14);
+ MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x28);
snd_soc_update_bits(codec,
MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10);
snd_soc_update_bits(codec,
@@ -1036,7 +1036,7 @@
break;
case DIG_CDC_EVENT_PRE_RX2_INT_ON:
snd_soc_update_bits(codec,
- MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x14);
+ MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x28);
snd_soc_update_bits(codec,
MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10);
snd_soc_update_bits(codec,
@@ -1044,7 +1044,7 @@
break;
case DIG_CDC_EVENT_POST_RX1_INT_OFF:
snd_soc_update_bits(codec,
- MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x00);
+ MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x00);
snd_soc_update_bits(codec,
MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF);
snd_soc_update_bits(codec,
@@ -1052,7 +1052,7 @@
break;
case DIG_CDC_EVENT_POST_RX2_INT_OFF:
snd_soc_update_bits(codec,
- MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x00);
+ MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x00);
snd_soc_update_bits(codec,
MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF);
snd_soc_update_bits(codec,
@@ -1207,6 +1207,8 @@
snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX2");
snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX3");
+ snd_soc_dapm_sync(dapm);
+
return 0;
}
@@ -1929,8 +1931,12 @@
.stream_name = "AIF1 Playback",
.channels_min = 1,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE,
},
.ops = &msm_dig_dai_ops,
},
@@ -2012,7 +2018,7 @@
const struct regmap_config msm_digital_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
- .val_bits = 32,
+ .val_bits = 8,
.lock = enable_digital_callback,
.unlock = disable_digital_callback,
.cache_type = REGCACHE_FLAT,
@@ -2123,8 +2129,8 @@
}
static const struct dev_pm_ops msm_dig_pm_ops = {
- .suspend = msm_dig_suspend,
- .resume = msm_dig_resume,
+ .suspend_late = msm_dig_suspend,
+ .resume_early = msm_dig_resume,
};
#endif
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index ebcb413..485e060 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -2057,6 +2057,9 @@
mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_right_ocp, mbhc);
if (mbhc->mbhc_cb && mbhc->mbhc_cb->register_notifier)
mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false);
+ if (mbhc->mbhc_fn->wcd_cancel_hs_detect_plug)
+ mbhc->mbhc_fn->wcd_cancel_hs_detect_plug(mbhc,
+ &mbhc->correct_plug_swch);
mutex_destroy(&mbhc->codec_resource_lock);
mutex_destroy(&mbhc->hphl_pa_lock);
mutex_destroy(&mbhc->hphr_pa_lock);
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index 7e217a6..a08b598 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -82,8 +82,15 @@
#define WCD_SPI_WORD_BYTE_CNT (4)
#define WCD_SPI_RW_MULTI_MIN_LEN (16)
-/* Max size is closest multiple of 16 less than 64Kbytes */
-#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 16)
+/* Max size is 32 bytes less than 64Kbytes */
+#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 32)
+
+/*
+ * Max size for the pre-allocated buffers is the max
+ * possible read/write length + 32 bytes for the SPI
+ * read/write command header itself.
+ */
+#define WCD_SPI_RW_MAX_BUF_SIZE (WCD_SPI_RW_MULTI_MAX_LEN + 32)
/* Alignment requirements */
#define WCD_SPI_RW_MIN_ALIGN WCD_SPI_WORD_BYTE_CNT
@@ -149,6 +156,10 @@
/* Completion object to indicate system resume completion */
struct completion resume_comp;
+
+ /* Buffers to hold memory used for transfers */
+ void *tx_buf;
+ void *rx_buf;
};
enum xfer_request {
@@ -230,17 +241,18 @@
struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0];
struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1];
- u8 *tx_buf;
+ u8 *tx_buf = wcd_spi->tx_buf;
u32 frame = 0;
int ret;
dev_dbg(&spi->dev, "%s: remote_addr = 0x%x\n",
__func__, remote_addr);
- tx_buf = kzalloc(WCD_SPI_READ_SINGLE_LEN,
- GFP_KERNEL | GFP_DMA);
- if (!tx_buf)
+ if (!tx_buf) {
+ dev_err(&spi->dev, "%s: tx_buf not allocated\n",
+ __func__);
return -ENOMEM;
+ }
frame |= WCD_SPI_READ_FRAME_OPCODE;
frame |= remote_addr & WCD_CMD_ADDR_MASK;
@@ -256,7 +268,6 @@
rx_xfer->len = sizeof(*val);
ret = spi_sync(spi, &wcd_spi->msg2);
- kfree(tx_buf);
return ret;
}
@@ -267,8 +278,8 @@
{
struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
struct spi_transfer *xfer = &wcd_spi->xfer1;
- u8 *tx_buf;
- u8 *rx_buf;
+ u8 *tx_buf = wcd_spi->tx_buf;
+ u8 *rx_buf = wcd_spi->rx_buf;
u32 frame = 0;
int ret;
@@ -278,15 +289,9 @@
frame |= WCD_SPI_FREAD_FRAME_OPCODE;
frame |= remote_addr & WCD_CMD_ADDR_MASK;
- tx_buf = kzalloc(WCD_SPI_CMD_FREAD_LEN + len,
- GFP_KERNEL | GFP_DMA);
- if (!tx_buf)
- return -ENOMEM;
-
- rx_buf = kzalloc(WCD_SPI_CMD_FREAD_LEN + len,
- GFP_KERNEL | GFP_DMA);
- if (!rx_buf) {
- kfree(tx_buf);
+ if (!tx_buf || !rx_buf) {
+ dev_err(&spi->dev, "%s: %s not allocated\n", __func__,
+ (!tx_buf) ? "tx_buf" : "rx_buf");
return -ENOMEM;
}
@@ -306,8 +311,6 @@
memcpy(data, rx_buf + WCD_SPI_CMD_FREAD_LEN, len);
done:
- kfree(tx_buf);
- kfree(rx_buf);
return ret;
}
@@ -344,7 +347,7 @@
struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
struct spi_transfer *xfer = &wcd_spi->xfer1;
u32 frame = 0;
- u8 *tx_buf;
+ u8 *tx_buf = wcd_spi->tx_buf;
int xfer_len, ret;
dev_dbg(&spi->dev, "%s: addr = 0x%x len = %zd\n",
@@ -356,9 +359,11 @@
frame = cpu_to_be32(frame);
xfer_len = len + sizeof(frame);
- tx_buf = kzalloc(xfer_len, GFP_KERNEL);
- if (!tx_buf)
+ if (!tx_buf) {
+ dev_err(&spi->dev, "%s: tx_buf not allocated\n",
+ __func__);
return -ENOMEM;
+ }
memcpy(tx_buf, &frame, sizeof(frame));
memcpy(tx_buf + sizeof(frame), data, len);
@@ -372,8 +377,6 @@
dev_err(&spi->dev,
"%s: Failed, addr = 0x%x, len = %zd\n",
__func__, remote_addr, len);
- kfree(tx_buf);
-
return ret;
}
@@ -1331,6 +1334,23 @@
spi_message_init(&wcd_spi->msg2);
spi_message_add_tail(&wcd_spi->xfer2[0], &wcd_spi->msg2);
spi_message_add_tail(&wcd_spi->xfer2[1], &wcd_spi->msg2);
+
+ /* Pre-allocate the buffers */
+ wcd_spi->tx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
+ GFP_KERNEL | GFP_DMA);
+ if (!wcd_spi->tx_buf) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ wcd_spi->rx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
+ GFP_KERNEL | GFP_DMA);
+ if (!wcd_spi->rx_buf) {
+ kfree(wcd_spi->tx_buf);
+ wcd_spi->tx_buf = NULL;
+ ret = -ENOMEM;
+ goto done;
+ }
done:
return ret;
}
@@ -1348,6 +1368,11 @@
spi_transfer_del(&wcd_spi->xfer1);
spi_transfer_del(&wcd_spi->xfer2[0]);
spi_transfer_del(&wcd_spi->xfer2[1]);
+
+ kfree(wcd_spi->tx_buf);
+ kfree(wcd_spi->rx_buf);
+ wcd_spi->tx_buf = NULL;
+ wcd_spi->rx_buf = NULL;
}
static const struct component_ops wcd_spi_component_ops = {
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index eb556f8..90d16fb 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -188,7 +188,7 @@
MODULE_PARM_DESC(sido_buck_svs_voltage,
"setting for SVS voltage for SIDO BUCK");
-#define TASHA_TX_UNMUTE_DELAY_MS 25
+#define TASHA_TX_UNMUTE_DELAY_MS 40
static int tx_unmute_delay = TASHA_TX_UNMUTE_DELAY_MS;
module_param(tx_unmute_delay, int, 0664);
@@ -4941,7 +4941,7 @@
int src_num,
int event)
{
- u16 src_paired_reg;
+ u16 src_paired_reg = 0;
struct tasha_priv *tasha;
u16 rx_path_cfg_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
u16 rx_path_ctl_reg = WCD9335_CDC_RX1_RX_PATH_CTL;
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 3c026e64..6df014f 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -505,7 +505,7 @@
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
-#define WCD934X_TX_UNMUTE_DELAY_MS 25
+#define WCD934X_TX_UNMUTE_DELAY_MS 40
static int tx_unmute_delay = WCD934X_TX_UNMUTE_DELAY_MS;
module_param(tx_unmute_delay, int, 0664);
@@ -5473,7 +5473,7 @@
u32 adc, i, mic_bias_found = 0;
int ret = 0;
char *mad_input;
- bool is_adc2_input = false;
+ bool is_adc_input = false;
tavil_mad_input = ucontrol->value.integer.value[0];
@@ -5521,8 +5521,7 @@
snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc);
mad_input_widget = mad_amic_input_widget;
- if (adc == 2)
- is_adc2_input = true;
+ is_adc_input = true;
} else {
/* DMIC type input widget*/
mad_input_widget = tavil_conn_mad_text[tavil_mad_input];
@@ -5530,7 +5529,7 @@
dev_dbg(codec->dev,
"%s: tavil input widget = %s, adc_input = %s\n", __func__,
- mad_input_widget, is_adc2_input ? "true" : "false");
+ mad_input_widget, is_adc_input ? "true" : "false");
for (i = 0; i < card->num_of_dapm_routes; i++) {
if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) {
@@ -5575,8 +5574,8 @@
0x0F, tavil_mad_input);
snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
0x07, mic_bias_found);
- /* for adc2 input, mad should be in micbias mode with BG enabled */
- if (is_adc2_input)
+ /* for all adc inputs, mad should be in micbias mode with BG enabled */
+ if (is_adc_input)
snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
0x88, 0x88);
else
@@ -8578,6 +8577,7 @@
{WCD934X_TLMM_DMIC3_CLK_PINCFG, 0xFF, 0x0a},
{WCD934X_TLMM_DMIC3_DATA_PINCFG, 0xFF, 0x0a},
{WCD934X_CPE_SS_SVA_CFG, 0x60, 0x00},
+ {WCD934X_CPE_SS_CPAR_CFG, 0x10, 0x10},
};
static void tavil_codec_init_reg(struct tavil_priv *priv)
@@ -9072,8 +9072,9 @@
codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
priv = snd_soc_codec_get_drvdata(codec);
- swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev,
- SWR_DEVICE_DOWN, NULL);
+ if (priv->swr.ctrl_data)
+ swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev,
+ SWR_DEVICE_DOWN, NULL);
tavil_dsd_reset(priv->dsd_config);
snd_soc_card_change_online_state(codec->component.card, 0);
for (count = 0; count < NUM_CODEC_DAIS; count++)
diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c
index 0c2f41a..153cc2e 100644
--- a/sound/soc/codecs/wcd_cpe_core.c
+++ b/sound/soc/codecs/wcd_cpe_core.c
@@ -3538,6 +3538,8 @@
pr_debug("%s: enter payload_size = %d Enable %d\n",
__func__, pld_size, enable);
+ memset(&cpe_lab_enable, 0, sizeof(cpe_lab_enable));
+
if (fill_lsm_cmd_header_v0_inband(&cpe_lab_enable.hdr, session->id,
(u8) pld_size, CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
return -EINVAL;
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 4189e59..ef493a8 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -104,6 +104,7 @@
int state;
struct delayed_work ocp_ctl_work;
struct device_node *wsa_rst_np;
+ int pa_mute;
};
#define SWR_SLV_MAX_REG_ADDR 0x390
@@ -170,9 +171,41 @@
return 0;
}
-static const struct snd_kcontrol_new wsa_analog_gain_controls[] = {
+static int wsa881x_get_mute(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = wsa881x->pa_mute;
+
+ return 0;
+}
+
+static int wsa881x_set_mute(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(codec->dev, "%s: mute current %d, new %d\n",
+ __func__, wsa881x->pa_mute, value);
+
+ if (value)
+ snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x80, 0x00);
+ wsa881x->pa_mute = value;
+
+ return 0;
+}
+
+
+static const struct snd_kcontrol_new wsa_snd_controls[] = {
SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
wsa_pa_gain_get, wsa_pa_gain_put),
+ SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
+ wsa881x_get_mute, wsa881x_set_mute),
};
static int codec_debug_open(struct inode *inode, struct file *file)
@@ -1050,8 +1083,8 @@
wsa881x->tz_pdata.codec = codec;
wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read;
wsa881x_init_thermal(&wsa881x->tz_pdata);
- snd_soc_add_codec_controls(codec, wsa_analog_gain_controls,
- ARRAY_SIZE(wsa_analog_gain_controls));
+ snd_soc_add_codec_controls(codec, wsa_snd_controls,
+ ARRAY_SIZE(wsa_snd_controls));
INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work);
return 0;
}
@@ -1092,54 +1125,6 @@
},
};
-static int wsa881x_swr_startup(struct swr_device *swr_dev)
-{
- int ret = 0;
- u8 devnum = 0;
- struct wsa881x_priv *wsa881x;
-
- wsa881x = swr_get_dev_data(swr_dev);
- if (!wsa881x) {
- dev_err(&swr_dev->dev, "%s: wsa881x is NULL\n", __func__);
- return -EINVAL;
- }
-
- /*
- * Add 5msec delay to provide sufficient time for
- * soundwire auto enumeration of slave devices as
- * as per HW requirement.
- */
- usleep_range(5000, 5010);
- ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
- if (ret) {
- dev_dbg(&swr_dev->dev,
- "%s get devnum %d for dev addr %lx failed\n",
- __func__, devnum, swr_dev->addr);
- goto err;
- }
- swr_dev->dev_num = devnum;
-
- wsa881x->regmap = devm_regmap_init_swr(swr_dev,
- &wsa881x_regmap_config);
- if (IS_ERR(wsa881x->regmap)) {
- ret = PTR_ERR(wsa881x->regmap);
- dev_err(&swr_dev->dev, "%s: regmap_init failed %d\n",
- __func__, ret);
- goto err;
- }
-
- ret = snd_soc_register_codec(&swr_dev->dev, &soc_codec_dev_wsa881x,
- NULL, 0);
- if (ret) {
- dev_err(&swr_dev->dev, "%s: Codec registration failed\n",
- __func__);
- goto err;
- }
-
-err:
- return ret;
-}
-
static int wsa881x_gpio_ctrl(struct wsa881x_priv *wsa881x, bool enable)
{
int ret = 0;
@@ -1201,6 +1186,8 @@
{
int ret = 0;
struct wsa881x_priv *wsa881x;
+ u8 devnum = 0;
+ bool pin_state_current = false;
wsa881x = devm_kzalloc(&pdev->dev, sizeof(struct wsa881x_priv),
GFP_KERNEL);
@@ -1231,6 +1218,9 @@
if (ret)
goto err;
}
+ if (wsa881x->wsa_rst_np)
+ pin_state_current = msm_cdc_pinctrl_get_state(
+ wsa881x->wsa_rst_np);
wsa881x_gpio_ctrl(wsa881x, true);
wsa881x->state = WSA881X_DEV_UP;
@@ -1257,8 +1247,45 @@
&codec_debug_ops);
}
}
+
+ /*
+ * Add 5msec delay to provide sufficient time for
+ * soundwire auto enumeration of slave devices as
+ * as per HW requirement.
+ */
+ usleep_range(5000, 5010);
+ ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
+ if (ret) {
+ dev_dbg(&pdev->dev,
+ "%s get devnum %d for dev addr %lx failed\n",
+ __func__, devnum, pdev->addr);
+ goto dev_err;
+ }
+ pdev->dev_num = devnum;
+
+ wsa881x->regmap = devm_regmap_init_swr(pdev,
+ &wsa881x_regmap_config);
+ if (IS_ERR(wsa881x->regmap)) {
+ ret = PTR_ERR(wsa881x->regmap);
+ dev_err(&pdev->dev, "%s: regmap_init failed %d\n",
+ __func__, ret);
+ goto dev_err;
+ }
+
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wsa881x,
+ NULL, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Codec registration failed\n",
+ __func__);
+ goto dev_err;
+ }
+
return 0;
+dev_err:
+ if (pin_state_current == false)
+ wsa881x_gpio_ctrl(wsa881x, false);
+ swr_remove_device(pdev);
err:
return ret;
}
@@ -1392,7 +1419,6 @@
.device_up = wsa881x_swr_up,
.device_down = wsa881x_swr_down,
.reset_device = wsa881x_swr_reset,
- .startup = wsa881x_swr_startup,
};
static int __init wsa881x_codec_init(void)
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 755b62a..f70dd8a 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -113,7 +113,7 @@
SNDRV_PCM_FMTBIT_S24_3LE |
SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index d8fcfa7..8bf7a9a 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -4163,9 +4163,6 @@
mi2s_clk[dai_id].clk_freq_in_hz =
mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
}
-
- if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
- mi2s_clk[dai_id].clk_freq_in_hz = 0;
}
static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
@@ -4214,6 +4211,13 @@
ret = -EINVAL;
goto err;
}
+
+ if (pinctrl_info->pinctrl == NULL) {
+ pr_err("%s: pinctrl_info->pinctrl is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
curr_state = pinctrl_info->curr_state;
pinctrl_info->curr_state = new_state;
pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
@@ -4482,6 +4486,7 @@
struct snd_soc_card *card = rtd->card;
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+ int ret_pinctrl = 0;
dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
@@ -4496,11 +4501,10 @@
goto done;
}
if (index == QUAT_MI2S) {
- ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
- if (ret) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+ if (ret_pinctrl) {
pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret);
- goto done;
+ __func__, ret_pinctrl);
}
}
@@ -4559,6 +4563,7 @@
struct snd_soc_card *card = rtd->card;
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+ int ret_pinctrl = 0;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
@@ -4579,10 +4584,10 @@
mutex_unlock(&mi2s_intf_conf[index].lock);
if (index == QUAT_MI2S) {
- ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
- if (ret)
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret_pinctrl)
pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret);
+ __func__, ret_pinctrl);
}
}
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index e8e4e04..55ec1a5 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -45,6 +45,7 @@
#include <sound/msm-dts-eagle.h>
#include "msm-pcm-routing-v2.h"
+#include "msm-qti-pp-config.h"
#define DSP_PP_BUFFERING_IN_MSEC 25
#define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC 150
@@ -186,7 +187,7 @@
const u32 compr_codecs[] = {
SND_AUDIOCODEC_AC3, SND_AUDIOCODEC_EAC3, SND_AUDIOCODEC_DTS,
- SND_AUDIOCODEC_DSD};
+ SND_AUDIOCODEC_DSD, SND_AUDIOCODEC_TRUEHD};
struct query_audio_effect {
uint32_t mod_id;
@@ -545,12 +546,19 @@
unsigned long flags;
uint64_t read_size;
uint32_t *buff_addr;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret = 0;
if (!prtd) {
pr_err("%s: prtd is NULL\n", __func__);
return;
}
cstream = prtd->cstream;
+ if (!cstream) {
+ pr_err("%s: cstream is NULL\n", __func__);
+ return;
+ }
+
ac = prtd->audio_client;
/*
@@ -718,6 +726,23 @@
prtd->gapless_state.gapless_transition = 0;
spin_unlock_irqrestore(&prtd->lock, flags);
break;
+ case ASM_STREAM_PP_EVENT:
+ pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__);
+ rtd = cstream->private_data;
+ if (!rtd) {
+ pr_err("%s: rtd is NULL\n", __func__);
+ return;
+ }
+
+ ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK,
+ payload);
+ if (ret) {
+ pr_err("%s: failed to inform mixer ctrl. err = %d\n",
+ __func__, ret);
+ return;
+ }
+
+ break;
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: {
pr_debug("ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY\n");
@@ -821,6 +846,10 @@
}
atomic_set(&prtd->close, 0);
break;
+ case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
+ pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
+ __func__);
+ break;
default:
break;
}
@@ -881,7 +910,7 @@
COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
prtd->compr_cap.max_fragments =
COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
- prtd->compr_cap.num_codecs = 15;
+ prtd->compr_cap.num_codecs = 16;
prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
@@ -897,6 +926,7 @@
prtd->compr_cap.codecs[12] = SND_AUDIOCODEC_DTS;
prtd->compr_cap.codecs[13] = SND_AUDIOCODEC_DSD;
prtd->compr_cap.codecs[14] = SND_AUDIOCODEC_APTX;
+ prtd->compr_cap.codecs[15] = SND_AUDIOCODEC_TRUEHD;
}
static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -1151,6 +1181,10 @@
pr_err("%s: CMD DSD Format block failed ret %d\n",
__func__, ret);
break;
+ case FORMAT_TRUEHD:
+ pr_debug("SND_AUDIOCODEC_TRUEHD\n");
+ /* no media format block needed */
+ break;
case FORMAT_APTX:
pr_debug("SND_AUDIOCODEC_APTX\n");
memset(&aptx_cfg, 0x0, sizeof(struct aptx_dec_bt_addr_cfg));
@@ -1948,6 +1982,12 @@
break;
}
+ case SND_AUDIOCODEC_TRUEHD: {
+ pr_debug("%s: SND_AUDIOCODEC_TRUEHD\n", __func__);
+ prtd->codec = FORMAT_TRUEHD;
+ break;
+ }
+
case SND_AUDIOCODEC_APTX: {
pr_debug("%s: SND_AUDIOCODEC_APTX\n", __func__);
prtd->codec = FORMAT_APTX;
@@ -2815,20 +2855,14 @@
SND_AUDIOSTREAMFORMAT_RAW);
break;
case SND_AUDIOCODEC_AC3:
- break;
case SND_AUDIOCODEC_EAC3:
- break;
case SND_AUDIOCODEC_FLAC:
- break;
case SND_AUDIOCODEC_VORBIS:
- break;
case SND_AUDIOCODEC_ALAC:
- break;
case SND_AUDIOCODEC_APE:
- break;
case SND_AUDIOCODEC_DTS:
- break;
case SND_AUDIOCODEC_DSD:
+ case SND_AUDIOCODEC_TRUEHD:
case SND_AUDIOCODEC_APTX:
break;
default:
@@ -3299,6 +3333,7 @@
switch (prtd->codec) {
case FORMAT_MP3:
case FORMAT_MPEG4_AAC:
+ case FORMAT_TRUEHD:
case FORMAT_APTX:
pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
prtd->codec);
@@ -3366,6 +3401,7 @@
case FORMAT_APE:
case FORMAT_DTS:
case FORMAT_DSD:
+ case FORMAT_TRUEHD:
case FORMAT_APTX:
pr_debug("%s: no runtime parameters for codec: %d\n", __func__,
prtd->codec);
@@ -3589,6 +3625,65 @@
return rc;
}
+static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ unsigned long fe_id = kcontrol->private_value;
+ struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+ snd_soc_component_get_drvdata(comp);
+ struct snd_compr_stream *cstream = NULL;
+ struct msm_compr_audio *prtd;
+ int ret = 0, param_length = 0;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received invalid fe_id %lu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cstream = pdata->cstream[fe_id];
+ if (cstream == NULL) {
+ pr_err("%s cstream is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ prtd = cstream->runtime->private_data;
+ if (!prtd) {
+ pr_err("%s: prtd is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (prtd->audio_client == NULL) {
+ pr_err("%s: audio_client is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(¶m_length, ucontrol->value.bytes.data,
+ sizeof(param_length));
+ if ((param_length + sizeof(param_length))
+ >= sizeof(ucontrol->value.bytes.data)) {
+ pr_err("%s param length=%d exceeds limit",
+ __func__, param_length);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = q6asm_send_stream_cmd(prtd->audio_client,
+ ASM_STREAM_CMD_REGISTER_PP_EVENTS,
+ ucontrol->value.bytes.data + sizeof(param_length),
+ param_length);
+ if (ret < 0)
+ pr_err("%s: failed to register pp event. err = %d\n",
+ __func__, ret);
+done:
+ return ret;
+}
+
static int msm_compr_gapless_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -3863,6 +3958,117 @@
return 0;
}
+static int msm_compr_add_audio_adsp_stream_cmd_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CMD;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_cmd_info,
+ .put = msm_compr_adsp_stream_cmd_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
+ fe_audio_adsp_stream_cmd_config_control[0].private_value =
+ rtd->dai_link->id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_audio_adsp_stream_cmd_config_control,
+ ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
+ if (ret < 0)
+ pr_err("%s: failed to add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
+static int msm_compr_add_audio_adsp_stream_callback_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol *kctl;
+
+ struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_callback_info,
+ .get = msm_adsp_stream_callback_get,
+ .put = msm_adsp_stream_callback_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s: rtd is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_audio_adsp_callback_config_control[0].name = mixer_str;
+ fe_audio_adsp_callback_config_control[0].private_value =
+ rtd->dai_link->id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_audio_adsp_callback_config_control,
+ ARRAY_SIZE(fe_audio_adsp_callback_config_control));
+ if (ret < 0) {
+ pr_err("%s: failed to add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+ if (!kctl) {
+ pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl->private_data = NULL;
+free_mixer_str:
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
static int msm_compr_add_dec_runtime_params_control(
struct snd_soc_pcm_runtime *rtd)
{
@@ -4050,6 +4256,16 @@
pr_err("%s: Could not add Compr Audio Effects Control\n",
__func__);
+ rc = msm_compr_add_audio_adsp_stream_cmd_control(rtd);
+ if (rc)
+ pr_err("%s: Could not add Compr ADSP Stream Cmd Control\n",
+ __func__);
+
+ rc = msm_compr_add_audio_adsp_stream_callback_control(rtd);
+ if (rc)
+ pr_err("%s: Could not add Compr ADSP Stream Callback Control\n",
+ __func__);
+
rc = msm_compr_add_query_audio_effect_control(rtd);
if (rc)
pr_err("%s: Could not add Compr Query Audio Effect Control\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 0c46763..dfac5fd 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -4131,12 +4131,13 @@
.stream_name = "INT0 MI2S Playback",
.aif_name = "INT0_MI2S_RX",
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
- SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100,
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S24_3LE,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 192000,
},
.capture = {
.stream_name = "INT0 MI2S Capture",
@@ -4235,12 +4236,13 @@
.stream_name = "INT4 MI2S Playback",
.aif_name = "INT4_MI2S_RX",
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
- SNDRV_PCM_RATE_16000,
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S24_3LE,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 192000,
},
.capture = {
.stream_name = "INT4 MI2S Capture",
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-slim.c b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
index 779a2e6..8115fee 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-slim.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
@@ -313,7 +313,7 @@
struct msm_slim_dai_data *dai_data = NULL;
struct slim_ch prop;
int rc;
- u8 i;
+ u8 i, j;
dai_data = msm_slim_get_dai_data(drv_data, dai);
if (!dai_data) {
@@ -350,10 +350,6 @@
}
}
- /* To decrement the channel ref count*/
- for (i = 0; i < dai_data->ch_cnt; i++)
- slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
-
prop.prot = SLIM_AUTO_ISO;
prop.baser = SLIM_RATE_4000HZ;
prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
@@ -377,6 +373,8 @@
error_define_chan:
error_chan_query:
+ for (j = 0; j < i; j++)
+ slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[j]);
return rc;
}
@@ -386,6 +384,7 @@
struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
struct msm_slim_dma_data *dma_data = NULL;
struct msm_slim_dai_data *dai_data;
+ int i, rc = 0;
dai_data = msm_slim_get_dai_data(drv_data, dai);
dma_data = snd_soc_dai_get_dma_data(dai, stream);
@@ -404,6 +403,15 @@
return;
}
+ for (i = 0; i < dai_data->ch_cnt; i++) {
+ rc = slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
+ if (rc) {
+ dev_err(dai->dev,
+ "%s: dealloc_ch failed, err = %d\n",
+ __func__, rc);
+ }
+ }
+
snd_soc_dai_set_dma_data(dai, stream, NULL);
/* clear prepared state for the dai */
CLR_DAI_STATE(dai_data->status, DAI_STATE_PREPARED);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 1799d0d..a3c7d8c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -37,6 +37,7 @@
#include "msm-pcm-q6-v2.h"
#include "msm-pcm-routing-v2.h"
+#include "msm-qti-pp-config.h"
enum stream_state {
IDLE = 0,
@@ -148,6 +149,8 @@
uint32_t idx = 0;
uint32_t size = 0;
uint8_t buf_index;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret = 0;
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE_V2: {
@@ -224,6 +227,29 @@
}
break;
}
+ case ASM_STREAM_PP_EVENT: {
+ pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__);
+ if (!substream) {
+ pr_err("%s: substream is NULL.\n", __func__);
+ return;
+ }
+
+ rtd = substream->private_data;
+ if (!rtd) {
+ pr_err("%s: rtd is NULL\n", __func__);
+ return;
+ }
+
+ ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK,
+ payload);
+ if (ret) {
+ pr_err("%s: failed to inform mixer ctl. err = %d\n",
+ __func__, ret);
+ return;
+ }
+
+ break;
+ }
case APR_BASIC_RSP_RESULT: {
switch (payload[0]) {
case ASM_SESSION_CMD_RUN_V2:
@@ -253,6 +279,10 @@
}
atomic_set(&prtd->start, 1);
break;
+ case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
+ pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
+ __func__);
+ break;
default:
pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
__func__, payload[0], payload[1]);
@@ -1036,6 +1066,177 @@
.mmap = msm_pcm_mmap,
};
+static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(pcm);
+ struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+ int ret = 0, param_length = 0;
+
+ if (!pdata) {
+ pr_err("%s pdata is NULL\n", __func__);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ prtd = substream->runtime->private_data;
+ if (prtd->audio_client == NULL) {
+ pr_err("%s prtd is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(¶m_length, ucontrol->value.bytes.data,
+ sizeof(param_length));
+ if ((param_length + sizeof(param_length))
+ >= sizeof(ucontrol->value.bytes.data)) {
+ pr_err("%s param length=%d exceeds limit",
+ __func__, param_length);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = q6asm_send_stream_cmd(prtd->audio_client,
+ ASM_STREAM_CMD_REGISTER_PP_EVENTS,
+ ucontrol->value.bytes.data + sizeof(param_length),
+ param_length);
+ if (ret < 0)
+ pr_err("%s: failed to register pp event. err = %d\n",
+ __func__, ret);
+done:
+ return ret;
+}
+
+static int msm_pcm_add_audio_adsp_stream_cmd_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CMD;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_cmd_info,
+ .put = msm_pcm_adsp_stream_cmd_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s rtd is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
+ fe_audio_adsp_stream_cmd_config_control[0].private_value =
+ rtd->dai_link->id;
+ pr_debug("Registering new mixer ctl %s\n", mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_audio_adsp_stream_cmd_config_control,
+ ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
+ if (ret < 0)
+ pr_err("%s: failed add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
+static int msm_pcm_add_audio_adsp_stream_callback_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol *kctl;
+
+ struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_callback_info,
+ .get = msm_adsp_stream_callback_get,
+ .put = msm_adsp_stream_callback_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
+ __func__, rtd->dai_link->name, rtd->dai_link->id,
+ rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_audio_adsp_callback_config_control[0].name = mixer_str;
+ fe_audio_adsp_callback_config_control[0].private_value =
+ rtd->dai_link->id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_audio_adsp_callback_config_control,
+ ARRAY_SIZE(fe_audio_adsp_callback_config_control));
+ if (ret < 0) {
+ pr_err("%s: failed to add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+ if (!kctl) {
+ pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl->private_data = NULL;
+free_mixer_str:
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
{
int rc = 0;
@@ -1550,6 +1751,16 @@
pr_err("%s: Could not add pcm Compress Control %d\n",
__func__, ret);
+ ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
+ if (ret)
+ pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
+ __func__);
+
+ ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
+ if (ret)
+ pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
+ __func__);
+
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 04ece53c..ce2ba75 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -5378,6 +5378,57 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_0,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -7898,6 +7949,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_port_mixer_controls[] = {
@@ -11176,6 +11230,9 @@
SND_SOC_DAPM_MIXER("TERT_TDM_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
tert_tdm_rx_3_mixer_controls,
ARRAY_SIZE(tert_tdm_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_TDM_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tert_tdm_rx_4_mixer_controls,
+ ARRAY_SIZE(tert_tdm_rx_4_mixer_controls)),
SND_SOC_DAPM_MIXER("QUAT_TDM_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
quat_tdm_rx_0_mixer_controls,
ARRAY_SIZE(quat_tdm_rx_0_mixer_controls)),
@@ -12200,6 +12257,24 @@
{"TERT_TDM_RX_3 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"TERT_TDM_RX_3", NULL, "TERT_TDM_RX_3 Audio Mixer"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"TERT_TDM_RX_4 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"TERT_TDM_RX_4", NULL, "TERT_TDM_RX_4 Audio Mixer"},
+
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -13271,6 +13346,7 @@
{"SLIM7_UL_HL", NULL, "HFP_SLIM7_UL_HL"},
{"HFP_SLIM7_UL_HL", "Switch", "SLIMBUS_7_TX"},
{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
+ {"AUX_PCM_RX", NULL, "INTHFP_DL_HL"},
{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
{"MI2S_RX", NULL, "MI2S_DL_HL"},
{"MI2S_UL_HL", NULL, "MI2S_TX"},
@@ -13675,6 +13751,7 @@
{"AUX_PCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"AUX_PCM_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"AUX_PCM_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"AUX_PCM_RX Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Port Mixer"},
{"SEC_AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
@@ -13909,6 +13986,7 @@
{"BE_OUT", NULL, "TERT_TDM_RX_1"},
{"BE_OUT", NULL, "TERT_TDM_RX_2"},
{"BE_OUT", NULL, "TERT_TDM_RX_3"},
+ {"BE_OUT", NULL, "TERT_TDM_RX_4"},
{"BE_OUT", NULL, "QUAT_TDM_RX_0"},
{"BE_OUT", NULL, "QUAT_TDM_RX_1"},
{"BE_OUT", NULL, "QUAT_TDM_RX_2"},
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index c60b27f..c78d429 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -821,6 +821,136 @@
return 0;
}
+
+int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
+ const char *mixer_ctl_name,
+ uint32_t *payload)
+{
+ /* adsp pp event notifier */
+ struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_value control;
+ uint32_t payload_size = 0;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+
+ if (!rtd || !payload) {
+ pr_err("%s: %s is NULL\n", __func__,
+ (!rtd) ? "rtd" : "payload");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_ATOMIC);
+ if (!mixer_str) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name,
+ rtd->pcm->device);
+ kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+ kfree(mixer_str);
+ if (!kctl) {
+ pr_err("%s: failed to get kctl.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ control.id = kctl->id;
+ payload_size = payload[0];
+ /* Copy complete payload */
+ memcpy(control.value.bytes.data, (void *)payload,
+ sizeof(payload_size) + payload_size);
+ kctl->put(kctl, &control);
+ if (rtd->card->snd_card == NULL) {
+ pr_err("%s: snd_card is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ snd_ctl_notify(rtd->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_INFO,
+ &control.id);
+done:
+ return ret;
+}
+
+int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = 512;
+
+ return 0;
+}
+
+int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t payload_size = 0, last_payload_size = 0;
+
+ /* fetch payload size in first four bytes */
+ memcpy(&payload_size, ucontrol->value.bytes.data, sizeof(uint32_t));
+
+ if (kcontrol->private_data == NULL) {
+ /* buffer is empty */
+ kcontrol->private_data =
+ kzalloc(payload_size + sizeof(payload_size),
+ GFP_ATOMIC);
+ if (kcontrol->private_data == NULL)
+ return -ENOMEM;
+ } else {
+ memcpy(&last_payload_size, kcontrol->private_data,
+ sizeof(uint32_t));
+ if (last_payload_size < payload_size) {
+ /* new payload size exceeds old one.
+ * reallocate buffer
+ */
+ kfree(kcontrol->private_data);
+ kcontrol->private_data =
+ kzalloc(payload_size + sizeof(payload_size),
+ GFP_ATOMIC);
+ if (kcontrol->private_data == NULL)
+ return -ENOMEM;
+ }
+ }
+
+ memcpy(kcontrol->private_data, ucontrol->value.bytes.data,
+ sizeof(uint32_t) + payload_size);
+
+ return 0;
+}
+
+int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t payload_size = 0;
+
+ if (kcontrol->private_data == NULL) {
+ pr_err("%s: ASM Stream PP Event Data Unavailable\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(&payload_size, kcontrol->private_data, sizeof(uint32_t));
+ memcpy(ucontrol->value.bytes.data, kcontrol->private_data,
+ sizeof(uint32_t) + payload_size);
+ kfree(kcontrol->private_data);
+ kcontrol->private_data = NULL;
+
+ return 0;
+}
+
+int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = 512;
+
+ return 0;
+}
+
static int msm_multichannel_ec_primary_mic_ch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
index 805fb3e..56fe42e 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
@@ -13,7 +13,17 @@
#define _MSM_QTI_PP_H_
#include <sound/soc.h>
-
+int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
+ const char *mixer_ctl_name,
+ uint32_t *payload);
+int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
#ifdef CONFIG_QTI_PP
void msm_qti_pp_send_eq_values(int fedai_id);
int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, int copp_idx,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 05d123b..ebb8eff 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -5191,7 +5191,7 @@
AFE_API_VERSION_LOOPBACK_CONFIG;
cmd_sidetone.cfg_data.dst_port_id = rx_port_id;
cmd_sidetone.cfg_data.routing_mode = LB_MODE_SIDETONE;
- cmd_sidetone.cfg_data.enable = ((enable == 1) ? sidetone_enable : 0);
+ cmd_sidetone.cfg_data.enable = enable;
pr_debug("%s rx(0x%x) tx(0x%x) enable(%d) mid(0x%x) gain(%d) sidetone_enable(%d)\n",
__func__, rx_port_id, tx_port_id,
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index b52c83b..6064849 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1028,12 +1028,14 @@
}
rtac_set_asm_handle(ac->session, NULL);
- apr_deregister(ac->apr2);
- apr_deregister(ac->apr);
- q6asm_mmap_apr_dereg();
- ac->apr2 = NULL;
- ac->apr = NULL;
- ac->mmap_apr = NULL;
+ if (!atomic_read(&ac->reset)) {
+ apr_deregister(ac->apr2);
+ apr_deregister(ac->apr);
+ q6asm_mmap_apr_dereg();
+ ac->apr2 = NULL;
+ ac->apr = NULL;
+ ac->mmap_apr = NULL;
+ }
q6asm_session_free(ac);
pr_debug("%s: APR De-Register\n", __func__);
@@ -1091,6 +1093,65 @@
return NULL;
}
+int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode,
+ void *param, uint32_t params_length)
+{
+ char *asm_params = NULL;
+ struct apr_hdr hdr;
+ int sz, rc;
+
+ if (!param || !ac) {
+ pr_err("%s: %s is NULL\n", __func__,
+ (!param) ? "param" : "ac");
+ rc = -EINVAL;
+ goto done;
+ }
+
+ sz = sizeof(struct apr_hdr) + params_length;
+ asm_params = kzalloc(sz, GFP_KERNEL);
+ if (!asm_params) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ q6asm_add_hdr_async(ac, &hdr, sizeof(struct apr_hdr) +
+ params_length, TRUE);
+ atomic_set(&ac->cmd_state_pp, -1);
+ hdr.opcode = opcode;
+ memcpy(asm_params, &hdr, sizeof(struct apr_hdr));
+ memcpy(asm_params + sizeof(struct apr_hdr),
+ param, params_length);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
+ if (rc < 0) {
+ pr_err("%s: audio adsp pp register failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_send_param;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state_pp) >= 0), 1 * HZ);
+ if (!rc) {
+ pr_err("%s: timeout, adsp pp register\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_send_param;
+ }
+
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
+ pr_err("%s: DSP returned error[%s] adsp pp register\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state_pp)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state_pp));
+ goto fail_send_param;
+ }
+
+ rc = 0;
+fail_send_param:
+ kfree(asm_params);
+done:
+ return rc;
+}
+
struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
{
struct audio_client *ac;
@@ -1162,6 +1223,7 @@
spin_lock_init(&ac->port[lcnt].dsp_lock);
}
atomic_set(&ac->cmd_state, 0);
+ atomic_set(&ac->cmd_state_pp, 0);
atomic_set(&ac->mem_state, 0);
rc = send_asm_custom_topology(ac);
@@ -1441,7 +1503,6 @@
}
pr_debug("%s: Clearing custom topology\n", __func__);
}
- this_mmap.apr = NULL;
cal_utils_clear_cal_block_q6maps(ASM_MAX_CAL_TYPES, cal_data);
common_client.mmap_apr = NULL;
@@ -1607,6 +1668,8 @@
int32_t ret = 0;
union asm_token_struct asm_token;
uint8_t buf_index;
+ char *pp_event_package = NULL;
+ uint32_t payload_size = 0;
if (ac == NULL) {
pr_err("%s: ac NULL\n", __func__);
@@ -1639,8 +1702,10 @@
if (data->opcode == RESET_EVENTS) {
mutex_lock(&ac->cmd_lock);
atomic_set(&ac->reset, 1);
- if (ac->apr == NULL)
+ if (ac->apr == NULL) {
ac->apr = ac->apr2;
+ ac->apr2 = NULL;
+ }
pr_debug("%s: Reset event is received: %d %d apr[%pK]\n",
__func__,
data->reset_event, data->reset_proc, ac->apr);
@@ -1652,6 +1717,7 @@
atomic_set(&ac->time_flag, 0);
atomic_set(&ac->cmd_state, 0);
atomic_set(&ac->mem_state, 0);
+ atomic_set(&ac->cmd_state_pp, 0);
wake_up(&ac->time_wait);
wake_up(&ac->cmd_wait);
wake_up(&ac->mem_wait);
@@ -1719,14 +1785,29 @@
pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
__func__, payload[0], payload[1]);
if (wakeup_flag) {
- atomic_set(&ac->cmd_state, payload[1]);
+ if (payload[0] ==
+ ASM_STREAM_CMD_SET_PP_PARAMS_V2)
+ atomic_set(&ac->cmd_state_pp,
+ payload[1]);
+ else
+ atomic_set(&ac->cmd_state,
+ payload[1]);
wake_up(&ac->cmd_wait);
}
return 0;
}
- if (atomic_read(&ac->cmd_state) && wakeup_flag) {
- atomic_set(&ac->cmd_state, 0);
- wake_up(&ac->cmd_wait);
+ if (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2) {
+ if (atomic_read(&ac->cmd_state_pp) &&
+ wakeup_flag) {
+ atomic_set(&ac->cmd_state_pp, 0);
+ wake_up(&ac->cmd_wait);
+ }
+ } else {
+ if (atomic_read(&ac->cmd_state) &&
+ wakeup_flag) {
+ atomic_set(&ac->cmd_state, 0);
+ wake_up(&ac->cmd_wait);
+ }
}
if (ac->cb)
ac->cb(data->opcode, data->token,
@@ -1773,6 +1854,17 @@
data->payload_size);
}
break;
+ case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
+ pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS session %d opcode 0x%x token 0x%x src %d dest %d\n",
+ __func__, ac->session,
+ data->opcode, data->token,
+ data->src_port, data->dest_port);
+ if (payload[1] != 0)
+ pr_err("%s: ASM get param error = %d, resuming\n",
+ __func__, payload[1]);
+ atomic_set(&ac->cmd_state_pp, payload[1]);
+ wake_up(&ac->cmd_wait);
+ break;
default:
pr_debug("%s: command[0x%x] not expecting rsp\n",
__func__, payload[0]);
@@ -1944,6 +2036,26 @@
case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
break;
+ case ASM_STREAM_PP_EVENT:
+ pr_debug("%s: ASM_STREAM_PP_EVENT payload[0][0x%x] payload[1][0x%x]",
+ __func__, payload[0], payload[1]);
+ /* repack payload for asm_stream_pp_event
+ * package is composed of size + actual payload
+ */
+ payload_size = data->payload_size;
+ pp_event_package =
+ kzalloc(payload_size + sizeof(payload_size),
+ GFP_ATOMIC);
+ if (!pp_event_package)
+ return -ENOMEM;
+ memcpy((void *)pp_event_package,
+ &payload_size, sizeof(payload_size));
+ memcpy((void *)pp_event_package + sizeof(payload_size),
+ data->payload, payload_size);
+ ac->cb(data->opcode, data->token,
+ (void *)pp_event_package, ac->priv);
+ kfree(pp_event_package);
+ return 0;
case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
__func__, ac->session, payload[0], payload[2],
@@ -2664,6 +2776,9 @@
case FORMAT_GEN_COMPR:
open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
break;
+ case FORMAT_TRUEHD:
+ open.dec_fmt_id = ASM_MEDIA_FMT_TRUEHD;
+ break;
default:
pr_err("%s: Invalid format 0x%x\n", __func__, format);
rc = -EINVAL;
@@ -4184,6 +4299,20 @@
PCM_CHANNEL_LB : PCM_CHANNEL_LS;
lchannel_mapping[5] = use_back_flavor ?
PCM_CHANNEL_RB : PCM_CHANNEL_RS;
+ } else if (channels == 7) {
+ /*
+ * Configured for 5.1 channel mapping + 1 channel for debug
+ * Can be customized based on DSP.
+ */
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
+ lchannel_mapping[3] = PCM_CHANNEL_LFE;
+ lchannel_mapping[4] = use_back_flavor ?
+ PCM_CHANNEL_LB : PCM_CHANNEL_LS;
+ lchannel_mapping[5] = use_back_flavor ?
+ PCM_CHANNEL_RB : PCM_CHANNEL_RS;
+ lchannel_mapping[6] = PCM_CHANNEL_CS;
} else if (channels == 8) {
lchannel_mapping[0] = PCM_CHANNEL_FL;
lchannel_mapping[1] = PCM_CHANNEL_FR;
@@ -6404,7 +6533,7 @@
memset(&multi_ch_gain, 0, sizeof(multi_ch_gain));
sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
q6asm_add_hdr_async(ac, &multi_ch_gain.hdr, sz, TRUE);
- atomic_set(&ac->cmd_state, -1);
+ atomic_set(&ac->cmd_state_pp, -1);
multi_ch_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
multi_ch_gain.param.data_payload_addr_lsw = 0;
multi_ch_gain.param.data_payload_addr_msw = 0;
@@ -6430,20 +6559,20 @@
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
if (!rc) {
pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
multi_ch_gain.data.param_id);
rc = -ETIMEDOUT;
goto fail_cmd;
}
- if (atomic_read(&ac->cmd_state) > 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%s] , set-params paramid[0x%x]\n",
__func__, adsp_err_get_err_str(
- atomic_read(&ac->cmd_state)),
+ atomic_read(&ac->cmd_state_pp)),
multi_ch_gain.data.param_id);
rc = adsp_err_get_lnx_err_code(
- atomic_read(&ac->cmd_state));
+ atomic_read(&ac->cmd_state_pp));
goto fail_cmd;
}
rc = 0;
@@ -6498,7 +6627,7 @@
memset(&multich_gain, 0, sizeof(multich_gain));
sz = sizeof(struct asm_volume_ctrl_multichannel_gain);
q6asm_add_hdr_async(ac, &multich_gain.hdr, sz, TRUE);
- atomic_set(&ac->cmd_state, 1);
+ atomic_set(&ac->cmd_state_pp, -1);
multich_gain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
multich_gain.param.data_payload_addr_lsw = 0;
multich_gain.param.data_payload_addr_msw = 0;
@@ -6536,17 +6665,17 @@
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) <= 0), 5*HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
if (!rc) {
pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
multich_gain.data.param_id);
rc = -EINVAL;
goto done;
}
- if (atomic_read(&ac->cmd_state) < 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%d] , set-params paramid[0x%x]\n",
- __func__, atomic_read(&ac->cmd_state),
- multich_gain.data.param_id);
+ __func__, atomic_read(&ac->cmd_state_pp),
+ multich_gain.data.param_id);
rc = -EINVAL;
goto done;
}
@@ -6574,7 +6703,7 @@
sz = sizeof(struct asm_volume_ctrl_mute_config);
q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
- atomic_set(&ac->cmd_state, -1);
+ atomic_set(&ac->cmd_state_pp, -1);
mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
mute.param.data_payload_addr_lsw = 0;
mute.param.data_payload_addr_msw = 0;
@@ -6596,20 +6725,20 @@
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
if (!rc) {
pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
mute.data.param_id);
rc = -ETIMEDOUT;
goto fail_cmd;
}
- if (atomic_read(&ac->cmd_state) > 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
__func__, adsp_err_get_err_str(
- atomic_read(&ac->cmd_state)),
+ atomic_read(&ac->cmd_state_pp)),
mute.data.param_id);
rc = adsp_err_get_lnx_err_code(
- atomic_read(&ac->cmd_state));
+ atomic_read(&ac->cmd_state_pp));
goto fail_cmd;
}
rc = 0;
@@ -6648,7 +6777,7 @@
ad->data.param_id = param_id;
ad->data.param_size = size;
ad->data.reserved = 0;
- atomic_set(&ac->cmd_state, -1);
+ atomic_set(&ac->cmd_state_pp, -1);
if (po) {
struct list_head *ptr, *next;
@@ -6700,7 +6829,7 @@
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 1*HZ);
if (!rc) {
pr_err("DTS_EAGLE_ASM - %s: timeout, set-params paramid[0x%x]\n",
__func__, ad->data.param_id);
@@ -6708,12 +6837,12 @@
goto fail_cmd;
}
- if (atomic_read(&ac->cmd_state) > 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%s]\n",
__func__, adsp_err_get_err_str(
- atomic_read(&ac->cmd_state)));
+ atomic_read(&ac->cmd_state_pp)));
rc = adsp_err_get_lnx_err_code(
- atomic_read(&ac->cmd_state));
+ atomic_read(&ac->cmd_state_pp));
goto fail_cmd;
}
rc = 0;
@@ -6870,7 +6999,7 @@
sz = sizeof(struct asm_volume_ctrl_master_gain);
q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
- atomic_set(&ac->cmd_state, -1);
+ atomic_set(&ac->cmd_state_pp, -1);
vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
vol.param.data_payload_addr_lsw = 0;
vol.param.data_payload_addr_msw = 0;
@@ -6892,20 +7021,20 @@
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
if (!rc) {
pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
vol.data.param_id);
rc = -ETIMEDOUT;
goto fail_cmd;
}
- if (atomic_read(&ac->cmd_state) > 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
__func__, adsp_err_get_err_str(
- atomic_read(&ac->cmd_state)),
+ atomic_read(&ac->cmd_state_pp)),
vol.data.param_id);
rc = adsp_err_get_lnx_err_code(
- atomic_read(&ac->cmd_state));
+ atomic_read(&ac->cmd_state_pp));
goto fail_cmd;
}
@@ -7007,7 +7136,7 @@
sz = sizeof(struct asm_soft_pause_params);
q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
- atomic_set(&ac->cmd_state, -1);
+ atomic_set(&ac->cmd_state_pp, -1);
softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
softpause.param.data_payload_addr_lsw = 0;
@@ -7034,20 +7163,20 @@
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
if (!rc) {
pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
softpause.data.param_id);
rc = -ETIMEDOUT;
goto fail_cmd;
}
- if (atomic_read(&ac->cmd_state) > 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
__func__, adsp_err_get_err_str(
- atomic_read(&ac->cmd_state)),
+ atomic_read(&ac->cmd_state_pp)),
softpause.data.param_id);
rc = adsp_err_get_lnx_err_code(
- atomic_read(&ac->cmd_state));
+ atomic_read(&ac->cmd_state_pp));
goto fail_cmd;
}
rc = 0;
@@ -7087,7 +7216,7 @@
sz = sizeof(struct asm_soft_step_volume_params);
q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
- atomic_set(&ac->cmd_state, -1);
+ atomic_set(&ac->cmd_state_pp, -1);
softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
softvol.param.data_payload_addr_lsw = 0;
softvol.param.data_payload_addr_msw = 0;
@@ -7112,20 +7241,20 @@
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
if (!rc) {
pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
softvol.data.param_id);
rc = -ETIMEDOUT;
goto fail_cmd;
}
- if (atomic_read(&ac->cmd_state) > 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
__func__, adsp_err_get_err_str(
- atomic_read(&ac->cmd_state)),
+ atomic_read(&ac->cmd_state_pp)),
softvol.data.param_id);
rc = adsp_err_get_lnx_err_code(
- atomic_read(&ac->cmd_state));
+ atomic_read(&ac->cmd_state_pp));
goto fail_cmd;
}
rc = 0;
@@ -7174,7 +7303,7 @@
sz = sizeof(struct asm_eq_params);
eq_params = (struct msm_audio_eq_stream_config *) eq_p;
q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
- atomic_set(&ac->cmd_state, -1);
+ atomic_set(&ac->cmd_state_pp, -1);
eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
eq.param.data_payload_addr_lsw = 0;
@@ -7219,20 +7348,20 @@
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 5*HZ);
if (!rc) {
pr_err("%s: timeout, set-params paramid[0x%x]\n", __func__,
eq.data.param_id);
rc = -ETIMEDOUT;
goto fail_cmd;
}
- if (atomic_read(&ac->cmd_state) > 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%s] set-params paramid[0x%x]\n",
__func__, adsp_err_get_err_str(
- atomic_read(&ac->cmd_state)),
+ atomic_read(&ac->cmd_state_pp)),
eq.data.param_id);
rc = adsp_err_get_lnx_err_code(
- atomic_read(&ac->cmd_state));
+ atomic_read(&ac->cmd_state_pp));
goto fail_cmd;
}
rc = 0;
@@ -7850,7 +7979,7 @@
q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
sizeof(struct asm_stream_cmd_set_pp_params_v2) +
params_length), TRUE);
- atomic_set(&ac->cmd_state, -1);
+ atomic_set(&ac->cmd_state_pp, -1);
hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
payload_params.data_payload_addr_lsw = 0;
payload_params.data_payload_addr_msw = 0;
@@ -7869,18 +7998,18 @@
goto fail_send_param;
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) >= 0), 1*HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 1*HZ);
if (!rc) {
pr_err("%s: timeout, audio effects set-params\n", __func__);
rc = -ETIMEDOUT;
goto fail_send_param;
}
- if (atomic_read(&ac->cmd_state) > 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%s] set-params\n",
__func__, adsp_err_get_err_str(
- atomic_read(&ac->cmd_state)));
+ atomic_read(&ac->cmd_state_pp)));
rc = adsp_err_get_lnx_err_code(
- atomic_read(&ac->cmd_state));
+ atomic_read(&ac->cmd_state_pp));
goto fail_send_param;
}
@@ -8733,7 +8862,7 @@
q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
sizeof(struct asm_stream_cmd_set_pp_params_v2)), TRUE);
- atomic_set(&ac->cmd_state, -1);
+ atomic_set(&ac->cmd_state_pp, -1);
hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
payload_params.data_payload_addr_lsw =
lower_32_bits(cal_block->cal_data.paddr);
@@ -8759,15 +8888,15 @@
goto free;
}
rc = wait_event_timeout(ac->cmd_wait,
- (atomic_read(&ac->cmd_state) >= 0), 5 * HZ);
+ (atomic_read(&ac->cmd_state_pp) >= 0), 5 * HZ);
if (!rc) {
pr_err("%s: timeout, audio audstrm cal send\n", __func__);
rc = -ETIMEDOUT;
goto free;
}
- if (atomic_read(&ac->cmd_state) > 0) {
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
pr_err("%s: DSP returned error[%d] audio audstrm cal send\n",
- __func__, atomic_read(&ac->cmd_state));
+ __func__, atomic_read(&ac->cmd_state_pp));
rc = -EINVAL;
goto free;
}
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index d6ad97d..c98b1f0 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -496,7 +496,7 @@
bool q6core_is_adsp_ready(void)
{
- int rc;
+ int rc = 0;
bool ret = false;
struct apr_hdr hdr;
@@ -509,21 +509,23 @@
mutex_lock(&(q6core_lcl.cmd_lock));
ocm_core_open();
- q6core_lcl.bus_bw_resp_received = 0;
- rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
- if (rc < 0) {
- pr_err("%s: Get ADSP state APR packet send event %d\n",
- __func__, rc);
- goto bail;
- }
+ if (q6core_lcl.core_handle_q) {
+ q6core_lcl.bus_bw_resp_received = 0;
+ rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
+ if (rc < 0) {
+ pr_err("%s: Get ADSP state APR packet send event %d\n",
+ __func__, rc);
+ goto bail;
+ }
- rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
- (q6core_lcl.bus_bw_resp_received == 1),
- msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
- if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
- /* ensure to read updated param by callback thread */
- rmb();
- ret = !!q6core_lcl.param;
+ rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
+ (q6core_lcl.bus_bw_resp_received == 1),
+ msecs_to_jiffies(Q6_READY_TIMEOUT_MS));
+ if (rc > 0 && q6core_lcl.bus_bw_resp_received) {
+ /* ensure to read updated param by callback thread */
+ rmb();
+ ret = !!q6core_lcl.param;
+ }
}
bail:
pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index 08ddde4..799d1be 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -1240,14 +1240,12 @@
mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
cal_block = cal_utils_get_only_cal_block(
lsm_common.cal_data[LSM_CAL_IDX]);
- if (cal_block == NULL)
- goto unlock;
- if (cal_block->cal_data.size <= 0) {
+ if (!cal_block || cal_block->cal_data.size <= 0) {
pr_debug("%s: No cal to send!\n", __func__);
- rc = -EINVAL;
goto unlock;
}
+
if (cal_block->cal_data.size != client->lsm_cal_size) {
pr_err("%s: Cal size %zd doesn't match lsm cal size %d\n",
__func__, cal_block->cal_data.size,
diff --git a/sound/soc/msm/sdm660-common.c b/sound/soc/msm/sdm660-common.c
index f1fbce3..eddcb45 100644
--- a/sound/soc/msm/sdm660-common.c
+++ b/sound/soc/msm/sdm660-common.c
@@ -2412,9 +2412,6 @@
mi2s_clk[dai_id].clk_freq_in_hz =
mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
}
-
- if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
- mi2s_clk[dai_id].clk_freq_in_hz = 0;
}
static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
diff --git a/sound/soc/msm/sdm660-external.c b/sound/soc/msm/sdm660-external.c
index b603b8a..2c3d7fc 100644
--- a/sound/soc/msm/sdm660-external.c
+++ b/sound/soc/msm/sdm660-external.c
@@ -1609,6 +1609,9 @@
snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
+ } else {
+ snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT1");
+ snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT2");
}
snd_soc_dapm_sync(dapm);
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 130cc56..22d6e0e 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -3934,6 +3934,13 @@
ret = -EINVAL;
goto err;
}
+
+ if (pinctrl_info->pinctrl == NULL) {
+ pr_err("%s: pinctrl_info->pinctrl is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
curr_state = pinctrl_info->curr_state;
pinctrl_info->curr_state = new_state;
pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
@@ -4202,6 +4209,7 @@
struct snd_soc_card *card = rtd->card;
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+ int ret_pinctrl = 0;
dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
@@ -4216,12 +4224,10 @@
goto err;
}
if (index == QUAT_MI2S) {
- ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
- if (ret) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+ if (ret_pinctrl)
pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret);
- goto err;
- }
+ __func__, ret_pinctrl);
}
/*
* Muxtex protection in case the same MI2S
@@ -4278,6 +4284,7 @@
struct snd_soc_card *card = rtd->card;
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+ int ret_pinctrl = 0;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
@@ -4298,10 +4305,10 @@
mutex_unlock(&mi2s_intf_conf[index].lock);
if (index == QUAT_MI2S) {
- ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
- if (ret)
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret_pinctrl)
pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret);
+ __func__, ret_pinctrl);
}
}